From 095fafb3ef5434d02e30682d2e9c367981f8ad67 Mon Sep 17 00:00:00 2001 From: "Scott R. Shinn" Date: Fri, 14 Dec 2018 09:11:06 -0500 Subject: [PATCH] JSON output support for archives.log and agent_control Merge from Pedro S agent_control changes: Adds the -j output modifier to agent_control for simple json format archives.log changes: yes will also modify archives.log output to format in json. Note: finer tuned configuration setting for this is planned in another pull request. Signed-off-by: Scott R. Shinn --- src/addagent/manage_agents.c | 4 +- src/addagent/manage_agents.h | 2 +- src/addagent/manage_keys.c | 2 +- src/addagent/validate.c | 14 +- src/analysisd/alerts/getloglocation.c | 31 ++- src/analysisd/alerts/getloglocation.h | 2 + src/analysisd/analysisd.c | 1 + src/analysisd/format/json_extended.c | 366 ++++++++++++++++++++++++++ src/analysisd/format/json_extended.h | 37 +++ src/analysisd/format/to_json.c | 170 +++++++++++- src/analysisd/format/to_json.h | 2 +- src/analysisd/output/jsonout.c | 12 + src/analysisd/output/jsonout.h | 1 + src/headers/defs.h | 1 + src/monitord/manage_files.c | 41 ++- src/util/agent_control.c | 24 +- src/util/rootcheck_control.c | 2 +- src/util/syscheck_control.c | 2 +- src/util/syscheck_update.c | 2 +- 19 files changed, 691 insertions(+), 25 deletions(-) create mode 100644 src/analysisd/format/json_extended.c create mode 100644 src/analysisd/format/json_extended.h diff --git a/src/addagent/manage_agents.c b/src/addagent/manage_agents.c index 2e05bb280..3b7073e7c 100644 --- a/src/addagent/manage_agents.c +++ b/src/addagent/manage_agents.c @@ -320,7 +320,7 @@ int remove_agent() - if (!print_agents(0, 0, 0)) { + if (!print_agents(0, 0, 0, 0)) { printf(NO_AGENT); return (0); } @@ -412,7 +412,7 @@ int remove_agent() int list_agents(int cmdlist) { - if (!print_agents(0, 0, 0)) { + if (!print_agents(0, 0, 0, 0)) { printf(NO_AGENT); } diff --git a/src/addagent/manage_agents.h b/src/addagent/manage_agents.h index 7b497254b..5547a3ae4 100644 --- a/src/addagent/manage_agents.h +++ b/src/addagent/manage_agents.h @@ -41,7 +41,7 @@ double OS_AgentAntiquity(const char *id); void FormatID(char *id); /* Print available agents */ -int print_agents(int print_status, int active_only, int csv_output); +int print_agents(int print_status, int active_only, int csv_output, int json_output); int list_agents(int cmdlist); /* Clear a line */ diff --git a/src/addagent/manage_keys.c b/src/addagent/manage_keys.c index 317549a12..85abed48b 100644 --- a/src/addagent/manage_keys.c +++ b/src/addagent/manage_keys.c @@ -197,7 +197,7 @@ int k_extract(const char *cmdextract) exit(1); } } else { - if (!print_agents(0, 0, 0)) { + if (!print_agents(0, 0, 0, 0)) { printf(NO_AGENT); printf(PRESS_ENTER); read_from_user(); diff --git a/src/addagent/validate.c b/src/addagent/validate.c index ad4902e75..3663e06a0 100644 --- a/src/addagent/validate.c +++ b/src/addagent/validate.c @@ -466,7 +466,7 @@ double OS_AgentAntiquity(const char *id) } /* Print available agents */ -int print_agents(int print_status, int active_only, int csv_output) +int print_agents(int print_status, int active_only, int csv_output, int json_output) { int total = 0; FILE *fp; @@ -520,11 +520,11 @@ int print_agents(int print_status, int active_only, int csv_output) } if (csv_output) { - printf("%s,%s,%s,%s,\n", line_read, name, ip, - print_agent_status(agt_status)); - } else { - printf(PRINT_AGENT_STATUS, line_read, name, ip, - print_agent_status(agt_status)); + printf("%s,%s,%s,%s,\n", line_read, name, ip, print_agent_status(agt_status)); + }else if (json_output) { + printf(", { \"ID\" : \"%s\", \"Name\" : \"%s\", \"IP\": \"%s\", \"Status\" : \"%s\" }",line_read, name, ip, print_agent_status(agt_status)); + } else { + printf(PRINT_AGENT_STATUS, line_read, name, ip, print_agent_status(agt_status)); } } else { printf(PRINT_AGENT, line_read, name, ip); @@ -540,7 +540,7 @@ int print_agents(int print_status, int active_only, int csv_output) DIR *dirp; struct dirent *dp; - if (!csv_output) { + if (!csv_output && !json_output) { printf("\nList of agentless devices:\n"); } diff --git a/src/analysisd/alerts/getloglocation.c b/src/analysisd/alerts/getloglocation.c index 76d615cbf..b80de8007 100644 --- a/src/analysisd/alerts/getloglocation.c +++ b/src/analysisd/alerts/getloglocation.c @@ -17,6 +17,7 @@ FILE *_eflog; FILE *_aflog; FILE *_fflog; FILE *_jflog; +FILE *_ejflog; /* Global variables */ static int __crt_day; @@ -24,7 +25,7 @@ static char __elogfile[OS_FLSIZE + 1]; static char __alogfile[OS_FLSIZE + 1]; static char __flogfile[OS_FLSIZE + 1]; static char __jlogfile[OS_FLSIZE + 1]; - +static char __ejlogfile[OS_FLSIZE + 1]; void OS_InitLog() { @@ -37,11 +38,13 @@ void OS_InitLog() memset(__elogfile, '\0', OS_FLSIZE + 1); memset(__flogfile, '\0', OS_FLSIZE + 1); memset(__jlogfile, '\0', OS_FLSIZE + 1); + memset(__ejlogfile, '\0', OS_FLSIZE + 1); _eflog = NULL; _aflog = NULL; _fflog = NULL; _jflog = NULL; + _ejflog = NULL; /* Set the umask */ umask(0027); @@ -53,7 +56,8 @@ int OS_GetLogLocation(const Eventinfo *lf) * Check if the year directory is there * If not, create it. Same for the month directory. */ - + + /* For the events */ if (_eflog) { if (ftell(_eflog) == 0) { @@ -95,7 +99,30 @@ int OS_GetLogLocation(const Eventinfo *lf) if (link(__elogfile, EVENTS_DAILY) == -1) { ErrorExit(LINK_ERROR, ARGV0, __elogfile, EVENTS_DAILY, errno, strerror(errno)); } + /* For the events in JSON */ + if (Config.jsonout_output) { + /* Create the json archives logfile name */ + snprintf(__ejlogfile, OS_FLSIZE, "%s/%d/%s/ossec-%s-%02d.json", + EVENTS, + lf->year, + lf->mon, + "archive", + lf->day); + + _ejflog = fopen(__ejlogfile, "a"); + if (!_ejflog) { + ErrorExit("%s: Error opening logfile: '%s'", ARGV0, __ejlogfile); + } + + /* Create a symlink */ + unlink(EVENTSJSON_DAILY); + + if (link(__ejlogfile, EVENTSJSON_DAILY) == -1) { + ErrorExit(LINK_ERROR, ARGV0, __ejlogfile, EVENTSJSON_DAILY, errno, strerror(errno)); + } + } + /* For the alerts logs */ if (_aflog) { if (ftell(_aflog) == 0) { diff --git a/src/analysisd/alerts/getloglocation.h b/src/analysisd/alerts/getloglocation.h index 493928650..30396c618 100644 --- a/src/analysisd/alerts/getloglocation.h +++ b/src/analysisd/alerts/getloglocation.h @@ -23,9 +23,11 @@ int OS_GetLogLocation(const Eventinfo *lf); /* Global declarations */ extern FILE *_eflog; +extern FILE *_ejflog; extern FILE *_aflog; extern FILE *_fflog; extern FILE *_jflog; +extern FILE *_ejflog; #endif /* __GETLL_H */ diff --git a/src/analysisd/analysisd.c b/src/analysisd/analysisd.c index 6ed5a99d3..1f8844eb7 100644 --- a/src/analysisd/analysisd.c +++ b/src/analysisd/analysisd.c @@ -1030,6 +1030,7 @@ void OS_ReadMSG_analysisd(int m_queue) /* If configured to log all, do it */ if (Config.logall) { OS_Store(lf); + jsonout_output_archive(lf); } CLMEM: diff --git a/src/analysisd/format/json_extended.c b/src/analysisd/format/json_extended.c new file mode 100644 index 000000000..8afd250a5 --- /dev/null +++ b/src/analysisd/format/json_extended.c @@ -0,0 +1,366 @@ +/* Copyright (C) 2015 Wazuh Inc + * All rights reserved. + * + */ + +#include "json_extended.h" +#include + +void W_ParseJSON(cJSON *root, const Eventinfo *lf){ + // Parse hostname & Parse AGENTIP + if(lf->hostname){ + W_JSON_ParseHostname(root, lf->hostname); + W_JSON_ParseAgentIP(root, lf); + } + // Parse timestamp + if(lf->year && lf->mon && lf->day && lf->hour){ + W_JSON_ParseTimestamp(root, lf); + } + // Parse Location + if (lf->location) { + W_JSON_ParseLocation(root,lf); + } + // Parse groups && Parse PCIDSS && Parse CIS + if (lf->generated_rule->group) { + W_JSON_ParseGroups(root,lf); + W_JSON_ParsePCIDSS(root); + W_JSON_ParseCIS(root); + } + // Parse CIS and PCIDSS rules from rootcheck .txt benchmarks + if (lf->full_log) { + W_JSON_ParseRootcheckCIS(root,lf); + W_JSON_ParseRootcheckPCIDSS(root,lf); + } + // TODO: Where did the alert came from? rootcheck or analysid? Maybe we don't need to search por pci or cis twice. + + + } + // Getting PCI field from rootcheck rules benchmarks .txt + void W_JSON_ParseRootcheckPCIDSS(cJSON *root, const Eventinfo *lf){ + regex_t r; + cJSON *groups; + cJSON *rule; + cJSON *pci; + + const char * regex_text; + const char * find_text; + char results[2][100]; + int matches; + char fullog[strlen(lf->full_log)]; + char buffer[25]; + // Getting groups object JSON + rule = cJSON_GetObjectItem(root,"rule"); + groups = cJSON_GetObjectItem(rule,"groups"); + // Getting full log string + strcpy(fullog, lf->full_log); + // Searching regex + regex_text = "PCI - ([[:digit:]]+[.[:digit:]]*) -"; + find_text = fullog; + compile_regex(& r, regex_text); + + matches = match_regex(& r, find_text, results, 1); + if(matches == -1){ + cJSON_AddItemToObject(rule,"PCI_DSS", pci = cJSON_CreateArray()); + memset(buffer, '\0', sizeof(buffer)); + strncpy(buffer, results[0], 20); + cJSON_AddItemToArray(groups, cJSON_CreateString("pci_dss")); + cJSON_AddItemToArray(pci, cJSON_CreateString(buffer)); + } + regfree (& r); +} + + // Getting CIS field from rootcheck rules benchmarks .txt + void W_JSON_ParseRootcheckCIS(cJSON *root, const Eventinfo *lf){ + regex_t r; + cJSON *groups; + cJSON *rule; + cJSON *cis; + + const char * regex_text; + const char * find_text; + char results[2][100]; + int matches; + char fullog[strlen(lf->full_log)]; + char buffer[150]; + // Getting groups object JSON + rule = cJSON_GetObjectItem(root,"rule"); + groups = cJSON_GetObjectItem(rule,"groups"); + // Getting full log string + strcpy(fullog, lf->full_log); + // Searching regex + regex_text = "CIS - ([[:alnum:]]+[ [:alnum:]]*) - ([[:digit:]]+[.[:digit:]]*) -"; + find_text = fullog; + compile_regex(& r, regex_text); + + matches = match_regex(& r, find_text, results, 2); + if(matches == -1){ + cJSON_AddItemToArray(groups, cJSON_CreateString("cis")); + cJSON_AddItemToObject(rule,"CIS", cis = cJSON_CreateArray()); + memset(buffer, '\0', sizeof(buffer)); + strncpy(buffer, results[1], 20); + strncat(buffer, " ", 20); + strncat(buffer, results[0], 20); + cJSON_AddItemToArray(cis, cJSON_CreateString(buffer)); + } + regfree (& r); +} + + + // Getting CIS field from rule groups + void W_JSON_ParseCIS(cJSON *root){ + cJSON *groups; + cJSON *group; + cJSON *rule; + cJSON *cis; + cis = cJSON_CreateArray(); + int i; + regex_t r; + const char * regex_text; + int totalGroups; + char results[2][100]; + int matches; + char buffer[150]; + int foundCIS = 0; + // Getting groups object JSON + rule = cJSON_GetObjectItem(root,"rule"); + groups = cJSON_GetObjectItem(rule,"groups"); + // Counting total groups + totalGroups = cJSON_GetArraySize(groups); + // Set regex! CAUTION !=!=!=!=!=!=!=! Start with '"' because JSON PRINT function give the string like that + regex_text = "^\"cis_([[:alnum:]]+[ [:alnum:]]*)_([[:digit:]]+[.[:digit:]]*)"; + compile_regex(& r, regex_text); + for(i = 0; i < totalGroups; i++){ + group = cJSON_GetArrayItem(groups,i); + matches = match_regex(& r, cJSON_Print(group), results, 2); + if(matches == -1){ + if(foundCIS == 0){ + foundCIS = 1; + cJSON_AddItemToArray(groups, cJSON_CreateString("cis")); + cJSON_AddItemToObject(rule,"CIS", cis); + } + memset(buffer, '\0', sizeof(buffer)); + strncpy(buffer, results[1], 20); + strncat(buffer, " ", 20); + strncat(buffer, results[0], 20); + cJSON_AddItemToArray(cis, cJSON_CreateString(buffer)); + + } + } + // Delete old groups + int counter = 0; + while(counter < cJSON_GetArraySize(groups)){ + group = cJSON_GetArrayItem(groups,counter); + matches = match_regex(& r, cJSON_Print(group), results, 2); + if(matches == -1){ + cJSON_DeleteItemFromArray(groups,counter); + counter--; + } + counter++; + } + regfree (& r); + } + + // Getting PCI DSS field from rule groups + void W_JSON_ParsePCIDSS(cJSON *root){ + cJSON *groups; + cJSON *group; + cJSON *rule; + cJSON *pci; + pci = cJSON_CreateArray(); + int i; + regex_t r; + const char * regex_text; + int totalGroups; + int foundPCI = 0; + char results[2][100]; + int matches; + char buffer[15]; + // Getting groups object JSON + rule = cJSON_GetObjectItem(root,"rule"); + groups = cJSON_GetObjectItem(rule,"groups"); + // Counting total groups + totalGroups = cJSON_GetArraySize(groups); + // Set regex! CAUTION !=!=!=!=!=!=!=! Start with '"' because JSON PRINT function give the string like that + regex_text = "^\"pci_dss_([[:digit:]]+[.[:digit:]]*)"; + compile_regex(& r, regex_text); + + for(i = 0; i < totalGroups; i++){ + group = cJSON_GetArrayItem(groups,i); + matches = match_regex(& r, cJSON_Print(group), results, 1); + if(matches == -1){ + //cJSON_DeleteItemFromArray(groups,i); + if(foundPCI == 0){ + foundPCI = 1; + cJSON_AddItemToObject(rule,"PCI_DSS", pci); + cJSON_AddItemToArray(groups, cJSON_CreateString("pci_dss")); + } + memset(buffer, '\0', sizeof(buffer)); + strncpy(buffer, results[0], 10); + cJSON_AddItemToArray(pci, cJSON_CreateString(buffer)); + + } + } + // Delete old groups + int counter = 0; + while(counter < cJSON_GetArraySize(groups)){ + group = cJSON_GetArrayItem(groups,counter); + matches = match_regex(& r, cJSON_Print(group), results, 1); + if(matches == -1){ + cJSON_DeleteItemFromArray(groups,counter); + counter--; + } + counter++; + } + regfree (& r); + } + +// STRTOK every "-" delimiter to get differents groups to our json array. + void W_JSON_ParseGroups(cJSON *root, const Eventinfo *lf){ + cJSON *groups; + cJSON *rule; + rule = cJSON_GetObjectItem(root,"rule"); + cJSON_AddItemToObject(rule,"groups", groups = cJSON_CreateArray()); + + char buffer[strlen(lf->generated_rule->group)]; + strcpy(buffer, lf->generated_rule->group); + char delim[2]; + delim[0] = ','; + delim[1] = 0; + char* token = strtok(buffer, delim); + while (token) + { + cJSON_AddItemToArray(groups, cJSON_CreateString(strdup(token))); + token = strtok(0, delim); + } + free(token); + } + +// If hostname being with "(" means that alerts came from an agent, so we will remove the brakets +// ** TODO ** Regex instead str_cut +void W_JSON_ParseHostname(cJSON *root, char *hostname){ + if(hostname[0] == '('){ + char *e; + char string[strlen(hostname)]; + strcpy(string,hostname); + int index; + e = strchr(string, ')'); + index = (int)(e - string); + str_cut(string, index, -1); + str_cut(string, 0, 1); + cJSON_AddStringToObject(root, "hostname", string); + }else{ + cJSON_AddStringToObject(root, "hostname", hostname); + } + } +// Parse timestamp + void W_JSON_ParseTimestamp(cJSON *root, const Eventinfo *lf){ + char *dateTimestamp = malloc(21); + sprintf(dateTimestamp, "%d %s %02d %s", lf->year, lf->mon, lf->day, lf->hour); + cJSON_AddStringToObject(root, "timestamp", dateTimestamp); + free (dateTimestamp); + } + +// The IP of an agent usually comes in "hostname" field, we will extract it. +// ** TODO ** Regex instead str_cut + void W_JSON_ParseAgentIP(cJSON *root, const Eventinfo *lf){ + if(lf->hostname[0] == '('){ + char *e; + char string[strlen(lf->hostname)]; + strcpy(string,lf->hostname); + int index; + e = strchr(string, ')'); + index = (int)(e - string); + str_cut(string, 0, index); + str_cut(string, 0, 2); + e = strchr(string, '-'); + index = (int)(e - string); + str_cut(string, index, -1); + cJSON_AddStringToObject(root, "agentip", string); + } + + } + // The file location usually comes with more information about the alert (like hostname or ip) we will extract just the "/var/folder/file.log". + void W_JSON_ParseLocation(cJSON *root, const Eventinfo *lf){ + if(lf->location[0] == '('){ + char *e; + char string[strlen(lf->location)]; + strcpy(string,lf->location); + int index; + e = strchr(string, '>'); + index = (int)(e - string); + str_cut(string, 0, index); + str_cut(string, 0, 1); + cJSON_AddStringToObject(root, "location", string); + }else{ + cJSON_AddStringToObject(root, "location", lf->location); + } + + } + +#define MAX_ERROR_MSG 0x1000 +// Regex compilator +int compile_regex (regex_t * r, const char * regex_text) +{ + int status = regcomp (r, regex_text, REG_EXTENDED|REG_NEWLINE); + if (status != 0) { + char error_message[MAX_ERROR_MSG]; + regerror (status, r, error_message, MAX_ERROR_MSG); + printf ("Regex error compiling '%s': %s\n", + regex_text, error_message); + return 1; + } + return 0; +} + +/* + Match the string in "to_match" against the compiled regular + expression in "r". + */ +// Reglex matcher to extract some strings from differentes LF fields. +// Results is static array because for now we don't need anymore fields. +int match_regex (regex_t * r, const char * to_match, char results[2][100], int totalResults) +{ + const char * p = to_match; + // 4 is max of matches to found. + const int n_matches = 4; + regmatch_t m[n_matches]; + while (1) { + int i = 0; + int nomatch = regexec (r, p, n_matches, m, 0); + if (nomatch) { + printf ("No more matches.\n"); + return nomatch; + } + for (i = 0; i < totalResults+1; i++) { + int start; + int finish; + if (m[i].rm_so == -1) { + break; + } + start = m[i].rm_so + (p - to_match); + finish = m[i].rm_eo + (p - to_match); + if (i == 0) { + // printf ("$& is "); + } + else { + sprintf (results[i-1], "%.*s", (finish - start),to_match + start); + if(i==totalResults) + return -1; + } + + } + p += m[0].rm_eo; + } + return 0; +} + +int str_cut(char *str, int begin, int len) +{ + int l = strlen(str); + + if (len < 0) len = l - begin; + if (begin + len > l) len = l - begin; + memmove(str + begin, str + begin + len, l - len + 1); + + return len; +} diff --git a/src/analysisd/format/json_extended.h b/src/analysisd/format/json_extended.h new file mode 100644 index 000000000..6e9937c97 --- /dev/null +++ b/src/analysisd/format/json_extended.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2015 Wazuh Inc + * All rights reserved. + * + */ + + #ifndef __WAZUH_EXTERNAL_FUNCTIONS_H__ +#define __WAZUH_EXTERNAL_FUNCTIONS_H__ + +#include "eventinfo.h" +#include "cJSON.h" +#include + +int str_cut(char *str, int begin, int len); +int compile_regex (regex_t * r, const char * regex_text); +int match_regex (regex_t * r, const char * to_match, char results[2][100], int totalResults); +// Main function, call the others parsers. +void W_ParseJSON(cJSON *root, const Eventinfo *lf); +// Parse hostname +void W_JSON_ParseHostname(cJSON *root, char *hostname); +// Parse Timestamp +void W_JSON_ParseTimestamp(cJSON *root, const Eventinfo *lf); +// Parse AgentIP +void W_JSON_ParseAgentIP(cJSON *root, const Eventinfo *lf); +// Parse Location +void W_JSON_ParseLocation(cJSON *root, const Eventinfo *lf); +// Parse Groups +void W_JSON_ParseGroups(cJSON *root, const Eventinfo *lf); +// Parse PCI DSS +void W_JSON_ParsePCIDSS(cJSON *root); +// Parse CIS +void W_JSON_ParseCIS(cJSON *root); +// Parse ROOTCHECK PCI DSS +void W_JSON_ParseRootcheckPCIDSS(cJSON *root, const Eventinfo *lf); +// Parse ROOTCHECK CIS +void W_JSON_ParseRootcheckCIS(cJSON *root, const Eventinfo *lf); + +#endif diff --git a/src/analysisd/format/to_json.c b/src/analysisd/format/to_json.c index 8d4fed69b..c06108cfa 100644 --- a/src/analysisd/format/to_json.c +++ b/src/analysisd/format/to_json.c @@ -8,13 +8,14 @@ */ #include "to_json.h" - +#include "json_extended.h" #include "shared.h" #include "rules.h" #include "cJSON.h" #include "config.h" + /* Convert Eventinfo to json */ char *Eventinfo_to_jsonstr(const Eventinfo *lf) { @@ -26,6 +27,7 @@ char *Eventinfo_to_jsonstr(const Eventinfo *lf) extern long int __crt_ftell; root = cJSON_CreateObject(); + cJSON_AddItemToObject(root, "rule", rule = cJSON_CreateObject()); cJSON_AddNumberToObject(rule, "level", lf->generated_rule->level); @@ -159,8 +161,174 @@ char *Eventinfo_to_jsonstr(const Eventinfo *lf) cJSON_AddStringToObject(root, "program_name", lf->program_name); } + W_ParseJSON(root, lf); + out = cJSON_PrintUnformatted(root); cJSON_Delete(root); return out; } +/* Convert Archiveinfo to json */ +char *Archiveinfo_to_jsonstr(const Eventinfo *lf) +{ + cJSON *root; + char *out; + + root = cJSON_CreateObject(); + if (lf->full_log) + cJSON_AddStringToObject(root, "full_log", lf->full_log); + if (lf->location) + cJSON_AddStringToObject(root, "location", lf->location); + if(lf->year && lf->mon && lf->day && lf->hour) + W_JSON_ParseTimestamp(root, lf); + if(lf->hostname){ + W_JSON_ParseHostname(root, lf->hostname); + W_JSON_ParseAgentIP(root, lf); + } + if (lf->location) + W_JSON_ParseLocation(root,lf); + + if(lf->program_name) + cJSON_AddStringToObject(root, "program_name", lf->program_name); + + if(lf->log) + cJSON_AddStringToObject(root, "log", lf->log); + + if(lf->srcip) + cJSON_AddStringToObject(root, "srcip", lf->srcip); + + if(lf->dstip) + cJSON_AddStringToObject(root, "dstip", lf->dstip); + + if(lf->srcport) + cJSON_AddStringToObject(root, "srcport", lf->srcport); + + if(lf->dstport) + cJSON_AddStringToObject(root, "dstport", lf->dstport); + + if(lf->protocol) + cJSON_AddStringToObject(root, "protocol", lf->protocol); + + if(lf->action) + cJSON_AddStringToObject(root, "action", lf->action); + + if(lf->srcuser) + cJSON_AddStringToObject(root, "srcuser", lf->srcuser); + + if(lf->dstuser) + cJSON_AddStringToObject(root, "dstuser", lf->dstuser); + + if(lf->id) + cJSON_AddStringToObject(root, "id", lf->id); + + if(lf->status) + cJSON_AddStringToObject(root, "status", lf->status); + + if(lf->command) + cJSON_AddStringToObject(root, "command", lf->command); + + if(lf->url) + cJSON_AddStringToObject(root, "url", lf->url); + + if(lf->data) + cJSON_AddStringToObject(root, "data", lf->data); + + if(lf->systemname) + cJSON_AddStringToObject(root, "systemname", lf->systemname); + + if(lf->filename) + cJSON_AddStringToObject(root, "filename", lf->filename); + + if(lf->perm_before) + cJSON_AddNumberToObject(root, "perm_before", lf->perm_before); + + if(lf->perm_after) + cJSON_AddNumberToObject(root, "perm_after", lf->perm_after); + + if(lf->md5_before) + cJSON_AddStringToObject(root, "md5_before", lf->md5_before); + + if(lf->md5_after) + cJSON_AddStringToObject(root, "md5_after", lf->md5_after); + + if(lf->sha1_before) + cJSON_AddStringToObject(root, "sha1_before", lf->sha1_before); + + if(lf->sha1_after) + cJSON_AddStringToObject(root, "sha1_after", lf->sha1_after); + + if(lf->size_before) + cJSON_AddStringToObject(root, "size_before", lf->size_before); + + if(lf->size_after) + cJSON_AddStringToObject(root, "size_after", lf->size_after); + + if(lf->owner_before) + cJSON_AddStringToObject(root, "owner_before", lf->owner_before); + + if(lf->owner_after) + cJSON_AddStringToObject(root, "owner_after", lf->owner_after); + + if(lf->gowner_before) + cJSON_AddStringToObject(root, "gowner_before", lf->gowner_before); + + if(lf->gowner_after) + cJSON_AddStringToObject(root, "gowner_after", lf->gowner_after); + + + // RuleInfo + if(lf->generated_rule){ + cJSON *rule; + + cJSON_AddItemToObject(root, "rule", rule = cJSON_CreateObject()); + + if (lf->generated_rule->level) + cJSON_AddNumberToObject(rule, "level", lf->generated_rule->level); + + if (lf->generated_rule->comment) + cJSON_AddStringToObject(rule, "comment", lf->generated_rule->comment); + + if (lf->generated_rule->sigid) + cJSON_AddNumberToObject(rule, "sidid", lf->generated_rule->sigid); + + if (lf->generated_rule->cve) + cJSON_AddStringToObject(rule, "cve", lf->generated_rule->cve); + + if (lf->generated_rule->info) + cJSON_AddStringToObject(rule, "info", lf->generated_rule->info); + + if (lf->generated_rule->frequency) + cJSON_AddNumberToObject(rule, "frequency", lf->generated_rule->frequency); + + if (lf->generated_rule->firedtimes) + cJSON_AddNumberToObject(rule, "firedtimes", lf->generated_rule->frequency); + + } + + // DecoderInfo + if(lf->generated_rule){ + cJSON *decoder; + cJSON_AddItemToObject(root, "decoder", decoder = cJSON_CreateObject()); + + if (lf->decoder_info->fts) + cJSON_AddNumberToObject(decoder, "fts", lf->decoder_info->fts); + if (lf->decoder_info->accumulate) + cJSON_AddNumberToObject(decoder, "accumulate", lf->decoder_info->accumulate); + if (lf->decoder_info->accumulate) + cJSON_AddNumberToObject(decoder, "accumulate", lf->decoder_info->accumulate); + + if (lf->decoder_info->parent) + cJSON_AddStringToObject(decoder, "parent", lf->decoder_info->parent); + if (lf->decoder_info->name) + cJSON_AddStringToObject(decoder, "name", lf->decoder_info->name); + if (lf->decoder_info->ftscomment) + cJSON_AddStringToObject(decoder, "ftscomment", lf->decoder_info->ftscomment); + + } + + + + out = cJSON_PrintUnformatted(root); + cJSON_Delete(root); + return out; +} diff --git a/src/analysisd/format/to_json.h b/src/analysisd/format/to_json.h index f9d6bc087..91c2393cf 100644 --- a/src/analysisd/format/to_json.h +++ b/src/analysisd/format/to_json.h @@ -12,5 +12,5 @@ #include "eventinfo.h" char *Eventinfo_to_jsonstr(const Eventinfo *lf); - +char *Archiveinfo_to_jsonstr(const Eventinfo *lf); #endif /* __TO_JSON_H__ */ diff --git a/src/analysisd/output/jsonout.c b/src/analysisd/output/jsonout.c index 83dc87373..237be3d02 100644 --- a/src/analysisd/output/jsonout.c +++ b/src/analysisd/output/jsonout.c @@ -23,3 +23,15 @@ void jsonout_output_event(const Eventinfo *lf) free(json_alert); return; } +void jsonout_output_archive(const Eventinfo *lf) +{ + char *json_alert = Archiveinfo_to_jsonstr(lf); + + fprintf(_ejflog, + "%s\n", + json_alert); + + fflush(_ejflog); + free(json_alert); + return; +} diff --git a/src/analysisd/output/jsonout.h b/src/analysisd/output/jsonout.h index 386f758a8..8a1a02b24 100644 --- a/src/analysisd/output/jsonout.h +++ b/src/analysisd/output/jsonout.h @@ -13,5 +13,6 @@ #include "eventinfo.h" void jsonout_output_event(const Eventinfo *lf); +void jsonout_output_archive(const Eventinfo *lf); #endif /* _JSONOUT_H_ */ diff --git a/src/headers/defs.h b/src/headers/defs.h index 9d40d6c7c..c20251c82 100644 --- a/src/headers/defs.h +++ b/src/headers/defs.h @@ -186,6 +186,7 @@ published by the Free Software Foundation. For more details, go to \n\ #define ALERTSJSON_DAILY "/logs/alerts/alerts.json" #define FWLOGS "/logs/firewall" #define FWLOGS_DAILY "/logs/firewall/firewall.log" +#define EVENTSJSON_DAILY "/logs/archives/archives.json" /* Stats directories */ #define STATWQUEUE "/stats/weekly-average" diff --git a/src/monitord/manage_files.c b/src/monitord/manage_files.c index 6ec288b0c..b11272a09 100644 --- a/src/monitord/manage_files.c +++ b/src/monitord/manage_files.c @@ -35,6 +35,9 @@ void manage_files(int cday, int cmon, int cyear) char flogfile[OS_FLSIZE + 1]; char flogfile_old[OS_FLSIZE + 1]; + + char ejlogfile[OS_FLSIZE + 1]; + char ejlogfile_old[OS_FLSIZE + 1]; /* Get time from the day before (for log signing) */ tm_old = time(NULL); @@ -53,7 +56,8 @@ void manage_files(int cday, int cmon, int cyear) memset(ajlogfile_old, '\0', OS_FLSIZE + 1); memset(flogfile, '\0', OS_FLSIZE + 1); memset(flogfile_old, '\0', OS_FLSIZE + 1); - + memset(ejlogfile, '\0', OS_FLSIZE + 1); + memset(ejlogfile_old, '\0', OS_FLSIZE + 1); /* When the day changes, we wait up to day_wait before compressing the file */ sleep(mond.day_wait); @@ -74,6 +78,41 @@ void manage_files(int cday, int cmon, int cyear) OS_SignLog(elogfile, elogfile_old, 0); OS_CompressLog(elogfile); + /* JSON Event logfile */ + snprintf(ejlogfile, OS_FLSIZE, "%s/%d/%s/ossec-%s-%02d.json", + EVENTS, + cyear, + months[cmon], + "archive", + cday); + /* JSON Event log file old */ + snprintf(ejlogfile_old, OS_FLSIZE, "%s/%d/%s/ossec-%s-%02d.json", + EVENTS, + pp_old->tm_year + 1900, + months[pp_old->tm_mon], + "archive", + pp_old->tm_mday); + + int exists_json_events = 0; + FILE *fopnetestjsonevents; + + if ((fopnetestjsonevents = fopen(ajlogfile, "r"))) { + exists_json_events = 1; + fclose(fopnetestjsonevents); + } + + if ((fopnetestjsonevents = fopen(ajlogfile_old, "r"))) { + exists_json_events = 1; + fclose(fopnetestjsonevents); + } + + if (exists_json_events) { + /* Only if there is a file to operate on. */ + OS_SignLog(ejlogfile, ejlogfile_old, 0); + OS_CompressLog(ejlogfile); + } + + /* alert logfile */ snprintf(alogfile, OS_FLSIZE, "%s/%d/%s/ossec-%s-%02d.log", ALERTS, diff --git a/src/util/agent_control.c b/src/util/agent_control.c index 90a62f70d..1281ff812 100644 --- a/src/util/agent_control.c +++ b/src/util/agent_control.c @@ -32,6 +32,7 @@ static void helpmsg() printf("\t-f Used with -b, specifies which response to run.\n"); printf("\t-L List available active responses.\n"); printf("\t-s Changes the output to CSV (comma delimited).\n"); + printf("\t-j Changes the output to JSON .\n"); exit(1); } @@ -48,7 +49,7 @@ int main(int argc, char **argv) gid_t gid; uid_t uid; int c = 0, restart_syscheck = 0, restart_all_agents = 0, list_agents = 0; - int info_agent = 0, agt_id = 0, active_only = 0, csv_output = 0; + int info_agent = 0, agt_id = 0, active_only = 0, csv_output = 0, json_output = 0; int list_responses = 0, end_time = 0, restart_agent = 0; char shost[512]; @@ -63,7 +64,7 @@ int main(int argc, char **argv) helpmsg(); } - while ((c = getopt(argc, argv, "VehdlLcsaru:i:b:f:R:")) != -1) { + while ((c = getopt(argc, argv, "VehdlLcsjaru:i:b:f:R:")) != -1) { switch (c) { case 'V': print_version(); @@ -88,6 +89,11 @@ int main(int argc, char **argv) break; case 's': csv_output = 1; + json_output = 0; + break; + case 'j': + json_output = 1; + csv_output = 0; break; case 'c': active_only++; @@ -169,7 +175,7 @@ int main(int argc, char **argv) /* List responses */ if (list_responses) { FILE *fp; - if (!csv_output) { + if (!csv_output && !json_output) { printf("\nOSSEC HIDS %s. Available active responses:\n", ARGV0); } @@ -220,16 +226,22 @@ int main(int argc, char **argv) /* List available agents */ if (list_agents) { - if (!csv_output) { + if (!csv_output && !json_output) { printf("\nOSSEC HIDS %s. List of available agents:", ARGV0); printf("\n ID: 000, Name: %s (server), IP: 127.0.0.1, Active/Local\n", shost); + } else if(json_output){ + printf("[ { \"ID\" : \"000\", \"Name\" : \"%s (server)\", \"IP\": \"127.0.0.1\", \"Status\" : \"Active/Local\" }",shost); } else { printf("000,%s (server),127.0.0.1,Active/Local,\n", shost); } - print_agents(1, active_only, csv_output); - printf("\n"); + print_agents(1, active_only, csv_output, json_output); + // Closing JSON Object array + if(json_output) + printf("]"); + else + printf("\n"); exit(0); } diff --git a/src/util/rootcheck_control.c b/src/util/rootcheck_control.c index 90efd9098..7e500005c 100644 --- a/src/util/rootcheck_control.c +++ b/src/util/rootcheck_control.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) } else { printf("000,%s (server),127.0.0.1,Active/Local,\n", shost); } - print_agents(1, active_only, csv_output); + print_agents(1, active_only, csv_output, 0); printf("\n"); exit(0); } diff --git a/src/util/syscheck_control.c b/src/util/syscheck_control.c index a48478643..c0731c14a 100644 --- a/src/util/syscheck_control.c +++ b/src/util/syscheck_control.c @@ -168,7 +168,7 @@ int main(int argc, char **argv) } else { printf("000,%s (server),127.0.0.1,Active/Local,\n", shost); } - print_agents(1, active_only, csv_output); + print_agents(1, active_only, csv_output, 0); printf("\n"); exit(0); } diff --git a/src/util/syscheck_update.c b/src/util/syscheck_update.c index 0eb2fb43f..dbd117b47 100644 --- a/src/util/syscheck_update.c +++ b/src/util/syscheck_update.c @@ -76,7 +76,7 @@ int main(int argc, char **argv) } else if (strcmp(argv[1], "-l") == 0) { printf("\nOSSEC HIDS %s: Updates the integrity check database.", ARGV0); - print_agents(0, 0, 0); + print_agents(0, 0, 0, 0); printf("\n"); exit(0); } else if (strcmp(argv[1], "-u") == 0) {