1 /* Copyright (C) 2015 Wazuh Inc
\r
2 * All rights reserved.
\r
6 #include "json_extended.h"
\r
9 #define MAX_MATCHES 10
\r
10 #define MAX_STRING 1024
\r
11 #define MAX_STRING_LESS 30
\r
13 void W_ParseJSON(cJSON* root, const Eventinfo* lf)
\r
16 // Parse hostname & Parse AGENTIP
\r
18 W_JSON_ParseHostname(root, lf->hostname);
\r
19 W_JSON_ParseAgentIP(root, lf);
\r
22 if(lf->year && lf->mon && lf->day && lf->hour) {
\r
23 W_JSON_ParseTimestamp(root, lf);
\r
27 W_JSON_ParseLocation(root, lf, 0);
\r
29 // Parse groups && Parse PCIDSS && Parse CIS
\r
30 if(lf->generated_rule->group) {
\r
31 W_JSON_ParseGroups(root, lf, 1);
\r
33 // Parse CIS and PCIDSS rules from rootcheck .txt benchmarks
\r
34 if(lf->full_log && W_isRootcheck(root, 1)) {
\r
35 W_JSON_ParseRootcheck(root, lf, 1);
\r
40 // Detect if the alert is coming from rootcheck controls.
\r
42 int W_isRootcheck(cJSON* root, int nested)
\r
54 rule = cJSON_GetObjectItem(root, "rule");
\r
56 groups = cJSON_GetObjectItem(rule, "groups");
\r
57 totalGroups = cJSON_GetArraySize(groups);
\r
58 for(i = 0; i < totalGroups; i++) {
\r
59 group = cJSON_GetArrayItem(groups, i);
\r
60 group_json = cJSON_Print(group);
\r
61 if(strcmp(group_json, "\"rootcheck\"") == 0) {
\r
71 // Getting security compliance field from rootcheck rules benchmarks .txt
\r
72 void W_JSON_ParseRootcheck(cJSON* root, const Eventinfo* lf, int nested)
\r
77 const char* regex_text;
\r
78 const char* find_text;
\r
81 char* results[MAX_MATCHES];
\r
83 const char delim[2] = ":";
\r
84 const char delim2[2] = ",";
\r
85 char fullog[MAX_STRING];
\r
88 for(i = 0; i < MAX_MATCHES; i++)
\r
89 results[i] = malloc((MAX_STRING_LESS) * sizeof(char));
\r
91 // Getting groups object JSON
\r
95 rule = cJSON_GetObjectItem(root, "rule");
\r
97 // Getting full log string
\r
98 strncpy(fullog, lf->full_log, MAX_STRING - 1);
\r
100 regex_text = "\\{([A-Za-z0-9_]*: [A-Za-z0-9_., ]*)\\}";
\r
101 find_text = fullog;
\r
102 compile_regex(&r, regex_text);
\r
103 matches = match_regex(&r, find_text, results);
\r
106 for(i = 0; i < matches; i++) {
\r
107 token = strtok(results[i], delim);
\r
110 cJSON_AddItemToObject(rule, token, compliance = cJSON_CreateArray());
\r
111 for(j = 0; token[j]; j++) {
\r
112 token[j] = tolower(token[j]);
\r
115 token = strtok(0, delim);
\r
117 token2 = strtok(token, delim2);
\r
121 cJSON_AddItemToArray(compliance, cJSON_CreateString(token2));
\r
122 token2 = strtok(0, delim2);
\r
128 for(i = 0; i < MAX_MATCHES; i++)
\r
134 // STRTOK every "-" delimiter to get differents groups to our json array.
\r
135 void W_JSON_ParseGroups(cJSON* root, const Eventinfo* lf, int nested)
\r
139 int firstPCI, firstCIS, foundCIS, foundPCI;
\r
141 char buffer[MAX_STRING];
\r
144 firstPCI = firstCIS = 1;
\r
145 foundPCI = foundCIS = 0;
\r
152 rule = cJSON_GetObjectItem(root, "rule");
\r
154 cJSON_AddItemToObject(rule, "groups", groups = cJSON_CreateArray());
\r
155 strncpy(buffer, lf->generated_rule->group, sizeof(buffer) - 1);
\r
157 token = strtok(buffer, delim);
\r
159 foundPCI = foundCIS = 0;
\r
160 foundPCI = add_groupPCI(rule, token, firstPCI);
\r
162 foundCIS = add_groupCIS(rule, token, firstCIS);
\r
164 if(foundPCI && firstPCI)
\r
166 if(foundCIS && firstCIS)
\r
169 if(!foundPCI && !foundCIS) {
\r
170 cJSON_AddItemToArray(groups, cJSON_CreateString(token));
\r
172 token = strtok(0, delim);
\r
177 // Parse groups PCI
\r
178 int add_groupPCI(cJSON* rule, char* group, int firstPCI)
\r
180 //char* len = NULL;
\r
182 char aux[strlen(group)];
\r
183 // If group begin with pci_dss_ we have a PCI group
\r
184 if((startsWith("pci_dss_", group)) == 1) {
\r
185 // Once we add pci_dss group and create array for PCI_DSS requirements
\r
186 if(firstPCI == 1) {
\r
187 pci = cJSON_CreateArray();
\r
188 cJSON_AddItemToObject(rule, "PCI_DSS", pci);
\r
190 pci = cJSON_GetObjectItem(rule, "PCI_DSS");
\r
192 // Prepare string and add it to PCI dss array
\r
193 strncpy(aux, group, strlen(group) - 1 );
\r
194 str_cut(aux, 0, 8);
\r
195 cJSON_AddItemToArray(pci, cJSON_CreateString(aux));
\r
202 int add_groupCIS(cJSON* rule, char* group, int firstCIS)
\r
204 //char* len = NULL;
\r
206 char aux[strlen(group)];
\r
207 if((startsWith("cis_", group)) == 1) {
\r
208 if(firstCIS == 1) {
\r
209 cis = cJSON_CreateArray();
\r
210 cJSON_AddItemToObject(rule, "CIS", cis);
\r
212 cis = cJSON_GetObjectItem(rule, "CIS");
\r
214 strncpy(aux, group, strlen(group) - 1);
\r
215 str_cut(aux, 0, 4);
\r
216 cJSON_AddItemToArray(cis, cJSON_CreateString(aux));
\r
223 // If hostname being with "(" means that alerts came from an agent, so we will remove the brakets
\r
224 // ** TODO ** Regex instead str_cut
\r
225 void W_JSON_ParseHostname(cJSON* root, char* hostname)
\r
227 if(hostname[0] == '(') {
\r
229 char string[MAX_STRING];
\r
230 strncpy(string, hostname, MAX_STRING - 1);
\r
232 search = strchr(string, ')');
\r
234 index = (int)(search - string);
\r
235 str_cut(string, index, -1);
\r
236 str_cut(string, 0, 1);
\r
237 cJSON_AddStringToObject(root, "hostname", string);
\r
240 cJSON_AddStringToObject(root, "hostname", hostname);
\r
244 void W_JSON_ParseTimestamp(cJSON* root, const Eventinfo* lf)
\r
246 char* dateTimestamp = malloc(21);
\r
247 sprintf(dateTimestamp, "%d %s %02d %s", lf->year, lf->mon, lf->day, lf->hour);
\r
248 cJSON_AddStringToObject(root, "timestamp", dateTimestamp);
\r
249 free(dateTimestamp);
\r
253 // The IP of an agent usually comes in "hostname" field, we will extract it.
\r
254 // ** TODO ** Regex instead str_cut
\r
255 void W_JSON_ParseAgentIP(cJSON* root, const Eventinfo* lf)
\r
257 if(lf->hostname[0] == '(') {
\r
259 char string[MAX_STRING];
\r
260 strncpy(string, lf->hostname, MAX_STRING - 1);
\r
262 search = strchr(string, ')');
\r
264 index = (int)(search - string);
\r
265 str_cut(string, 0, index);
\r
266 str_cut(string, 0, 2);
\r
267 search = strchr(string, '-');
\r
268 index = (int)(search - string);
\r
269 str_cut(string, index, -1);
\r
270 cJSON_AddStringToObject(root, "agentip", string);
\r
275 // The file location usually comes with more information about the alert (like hostname or ip) we will extract just the "/var/folder/file.log".
\r
276 void W_JSON_ParseLocation(cJSON* root, const Eventinfo* lf, int archives)
\r
278 if(lf->location[0] == '(') {
\r
280 char string[MAX_STRING];
\r
281 strncpy(string, lf->location, MAX_STRING - 1);
\r
283 search = strchr(string, '>');
\r
285 index = (int)(search - string);
\r
286 str_cut(string, 0, index);
\r
287 str_cut(string, 0, 1);
\r
290 cJSON_AddStringToObject(root, "location_desc", string);
\r
292 cJSON_AddStringToObject(root, "location", string);
\r
296 cJSON_AddStringToObject(root, "location_desc", lf->location);
\r
298 cJSON_AddStringToObject(root, "location", lf->location);
\r
303 #define MAX_ERROR_MSG 0x1000
\r
304 // Regex compilator
\r
305 int compile_regex(regex_t* r, const char* regex_text)
\r
307 int status = regcomp(r, regex_text, REG_EXTENDED | REG_NEWLINE);
\r
309 char error_message[MAX_ERROR_MSG];
\r
310 regerror(status, r, error_message, MAX_ERROR_MSG);
\r
311 debug1("Regex error compiling '%s': %s\n", regex_text, error_message);
\r
317 int match_regex(regex_t* r, const char* to_match, char* results[MAX_MATCHES])
\r
319 const char* p = to_match;
\r
320 const int n_matches = 10;
\r
321 regmatch_t m[n_matches];
\r
322 int totalResults = 0;
\r
325 int nomatch = regexec(r, p, n_matches, m, 0);
\r
327 //printf ("No more matches.\n");
\r
328 return totalResults;
\r
330 for(i = 0; i < n_matches; i++) {
\r
333 if(m[i].rm_so == -1) {
\r
337 start = m[i].rm_so + (p - to_match);
\r
338 finish = m[i].rm_eo + (p - to_match);
\r
340 sprintf(results[totalResults], "%.*s", (finish - start), to_match + start);
\r
341 totalResults = totalResults + 1;
\r
350 int str_cut(char* str, int begin, int len)
\r
352 int l = strlen(str);
\r
356 if(begin + len > l)
\r
358 memmove(str + begin, str + begin + len, l - len + 1);
\r
368 while(isspace(p[l - 1]))
\r
370 while(*p && isspace(*p))
\r
373 memmove(s, p, l + 1);
\r
376 int startsWith(const char *pre, const char *str)
\r
378 size_t lenpre = strlen(pre),
\r
379 lenstr = strlen(str);
\r
380 return lenstr < lenpre ? 0 : strncmp(pre, str, lenpre) == 0;
\r