Imported Upstream version 2.7
[ossec-hids.git] / src / analysisd / rules_list.c
1 /* @(#) $Id: ./src/analysisd/rules_list.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right 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
13
14 #include "shared.h"
15 #include "rules.h"
16
17 /* Rulenode global  */
18 RuleNode *rulenode;
19
20 /* _OS_Addrule: Internal AddRule */
21 RuleNode *_OS_AddRule(RuleNode *_rulenode, RuleInfo *read_rule);
22
23
24 /* Create the RuleList */
25 void OS_CreateRuleList()
26 {
27     rulenode = NULL;
28
29     return;
30 }
31
32
33 /* Get first node from rule */
34 RuleNode *OS_GetFirstRule()
35 {
36     RuleNode *rulenode_pt = rulenode;
37
38     return(rulenode_pt);
39 }
40
41
42 /* Search all rules, including childs */
43 int _AddtoRule(int sid, int level, int none, char *group,
44                RuleNode *r_node, RuleInfo *read_rule)
45 {
46     int r_code = 0;
47
48     /* If we don't have the first node, start from
49      * the beginning of the list
50      */
51     if(!r_node)
52     {
53         r_node = OS_GetFirstRule();
54     }
55
56     while(r_node)
57     {
58         /* Checking if the sigid matches */
59         if(sid)
60         {
61             if(r_node->ruleinfo->sigid == sid)
62             {
63                 /* Assign the category of this rule to the child
64                  * as they must match
65                  */
66                 read_rule->category = r_node->ruleinfo->category;
67
68
69                 /* If no context for rule, check if the parent has
70                  * and use it.
71                  */
72                 if(!read_rule->last_events && r_node->ruleinfo->last_events)
73                 {
74                     read_rule->last_events = r_node->ruleinfo->last_events;
75                 }
76
77                 r_node->child=
78                     _OS_AddRule(r_node->child, read_rule);
79                 return(1);
80             }
81         }
82
83         /* Checking if the group matches */
84         else if(group)
85         {
86             if(OS_WordMatch(group, r_node->ruleinfo->group) &&
87                (r_node->ruleinfo->sigid != read_rule->sigid))
88             {
89                 /* If no context for rule, check if the parent has
90                  * and use it.
91                  */
92                 if(!read_rule->last_events && r_node->ruleinfo->last_events)
93                 {
94                     read_rule->last_events = r_node->ruleinfo->last_events;
95                 }
96
97                 /* We will loop on all rules until we find */
98                 r_node->child =
99                     _OS_AddRule(r_node->child, read_rule);
100                 r_code = 1;
101             }
102         }
103
104         /* Checking if the level matches */
105         else if(level)
106         {
107             if((r_node->ruleinfo->level >= level) &&
108                (r_node->ruleinfo->sigid != read_rule->sigid))
109             {
110                 r_node->child=
111                     _OS_AddRule(r_node->child, read_rule);
112                 r_code = 1;
113             }
114         }
115
116
117         /* If we are not searching for the sid/group, the category must
118          * be the same.
119          */
120         else if(read_rule->category != r_node->ruleinfo->category)
121         {
122             r_node = r_node->next;
123             continue;
124         }
125
126
127         /* If none of them is set, add for the category */
128         else
129         {
130             /* Setting the parent category to it */
131             read_rule->category = r_node->ruleinfo->category;
132             r_node->child =
133                     _OS_AddRule(r_node->child, read_rule);
134             return(1);
135         }
136
137         /* Checking if the child has a rule */
138         if(r_node->child)
139         {
140             if(_AddtoRule(sid, level, none, group, r_node->child, read_rule))
141             {
142                 r_code = 1;
143             }
144         }
145
146         r_node = r_node->next;
147     }
148
149     return(r_code);
150 }
151
152
153 /* Add a child */
154 int OS_AddChild(RuleInfo *read_rule)
155 {
156     if(!read_rule)
157     {
158         merror("rules_list: Passing a NULL rule. Inconsistent state");
159         return(1);
160     }
161
162     /* Adding for if_sid */
163     if(read_rule->if_sid)
164     {
165         int val = 0;
166         char *sid;
167
168         sid  = read_rule->if_sid;
169
170         /* Loop to read all the rules (comma or space separated */
171         do
172         {
173             int rule_id = 0;
174             if((*sid == ',')||(*sid == ' '))
175             {
176                 val = 0;
177                 continue;
178             }
179             else if((isdigit((int)*sid)) || (*sid == '\0'))
180             {
181                 if(val == 0)
182                 {
183                     rule_id = atoi(sid);
184                     if(!_AddtoRule(rule_id, 0, 0, NULL, NULL, read_rule))
185                     {
186                         ErrorExit("rules_list: Signature ID '%d' not "
187                                   "found. Invalid 'if_sid'.", rule_id);
188                     }
189                     val = 1;
190                 }
191             }
192             else
193             {
194                 ErrorExit("rules_list: Signature ID must be an integer. "
195                           "Exiting...");
196             }
197         }while(*sid++ != '\0');
198     }
199
200     /* Adding for if_level */
201     else if(read_rule->if_level)
202     {
203         int  ilevel = 0;
204
205         ilevel = atoi(read_rule->if_level);
206         if(ilevel == 0)
207         {
208             merror("%s: Invalid level (atoi)",ARGV0);
209             return(1);
210         }
211
212         ilevel*=100;
213
214         if(!_AddtoRule(0, ilevel, 0, NULL, NULL, read_rule))
215         {
216             ErrorExit("rules_list: Level ID '%d' not "
217                     "found. Invalid 'if_level'.", ilevel);
218         }
219     }
220
221     /* Adding for if_group */
222     else if(read_rule->if_group)
223     {
224         if(!_AddtoRule(0, 0, 0, read_rule->if_group, NULL, read_rule))
225         {
226             ErrorExit("rules_list: Group '%s' not "
227                       "found. Invalid 'if_group'.", read_rule->if_group);
228         }
229     }
230
231     /* Just add based on the category */
232     else
233     {
234         if(!_AddtoRule(0, 0, 0, NULL, NULL, read_rule))
235         {
236             ErrorExit("rules_list: Category '%d' not "
237                     "found. Invalid 'category'.", read_rule->category);
238         }
239     }
240
241     /* done over here */
242     return(0);
243 }
244
245
246
247 /* Add a rule in the chain */
248 RuleNode *_OS_AddRule(RuleNode *_rulenode, RuleInfo *read_rule)
249 {
250     RuleNode *tmp_rulenode = _rulenode;
251
252
253     if(tmp_rulenode != NULL)
254     {
255         int middle_insertion = 0;
256         RuleNode *prev_rulenode = NULL;
257         RuleNode *new_rulenode = NULL;
258
259         while(tmp_rulenode != NULL)
260         {
261             if(read_rule->level > tmp_rulenode->ruleinfo->level)
262             {
263                 middle_insertion = 1;
264                 break;
265             }
266             prev_rulenode = tmp_rulenode;
267             tmp_rulenode = tmp_rulenode->next;
268         }
269
270         new_rulenode = (RuleNode *)calloc(1,sizeof(RuleNode));
271
272         if(!new_rulenode)
273         {
274             ErrorExit(MEM_ERROR,ARGV0);
275         }
276
277         if(middle_insertion == 1)
278         {
279             if(prev_rulenode == NULL)
280             {
281                 _rulenode = new_rulenode;
282             }
283             else
284             {
285                 prev_rulenode->next = new_rulenode;
286             }
287
288             new_rulenode->next = tmp_rulenode;
289             new_rulenode->ruleinfo = read_rule;
290             new_rulenode->child = NULL;
291         }
292
293         else
294         {
295             prev_rulenode->next = new_rulenode;
296             prev_rulenode->next->ruleinfo = read_rule;
297             prev_rulenode->next->next = NULL;
298             prev_rulenode->next->child = NULL;
299         }
300     }
301
302     else
303     {
304         _rulenode = (RuleNode *)calloc(1,sizeof(RuleNode));
305         if(_rulenode == NULL)
306         {
307             ErrorExit(MEM_ERROR,ARGV0);
308         }
309
310         _rulenode->ruleinfo = read_rule;
311         _rulenode->next = NULL;
312         _rulenode->child= NULL;
313     }
314
315     return(_rulenode);
316 }
317
318 /* External AddRule */
319 int OS_AddRule(RuleInfo *read_rule)
320 {
321     rulenode = _OS_AddRule(rulenode,read_rule);
322
323     return(0);
324 }
325
326
327 /* Update rule info for overwritten ones */
328 int OS_AddRuleInfo(RuleNode *r_node, RuleInfo *newrule, int sid)
329 {
330     /* If no r_node is given, get first node */
331     if(r_node == NULL)
332     {
333         r_node = OS_GetFirstRule();
334     }
335
336     if(sid == 0)
337         return(0);
338
339     while(r_node)
340     {
341         /* Checking if the sigid matches */
342         if(r_node->ruleinfo->sigid == sid)
343         {
344             r_node->ruleinfo->level = newrule->level;
345             r_node->ruleinfo->maxsize = newrule->maxsize;
346             r_node->ruleinfo->frequency = newrule->frequency;
347             r_node->ruleinfo->timeframe = newrule->timeframe;
348             r_node->ruleinfo->ignore_time = newrule->ignore_time;
349
350             r_node->ruleinfo->group = newrule->group;
351             r_node->ruleinfo->match = newrule->match;
352             r_node->ruleinfo->regex = newrule->regex;
353             r_node->ruleinfo->day_time = newrule->day_time;
354             r_node->ruleinfo->week_day = newrule->week_day;
355             r_node->ruleinfo->srcip = newrule->srcip;
356             r_node->ruleinfo->dstip = newrule->dstip;
357             r_node->ruleinfo->srcport = newrule->srcport;
358             r_node->ruleinfo->dstport = newrule->dstport;
359             r_node->ruleinfo->user = newrule->user;
360             r_node->ruleinfo->url = newrule->url;
361             r_node->ruleinfo->id = newrule->id;
362             r_node->ruleinfo->status = newrule->status;
363             r_node->ruleinfo->hostname = newrule->hostname;
364             r_node->ruleinfo->program_name = newrule->program_name;
365             r_node->ruleinfo->extra_data = newrule->extra_data;
366             r_node->ruleinfo->action = newrule->action;
367             r_node->ruleinfo->comment = newrule->comment;
368             r_node->ruleinfo->info = newrule->info;
369             r_node->ruleinfo->cve = newrule->cve;
370             r_node->ruleinfo->if_matched_regex = newrule->if_matched_regex;
371             r_node->ruleinfo->if_matched_group = newrule->if_matched_group;
372             r_node->ruleinfo->if_matched_sid = newrule->if_matched_sid;
373             r_node->ruleinfo->alert_opts = newrule->alert_opts;
374             r_node->ruleinfo->context_opts = newrule->context_opts;
375             r_node->ruleinfo->context = newrule->context;
376             r_node->ruleinfo->decoded_as = newrule->decoded_as;
377             r_node->ruleinfo->ar = newrule->ar;
378             r_node->ruleinfo->compiled_rule = newrule->compiled_rule;
379             if((newrule->context_opts & SAME_DODIFF) && r_node->ruleinfo->last_events == NULL)
380             {
381                 r_node->ruleinfo->last_events = newrule->last_events;
382             }
383
384             return(1);
385         }
386
387
388         /* Checking if the child has a rule */
389         if(r_node->child)
390         {
391             if(OS_AddRuleInfo(r_node->child, newrule, sid))
392             {
393                 return(1);
394             }
395         }
396
397         r_node = r_node->next;
398     }
399
400     return(0);
401 }
402
403
404 /* Mark rules that match specific id (for if_matched_sid) */
405 int OS_MarkID(RuleNode *r_node, RuleInfo *orig_rule)
406 {
407     /* If no r_node is given, get first node */
408     if(r_node == NULL)
409     {
410         r_node = OS_GetFirstRule();
411     }
412
413     while(r_node)
414     {
415         if(r_node->ruleinfo->sigid == orig_rule->if_matched_sid)
416         {
417             /* If child does not have a list, create one */
418             if(!r_node->ruleinfo->sid_prev_matched)
419             {
420                 r_node->ruleinfo->sid_prev_matched = OSList_Create();
421                 if(!r_node->ruleinfo->sid_prev_matched)
422                 {
423                     ErrorExit(MEM_ERROR, ARGV0);
424                 }
425             }
426
427             /* Assigning the parent pointer to it */
428             orig_rule->sid_search = r_node->ruleinfo->sid_prev_matched;
429         }
430
431
432         /* Checking if the child has a rule */
433         if(r_node->child)
434         {
435             OS_MarkID(r_node->child, orig_rule);
436         }
437
438         r_node = r_node->next;
439     }
440
441     return(0);
442 }
443
444
445
446 /* Mark rules that match specific group (for if_matched_group) */
447 int OS_MarkGroup(RuleNode *r_node, RuleInfo *orig_rule)
448 {
449     /* If no r_node is given, get first node */
450     if(r_node == NULL)
451     {
452         r_node = OS_GetFirstRule();
453     }
454
455     while(r_node)
456     {
457         if(OSMatch_Execute(r_node->ruleinfo->group,
458                            strlen(r_node->ruleinfo->group),
459                            orig_rule->if_matched_group))
460         {
461             int rule_g = 0;
462             if(r_node->ruleinfo->group_prev_matched)
463             {
464                 while(r_node->ruleinfo->group_prev_matched[rule_g])
465                 {
466                     rule_g++;
467                 }
468             }
469
470             os_realloc(r_node->ruleinfo->group_prev_matched,
471                        (rule_g + 2)*sizeof(OSList *),
472                        r_node->ruleinfo->group_prev_matched);
473
474             r_node->ruleinfo->group_prev_matched[rule_g] = NULL;
475             r_node->ruleinfo->group_prev_matched[rule_g +1] = NULL;
476
477             /* Setting the size */
478             r_node->ruleinfo->group_prev_matched_sz = rule_g +1;
479
480             r_node->ruleinfo->group_prev_matched[rule_g] =
481                               orig_rule->group_search;
482         }
483
484
485         /* Checking if the child has a rule */
486         if(r_node->child)
487         {
488             OS_MarkGroup(r_node->child, orig_rule);
489         }
490
491         r_node = r_node->next;
492     }
493
494     return(0);
495 }
496 /* EOF */