Imported Upstream version 2.3
[ossec-hids.git] / src / analysisd / rules_list.c
1 /* @(#) $Id: rules_list.c,v 1.28 2009/06/24 17:06:22 dcid Exp $ */
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 3) 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
348             r_node->ruleinfo->group = newrule->group;
349             r_node->ruleinfo->match = newrule->match;
350             r_node->ruleinfo->regex = newrule->regex;
351             r_node->ruleinfo->day_time = newrule->day_time;
352             r_node->ruleinfo->week_day = newrule->week_day;
353             r_node->ruleinfo->srcip = newrule->srcip;
354             r_node->ruleinfo->dstip = newrule->dstip;
355             r_node->ruleinfo->srcport = newrule->srcport;
356             r_node->ruleinfo->dstport = newrule->dstport;
357             r_node->ruleinfo->user = newrule->user;
358             r_node->ruleinfo->url = newrule->url;
359             r_node->ruleinfo->id = newrule->id;
360             r_node->ruleinfo->status = newrule->status;
361             r_node->ruleinfo->hostname = newrule->hostname;
362             r_node->ruleinfo->program_name = newrule->program_name;
363             r_node->ruleinfo->extra_data = newrule->extra_data;
364             r_node->ruleinfo->action = newrule->action;
365             r_node->ruleinfo->comment = newrule->comment;
366             r_node->ruleinfo->info = newrule->info;
367             r_node->ruleinfo->cve = newrule->cve;
368             r_node->ruleinfo->if_matched_regex = newrule->if_matched_regex;
369             r_node->ruleinfo->if_matched_group = newrule->if_matched_group;
370             r_node->ruleinfo->if_matched_sid = newrule->if_matched_sid;
371             r_node->ruleinfo->alert_opts = newrule->alert_opts;
372             r_node->ruleinfo->context_opts = newrule->context_opts;
373             r_node->ruleinfo->context = newrule->context;
374             r_node->ruleinfo->decoded_as = newrule->decoded_as;
375             r_node->ruleinfo->ar = newrule->ar;
376             r_node->ruleinfo->compiled_rule = newrule->compiled_rule;
377
378             return(1);
379         }
380
381
382         /* Checking if the child has a rule */
383         if(r_node->child)
384         {
385             if(OS_AddRuleInfo(r_node->child, newrule, sid))
386             {
387                 return(1);
388             }
389         }
390
391         r_node = r_node->next;
392     }
393
394     return(0);
395 }
396
397
398 /* Mark rules that match specific id (for if_matched_sid) */
399 int OS_MarkID(RuleNode *r_node, RuleInfo *orig_rule)
400 {
401     /* If no r_node is given, get first node */
402     if(r_node == NULL)
403     {
404         r_node = OS_GetFirstRule();
405     }
406
407     while(r_node)
408     {
409         if(r_node->ruleinfo->sigid == orig_rule->if_matched_sid)
410         {
411             /* If child does not have a list, create one */
412             if(!r_node->ruleinfo->sid_prev_matched)
413             {
414                 r_node->ruleinfo->sid_prev_matched = OSList_Create();
415                 if(!r_node->ruleinfo->sid_prev_matched)
416                 {
417                     ErrorExit(MEM_ERROR, ARGV0);
418                 }
419             }
420
421             /* Assigning the parent pointer to it */
422             orig_rule->sid_search = r_node->ruleinfo->sid_prev_matched;
423         }
424
425
426         /* Checking if the child has a rule */
427         if(r_node->child)
428         {
429             OS_MarkID(r_node->child, orig_rule);
430         }
431
432         r_node = r_node->next;
433     }
434
435     return(0);
436 }
437
438
439
440 /* Mark rules that match specific group (for if_matched_group) */
441 int OS_MarkGroup(RuleNode *r_node, RuleInfo *orig_rule)
442 {
443     /* If no r_node is given, get first node */
444     if(r_node == NULL)
445     {
446         r_node = OS_GetFirstRule();
447     }
448
449     while(r_node)
450     {
451         if(OSMatch_Execute(r_node->ruleinfo->group, 
452                            strlen(r_node->ruleinfo->group),
453                            orig_rule->if_matched_group))
454         {
455             int rule_g = 0;
456             if(r_node->ruleinfo->group_prev_matched)
457             {
458                 while(r_node->ruleinfo->group_prev_matched[rule_g])
459                 {
460                     rule_g++;
461                 }
462             }
463             
464             os_realloc(r_node->ruleinfo->group_prev_matched, 
465                        (rule_g + 2)*sizeof(OSList *),
466                        r_node->ruleinfo->group_prev_matched); 
467             
468             r_node->ruleinfo->group_prev_matched[rule_g] = NULL;
469             r_node->ruleinfo->group_prev_matched[rule_g +1] = NULL;
470             
471             /* Setting the size */
472             r_node->ruleinfo->group_prev_matched_sz = rule_g +1;
473             
474             r_node->ruleinfo->group_prev_matched[rule_g] = 
475                               orig_rule->group_search;
476         }
477
478
479         /* Checking if the child has a rule */
480         if(r_node->child)
481         {
482             OS_MarkGroup(r_node->child, orig_rule);
483         }
484
485         r_node = r_node->next;
486     }
487
488     return(0);
489 }
490 /* EOF */