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