new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / analysisd / rules.c
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 */
37 void Rules_OP_CreateRules()
38 {
39     /* Initialize the rule list */
40     OS_CreateRuleList();
41
42     return;
43 }
44
45 /* Read the log rules */
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  */
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
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
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
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 */
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 */
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
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 */
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
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  */
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 }