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