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