1 /* Copyright (C) 2009 Trend Micro Inc.
2 * All rights reserved.
3 *
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
7 * Foundation.
8 */
9
10 #include "rules.h"
11 #include "config.h"
12 #include "eventinfo.h"
13 #include "compiled_rules/compiled_rules.h"
14
15 /* Global definition */
16 RuleInfo *currently_rule;
17
18 /* Change path for test rule */
19 #ifdef TESTRULE
20 #undef RULEPATH
21 #define RULEPATH "rules/"
22 #endif
23
24 /* Prototypes */
25 static int getattributes(char **attributes,
26 char **values,
27 int *id, int *level,
28 int *maxsize, int *timeframe,
29 int *frequency, int *accuracy,
30 int *noalert, int *ignore_time, int *overwrite);
31 static int doesRuleExist(int sid, RuleNode *r_node);
32 static void Rule_AddAR(RuleInfo *config_rule);
33 static char *loadmemory(char *at, const char *str);
34 static void printRuleinfo(const RuleInfo *rule, int node);
35
36 /* Will initialize the rules list */
Rules_OP_CreateRules()37 void Rules_OP_CreateRules()
38 {
39 /* Initialize the rule list */
40 OS_CreateRuleList();
41
42 return;
43 }
44
45 /* Read the log rules */
Rules_OP_ReadRules(const char * rulefile)46 int Rules_OP_ReadRules(const char *rulefile)
47 {
48 OS_XML xml;
49 XML_NODE node = NULL;
50
51 /* XML variables */
52 /* These are the available options for the rule configuration */
53
54 const char *xml_group = "group";
55 const char *xml_rule = "rule";
56
57 const char *xml_regex = "regex";
58 const char *xml_pcre2 = "pcre2";
59 const char *xml_match = "match";
60 const char *xml_match_pcre2 = "match_pcre2";
61 const char *xml_decoded = "decoded_as";
62 const char *xml_category = "category";
63 const char *xml_cve = "cve";
64 const char *xml_info = "info";
65 const char *xml_day_time = "time";
66 const char *xml_week_day = "weekday";
67 const char *xml_comment = "description";
68 const char *xml_ignore = "ignore";
69 const char *xml_check_if_ignored = "check_if_ignored";
70
71 const char *xml_srcip = "srcip";
72 const char *xml_srcgeoip = "srcgeoip";
73 const char *xml_srcport = "srcport";
74 const char *xml_srcgeoip_pcre2 = "srcgeoip_pcre2";
75 const char *xml_srcport_pcre2 = "srcport_pcre2";
76 const char *xml_dstip = "dstip";
77 const char *xml_dstgeoip = "dstgeoip";
78 const char *xml_dstport = "dstport";
79 const char *xml_user = "user";
80 const char *xml_url = "url";
81 const char *xml_id = "id";
82 const char *xml_data = "extra_data";
83 const char *xml_hostname = "hostname";
84 const char *xml_program_name = "program_name";
85 const char *xml_status = "status";
86 const char *xml_dstgeoip_pcre2 = "dstgeoip_pcre2";
87 const char *xml_dstport_pcre2 = "dstport_pcre2";
88 const char *xml_user_pcre2 = "user_pcre2";
89 const char *xml_url_pcre2 = "url_pcre2";
90 const char *xml_id_pcre2 = "id_pcre2";
91 const char *xml_data_pcre2 = "extra_data_pcre2";
92 const char *xml_hostname_pcre2 = "hostname_pcre2";
93 const char *xml_program_name_pcre2 = "program_name_pcre2";
94 const char *xml_status_pcre2 = "status_pcre2";
95 const char *xml_action = "action";
96 const char *xml_compiled = "compiled_rule";
97 const char *xml_field = "field";
98 const char *xml_name = "name";
99
100
101 const char *xml_list = "list";
102 const char *xml_list_lookup = "lookup";
103 const char *xml_list_field = "field";
104 const char *xml_list_cvalue = "check_value";
105 const char *xml_match_key = "match_key";
106 const char *xml_not_match_key = "not_match_key";
107 const char *xml_match_key_value = "match_key_value";
108 const char *xml_address_key = "address_match_key";
109 const char *xml_not_address_key = "not_address_match_key";
110 const char *xml_address_key_value = "address_match_key_value";
111
112 const char *xml_if_sid = "if_sid";
113 const char *xml_if_group = "if_group";
114 const char *xml_if_level = "if_level";
115 const char *xml_fts = "if_fts";
116
117 const char *xml_if_matched_regex = "if_matched_regex";
118 const char *xml_if_matched_group = "if_matched_group";
119 const char *xml_if_matched_sid = "if_matched_sid";
120
121 const char *xml_same_source_ip = "same_source_ip";
122 const char *xml_same_src_port = "same_src_port";
123 const char *xml_same_dst_port = "same_dst_port";
124 const char *xml_same_user = "same_user";
125 const char *xml_same_location = "same_location";
126 const char *xml_same_id = "same_id";
127 const char *xml_dodiff = "check_diff";
128
129 const char *xml_different_url = "different_url";
130 const char *xml_different_srcip = "different_srcip";
131 const char *xml_different_srcgeoip = "different_srcgeoip";
132
133 const char *xml_notsame_source_ip = "not_same_source_ip";
134 const char *xml_notsame_user = "not_same_user";
135 const char *xml_notsame_agent = "not_same_agent";
136 const char *xml_notsame_id = "not_same_id";
137
138 const char *xml_options = "options";
139
140 char *rulepath;
141
142 size_t i;
143 int default_timeframe = 360;
144
145 /* If no directory in the rulefile, add the default */
146 if ((strchr(rulefile, '/')) == NULL) {
147 /* Build the rule file name + path */
148 i = strlen(RULEPATH) + strlen(rulefile) + 2;
149 rulepath = (char *)calloc(i, sizeof(char));
150 if (!rulepath) {
151 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
152 }
153 snprintf(rulepath, i, "%s/%s", RULEPATH, rulefile);
154 } else {
155 os_strdup(rulefile, rulepath);
156 debug1("%s is the rulefile", rulefile);
157 debug1("Not modifing the rule path");
158 }
159
160 i = 0;
161
162 /* Read the XML */
163 if (OS_ReadXML(rulepath, &xml) < 0) {
164 merror(XML_ERROR, ARGV0, rulepath, xml.err, xml.err_line);
165 free(rulepath);
166 return (-1);
167 }
168 debug2("%s: DEBUG: read xml for rule.", ARGV0);
169
170 /* Apply any variable found */
171 if (OS_ApplyVariables(&xml) != 0) {
172 merror(XML_ERROR_VAR, ARGV0, rulepath, xml.err);
173 free(rulepath);
174 return (-1);
175 }
176 debug2("%s: DEBUG: XML Variables applied.", ARGV0);
177
178 /* Get the root elements */
179 node = OS_GetElementsbyNode(&xml, NULL);
180 if (!node) {
181 merror(CONFIG_ERROR, ARGV0, rulepath);
182 OS_ClearXML(&xml);
183 free(rulepath);
184 return (-1);
185 }
186
187 /* Zero the rule memory -- not used anymore */
188 free(rulepath);
189
190 /* Get default time frame */
191 default_timeframe = getDefine_Int("analysisd",
192 "default_timeframe",
193 60, MAX_TIMEFRAME);
194
195 /* Check if there is any invalid global option */
196 while (node[i]) {
197 if (node[i]->element) {
198 if (strcasecmp(node[i]->element, xml_group) != 0) {
199 merror("rules_op: Invalid root element \"%s\"."
200 "Only \"group\" is allowed", node[i]->element);
201 OS_ClearXML(&xml);
202 return (-1);
203 }
204 if ((!node[i]->attributes) || (!node[i]->values) ||
205 (!node[i]->values[0]) || (!node[i]->attributes[0]) ||
206 (strcasecmp(node[i]->attributes[0], "name") != 0) ||
207 (node[i]->attributes[1])) {
208 merror("rules_op: Invalid root element '%s'."
209 "Only the group name is allowed", node[i]->element);
210 OS_ClearXML(&xml);
211 return (-1);
212 }
213 } else {
214 merror(XML_READ_ERROR, ARGV0);
215 OS_ClearXML(&xml);
216 return (-1);
217 }
218 i++;
219 }
220
221 /* Get the rules */
222 i = 0;
223 while (node[i]) {
224 XML_NODE rule = NULL;
225
226 int j = 0;
227
228 /* Get all rules for a global group */
229 rule = OS_GetElementsbyNode(&xml, node[i]);
230 if (rule == NULL) {
231 merror("%s: Group '%s' without any rule.",
232 ARGV0, node[i]->element);
233 OS_ClearXML(&xml);
234 return (-1);
235 }
236
237 while (rule[j]) {
238 RuleInfo *config_ruleinfo = NULL;
239
240 /* Check if the rule element is correct */
241 if ((!rule[j]->element) ||
242 (strcasecmp(rule[j]->element, xml_rule) != 0)) {
243 merror("%s: Invalid configuration. '%s' is not "
244 "a valid element.", ARGV0, rule[j]->element);
245 OS_ClearXML(&xml);
246 return (-1);
247 }
248
249 /* Check for the attributes of the rule */
250 if ((!rule[j]->attributes) || (!rule[j]->values)) {
251 merror("%s: Invalid rule '%d'. You must specify"
252 " an ID and a level at least.", ARGV0, j);
253 OS_ClearXML(&xml);
254 return (-1);
255 }
256
257 /* Attribute block */
258 {
259 int id = -1, level = -1, maxsize = 0, timeframe = 0;
260 int frequency = 0, accuracy = 1, noalert = 0, ignore_time = 0;
261 int overwrite = 0;
262
263 /* Get default timeframe */
264 timeframe = default_timeframe;
265
266 if (getattributes(rule[j]->attributes, rule[j]->values,
267 &id, &level, &maxsize, &timeframe,
268 &frequency, &accuracy, &noalert,
269 &ignore_time, &overwrite) < 0) {
270 merror("%s: Invalid attribute for rule.", ARGV0);
271 OS_ClearXML(&xml);
272 return (-1);
273 }
274
275 if ((id == -1) || (level == -1)) {
276 merror("%s: No rule id or level specified for "
277 "rule '%d'.", ARGV0, j);
278 OS_ClearXML(&xml);
279 return (-1);
280 }
281
282 if (overwrite != 1 && doesRuleExist(id, NULL)) {
283 merror("%s: Duplicate rule ID:%d", ARGV0, id);
284 OS_ClearXML(&xml);
285 return (-1);
286 }
287
288 /* Allocate memory and initialize structure */
289 config_ruleinfo = zerorulemember(id, level, maxsize,
290 frequency, timeframe,
291 noalert, ignore_time, overwrite);
292
293 /* If rule is 0, set it to level 99 to have high priority.
294 * Set it to 0 again later.
295 */
296 if (config_ruleinfo->level == 0) {
297 config_ruleinfo->level = 99;
298 }
299
300 /* Each level now is going to be multiplied by 100.
301 * If the accuracy is set to 0 we don't multiply,
302 * so it will be at the end of the list. We will
303 * divide by 100 later.
304 */
305 if (accuracy) {
306 config_ruleinfo->level *= 100;
307 }
308
309 if (config_ruleinfo->maxsize > 0) {
310 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
311 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
312 }
313 }
314
315 } /* end attributes/memory allocation block */
316
317 /* Here we can assign the group name to the rule.
318 * The level is correct so the rule is probably going to
319 * be fine
320 */
321 os_strdup(node[i]->values[0], config_ruleinfo->group);
322
323 /* Rule elements block */
324 {
325 int k = 0;
326 int ifield = 0;
327 int info_type = 0;
328 int count_info_detail = 0;
329 RuleInfoDetail *last_info_detail = NULL;
330 char *regex = NULL;
331 char *match = NULL;
332 char *pcre2 = NULL;
333 char *match_pcre2 = NULL;
334 char *url = NULL;
335 char *url_pcre2 = NULL;
336 char *if_matched_regex = NULL;
337 char *if_matched_group = NULL;
338 char *user = NULL;
339 char *id = NULL;
340 char *srcport = NULL;
341 char *dstport = NULL;
342 char *srcgeoip = NULL;
343 char *dstgeoip = NULL;
344
345 char *status = NULL;
346 char *hostname = NULL;
347 char *extra_data = NULL;
348 char *program_name = NULL;
349
350 char *user_pcre2 = NULL;
351 char *id_pcre2 = NULL;
352 char *srcport_pcre2 = NULL;
353 char *dstport_pcre2 = NULL;
354 char *srcgeoip_pcre2 = NULL;
355 char *dstgeoip_pcre2 = NULL;
356
357 char *status_pcre2 = NULL;
358 char *hostname_pcre2 = NULL;
359 char *extra_data_pcre2 = NULL;
360 char *program_name_pcre2 = NULL;
361
362 XML_NODE rule_opt = NULL;
363 rule_opt = OS_GetElementsbyNode(&xml, rule[j]);
364 if (rule_opt == NULL) {
365 merror("%s: Rule '%d' without any option. "
366 "It may lead to false positives and some "
367 "other problems for the system. Exiting.",
368 ARGV0, config_ruleinfo->sigid);
369 OS_ClearXML(&xml);
370 return (-1);
371 }
372
373 while (rule_opt[k]) {
374 if ((!rule_opt[k]->element) || (!rule_opt[k]->content)) {
375 break;
376 } else if (strcasecmp(rule_opt[k]->element, xml_regex) == 0) {
377 regex =
378 loadmemory(regex,
379 rule_opt[k]->content);
380 } else if (strcasecmp(rule_opt[k]->element, xml_pcre2) == 0) {
381 pcre2 =
382 loadmemory(pcre2,
383 rule_opt[k]->content);
384 } else if (strcasecmp(rule_opt[k]->element, xml_match) == 0) {
385 match =
386 loadmemory(match,
387 rule_opt[k]->content);
388 } else if (strcasecmp(rule_opt[k]->element, xml_match_pcre2) == 0) {
389 match_pcre2 =
390 loadmemory(match_pcre2,
391 rule_opt[k]->content);
392 } else if (strcasecmp(rule_opt[k]->element, xml_decoded) == 0) {
393 config_ruleinfo->decoded_as =
394 getDecoderfromlist(rule_opt[k]->content);
395
396 if (config_ruleinfo->decoded_as == 0) {
397 merror("%s: Invalid decoder name: '%s'.",
398 ARGV0, rule_opt[k]->content);
399 OS_ClearXML(&xml);
400 return (-1);
401 }
402 } else if (strcasecmp(rule_opt[k]->element, xml_cve) == 0) {
403 if (config_ruleinfo->info_details == NULL) {
404 config_ruleinfo->info_details = zeroinfodetails(RULEINFODETAIL_CVE,
405 rule_opt[k]->content);
406 } else {
407 for (last_info_detail = config_ruleinfo->info_details;
408 last_info_detail->next != NULL;
409 last_info_detail = last_info_detail->next) {
410 count_info_detail++;
411 }
412 /* Silently Drop info messages if their are more then MAX_RULEINFODETAIL */
413 if (count_info_detail <= MAX_RULEINFODETAIL) {
414 last_info_detail->next = zeroinfodetails(RULEINFODETAIL_CVE,
415 rule_opt[k]->content);
416 }
417 }
418
419 /* keep old methods for now */
420 config_ruleinfo->cve =
421 loadmemory(config_ruleinfo->cve,
422 rule_opt[k]->content);
423 } else if (strcasecmp(rule_opt[k]->element, xml_info) == 0) {
424
425 info_type = get_info_attributes(rule_opt[k]->attributes,
426 rule_opt[k]->values);
427 debug1("info_type = %d", info_type);
428
429 if (config_ruleinfo->info_details == NULL) {
430 config_ruleinfo->info_details = zeroinfodetails(info_type,
431 rule_opt[k]->content);
432 } else {
433 for (last_info_detail = config_ruleinfo->info_details;
434 last_info_detail->next != NULL;
435 last_info_detail = last_info_detail->next) {
436 count_info_detail++;
437 }
438 /* Silently Drop info messages if their are more then MAX_RULEINFODETAIL */
439 if (count_info_detail <= MAX_RULEINFODETAIL) {
440 last_info_detail->next = zeroinfodetails(info_type, rule_opt[k]->content);
441 }
442 }
443
444
445 /* keep old methods for now */
446 config_ruleinfo->info =
447 loadmemory(config_ruleinfo->info,
448 rule_opt[k]->content);
449 } else if (strcasecmp(rule_opt[k]->element, xml_day_time) == 0) {
450 config_ruleinfo->day_time =
451 OS_IsValidTime(rule_opt[k]->content);
452 if (!config_ruleinfo->day_time) {
453 merror(INVALID_CONFIG, ARGV0,
454 rule_opt[k]->element,
455 rule_opt[k]->content);
456 return (-1);
457 }
458
459 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
460 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
461 }
462 } else if (strcasecmp(rule_opt[k]->element, xml_week_day) == 0) {
463 config_ruleinfo->week_day =
464 OS_IsValidDay(rule_opt[k]->content);
465
466 if (!config_ruleinfo->week_day) {
467 merror(INVALID_CONFIG, ARGV0,
468 rule_opt[k]->element,
469 rule_opt[k]->content);
470 return (-1);
471 }
472 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
473 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
474 }
475 } else if (strcasecmp(rule_opt[k]->element, xml_group) == 0) {
476 config_ruleinfo->group =
477 loadmemory(config_ruleinfo->group,
478 rule_opt[k]->content);
479 } else if (strcasecmp(rule_opt[k]->element, xml_comment) == 0) {
480 char *newline;
481
482 newline = strchr(rule_opt[k]->content, '\n');
483 if (newline) {
484 *newline = ' ';
485 }
486
487 config_ruleinfo->comment =
488 loadmemory(config_ruleinfo->comment,
489 rule_opt[k]->content);
490 } else if (strcasecmp(rule_opt[k]->element, xml_srcip) == 0) {
491 unsigned int ip_s = 0;
492
493 /* Getting size of source ip list */
494 while (config_ruleinfo->srcip &&
495 config_ruleinfo->srcip[ip_s]) {
496 ip_s++;
497 }
498
499 config_ruleinfo->srcip =
500 (os_ip **) realloc(config_ruleinfo->srcip,
501 (ip_s + 2) * sizeof(os_ip *));
502
503
504 /* Allocating memory for the individual entries */
505 os_calloc(1, sizeof(os_ip),
506 config_ruleinfo->srcip[ip_s]);
507 config_ruleinfo->srcip[ip_s + 1] = NULL;
508
509
510 /* Checking if the ip is valid */
511 if (!OS_IsValidIP(rule_opt[k]->content,
512 config_ruleinfo->srcip[ip_s])) {
513 merror(INVALID_IP, ARGV0, rule_opt[k]->content);
514 return (-1);
515 }
516
517 if (!(config_ruleinfo->alert_opts & DO_PACKETINFO)) {
518 config_ruleinfo->alert_opts |= DO_PACKETINFO;
519 }
520 } else if (strcasecmp(rule_opt[k]->element, xml_dstip) == 0) {
521 unsigned int ip_s = 0;
522
523 /* Getting size of source ip list */
524 while (config_ruleinfo->dstip &&
525 config_ruleinfo->dstip[ip_s]) {
526 ip_s++;
527 }
528
529 config_ruleinfo->dstip =
530 (os_ip **) realloc(config_ruleinfo->dstip,
531 (ip_s + 2) * sizeof(os_ip *));
532
533
534 /* Allocating memory for the individual entries */
535 os_calloc(1, sizeof(os_ip),
536 config_ruleinfo->dstip[ip_s]);
537 config_ruleinfo->dstip[ip_s + 1] = NULL;
538
539
540 /* Checking if the ip is valid */
541 if (!OS_IsValidIP(rule_opt[k]->content,
542 config_ruleinfo->dstip[ip_s])) {
543 merror(INVALID_IP, ARGV0, rule_opt[k]->content);
544 return (-1);
545 }
546
547 if (!(config_ruleinfo->alert_opts & DO_PACKETINFO)) {
548 config_ruleinfo->alert_opts |= DO_PACKETINFO;
549 }
550 } else if (strcasecmp(rule_opt[k]->element, xml_user) == 0) {
551 user =
552 loadmemory(user,
553 rule_opt[k]->content);
554
555 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
556 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
557 }
558 } else if(strcasecmp(rule_opt[k]->element,xml_srcgeoip)==0) {
559 srcgeoip =
560 loadmemory(srcgeoip,
561 rule_opt[k]->content);
562
563 if(!(config_ruleinfo->alert_opts & DO_EXTRAINFO))
564 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
565 } else if(strcasecmp(rule_opt[k]->element,xml_dstgeoip)==0) {
566 dstgeoip =
567 loadmemory(dstgeoip,
568 rule_opt[k]->content);
569
570 if(!(config_ruleinfo->alert_opts & DO_EXTRAINFO))
571 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
572 } else if (strcasecmp(rule_opt[k]->element, xml_id) == 0) {
573 id =
574 loadmemory(id,
575 rule_opt[k]->content);
576 } else if (strcasecmp(rule_opt[k]->element, xml_srcport) == 0) {
577 srcport =
578 loadmemory(srcport,
579 rule_opt[k]->content);
580 if (!(config_ruleinfo->alert_opts & DO_PACKETINFO)) {
581 config_ruleinfo->alert_opts |= DO_PACKETINFO;
582 }
583 } else if (strcasecmp(rule_opt[k]->element, xml_dstport) == 0) {
584 dstport =
585 loadmemory(dstport,
586 rule_opt[k]->content);
587
588 if (!(config_ruleinfo->alert_opts & DO_PACKETINFO)) {
589 config_ruleinfo->alert_opts |= DO_PACKETINFO;
590 }
591 } else if (strcasecmp(rule_opt[k]->element, xml_status) == 0) {
592 status =
593 loadmemory(status,
594 rule_opt[k]->content);
595
596 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
597 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
598 }
599 } else if (strcasecmp(rule_opt[k]->element, xml_hostname) == 0) {
600 hostname =
601 loadmemory(hostname,
602 rule_opt[k]->content);
603
604 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
605 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
606 }
607 } else if (strcasecmp(rule_opt[k]->element, xml_data) == 0) {
608 extra_data =
609 loadmemory(extra_data,
610 rule_opt[k]->content);
611
612 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
613 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
614 }
615 } else if (strcasecmp(rule_opt[k]->element,
616 xml_program_name) == 0) {
617 program_name =
618 loadmemory(program_name,
619 rule_opt[k]->content);
620 } else if (strcasecmp(rule_opt[k]->element, xml_user_pcre2) == 0) {
621 user_pcre2 =
622 loadmemory(user_pcre2,
623 rule_opt[k]->content);
624
625 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
626 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
627 }
628 } else if(strcasecmp(rule_opt[k]->element,xml_srcgeoip_pcre2)==0) {
629 srcgeoip_pcre2 =
630 loadmemory(srcgeoip_pcre2,
631 rule_opt[k]->content);
632
633 if(!(config_ruleinfo->alert_opts & DO_EXTRAINFO))
634 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
635 } else if(strcasecmp(rule_opt[k]->element,xml_dstgeoip_pcre2)==0) {
636 dstgeoip_pcre2 =
637 loadmemory(dstgeoip_pcre2,
638 rule_opt[k]->content);
639
640 if(!(config_ruleinfo->alert_opts & DO_EXTRAINFO))
641 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
642 } else if (strcasecmp(rule_opt[k]->element, xml_id_pcre2) == 0) {
643 id_pcre2 =
644 loadmemory(id_pcre2,
645 rule_opt[k]->content);
646 } else if (strcasecmp(rule_opt[k]->element, xml_srcport_pcre2) == 0) {
647 srcport_pcre2 =
648 loadmemory(srcport_pcre2,
649 rule_opt[k]->content);
650 if (!(config_ruleinfo->alert_opts & DO_PACKETINFO)) {
651 config_ruleinfo->alert_opts |= DO_PACKETINFO;
652 }
653 } else if (strcasecmp(rule_opt[k]->element, xml_dstport_pcre2) == 0) {
654 dstport_pcre2 =
655 loadmemory(dstport_pcre2,
656 rule_opt[k]->content);
657
658 if (!(config_ruleinfo->alert_opts & DO_PACKETINFO)) {
659 config_ruleinfo->alert_opts |= DO_PACKETINFO;
660 }
661 } else if (strcasecmp(rule_opt[k]->element, xml_status_pcre2) == 0) {
662 status_pcre2 =
663 loadmemory(status_pcre2,
664 rule_opt[k]->content);
665
666 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
667 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
668 }
669 } else if (strcasecmp(rule_opt[k]->element, xml_hostname_pcre2) == 0) {
670 hostname_pcre2 =
671 loadmemory(hostname_pcre2,
672 rule_opt[k]->content);
673
674 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
675 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
676 }
677 } else if (strcasecmp(rule_opt[k]->element, xml_data_pcre2) == 0) {
678 extra_data_pcre2 =
679 loadmemory(extra_data_pcre2,
680 rule_opt[k]->content);
681
682 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
683 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
684 }
685 } else if (strcasecmp(rule_opt[k]->element,
686 xml_program_name_pcre2) == 0) {
687 program_name_pcre2 =
688 loadmemory(program_name_pcre2,
689 rule_opt[k]->content);
690 } else if (strcasecmp(rule_opt[k]->element, xml_action) == 0) {
691 config_ruleinfo->action =
692 loadmemory(config_ruleinfo->action,
693 rule_opt[k]->content);
694 } else if (strcasecmp(rule_opt[k]->element, xml_field) == 0) {
695 if (rule_opt[k]->attributes[0]) {
696 os_calloc(1, sizeof(FieldInfo), config_ruleinfo->fields[ifield]);
697
698 if (strcasecmp(rule_opt[k]->attributes[0], xml_name) == 0) {
699 config_ruleinfo->fields[ifield]->name = loadmemory(config_ruleinfo->fields[ifield]->name, rule_opt[k]->values[0]);
700 } else {
701 merror("%s: Bad attribute '%s' for field.", ARGV0, rule_opt[k]->attributes[0]);
702 return -1;
703 }
704 } else {
705 merror("%s: No such attribute '%s' for field.", ARGV0, xml_name);
706 return (-1);
707 }
708
709 os_calloc(1, sizeof(OSRegex), config_ruleinfo->fields[ifield]->regex);
710
711 if (!OSRegex_Compile(rule_opt[k]->content, config_ruleinfo->fields[ifield]->regex, 0)) {
712 merror(REGEX_COMPILE, ARGV0, rule_opt[k]->content, config_ruleinfo->fields[ifield]->regex->error);
713 return -1;
714 }
715
716 ifield++;
717
718 } else if (strcasecmp(rule_opt[k]->element, xml_list) == 0) {
719 debug1("-> %s == %s", rule_opt[k]->element, xml_list);
720 if (rule_opt[k]->attributes && rule_opt[k]->values && rule_opt[k]->content) {
721 int list_att_num = 0;
722 int rule_type = 0;
723 OSMatch *matcher = NULL;
724 int lookup_type = LR_STRING_MATCH;
725 while (rule_opt[k]->attributes[list_att_num]) {
726 if (strcasecmp(rule_opt[k]->attributes[list_att_num], xml_list_lookup) == 0) {
727 if (strcasecmp(rule_opt[k]->values[list_att_num], xml_match_key) == 0) {
728 lookup_type = LR_STRING_MATCH;
729 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_not_match_key) == 0) {
730 lookup_type = LR_STRING_NOT_MATCH;
731 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_match_key_value) == 0) {
732 lookup_type = LR_STRING_MATCH_VALUE;
733 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_address_key) == 0) {
734 lookup_type = LR_ADDRESS_MATCH;
735 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_not_address_key) == 0) {
736 lookup_type = LR_ADDRESS_NOT_MATCH;
737 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_address_key_value) == 0) {
738 lookup_type = LR_ADDRESS_MATCH_VALUE;
739 } else {
740 merror(INVALID_CONFIG, ARGV0,
741 rule_opt[k]->element,
742 rule_opt[k]->content);
743 merror("%s: List match lookup=\"%s\" is not valid.",
744 ARGV0, rule_opt[k]->values[list_att_num]);
745 return (-1);
746 }
747 } else if (strcasecmp(rule_opt[k]->attributes[list_att_num], xml_list_field) == 0) {
748 if (strcasecmp(rule_opt[k]->values[list_att_num], xml_srcip) == 0) {
749 rule_type = RULE_SRCIP;
750 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_srcport) == 0) {
751 rule_type = RULE_SRCPORT;
752 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_dstip) == 0) {
753 rule_type = RULE_DSTIP;
754 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_dstport) == 0) {
755 rule_type = RULE_DSTPORT;
756 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_user) == 0) {
757 rule_type = RULE_USER;
758 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_url) == 0) {
759 rule_type = RULE_URL;
760 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_id) == 0) {
761 rule_type = RULE_ID;
762 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_hostname) == 0) {
763 rule_type = RULE_HOSTNAME;
764 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_program_name) == 0) {
765 rule_type = RULE_PROGRAM_NAME;
766 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_status) == 0) {
767 rule_type = RULE_STATUS;
768 } else if (strcasecmp(rule_opt[k]->values[list_att_num], xml_action) == 0) {
769 rule_type = RULE_ACTION;
770 } else {
771 merror(INVALID_CONFIG, ARGV0,
772 rule_opt[k]->element,
773 rule_opt[k]->content);
774 merror("%s: List match field=\"%s\" is not valid.",
775 ARGV0, rule_opt[k]->values[list_att_num]);
776 return (-1);
777 }
778 } else if (strcasecmp(rule_opt[k]->attributes[list_att_num], xml_list_cvalue) == 0) {
779 os_calloc(1, sizeof(OSMatch), matcher);
780 if (!OSMatch_Compile(rule_opt[k]->values[list_att_num], matcher, 0)) {
781 merror(INVALID_CONFIG, ARGV0,
782 rule_opt[k]->element,
783 rule_opt[k]->content);
784 merror(REGEX_COMPILE,
785 ARGV0,
786 rule_opt[k]->values[list_att_num],
787 matcher->error);
788 return (-1);
789 }
790 } else {
791 merror("%s:List field=\"%s\" is not valid", ARGV0,
792 rule_opt[k]->values[list_att_num]);
793 merror(INVALID_CONFIG, ARGV0,
794 rule_opt[k]->element, rule_opt[k]->content);
795 return (-1);
796 }
797 list_att_num++;
798 }
799 if (rule_type == 0) {
800 merror("%s:List requires the field=\"\" Attrubute", ARGV0);
801 merror(INVALID_CONFIG, ARGV0,
802 rule_opt[k]->element, rule_opt[k]->content);
803 return (-1);
804 }
805
806 /* Wow it's all ready - this seems too complex to get to this point */
807 config_ruleinfo->lists = OS_AddListRule(config_ruleinfo->lists,
808 lookup_type,
809 rule_type,
810 rule_opt[k]->content,
811 matcher);
812 if (config_ruleinfo->lists == NULL) {
813 merror("%s: List error: Could not load %s", ARGV0, rule_opt[k]->content);
814 return (-1);
815 }
816 } else {
817 merror("%s:List must have a correctly formatted field attribute",
818 ARGV0);
819 merror(INVALID_CONFIG,
820 ARGV0,
821 rule_opt[k]->element,
822 rule_opt[k]->content);
823 return (-1);
824 }
825 /* xml_list eval is done */
826 } else if (strcasecmp(rule_opt[k]->element, xml_url) == 0) {
827 url =
828 loadmemory(url,
829 rule_opt[k]->content);
830 } else if (strcasecmp(rule_opt[k]->element, xml_url_pcre2) == 0) {
831 url_pcre2 =
832 loadmemory(url_pcre2,
833 rule_opt[k]->content);
834 } else if (strcasecmp(rule_opt[k]->element, xml_compiled) == 0) {
835 int it_id = 0;
836
837 while (compiled_rules_name[it_id]) {
838 if (strcmp(compiled_rules_name[it_id],
839 rule_opt[k]->content) == 0) {
840 break;
841 }
842 it_id++;
843 }
844
845 /* Checking if the name is valid */
846 if (!compiled_rules_name[it_id]) {
847 merror("%s: ERROR: Compiled rule not found: '%s'",
848 ARGV0, rule_opt[k]->content);
849 merror(INVALID_CONFIG, ARGV0,
850 rule_opt[k]->element, rule_opt[k]->content);
851 return (-1);
852
853 }
854
855 config_ruleinfo->compiled_rule = (void *(*)(void *)) compiled_rules_list[it_id];
856 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
857 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
858 }
859 }
860
861 else if (strcasecmp(rule_opt[k]->element, xml_category) == 0) {
862 if (strcmp(rule_opt[k]->content, "firewall") == 0) {
863 config_ruleinfo->category = FIREWALL;
864 } else if (strcmp(rule_opt[k]->content, "ids") == 0) {
865 config_ruleinfo->category = IDS;
866 } else if (strcmp(rule_opt[k]->content, "syslog") == 0) {
867 config_ruleinfo->category = SYSLOG;
868 } else if (strcmp(rule_opt[k]->content, "web-log") == 0) {
869 config_ruleinfo->category = WEBLOG;
870 } else if (strcmp(rule_opt[k]->content, "squid") == 0) {
871 config_ruleinfo->category = SQUID;
872 } else if (strcmp(rule_opt[k]->content, "windows") == 0) {
873 config_ruleinfo->category = DECODER_WINDOWS;
874 } else if (strcmp(rule_opt[k]->content, "ossec") == 0) {
875 config_ruleinfo->category = OSSEC_RL;
876 } else {
877 merror(INVALID_CAT, ARGV0, rule_opt[k]->content);
878 return (-1);
879 }
880 } else if (strcasecmp(rule_opt[k]->element, xml_if_sid) == 0) {
881 config_ruleinfo->if_sid =
882 loadmemory(config_ruleinfo->if_sid,
883 rule_opt[k]->content);
884 } else if (strcasecmp(rule_opt[k]->element, xml_if_level) == 0) {
885 if (!OS_StrIsNum(rule_opt[k]->content)) {
886 merror(INVALID_CONFIG, ARGV0,
887 "if_level",
888 rule_opt[k]->content);
889 return (-1);
890 }
891
892 config_ruleinfo->if_level =
893 loadmemory(config_ruleinfo->if_level,
894 rule_opt[k]->content);
895 } else if (strcasecmp(rule_opt[k]->element, xml_if_group) == 0) {
896 config_ruleinfo->if_group =
897 loadmemory(config_ruleinfo->if_group,
898 rule_opt[k]->content);
899 } else if (strcasecmp(rule_opt[k]->element,
900 xml_if_matched_regex) == 0) {
901 config_ruleinfo->context = 1;
902 if_matched_regex =
903 loadmemory(if_matched_regex,
904 rule_opt[k]->content);
905 } else if (strcasecmp(rule_opt[k]->element,
906 xml_if_matched_group) == 0) {
907 config_ruleinfo->context = 1;
908 if_matched_group =
909 loadmemory(if_matched_group,
910 rule_opt[k]->content);
911 } else if (strcasecmp(rule_opt[k]->element,
912 xml_if_matched_sid) == 0) {
913 config_ruleinfo->context = 1;
914 if (!OS_StrIsNum(rule_opt[k]->content)) {
915 merror(INVALID_CONFIG, ARGV0,
916 "if_matched_sid",
917 rule_opt[k]->content);
918 return (-1);
919 }
920 config_ruleinfo->if_matched_sid =
921 atoi(rule_opt[k]->content);
922
923 } else if (strcasecmp(rule_opt[k]->element,
924 xml_same_source_ip) == 0) {
925 config_ruleinfo->context_opts |= SAME_SRCIP;
926 } else if (strcasecmp(rule_opt[k]->element,
927 xml_same_src_port) == 0) {
928 config_ruleinfo->context_opts |= SAME_SRCPORT;
929
930 if (!(config_ruleinfo->alert_opts & SAME_EXTRAINFO)) {
931 config_ruleinfo->alert_opts |= SAME_EXTRAINFO;
932 }
933 } else if (strcasecmp(rule_opt[k]->element,
934 xml_dodiff) == 0) {
935 config_ruleinfo->context = 1;
936 config_ruleinfo->context_opts |= SAME_DODIFF;
937 if (!(config_ruleinfo->alert_opts & DO_EXTRAINFO)) {
938 config_ruleinfo->alert_opts |= DO_EXTRAINFO;
939 }
940 } else if (strcasecmp(rule_opt[k]->element,
941 xml_same_dst_port) == 0) {
942 config_ruleinfo->context_opts |= SAME_DSTPORT;
943
944 if (!(config_ruleinfo->alert_opts & SAME_EXTRAINFO)) {
945 config_ruleinfo->alert_opts |= SAME_EXTRAINFO;
946 }
947 } else if (strcasecmp(rule_opt[k]->element,
948 xml_notsame_source_ip) == 0) {
949 config_ruleinfo->context_opts &= NOT_SAME_SRCIP;
950 } else if (strcmp(rule_opt[k]->element, xml_same_id) == 0) {
951 config_ruleinfo->context_opts |= SAME_ID;
952 } else if (strcmp(rule_opt[k]->element,
953 xml_different_url) == 0) {
954 config_ruleinfo->context_opts |= DIFFERENT_URL;
955
956 if (!(config_ruleinfo->alert_opts & SAME_EXTRAINFO)) {
957 config_ruleinfo->alert_opts |= SAME_EXTRAINFO;
958 }
959 } else if(strcmp(rule_opt[k]->element,
960 xml_different_srcip) == 0) {
961 config_ruleinfo->context_opts|= DIFFERENT_SRCIP;
962
963 if(!(config_ruleinfo->alert_opts & SAME_EXTRAINFO))
964 config_ruleinfo->alert_opts |= SAME_EXTRAINFO;
965 } else if(strcmp(rule_opt[k]->element,
966 xml_different_srcgeoip) == 0) {
967 config_ruleinfo->context_opts|= DIFFERENT_SRCGEOIP;
968
969 if(!(config_ruleinfo->alert_opts & SAME_EXTRAINFO))
970 config_ruleinfo->alert_opts |= SAME_EXTRAINFO;
971 } else if (strcmp(rule_opt[k]->element, xml_notsame_id) == 0) {
972 config_ruleinfo->context_opts &= NOT_SAME_ID;
973 } else if (strcasecmp(rule_opt[k]->element,
974 xml_fts) == 0) {
975 config_ruleinfo->alert_opts |= DO_FTS;
976 } else if (strcasecmp(rule_opt[k]->element,
977 xml_same_user) == 0) {
978 config_ruleinfo->context_opts |= SAME_USER;
979
980 if (!(config_ruleinfo->alert_opts & SAME_EXTRAINFO)) {
981 config_ruleinfo->alert_opts |= SAME_EXTRAINFO;
982 }
983 } else if (strcasecmp(rule_opt[k]->element,
984 xml_notsame_user) == 0) {
985 config_ruleinfo->context_opts &= NOT_SAME_USER;
986 } else if (strcasecmp(rule_opt[k]->element,
987 xml_same_location) == 0) {
988 config_ruleinfo->context_opts |= SAME_LOCATION;
989 if (!(config_ruleinfo->alert_opts & SAME_EXTRAINFO)) {
990 config_ruleinfo->alert_opts |= SAME_EXTRAINFO;
991 }
992 } else if (strcasecmp(rule_opt[k]->element,
993 xml_notsame_agent) == 0) {
994 config_ruleinfo->context_opts &= NOT_SAME_AGENT;
995 } else if (strcasecmp(rule_opt[k]->element,
996 xml_options) == 0) {
997 if (strcmp("alert_by_email",
998 rule_opt[k]->content) == 0) {
999 if (!(config_ruleinfo->alert_opts & DO_MAILALERT)) {
1000 config_ruleinfo->alert_opts |= DO_MAILALERT;
1001 }
1002 } else if (strcmp("no_email_alert",
1003 rule_opt[k]->content) == 0) {
1004 if (config_ruleinfo->alert_opts & DO_MAILALERT) {
1005 config_ruleinfo->alert_opts &= 0xfff - DO_MAILALERT;
1006 }
1007 } else if (strcmp("log_alert",
1008 rule_opt[k]->content) == 0) {
1009 if (!(config_ruleinfo->alert_opts & DO_LOGALERT)) {
1010 config_ruleinfo->alert_opts |= DO_LOGALERT;
1011 }
1012 } else if (strcmp("no_log", rule_opt[k]->content) == 0) {
1013 if (config_ruleinfo->alert_opts & DO_LOGALERT) {
1014 config_ruleinfo->alert_opts &= 0xfff - DO_LOGALERT;
1015 }
1016 } else if (strcmp("no_ar", rule_opt[k]->content) == 0) {
1017 if (!(config_ruleinfo->alert_opts & NO_AR)) {
1018 config_ruleinfo->alert_opts |= NO_AR;
1019 }
1020 } else {
1021 merror(XML_VALUEERR, ARGV0, xml_options,
1022 rule_opt[k]->content);
1023
1024 merror("%s: Invalid option '%s' for "
1025 "rule '%d'.", ARGV0, rule_opt[k]->element,
1026 config_ruleinfo->sigid);
1027 OS_ClearXML(&xml);
1028 return (-1);
1029 }
1030 } else if (strcasecmp(rule_opt[k]->element,
1031 xml_ignore) == 0) {
1032 if (strstr(rule_opt[k]->content, "user") != NULL) {
1033 config_ruleinfo->ignore |= FTS_DSTUSER;
1034 }
1035 if (strstr(rule_opt[k]->content, "srcip") != NULL) {
1036 config_ruleinfo->ignore |= FTS_SRCIP;
1037 }
1038 if (strstr(rule_opt[k]->content, "dstip") != NULL) {
1039 config_ruleinfo->ignore |= FTS_DSTIP;
1040 }
1041 if (strstr(rule_opt[k]->content, "id") != NULL) {
1042 config_ruleinfo->ignore |= FTS_ID;
1043 }
1044 if (strstr(rule_opt[k]->content, "location") != NULL) {
1045 config_ruleinfo->ignore |= FTS_LOCATION;
1046 }
1047 if (strstr(rule_opt[k]->content, "data") != NULL) {
1048 config_ruleinfo->ignore |= FTS_DATA;
1049 }
1050 if (strstr(rule_opt[k]->content, "name") != NULL) {
1051 config_ruleinfo->ignore |= FTS_NAME;
1052
1053 }
1054 if (!config_ruleinfo->ignore) {
1055 merror("%s: Wrong ignore option: '%s'",
1056 ARGV0,
1057 rule_opt[k]->content);
1058 return (-1);
1059 }
1060 } else if (strcasecmp(rule_opt[k]->element,
1061 xml_check_if_ignored) == 0) {
1062 if (strstr(rule_opt[k]->content, "user") != NULL) {
1063 config_ruleinfo->ckignore |= FTS_DSTUSER;
1064 }
1065 if (strstr(rule_opt[k]->content, "srcip") != NULL) {
1066 config_ruleinfo->ckignore |= FTS_SRCIP;
1067 }
1068 if (strstr(rule_opt[k]->content, "dstip") != NULL) {
1069 config_ruleinfo->ckignore |= FTS_DSTIP;
1070 }
1071 if (strstr(rule_opt[k]->content, "id") != NULL) {
1072 config_ruleinfo->ckignore |= FTS_ID;
1073 }
1074 if (strstr(rule_opt[k]->content, "location") != NULL) {
1075 config_ruleinfo->ckignore |= FTS_LOCATION;
1076 }
1077 if (strstr(rule_opt[k]->content, "data") != NULL) {
1078 config_ruleinfo->ckignore |= FTS_DATA;
1079 }
1080 if (strstr(rule_opt[k]->content, "name") != NULL) {
1081 config_ruleinfo->ckignore |= FTS_NAME;
1082
1083 }
1084 if (!config_ruleinfo->ckignore) {
1085 merror("%s: Wrong check_if_ignored option: '%s'",
1086 ARGV0,
1087 rule_opt[k]->content);
1088 return (-1);
1089 }
1090 } else {
1091 merror("%s: Invalid option '%s' for "
1092 "rule '%d'.", ARGV0, rule_opt[k]->element,
1093 config_ruleinfo->sigid);
1094 OS_ClearXML(&xml);
1095 return (-1);
1096 }
1097 k++;
1098 }
1099
1100 /* Check for valid use of frequency */
1101 if ((config_ruleinfo->context_opts ||
1102 config_ruleinfo->frequency) &&
1103 !config_ruleinfo->context) {
1104 merror("%s: Invalid use of frequency/context options. "
1105 "Missing if_matched on rule '%d'.",
1106 ARGV0, config_ruleinfo->sigid);
1107 OS_ClearXML(&xml);
1108 return (-1);
1109 }
1110
1111 /* If if_matched_group we must have a if_sid or if_group */
1112 if (if_matched_group) {
1113 if (!config_ruleinfo->if_sid && !config_ruleinfo->if_group) {
1114 os_strdup(if_matched_group,
1115 config_ruleinfo->if_group);
1116 }
1117 }
1118
1119 /* If_matched_sid, we need to get the if_sid */
1120 if (config_ruleinfo->if_matched_sid &&
1121 !config_ruleinfo->if_sid &&
1122 !config_ruleinfo->if_group) {
1123 os_calloc(16, sizeof(char), config_ruleinfo->if_sid);
1124 snprintf(config_ruleinfo->if_sid, 15, "%d",
1125 config_ruleinfo->if_matched_sid);
1126 }
1127
1128 /* Check the regexes */
1129 if (regex) {
1130 os_calloc(1, sizeof(OSRegex), config_ruleinfo->regex);
1131 if (!OSRegex_Compile(regex, config_ruleinfo->regex, 0)) {
1132 merror(REGEX_COMPILE, ARGV0, regex,
1133 config_ruleinfo->regex->error);
1134 return (-1);
1135 }
1136 free(regex);
1137 regex = NULL;
1138 }
1139
1140 if (pcre2) {
1141 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->pcre2);
1142 if (!OSPcre2_Compile(pcre2, config_ruleinfo->pcre2, PCRE2_CASELESS)) {
1143 merror(REGEX_COMPILE, ARGV0, pcre2,
1144 config_ruleinfo->pcre2->error);
1145 return (-1);
1146 }
1147 free(pcre2);
1148 pcre2 = NULL;
1149 }
1150
1151 /* Add in match */
1152 if (match) {
1153 os_calloc(1, sizeof(OSMatch), config_ruleinfo->match);
1154 if (!OSMatch_Compile(match, config_ruleinfo->match, 0)) {
1155 merror(REGEX_COMPILE, ARGV0, match,
1156 config_ruleinfo->match->error);
1157 return (-1);
1158 }
1159 free(match);
1160 match = NULL;
1161 }
1162 else if (match_pcre2) {
1163 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->match_pcre2);
1164 if (!OSPcre2_Compile(match_pcre2, config_ruleinfo->match_pcre2, PCRE2_CASELESS)) {
1165 merror(REGEX_COMPILE, ARGV0, match_pcre2,
1166 config_ruleinfo->match_pcre2->error);
1167 return (-1);
1168 }
1169 free(match_pcre2);
1170 match_pcre2 = NULL;
1171 }
1172
1173 /* Add in id */
1174 if (id) {
1175 os_calloc(1, sizeof(OSMatch), config_ruleinfo->id);
1176 if (!OSMatch_Compile(id, config_ruleinfo->id, 0)) {
1177 merror(REGEX_COMPILE, ARGV0, id,
1178 config_ruleinfo->id->error);
1179 return (-1);
1180 }
1181 free(id);
1182 id = NULL;
1183 }
1184 if (id_pcre2) {
1185 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->id_pcre2);
1186 if (!OSPcre2_Compile(id_pcre2, config_ruleinfo->id_pcre2, PCRE2_CASELESS)) {
1187 merror(REGEX_COMPILE, ARGV0, id,
1188 config_ruleinfo->id_pcre2->error);
1189 return (-1);
1190 }
1191 free(id_pcre2);
1192 id_pcre2 = NULL;
1193 }
1194
1195 /* Add srcport */
1196 if (srcport) {
1197 os_calloc(1, sizeof(OSMatch), config_ruleinfo->srcport);
1198 if (!OSMatch_Compile(srcport, config_ruleinfo->srcport, 0)) {
1199 merror(REGEX_COMPILE, ARGV0, srcport,
1200 config_ruleinfo->id->error);
1201 return (-1);
1202 }
1203 free(srcport);
1204 srcport = NULL;
1205 }
1206 if (srcport_pcre2) {
1207 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->srcport_pcre2);
1208 if (!OSPcre2_Compile(srcport_pcre2, config_ruleinfo->srcport_pcre2, PCRE2_CASELESS)) {
1209 merror(REGEX_COMPILE, ARGV0, srcport_pcre2,
1210 config_ruleinfo->id->error);
1211 return (-1);
1212 }
1213 free(srcport_pcre2);
1214 srcport_pcre2 = NULL;
1215 }
1216
1217 /* Add dstport */
1218 if (dstport) {
1219 os_calloc(1, sizeof(OSMatch), config_ruleinfo->dstport);
1220 if (!OSMatch_Compile(dstport, config_ruleinfo->dstport, 0)) {
1221 merror(REGEX_COMPILE, ARGV0, dstport,
1222 config_ruleinfo->id->error);
1223 return (-1);
1224 }
1225 free(dstport);
1226 dstport = NULL;
1227 }
1228 else if (dstport_pcre2) {
1229 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->dstport_pcre2);
1230 if (!OSPcre2_Compile(dstport_pcre2, config_ruleinfo->dstport_pcre2, PCRE2_CASELESS)) {
1231 merror(REGEX_COMPILE, ARGV0, dstport_pcre2,
1232 config_ruleinfo->id->error);
1233 return (-1);
1234 }
1235 free(dstport_pcre2);
1236 dstport_pcre2 = NULL;
1237 }
1238
1239 /* Add in status */
1240 if (status) {
1241 os_calloc(1, sizeof(OSMatch), config_ruleinfo->status);
1242 if (!OSMatch_Compile(status, config_ruleinfo->status, 0)) {
1243 merror(REGEX_COMPILE, ARGV0, status,
1244 config_ruleinfo->status->error);
1245 return (-1);
1246 }
1247 free(status);
1248 status = NULL;
1249 }
1250 else if (status_pcre2) {
1251 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->status_pcre2);
1252 if (!OSPcre2_Compile(status_pcre2, config_ruleinfo->status_pcre2, PCRE2_CASELESS)) {
1253 merror(REGEX_COMPILE, ARGV0, status_pcre2,
1254 config_ruleinfo->status_pcre2->error);
1255 return (-1);
1256 }
1257 free(status_pcre2);
1258 status_pcre2 = NULL;
1259 }
1260
1261 /* Add in hostname */
1262 if (hostname) {
1263 os_calloc(1, sizeof(OSMatch), config_ruleinfo->hostname);
1264 if (!OSMatch_Compile(hostname, config_ruleinfo->hostname, 0)) {
1265 merror(REGEX_COMPILE, ARGV0, hostname,
1266 config_ruleinfo->hostname->error);
1267 return (-1);
1268 }
1269 free(hostname);
1270 hostname = NULL;
1271 }
1272 else if (hostname_pcre2) {
1273 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->hostname_pcre2);
1274 if (!OSPcre2_Compile(hostname_pcre2, config_ruleinfo->hostname_pcre2, PCRE2_CASELESS)) {
1275 merror(REGEX_COMPILE, ARGV0, hostname_pcre2,
1276 config_ruleinfo->hostname_pcre2->error);
1277 return (-1);
1278 }
1279 free(hostname_pcre2);
1280 hostname_pcre2 = NULL;
1281 }
1282
1283 /* Add extra data */
1284 if (extra_data) {
1285 os_calloc(1, sizeof(OSMatch), config_ruleinfo->extra_data);
1286 if (!OSMatch_Compile(extra_data,
1287 config_ruleinfo->extra_data, 0)) {
1288 merror(REGEX_COMPILE, ARGV0, extra_data,
1289 config_ruleinfo->extra_data->error);
1290 return (-1);
1291 }
1292 free(extra_data);
1293 extra_data = NULL;
1294 }
1295 else if (extra_data_pcre2) {
1296 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->extra_data_pcre2);
1297 if (!OSPcre2_Compile(extra_data_pcre2,
1298 config_ruleinfo->extra_data_pcre2, PCRE2_CASELESS)) {
1299 merror(REGEX_COMPILE, ARGV0, extra_data_pcre2,
1300 config_ruleinfo->extra_data_pcre2->error);
1301 return (-1);
1302 }
1303 free(extra_data_pcre2);
1304 extra_data_pcre2 = NULL;
1305 }
1306
1307 /* Add in program name */
1308 if (program_name) {
1309 os_calloc(1, sizeof(OSMatch), config_ruleinfo->program_name);
1310 if (!OSMatch_Compile(program_name,
1311 config_ruleinfo->program_name, 0)) {
1312 merror(REGEX_COMPILE, ARGV0, program_name,
1313 config_ruleinfo->program_name->error);
1314 return (-1);
1315 }
1316 free(program_name);
1317 program_name = NULL;
1318 }
1319 else if (program_name_pcre2) {
1320 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->program_name_pcre2);
1321 if (!OSPcre2_Compile(program_name_pcre2,
1322 config_ruleinfo->program_name_pcre2, PCRE2_CASELESS)) {
1323 merror(REGEX_COMPILE, ARGV0, program_name_pcre2,
1324 config_ruleinfo->program_name_pcre2->error);
1325 return (-1);
1326 }
1327 free(program_name_pcre2);
1328 program_name_pcre2 = NULL;
1329 }
1330
1331 /* Add in user */
1332 if (user) {
1333 os_calloc(1, sizeof(OSMatch), config_ruleinfo->user);
1334 if (!OSMatch_Compile(user, config_ruleinfo->user, 0)) {
1335 merror(REGEX_COMPILE, ARGV0, user,
1336 config_ruleinfo->user->error);
1337 return (-1);
1338 }
1339 free(user);
1340 user = NULL;
1341 }
1342 else if (user_pcre2) {
1343 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->user_pcre2);
1344 if (!OSPcre2_Compile(user_pcre2, config_ruleinfo->user_pcre2, PCRE2_CASELESS)) {
1345 merror(REGEX_COMPILE, ARGV0, user_pcre2,
1346 config_ruleinfo->user_pcre2->error);
1347 return (-1);
1348 }
1349 free(user_pcre2);
1350 user_pcre2 = NULL;
1351 }
1352
1353 /* Adding in srcgeoip */
1354 if(srcgeoip) {
1355 os_calloc(1, sizeof(OSMatch), config_ruleinfo->srcgeoip);
1356 if(!OSMatch_Compile(srcgeoip, config_ruleinfo->srcgeoip, 0)) {
1357 merror(REGEX_COMPILE, ARGV0, srcgeoip,
1358 config_ruleinfo->srcgeoip->error);
1359 return(-1);
1360 }
1361 free(srcgeoip);
1362 srcgeoip = NULL;
1363 }
1364 else if(srcgeoip_pcre2) {
1365 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->srcgeoip_pcre2);
1366 if(!OSPcre2_Compile(srcgeoip_pcre2, config_ruleinfo->srcgeoip_pcre2, PCRE2_CASELESS)) {
1367 merror(REGEX_COMPILE, ARGV0, srcgeoip_pcre2,
1368 config_ruleinfo->srcgeoip_pcre2->error);
1369 return(-1);
1370 }
1371 free(srcgeoip_pcre2);
1372 srcgeoip_pcre2 = NULL;
1373 }
1374
1375
1376 /* Adding in dstgeoip */
1377 if(dstgeoip) {
1378 os_calloc(1, sizeof(OSMatch), config_ruleinfo->dstgeoip);
1379 if(!OSMatch_Compile(dstgeoip, config_ruleinfo->dstgeoip, 0)) {
1380 merror(REGEX_COMPILE, ARGV0, dstgeoip,
1381 config_ruleinfo->dstgeoip->error);
1382 return(-1);
1383 }
1384 free(dstgeoip);
1385 dstgeoip = NULL;
1386 }
1387 else if(dstgeoip_pcre2) {
1388 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->dstgeoip_pcre2);
1389 if(!OSPcre2_Compile(dstgeoip_pcre2, config_ruleinfo->dstgeoip_pcre2, PCRE2_CASELESS)) {
1390 merror(REGEX_COMPILE, ARGV0, dstgeoip_pcre2,
1391 config_ruleinfo->dstgeoip_pcre2->error);
1392 return(-1);
1393 }
1394 free(dstgeoip_pcre2);
1395 dstgeoip_pcre2 = NULL;
1396 }
1397
1398
1399 /* Add in URL */
1400 if (url) {
1401 os_calloc(1, sizeof(OSMatch), config_ruleinfo->url);
1402 if (!OSMatch_Compile(url, config_ruleinfo->url, 0)) {
1403 merror(REGEX_COMPILE, ARGV0, url,
1404 config_ruleinfo->url->error);
1405 return (-1);
1406 }
1407 free(url);
1408 url = NULL;
1409 }
1410 else if (url_pcre2) {
1411 os_calloc(1, sizeof(OSPcre2), config_ruleinfo->url_pcre2);
1412 if (!OSPcre2_Compile(url_pcre2, config_ruleinfo->url_pcre2, PCRE2_CASELESS)) {
1413 merror(REGEX_COMPILE, ARGV0, url_pcre2,
1414 config_ruleinfo->url_pcre2->error);
1415 return (-1);
1416 }
1417 free(url_pcre2);
1418 url_pcre2 = NULL;
1419 }
1420
1421 /* Add matched_group */
1422 if (if_matched_group) {
1423 os_calloc(1, sizeof(OSMatch),
1424 config_ruleinfo->if_matched_group);
1425
1426 if (!OSMatch_Compile(if_matched_group,
1427 config_ruleinfo->if_matched_group,
1428 0)) {
1429 merror(REGEX_COMPILE, ARGV0, if_matched_group,
1430 config_ruleinfo->if_matched_group->error);
1431 return (-1);
1432 }
1433 free(if_matched_group);
1434 if_matched_group = NULL;
1435 }
1436
1437 /* Add matched_regex */
1438 if (if_matched_regex) {
1439 os_calloc(1, sizeof(OSRegex),
1440 config_ruleinfo->if_matched_regex);
1441 if (!OSRegex_Compile(if_matched_regex,
1442 config_ruleinfo->if_matched_regex, 0)) {
1443 merror(REGEX_COMPILE, ARGV0, if_matched_regex,
1444 config_ruleinfo->if_matched_regex->error);
1445 return (-1);
1446 }
1447 free(if_matched_regex);
1448 if_matched_regex = NULL;
1449 }
1450 OS_ClearNode(rule_opt);
1451 } /* end of elements block */
1452
1453 /* Assign an active response to the rule */
1454 Rule_AddAR(config_ruleinfo);
1455
1456 j++; /* next rule */
1457
1458 /* Create the last_events if necessary */
1459 if (config_ruleinfo->context) {
1460 int ii = 0;
1461 os_calloc(MAX_LAST_EVENTS + 1, sizeof(char *),
1462 config_ruleinfo->last_events);
1463
1464 /* Zero each entry */
1465 for (; ii <= MAX_LAST_EVENTS; ii++) {
1466 config_ruleinfo->last_events[ii] = NULL;
1467 }
1468 }
1469
1470 /* Add the rule to the rules list.
1471 * Only the template rules are supposed
1472 * to be at the top level. All others
1473 * will be a "child" of someone.
1474 */
1475 if (config_ruleinfo->sigid < 10) {
1476 OS_AddRule(config_ruleinfo);
1477 } else if (config_ruleinfo->alert_opts & DO_OVERWRITE) {
1478 if (!OS_AddRuleInfo(NULL, config_ruleinfo,
1479 config_ruleinfo->sigid)) {
1480 merror("%s: Overwrite rule '%d' not found.",
1481 ARGV0, config_ruleinfo->sigid);
1482 OS_ClearXML(&xml);
1483 return (-1);
1484 }
1485 } else {
1486 OS_AddChild(config_ruleinfo);
1487 }
1488
1489 /* Clean what we do not need */
1490 if (config_ruleinfo->if_group) {
1491 free(config_ruleinfo->if_group);
1492 config_ruleinfo->if_group = NULL;
1493 }
1494
1495 /* Set the event_search pointer */
1496 if (config_ruleinfo->if_matched_sid) {
1497 config_ruleinfo->event_search = (void *(*)(void *, void *))
1498 Search_LastSids;
1499
1500 /* Mark rules that match this id */
1501 OS_MarkID(NULL, config_ruleinfo);
1502 }
1503
1504 /* Mark the rules that match if_matched_group */
1505 else if (config_ruleinfo->if_matched_group) {
1506 /* Create list */
1507 config_ruleinfo->group_search = OSList_Create();
1508 if (!config_ruleinfo->group_search) {
1509 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
1510 }
1511
1512 /* Mark rules that match this group */
1513 OS_MarkGroup(NULL, config_ruleinfo);
1514
1515 /* Set function pointer */
1516 config_ruleinfo->event_search = (void *(*)(void *, void *))
1517 Search_LastGroups;
1518 } else if (config_ruleinfo->context) {
1519 if ((config_ruleinfo->context == 1) &&
1520 (config_ruleinfo->context_opts & SAME_DODIFF)) {
1521 config_ruleinfo->context = 0;
1522 } else {
1523 config_ruleinfo->event_search = (void *(*)(void *, void *))
1524 Search_LastEvents;
1525 }
1526 }
1527
1528 } /* while(rule[j]) */
1529 OS_ClearNode(rule);
1530 i++;
1531
1532 } /* while (node[i]) */
1533
1534 /* Clean global node */
1535 OS_ClearNode(node);
1536 OS_ClearXML(&xml);
1537
1538 #ifdef DEBUG
1539 {
1540 RuleNode *dbg_node = OS_GetFirstRule();
1541 while (dbg_node) {
1542 if (dbg_node->child) {
1543 RuleNode *child_node = dbg_node->child;
1544
1545 printf("** Child Node for %d **\n", dbg_node->ruleinfo->sigid);
1546 while (child_node) {
1547 child_node = child_node->next;
1548 }
1549 }
1550 dbg_node = dbg_node->next;
1551 }
1552 }
1553 #endif
1554
1555 /* Done over here */
1556 return (0);
1557 }
1558
1559 /* Allocate memory at "*at" and copy *str to it.
1560 * If *at already exist, realloc the memory and cat str on it.
1561 * Returns the new string
1562 */
loadmemory(char * at,const char * str)1563 static char *loadmemory(char *at, const char *str)
1564 {
1565 if (at == NULL) {
1566 size_t strsize = 0;
1567 if ((strsize = strlen(str)) < OS_SIZE_2048) {
1568 at = (char *) calloc(strsize + 1, sizeof(char));
1569 if (at == NULL) {
1570 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
1571 return (NULL);
1572 }
1573 strncpy(at, str, strsize);
1574 return (at);
1575 } else {
1576 merror(SIZE_ERROR, ARGV0, str);
1577 return (NULL);
1578 }
1579 } else {
1580 /* at is not null. Need to reallocate its memory and copy str to it */
1581 size_t strsize = strlen(str);
1582 size_t atsize = strlen(at);
1583 size_t finalsize = atsize + strsize + 1;
1584
1585 if ((atsize > OS_SIZE_2048) || (strsize > OS_SIZE_2048)) {
1586 merror(SIZE_ERROR, ARGV0, str);
1587 return (NULL);
1588 }
1589
1590 at = (char *) realloc(at, (finalsize) * sizeof(char));
1591
1592 if (at == NULL) {
1593 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
1594 return (NULL);
1595 }
1596
1597 strncat(at, str, strsize);
1598 at[finalsize - 1] = '\0';
1599
1600 return (at);
1601 }
1602 return (NULL);
1603 }
1604
zeroinfodetails(int type,const char * data)1605 RuleInfoDetail *zeroinfodetails(int type, const char *data)
1606 {
1607 RuleInfoDetail *info_details_pt = NULL;
1608
1609 info_details_pt = (RuleInfoDetail *)calloc(1, sizeof(RuleInfoDetail));
1610
1611 if (info_details_pt == NULL) {
1612 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
1613 }
1614
1615 info_details_pt->type = type;
1616 os_strdup(data, info_details_pt->data);
1617 info_details_pt->next = NULL;
1618
1619 return (info_details_pt);
1620 }
1621
zerorulemember(int id,int level,int maxsize,int frequency,int timeframe,int noalert,int ignore_time,int overwrite)1622 RuleInfo *zerorulemember(int id, int level,
1623 int maxsize, int frequency,
1624 int timeframe, int noalert,
1625 int ignore_time, int overwrite)
1626 {
1627 RuleInfo *ruleinfo_pt = NULL;
1628
1629 /* Allocate memory for structure */
1630 ruleinfo_pt = (RuleInfo *)calloc(1, sizeof(RuleInfo));
1631
1632 if (ruleinfo_pt == NULL) {
1633 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
1634 }
1635
1636 /* Default values */
1637 ruleinfo_pt->level = level;
1638
1639 /* Default category is syslog */
1640 ruleinfo_pt->category = SYSLOG;
1641
1642 ruleinfo_pt->ar = NULL;
1643
1644 ruleinfo_pt->context = 0;
1645
1646 ruleinfo_pt->sigid = id;
1647 ruleinfo_pt->firedtimes = 0;
1648 ruleinfo_pt->maxsize = maxsize;
1649 ruleinfo_pt->frequency = frequency;
1650 if (ruleinfo_pt->frequency > _max_freq) {
1651 _max_freq = ruleinfo_pt->frequency;
1652 }
1653 ruleinfo_pt->ignore_time = ignore_time;
1654 ruleinfo_pt->timeframe = timeframe;
1655 ruleinfo_pt->time_ignored = 0;
1656
1657 ruleinfo_pt->context_opts = 0;
1658 ruleinfo_pt->alert_opts = 0;
1659 ruleinfo_pt->ignore = 0;
1660 ruleinfo_pt->ckignore = 0;
1661
1662 if (noalert) {
1663 ruleinfo_pt->alert_opts |= NO_ALERT;
1664 }
1665 if (Config.mailbylevel <= level) {
1666 ruleinfo_pt->alert_opts |= DO_MAILALERT;
1667 }
1668 if (Config.logbylevel <= level) {
1669 ruleinfo_pt->alert_opts |= DO_LOGALERT;
1670 }
1671
1672 /* Overwrite a rule */
1673 if (overwrite) {
1674 ruleinfo_pt->alert_opts |= DO_OVERWRITE;
1675 }
1676
1677 ruleinfo_pt->day_time = NULL;
1678 ruleinfo_pt->week_day = NULL;
1679
1680 ruleinfo_pt->group = NULL;
1681 ruleinfo_pt->regex = NULL;
1682 ruleinfo_pt->match = NULL;
1683 ruleinfo_pt->decoded_as = 0;
1684
1685 ruleinfo_pt->comment = NULL;
1686 ruleinfo_pt->info = NULL;
1687 ruleinfo_pt->cve = NULL;
1688 ruleinfo_pt->info_details = NULL;
1689
1690 ruleinfo_pt->if_sid = NULL;
1691 ruleinfo_pt->if_group = NULL;
1692 ruleinfo_pt->if_level = NULL;
1693
1694 ruleinfo_pt->if_matched_regex = NULL;
1695 ruleinfo_pt->if_matched_group = NULL;
1696 ruleinfo_pt->if_matched_sid = 0;
1697
1698 ruleinfo_pt->user = NULL;
1699 ruleinfo_pt->srcip = NULL;
1700 ruleinfo_pt->srcport = NULL;
1701 ruleinfo_pt->dstip = NULL;
1702 ruleinfo_pt->dstport = NULL;
1703 ruleinfo_pt->url = NULL;
1704 ruleinfo_pt->id = NULL;
1705 ruleinfo_pt->status = NULL;
1706 ruleinfo_pt->hostname = NULL;
1707 ruleinfo_pt->program_name = NULL;
1708 ruleinfo_pt->action = NULL;
1709 os_calloc(Config.decoder_order_size, sizeof(FieldInfo*), ruleinfo_pt->fields);
1710
1711
1712 /* Zero last matched events */
1713 ruleinfo_pt->__frequency = 0;
1714 ruleinfo_pt->last_events = NULL;
1715
1716 /* Zeroing the list of previous matches */
1717 ruleinfo_pt->sid_prev_matched = NULL;
1718 ruleinfo_pt->group_prev_matched = NULL;
1719
1720 ruleinfo_pt->sid_search = NULL;
1721 ruleinfo_pt->group_search = NULL;
1722
1723 ruleinfo_pt->event_search = NULL;
1724 ruleinfo_pt->compiled_rule = NULL;
1725 ruleinfo_pt->lists = NULL;
1726
1727 return (ruleinfo_pt);
1728 }
1729
get_info_attributes(char ** attributes,char ** values)1730 int get_info_attributes(char **attributes, char **values)
1731 {
1732 const char *xml_type = "type";
1733 int k = 0;
1734
1735 if (!attributes) {
1736 return (RULEINFODETAIL_TEXT);
1737 }
1738
1739 while (attributes[k]) {
1740 if (!values[k]) {
1741 merror("rules_op: Entry info type \"%s\" does not have a value",
1742 attributes[k]);
1743 return (-1);
1744 } else if (strcasecmp(attributes[k], xml_type) == 0) {
1745 if (strcmp(values[k], "text") == 0) {
1746 return (RULEINFODETAIL_TEXT);
1747 } else if (strcmp(values[k], "link") == 0) {
1748 return (RULEINFODETAIL_LINK);
1749 } else if (strcmp(values[k], "cve") == 0) {
1750 return (RULEINFODETAIL_CVE);
1751 } else if (strcmp(values[k], "osvdb") == 0) {
1752 return (RULEINFODETAIL_OSVDB);
1753 }
1754 }
1755 }
1756 return (RULEINFODETAIL_TEXT);
1757 }
1758
1759 /* Get the attributes */
getattributes(char ** attributes,char ** values,int * id,int * level,int * maxsize,int * timeframe,int * frequency,int * accuracy,int * noalert,int * ignore_time,int * overwrite)1760 static int getattributes(char **attributes, char **values,
1761 int *id, int *level,
1762 int *maxsize, int *timeframe,
1763 int *frequency, int *accuracy,
1764 int *noalert, int *ignore_time, int *overwrite)
1765 {
1766 int k = 0;
1767
1768 const char *xml_id = "id";
1769 const char *xml_level = "level";
1770 const char *xml_maxsize = "maxsize";
1771 const char *xml_timeframe = "timeframe";
1772 const char *xml_frequency = "frequency";
1773 const char *xml_accuracy = "accuracy";
1774 const char *xml_noalert = "noalert";
1775 const char *xml_ignore_time = "ignore";
1776 const char *xml_overwrite = "overwrite";
1777
1778 /* Get attributes */
1779 while (attributes[k]) {
1780 if (!values[k]) {
1781 merror("rules_op: Attribute \"%s\" without value."
1782 , attributes[k]);
1783 return (-1);
1784 }
1785 /* Get rule id */
1786 else if (strcasecmp(attributes[k], xml_id) == 0) {
1787 if (OS_StrIsNum(values[k])) {
1788 sscanf(values[k], "%6d", id);
1789 } else {
1790 merror("rules_op: Invalid rule id: %s. "
1791 "Must be integer" ,
1792 values[k]);
1793 return (-1);
1794 }
1795 }
1796 /* Get level */
1797 else if (strcasecmp(attributes[k], xml_level) == 0) {
1798 if (OS_StrIsNum(values[k])) {
1799 sscanf(values[k], "%4d", level);
1800 } else {
1801 merror("rules_op: Invalid level: %s. "
1802 "Must be integer" ,
1803 values[k]);
1804 return (-1);
1805 }
1806 }
1807 /* Get maxsize */
1808 else if (strcasecmp(attributes[k], xml_maxsize) == 0) {
1809 if (OS_StrIsNum(values[k])) {
1810 sscanf(values[k], "%4d", maxsize);
1811 } else {
1812 merror("rules_op: Invalid maxsize: %s. "
1813 "Must be integer" ,
1814 values[k]);
1815 return (-1);
1816 }
1817 }
1818 /* Get timeframe */
1819 else if (strcasecmp(attributes[k], xml_timeframe) == 0) {
1820 if (OS_StrIsNum(values[k])) {
1821 sscanf(values[k], "%5d", timeframe);
1822 } else {
1823 merror("rules_op: Invalid timeframe: %s. "
1824 "Must be integer" ,
1825 values[k]);
1826 return (-1);
1827 }
1828 }
1829 /* Get frequency */
1830 else if (strcasecmp(attributes[k], xml_frequency) == 0) {
1831 if (OS_StrIsNum(values[k])) {
1832 sscanf(values[k], "%4d", frequency);
1833 } else {
1834 merror("rules_op: Invalid frequency: %s. "
1835 "Must be integer" ,
1836 values[k]);
1837 return (-1);
1838 }
1839 }
1840 /* Rule accuracy */
1841 else if (strcasecmp(attributes[k], xml_accuracy) == 0) {
1842 if (OS_StrIsNum(values[k])) {
1843 sscanf(values[k], "%4d", accuracy);
1844 } else {
1845 merror("rules_op: Invalid accuracy: %s. "
1846 "Must be integer" ,
1847 values[k]);
1848 return (-1);
1849 }
1850 }
1851 /* Rule ignore_time */
1852 else if (strcasecmp(attributes[k], xml_ignore_time) == 0) {
1853 if (OS_StrIsNum(values[k])) {
1854 sscanf(values[k], "%6d", ignore_time);
1855 } else {
1856 merror("rules_op: Invalid ignore_time: %s. "
1857 "Must be integer" ,
1858 values[k]);
1859 return (-1);
1860 }
1861 }
1862 /* Rule noalert */
1863 else if (strcasecmp(attributes[k], xml_noalert) == 0) {
1864 *noalert = 1;
1865 } else if (strcasecmp(attributes[k], xml_overwrite) == 0) {
1866 if (strcmp(values[k], "yes") == 0) {
1867 *overwrite = 1;
1868 } else if (strcmp(values[k], "no") == 0) {
1869 *overwrite = 0;
1870 } else {
1871 merror("rules_op: Invalid overwrite: %s. "
1872 "Can only by 'yes' or 'no'.", values[k]);
1873 return (-1);
1874 }
1875 } else {
1876 merror("rules_op: Invalid attribute \"%s\". "
1877 "Only id, level, maxsize, accuracy, noalert and timeframe "
1878 "are allowed.", attributes[k]);
1879 return (-1);
1880 }
1881 k++;
1882 }
1883 return (0);
1884 }
1885
1886 /* Bind active responses to a rule */
Rule_AddAR(RuleInfo * rule_config)1887 static void Rule_AddAR(RuleInfo *rule_config)
1888 {
1889 unsigned int rule_ar_size = 0;
1890 int mark_to_ar = 0;
1891 int rule_real_level = 0;
1892
1893 OSListNode *my_ars_node;
1894
1895 /* Set the correct levels
1896 * We play internally with the rules, to set
1897 * the priorities... Rules with 0 of accuracy,
1898 * receive a low level and go down in the list
1899 */
1900 if (rule_config->level == 9900) {
1901 rule_real_level = 0;
1902 }
1903
1904 else if (rule_config->level >= 100) {
1905 rule_real_level = rule_config->level / 100;
1906 }
1907
1908 /* No AR for ignored rules */
1909 if (rule_real_level == 0) {
1910 return;
1911 }
1912
1913 /* No AR when options no_ar is set */
1914 if (rule_config->alert_opts & NO_AR) {
1915 return;
1916 }
1917
1918 if (!active_responses) {
1919 return;
1920 }
1921
1922 /* Loop on all AR */
1923 my_ars_node = OSList_GetFirstNode(active_responses);
1924 while (my_ars_node) {
1925 active_response *my_ar;
1926
1927
1928 my_ar = (active_response *)my_ars_node->data;
1929 mark_to_ar = 0;
1930
1931 /* Check if the level for the ar is higher */
1932 if (my_ar->level) {
1933 if (rule_real_level >= my_ar->level) {
1934 mark_to_ar = 1;
1935 }
1936 }
1937
1938 /* Check if group matches */
1939 if (my_ar->rules_group) {
1940 if (OS_Regex(my_ar->rules_group, rule_config->group)) {
1941 mark_to_ar = 1;
1942 }
1943 }
1944
1945 /* Check if rule id matches */
1946 if (my_ar->rules_id) {
1947 int r_id = 0;
1948 char *str_pt = my_ar->rules_id;
1949
1950 while (*str_pt != '\0') {
1951 /* We allow spaces in between */
1952 if (*str_pt == ' ') {
1953 str_pt++;
1954 continue;
1955 }
1956
1957 /* If is digit, we get the value
1958 * and search for the next digit
1959 * available
1960 */
1961 else if (isdigit((int)*str_pt)) {
1962 r_id = atoi(str_pt);
1963
1964 /* mark to ar if id matches */
1965 if (r_id == rule_config->sigid) {
1966 mark_to_ar = 1;
1967 }
1968
1969 str_pt = strchr(str_pt, ',');
1970 if (str_pt) {
1971 str_pt++;
1972 } else {
1973 break;
1974 }
1975 }
1976
1977 /* Check for duplicate commas */
1978 else if (*str_pt == ',') {
1979 str_pt++;
1980 continue;
1981 }
1982
1983 else {
1984 break;
1985 }
1986 }
1987 } /* eof of rules_id */
1988
1989 /* Bind AR to the rule */
1990 if (mark_to_ar == 1) {
1991 rule_ar_size++;
1992
1993 rule_config->ar = (active_response **) realloc(rule_config->ar,
1994 (rule_ar_size + 1)
1995 * sizeof(active_response *));
1996
1997 /* Always set the last node to NULL */
1998 rule_config->ar[rule_ar_size - 1] = my_ar;
1999 rule_config->ar[rule_ar_size] = NULL;
2000 }
2001
2002 my_ars_node = OSList_GetNextNode(active_responses);
2003 }
2004
2005 return;
2006 }
2007
printRuleinfo(const RuleInfo * rule,int node)2008 static void printRuleinfo(const RuleInfo *rule, int node)
2009 {
2010 debug1("%d : rule:%d, level %d, timeout: %d",
2011 node,
2012 rule->sigid,
2013 rule->level,
2014 rule->ignore_time);
2015 }
2016
2017 /* Add rule to hash */
AddHash_Rule(RuleNode * node)2018 int AddHash_Rule(RuleNode *node)
2019 {
2020 while (node) {
2021 char id_key[15];
2022
2023 snprintf(id_key, 14, "%d", node->ruleinfo->sigid);
2024
2025 /* Add key to hash */
2026 OSHash_Add(Config.g_rules_hash, id_key, node->ruleinfo);
2027 if (node->child) {
2028 AddHash_Rule(node->child);
2029 }
2030
2031 node = node->next;
2032 }
2033
2034 return (0);
2035 }
2036
_setlevels(RuleNode * node,int nnode)2037 int _setlevels(RuleNode *node, int nnode)
2038 {
2039 int l_size = 0;
2040 while (node) {
2041 if (node->ruleinfo->level == 9900) {
2042 node->ruleinfo->level = 0;
2043 }
2044
2045 if (node->ruleinfo->level >= 100) {
2046 node->ruleinfo->level /= 100;
2047 }
2048
2049 l_size++;
2050
2051 /* Rule information */
2052 printRuleinfo(node->ruleinfo, nnode);
2053
2054 if (node->child) {
2055 int chl_size = 0;
2056 chl_size = _setlevels(node->child, nnode + 1);
2057
2058 l_size += chl_size;
2059 }
2060
2061 node = node->next;
2062 }
2063
2064 return (l_size);
2065 }
2066
2067 /* Test if a rule id exists
2068 * return 1 if exists, otherwise 0
2069 */
doesRuleExist(int sid,RuleNode * r_node)2070 static int doesRuleExist(int sid, RuleNode *r_node)
2071 {
2072 /* Start from the beginning of the list by default */
2073 if (!r_node) {
2074 r_node = OS_GetFirstRule();
2075 }
2076
2077 while (r_node) {
2078 /* Check if the sigid matches */
2079 if (r_node->ruleinfo->sigid == sid) {
2080 return (1);
2081 }
2082
2083 /* Check if the rule has a child */
2084 if (r_node->child) {
2085 /* Check recursively */
2086 if (doesRuleExist(sid, r_node->child)) {
2087 return (1);
2088 }
2089 }
2090
2091 /* Go to the next rule */
2092 r_node = r_node->next;
2093 }
2094
2095 return (0);
2096 }
2097