Imported Upstream version 2.3
[ossec-hids.git] / src / analysisd / testrule.c
1 /* @(#) $Id: testrule.c,v 1.7 2009/08/25 11:30:57 dcid Exp $ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All rights 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  * License details at the LICENSE file included with OSSEC or 
12  * online at: http://www.ossec.net/en/licensing.html
13  */
14
15
16 /* Part of the OSSEC
17  * Available at http://www.ossec.net
18  */
19   
20
21 /* ossec-analysisd.
22  * Responsible for correlation and log decoding.
23  */
24
25 #ifdef ARGV0
26    #undef ARGV0
27    #define ARGV0 "ossec-testrule"
28 #endif
29
30 #include "shared.h"
31
32 #include "alerts/alerts.h"
33 #include "alerts/getloglocation.h"
34 #include "os_execd/execd.h"
35
36 #include "os_regex/os_regex.h"
37 #include "os_net/os_net.h"
38
39
40 /** Local headers **/
41 #include "active-response.h"
42 #include "config.h"
43 #include "rules.h"
44 #include "stats.h"
45 #include "eventinfo.h"
46 #include "analysisd.h"
47
48
49
50 /** Internal Functions **/
51 void OS_ReadMSG(int m_queue);
52 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
53
54
55 /** External functions prototypes (only called here) **/
56
57 /* For config  */
58 int GlobalConf(char * cfgfile);
59
60
61 /* For rules */
62 void Rules_OP_CreateRules();
63 int Rules_OP_ReadRules(char * cfgfile);
64 int _setlevels(RuleNode *node, int nnode);
65 int AddHash_Rule(RuleNode *node);
66
67
68 /* For cleanmsg */
69 int OS_CleanMSG(char *msg, Eventinfo *lf);
70
71
72 /* for FTS */
73 int FTS_Init();
74 int FTS(Eventinfo *lf);
75 int AddtoIGnore(Eventinfo *lf);
76 int IGnore(Eventinfo *lf);
77
78
79 /* For decoders */
80 void DecodeEvent(Eventinfo *lf);
81 int DecodeSyscheck(Eventinfo *lf);
82 int DecodeRootcheck(Eventinfo *lf);
83 int DecodeHostinfo(Eventinfo *lf);
84
85
86 /* For Decoders */
87 int ReadDecodeXML(char *file);
88 int SetDecodeXML();
89
90
91
92
93 /** int main(int argc, char **argv)
94  */
95 int main(int argc, char **argv)
96 {
97     int c = 0, m_queue = 0;
98     char *dir = DEFAULTDIR;
99     char *user = USER;
100     char *group = GROUPGLOBAL;
101
102     char *cfg = DEFAULTCPATH;
103
104     /* Setting the name */
105     OS_SetName(ARGV0);
106
107     thishour = 0;
108     today = 0;
109     prev_year = 0;
110     full_output = 0;
111     active_responses = NULL;
112     memset(prev_month, '\0', 4);
113
114     while((c = getopt(argc, argv, "Vfdhu:g:D:c:")) != -1){
115         switch(c){
116             case 'V':
117                 print_version();
118                 break;
119             case 'h':
120                 help(ARGV0);
121                 break;
122             case 'd':
123                 nowDebug();
124                 break;
125             case 'u':
126                 if(!optarg)
127                     ErrorExit("%s: -u needs an argument",ARGV0);
128                 user = optarg;
129                 break;
130             case 'g':
131                 if(!optarg)
132                     ErrorExit("%s: -g needs an argument",ARGV0);
133                 group = optarg;
134                 break;
135             case 'D':
136                 if(!optarg)
137                     ErrorExit("%s: -D needs an argument",ARGV0);
138                 dir = optarg;
139             case 'c':
140                 if(!optarg)
141                     ErrorExit("%s: -c needs an argument",ARGV0);
142                 cfg = optarg;
143                 break;
144             case 'f':
145                 full_output = 1;    
146                 break;
147             default:
148                 help(ARGV0);
149                 break;
150         }
151
152     }
153
154
155     /* Reading configuration file */
156     if(GlobalConf(cfg) < 0)
157     {
158         ErrorExit(CONFIG_ERROR,ARGV0, cfg);
159     }
160
161     debug1(READ_CONFIG, ARGV0);
162         
163
164     
165     /* Getting servers hostname */
166     memset(__shost, '\0', 512);
167     if(gethostname(__shost, 512 -1) != 0)
168     {
169         strncpy(__shost, OSSEC_SERVER, 512 -1);    
170     }
171     else
172     {
173         char *_ltmp;
174
175         /* Remove domain part if available */
176         _ltmp = strchr(__shost, '.');
177         if(_ltmp)
178             *_ltmp = '\0';
179     }
180     
181
182
183     if(chdir(dir) != 0)
184         ErrorExit(CHROOT_ERROR,ARGV0,dir);
185
186
187
188     /* Reading decoders */
189     OS_CreateOSDecoderList();
190     if(!ReadDecodeXML("etc/decoder.xml"))
191     {
192         ErrorExit(CONFIG_ERROR, ARGV0,  XML_DECODER);
193     }
194
195     c = ReadDecodeXML("etc/local_decoder.xml");
196     if(!c)
197     {
198         if((c != -2))
199             ErrorExit(CONFIG_ERROR, ARGV0,  XML_LDECODER);
200     }
201     SetDecodeXML();
202
203     
204     /* Creating the rules list */
205     Rules_OP_CreateRules();
206
207    
208     /* Reading the rules */
209     {
210         char **rulesfiles;
211         rulesfiles = Config.includes;
212         while(rulesfiles && *rulesfiles)
213         {
214             debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
215             if(Rules_OP_ReadRules(*rulesfiles) < 0)
216                 ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
217                 
218             free(*rulesfiles);    
219             rulesfiles++;    
220         }
221
222         free(Config.includes);
223         Config.includes = NULL;
224     }
225     
226     
227     /* Fixing the levels/accuracy */
228     {
229         int total_rules;
230         RuleNode *tmp_node = OS_GetFirstRule();
231
232         total_rules = _setlevels(tmp_node, 0);
233         debug1("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);    
234     }
235
236
237     /* Creating a rules hash (for reading alerts from other servers). */
238     {
239         RuleNode *tmp_node = OS_GetFirstRule();
240         Config.g_rules_hash = OSHash_Create();
241         if(!Config.g_rules_hash)
242         {
243             ErrorExit(MEM_ERROR, ARGV0);
244         }
245         AddHash_Rule(tmp_node);
246     }
247
248
249     
250     /* Start up message */
251     verbose(STARTUP_MSG, ARGV0, getpid());
252
253
254     /* Going to main loop */    
255     OS_ReadMSG(m_queue);
256
257
258     exit(0);
259     
260 }
261
262
263
264 /* OS_ReadMSG.
265  * Main function. Receives the messages(events)
266  * and analyze them all.
267  */
268 void OS_ReadMSG(int m_queue)
269 {
270     int i;
271     char msg[OS_MAXSTR +1];
272     Eventinfo *lf;
273
274
275     /* Null to global currently pointers */
276     currently_rule = NULL;
277
278
279     /* Creating the event list */
280     OS_CreateEventList(Config.memorysize);
281
282
283     /* Initiating the FTS list */
284     if(!FTS_Init())
285     {
286         ErrorExit(FTS_LIST_ERROR, ARGV0);
287     }
288                                 
289
290
291     /* Getting currently time before starting */
292     c_time = time(NULL);
293
294
295     /* Doing some cleanup */
296     memset(msg, '\0', OS_MAXSTR +1);
297     
298
299     print_out("%s: Type one log per line.\n", ARGV0);
300     
301     
302     /* Daemon loop */
303     while(1)
304     {
305         lf = (Eventinfo *)calloc(1,sizeof(Eventinfo));
306         
307         /* This shouldn't happen .. */
308         if(lf == NULL)
309         {
310             ErrorExit(MEM_ERROR,ARGV0);
311         }
312
313
314         /* Fixing the msg. */
315         strncpy(msg, "1:a:", 5);
316         
317     
318         
319         /* Receive message from queue */
320         if(fgets(msg +4, OS_MAXSTR, stdin))
321         {
322             RuleNode *rulenode_pt;
323
324             /* Getting the time we received the event */
325             c_time = time(NULL);
326
327
328             /* Removing new line. */
329             if(msg[strlen(msg) -1] == '\n')
330                 msg[strlen(msg) -1] = '\0';
331
332
333             /* Make sure we ignore blank lines. */
334             if(strlen(msg) < 6)
335             {
336                 continue;
337             }
338             
339             
340             print_out("\n");
341             
342
343             /* Default values for the log info */
344             Zero_Eventinfo(lf);
345
346
347             /* Clean the msg appropriately */
348             if(OS_CleanMSG(msg, lf) < 0)
349             {
350                 merror(IMSG_ERROR,ARGV0,msg);
351
352                 Free_Eventinfo(lf);
353
354                 continue;
355             }
356
357
358             /* Currently rule must be null in here */
359             currently_rule = NULL;
360
361
362             /***  Running decoders ***/
363
364             /* Getting log size */
365             lf->size = strlen(lf->log);
366
367
368             /* Decoding event. */
369             DecodeEvent(lf);
370             
371
372             /* Looping all the rules */
373             rulenode_pt = OS_GetFirstRule();
374             if(!rulenode_pt) 
375             {
376                 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
377                         ARGV0);
378             }
379
380             
381             #ifdef TESTRULE
382             if(full_output)
383                 print_out("\n**Rule debugging:");
384             #endif
385
386
387             do
388             {
389                 if(lf->decoder_info->type == OSSEC_ALERT)
390                 {
391                     if(!lf->generated_rule)
392                     {
393                         break;
394                     }
395
396                     /* We go ahead in here and process the alert. */
397                     currently_rule = lf->generated_rule;
398                 }
399                                                                                                                                                                                             
400                 /* The categories must match */
401                 else if(rulenode_pt->ruleinfo->category != 
402                         lf->decoder_info->type)
403                 {
404                     continue;
405                 }
406
407
408                 /* Checking each rule. */
409                 else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt)) 
410                         == NULL)
411                 {
412                     continue;
413                 }
414
415                 #ifdef TESTRULE
416                   print_out("\n**Phase 3: Completed filtering (rules).");
417                   print_out("       Rule id: '%d'", currently_rule->sigid);
418                   print_out("       Level: '%d'", currently_rule->level);
419                   print_out("       Description: '%s'",currently_rule->comment);
420                 #endif
421                                             
422
423
424                 /* Ignore level 0 */
425                 if(currently_rule->level == 0)
426                 {
427                     break;
428                 }
429
430
431                 /* Checking ignore time */ 
432                 if(currently_rule->ignore_time)
433                 {
434                     if(currently_rule->time_ignored == 0)
435                     {
436                         currently_rule->time_ignored = lf->time;
437                     }
438                     /* If the currently time - the time the rule was ignored
439                      * is less than the time it should be ignored,
440                      * leave (do not alert again).
441                      */
442                     else if((lf->time - currently_rule->time_ignored) 
443                             < currently_rule->ignore_time)
444                     {
445                         break;
446                     }
447                     else
448                     {
449                         currently_rule->time_ignored = 0;
450                     }
451                 }
452
453                 /* Pointer to the rule that generated it */
454                 lf->generated_rule = currently_rule;
455
456                 
457                 /* Checking if we should ignore it */
458                 if(currently_rule->ckignore && IGnore(lf))
459                 {
460                     /* Ignoring rule */
461                     lf->generated_rule = NULL;
462                     break;
463                 }
464                 
465                 /* Checking if we need to add to ignore list */
466                 if(currently_rule->ignore)
467                 {
468                     AddtoIGnore(lf);
469                 }
470
471
472                 /* Log the alert if configured to ... */
473                 if(currently_rule->alert_opts & DO_LOGALERT)
474                 {
475                     print_out("**Alert to be generated.\n\n");
476                 }
477
478
479                 /* Copy the structure to the state memory of if_matched_sid */
480                 if(currently_rule->sid_prev_matched)
481                 {
482                     if(!OSList_AddData(currently_rule->sid_prev_matched, lf))
483                     {
484                         merror("%s: Unable to add data to sig list.", ARGV0);
485                     }
486                     else
487                     {
488                         lf->sid_node_to_delete = 
489                             currently_rule->sid_prev_matched->last_node;
490                     }
491                 }
492                 /* Group list */
493                 else if(currently_rule->group_prev_matched)
494                 {
495                     i = 0;  
496                     
497                     while(i < currently_rule->group_prev_matched_sz)
498                     {
499                         if(!OSList_AddData(
500                                 currently_rule->group_prev_matched[i], 
501                                 lf))
502                         {
503                            merror("%s: Unable to add data to grp list.",ARGV0);
504                         }
505                         i++;
506                     }
507                 }
508                 
509                 OS_AddEvent(lf);
510
511                 break;
512
513             }while((rulenode_pt = rulenode_pt->next) != NULL);
514
515
516             /* Only clear the memory if the eventinfo was not
517              * added to the stateful memory 
518              * -- message is free inside clean event --
519              */
520             if(lf->generated_rule == NULL)
521                 Free_Eventinfo(lf);
522
523         }
524         else
525         {
526             exit(0);   
527         }
528     }
529     return;
530 }
531
532
533
534 /* EOF */