Imported Upstream version 2.5.1
[ossec-hids.git] / src / analysisd / testrule.c
1 /* @(#) $Id$ */
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 2) 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
31
32 #include "shared.h"
33
34 #include "alerts/alerts.h"
35 #include "alerts/getloglocation.h"
36 #include "os_execd/execd.h"
37
38 #include "os_regex/os_regex.h"
39 #include "os_net/os_net.h"
40
41
42 /** Local headers **/
43 #include "active-response.h"
44 #include "config.h"
45 #include "rules.h"
46 #include "stats.h"
47
48 #include "eventinfo.h"
49 #include "analysisd.h"
50
51
52
53 /** Internal Functions **/
54 void OS_ReadMSG(int m_queue, char *ut_str);
55 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
56
57
58 /** External functions prototypes (only called here) **/
59
60 /* For config  */
61 int GlobalConf(char * cfgfile);
62
63
64 /* For rules */
65 void Rules_OP_CreateRules();
66 void Lists_OP_CreateLists();
67 int Rules_OP_ReadRules(char * cfgfile);
68 int _setlevels(RuleNode *node, int nnode);
69 int AddHash_Rule(RuleNode *node);
70
71
72 /* For cleanmsg */
73 int OS_CleanMSG(char *msg, Eventinfo *lf);
74
75
76 /* for FTS */
77 int FTS_Init();
78 int FTS(Eventinfo *lf);
79 int AddtoIGnore(Eventinfo *lf);
80 int IGnore(Eventinfo *lf);
81
82
83 /* For decoders */
84 void DecodeEvent(Eventinfo *lf);
85 int DecodeSyscheck(Eventinfo *lf);
86 int DecodeRootcheck(Eventinfo *lf);
87 int DecodeHostinfo(Eventinfo *lf);
88
89
90 /* For Decoders */
91 int ReadDecodeXML(char *file);
92 int SetDecodeXML();
93
94
95
96
97 /** int main(int argc, char **argv)
98  */
99 int main(int argc, char **argv)
100 {
101     int t_config = 0;
102     int c = 0, m_queue = 0;
103     char *ut_str = NULL; 
104
105     char *dir = DEFAULTDIR;
106     char *user = USER;
107     char *group = GROUPGLOBAL;
108
109     char *cfg = DEFAULTCPATH;
110
111     /* Setting the name */
112     OS_SetName(ARGV0);
113
114     thishour = 0;
115     today = 0;
116     prev_year = 0;
117     full_output = 0;
118     alert_only = 0;
119
120     active_responses = NULL;
121     memset(prev_month, '\0', 4);
122
123     while((c = getopt(argc, argv, "VatfdhU:u:g:D:c:")) != -1){
124         switch(c){
125             case 'V':
126                 print_version();
127                 break;
128             case 't':
129                 t_config = 1;
130                 break;
131             case 'h':
132                 help(ARGV0);
133                 break;
134             case 'd':
135                 nowDebug();
136                 break;
137             case 'U':
138                 if(!optarg)
139                     ErrorExit("%s: -U needs an argument",ARGV0);
140                 ut_str = optarg;
141                 break;
142             case 'u':
143                 if(!optarg)
144                     ErrorExit("%s: -u needs an argument",ARGV0);
145                 user = optarg;
146                 break;
147             case 'g':
148                 if(!optarg)
149                     ErrorExit("%s: -g needs an argument",ARGV0);
150                 group = optarg;
151                 break;
152             case 'D':
153                 if(!optarg)
154                     ErrorExit("%s: -D needs an argument",ARGV0);
155                 dir = optarg;
156             case 'c':
157                 if(!optarg)
158                     ErrorExit("%s: -c needs an argument",ARGV0);
159                 cfg = optarg;
160                 break;
161             case 'a':
162                 alert_only = 1;
163                 break;    
164             case 'f':
165                 full_output = 1;    
166                 break;
167             default:
168                 help(ARGV0);
169                 break;
170         }
171
172     }
173
174
175
176
177     /* Reading configuration file */
178     if(GlobalConf(cfg) < 0)
179     {
180         ErrorExit(CONFIG_ERROR,ARGV0, cfg);
181     }
182
183     debug1(READ_CONFIG, ARGV0);
184         
185
186     
187     /* Getting servers hostname */
188     memset(__shost, '\0', 512);
189     if(gethostname(__shost, 512 -1) != 0)
190     {
191         strncpy(__shost, OSSEC_SERVER, 512 -1);    
192     }
193     else
194     {
195         char *_ltmp;
196
197         /* Remove domain part if available */
198         _ltmp = strchr(__shost, '.');
199         if(_ltmp)
200             *_ltmp = '\0';
201     }
202     
203
204
205     if(chdir(dir) != 0)
206         ErrorExit(CHROOT_ERROR,ARGV0,dir);
207
208
209     /*
210      * Anonymous Section: Load rules, decoders, and lists 
211      *
212      * As lists require two pass loading of rules that make use of list lookups
213      * are created with blank database structs, and need to be filled in after 
214      * completion of all rules and lists. 
215      */
216     {
217         { /* Lad decders */
218             /* Initializing the decoders list */
219             OS_CreateOSDecoderList();
220
221             if(!Config.decoders) 
222             { /* Legacy loading */
223                 /* Reading decoders */
224                 if(!ReadDecodeXML("etc/decoder.xml"))
225                 {
226                     ErrorExit(CONFIG_ERROR, ARGV0,  XML_DECODER);
227                 }
228
229                 /* Reading local ones. */
230                 c = ReadDecodeXML("etc/local_decoder.xml");
231                 if(!c)
232                 {
233                     if((c != -2))
234                         ErrorExit(CONFIG_ERROR, ARGV0,  XML_LDECODER);
235                 }
236                 else
237                 {
238                     verbose("%s: INFO: Reading local decoder file.", ARGV0);
239                 }
240             }
241             else
242             { /* New loaded based on file speified in ossec.conf */
243                 char **decodersfiles;
244                 decodersfiles = Config.decoders;
245                 while( decodersfiles && *decodersfiles)
246                 {
247
248                     verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
249                     if(!ReadDecodeXML(*decodersfiles))
250                         ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
251                     
252                     free(*decodersfiles);    
253                     decodersfiles++;    
254                 }
255             }
256
257             /* Load decoders */
258             SetDecodeXML();
259         }
260         { /* Load Lists */
261             /* Initializing the lists of list struct */
262             Lists_OP_CreateLists(); 
263             /* Load each list into list struct */
264             {
265                 char **listfiles;
266                 listfiles = Config.lists;
267                 while(listfiles && *listfiles)
268                 {
269                     verbose("%s: INFO: Reading loading the lists file: '%s'", ARGV0, *listfiles);
270                     if(Lists_OP_LoadList(*listfiles) < 0)
271                         ErrorExit(LISTS_ERROR, ARGV0, *listfiles);
272                     free(*listfiles);
273                     listfiles++;
274                 }
275                 free(Config.lists);
276                 Config.lists = NULL;
277             }
278         }
279         { /* Load Rules */
280             /* Creating the rules list */
281             Rules_OP_CreateRules();
282
283             /* Reading the rules */
284             {
285                 char **rulesfiles;
286                 rulesfiles = Config.includes;
287                 while(rulesfiles && *rulesfiles)
288                 {
289                     debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
290                     if(Rules_OP_ReadRules(*rulesfiles) < 0)
291                         ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
292                         
293                     free(*rulesfiles);    
294                     rulesfiles++;    
295                 }
296
297                 free(Config.includes);
298                 Config.includes = NULL;
299             }
300             
301             /* Find all rules with that require list lookups and attache the
302              * the correct list struct to the rule.  This keeps rules from having to 
303              * search thought the list of lists for the correct file during rule evaluation.
304              */
305             OS_ListLoadRules();
306         }
307     }
308
309     
310     /* Fixing the levels/accuracy */
311     {
312         int total_rules;
313         RuleNode *tmp_node = OS_GetFirstRule();
314
315         total_rules = _setlevels(tmp_node, 0);
316         debug1("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);    
317     }
318
319
320     /* Creating a rules hash (for reading alerts from other servers). */
321     {
322         RuleNode *tmp_node = OS_GetFirstRule();
323         Config.g_rules_hash = OSHash_Create();
324         if(!Config.g_rules_hash)
325         {
326             ErrorExit(MEM_ERROR, ARGV0);
327         }
328         AddHash_Rule(tmp_node);
329     }
330
331
332     if(t_config == 1)
333     {
334         exit(0);
335     }
336
337     
338     /* Start up message */
339     verbose(STARTUP_MSG, ARGV0, getpid());
340
341
342     /* Going to main loop */    
343     OS_ReadMSG(m_queue, ut_str);
344
345
346     exit(0);
347     
348 }
349
350
351
352 /* OS_ReadMSG.
353  * Main function. Receives the messages(events)
354  * and analyze them all.
355  */
356 void OS_ReadMSG(int m_queue, char *ut_str)
357 {
358     int i;
359     char msg[OS_MAXSTR +1];
360     int exit_code = 0;
361     char *ut_alertlevel = NULL;
362     char *ut_rulelevel = NULL;
363     char *ut_decoder_name = NULL; 
364
365     if(ut_str)
366     {
367         /* XXX Break apart string */
368         ut_rulelevel = ut_str; 
369         ut_alertlevel =  strchr(ut_rulelevel, ':');
370         if(!ut_alertlevel)
371         {
372             ErrorExit("%s: -U requires the matching format to be "
373                       "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
374         }
375         else
376         {
377             *ut_alertlevel = '\0';
378             ut_alertlevel++; 
379         }
380         ut_decoder_name = strchr(ut_alertlevel, ':');
381         if(!ut_decoder_name)
382         {
383             ErrorExit("%s: -U requires the matching format to be "
384                       "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
385         }
386         else
387         {
388             *ut_decoder_name = '\0';
389             ut_decoder_name++;
390         }
391     }
392
393     RuleInfoDetail *last_info_detail;
394     Eventinfo *lf;
395
396
397     /* Null to global currently pointers */
398     currently_rule = NULL;
399
400
401     /* Creating the event list */
402     OS_CreateEventList(Config.memorysize);
403
404
405     /* Initiating the FTS list */
406     if(!FTS_Init())
407     {
408         ErrorExit(FTS_LIST_ERROR, ARGV0);
409     }
410                                 
411
412     __crt_ftell = 1;
413
414
415     /* Getting currently time before starting */
416     c_time = time(NULL);
417
418
419     /* Doing some cleanup */
420     memset(msg, '\0', OS_MAXSTR +1);
421     
422
423     if(!alert_only)
424     print_out("%s: Type one log per line.\n", ARGV0);
425     
426     
427     /* Daemon loop */
428     while(1)
429     {
430         lf = (Eventinfo *)calloc(1,sizeof(Eventinfo));
431         
432         /* This shouldn't happen .. */
433         if(lf == NULL)
434         {
435             ErrorExit(MEM_ERROR,ARGV0);
436         }
437
438
439         /* Fixing the msg. */
440         snprintf(msg, 15, "1:stdin:");
441         
442     
443         
444         /* Receive message from queue */
445         if(fgets(msg +8, OS_MAXSTR, stdin))
446         {
447             RuleNode *rulenode_pt;
448
449             /* Getting the time we received the event */
450             c_time = time(NULL);
451
452
453             /* Removing new line. */
454             if(msg[strlen(msg) -1] == '\n')
455                 msg[strlen(msg) -1] = '\0';
456
457
458             /* Make sure we ignore blank lines. */
459             if(strlen(msg) < 10)
460             {
461                 continue;
462             }
463             
464             
465             if(!alert_only)print_out("\n");
466             
467
468             /* Default values for the log info */
469             Zero_Eventinfo(lf);
470
471
472             /* Clean the msg appropriately */
473             if(OS_CleanMSG(msg, lf) < 0)
474             {
475                 merror(IMSG_ERROR,ARGV0,msg);
476
477                 Free_Eventinfo(lf);
478
479                 continue;
480             }
481
482
483             /* Currently rule must be null in here */
484             currently_rule = NULL;
485
486
487             /***  Running decoders ***/
488
489             /* Getting log size */
490             lf->size = strlen(lf->log);
491
492
493             /* Decoding event. */
494             DecodeEvent(lf);
495             
496
497             /* Looping all the rules */
498             rulenode_pt = OS_GetFirstRule();
499             if(!rulenode_pt) 
500             {
501                 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
502                         ARGV0);
503             }
504
505             
506             #ifdef TESTRULE
507             if(full_output && !alert_only)
508                 print_out("\n**Rule debugging:");
509             #endif
510
511
512             do
513             {
514                 if(lf->decoder_info->type == OSSEC_ALERT)
515                 {
516                     if(!lf->generated_rule)
517                     {
518                         break;
519                     }
520
521                     /* We go ahead in here and process the alert. */
522                     currently_rule = lf->generated_rule;
523                 }
524                                                                                                                                                                                             
525                 /* The categories must match */
526                 else if(rulenode_pt->ruleinfo->category != 
527                         lf->decoder_info->type)
528                 {
529                     continue;
530                 }
531
532
533                 /* Checking each rule. */
534                 else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt)) 
535                         == NULL)
536                 {
537                     continue;
538                 }
539
540                 #ifdef TESTRULE
541                 if(!alert_only)
542                 {
543                   char *(ruleinfodetail_text[])={"Text","Link","CVE","OSVDB","BUGTRACKID"};
544                   print_out("\n**Phase 3: Completed filtering (rules).");
545                   print_out("       Rule id: '%d'", currently_rule->sigid);
546                   print_out("       Level: '%d'", currently_rule->level);
547                   print_out("       Description: '%s'",currently_rule->comment);
548                   for (last_info_detail = currently_rule->info_details; last_info_detail != NULL; last_info_detail = last_info_detail->next) 
549                   {
550                       print_out("       Info - %s: '%s'", ruleinfodetail_text[last_info_detail->type], last_info_detail->data);
551                   }
552                 }
553                 #endif
554                                             
555
556
557                 /* Ignore level 0 */
558                 if(currently_rule->level == 0)
559                 {
560                     break;
561                 }
562
563
564                 /* Checking ignore time */ 
565                 if(currently_rule->ignore_time)
566                 {
567                     if(currently_rule->time_ignored == 0)
568                     {
569                         currently_rule->time_ignored = lf->time;
570                     }
571                     /* If the currently time - the time the rule was ignored
572                      * is less than the time it should be ignored,
573                      * leave (do not alert again).
574                      */
575                     else if((lf->time - currently_rule->time_ignored) 
576                             < currently_rule->ignore_time)
577                     {
578                         break;
579                     }
580                     else
581                     {
582                         currently_rule->time_ignored = 0;
583                     }
584                 }
585
586                 /* Pointer to the rule that generated it */
587                 lf->generated_rule = currently_rule;
588
589                 
590                 /* Checking if we should ignore it */
591                 if(currently_rule->ckignore && IGnore(lf))
592                 {
593                     /* Ignoring rule */
594                     lf->generated_rule = NULL;
595                     break;
596                 }
597                 
598                 /* Checking if we need to add to ignore list */
599                 if(currently_rule->ignore)
600                 {
601                     AddtoIGnore(lf);
602                 }
603
604
605                 /* Log the alert if configured to ... */
606                 if(currently_rule->alert_opts & DO_LOGALERT)
607                 {
608                     if(alert_only)
609                     {
610                         OS_LogOutput(lf);
611                         __crt_ftell++;
612                     }
613                     else
614                     {
615                         print_out("**Alert to be generated.\n\n");
616                     }
617                 }
618
619
620                 /* Copy the structure to the state memory of if_matched_sid */
621                 if(currently_rule->sid_prev_matched)
622                 {
623                     if(!OSList_AddData(currently_rule->sid_prev_matched, lf))
624                     {
625                         merror("%s: Unable to add data to sig list.", ARGV0);
626                     }
627                     else
628                     {
629                         lf->sid_node_to_delete = 
630                             currently_rule->sid_prev_matched->last_node;
631                     }
632                 }
633                 /* Group list */
634                 else if(currently_rule->group_prev_matched)
635                 {
636                     i = 0;  
637                     
638                     while(i < currently_rule->group_prev_matched_sz)
639                     {
640                         if(!OSList_AddData(
641                                 currently_rule->group_prev_matched[i], 
642                                 lf))
643                         {
644                            merror("%s: Unable to add data to grp list.",ARGV0);
645                         }
646                         i++;
647                     }
648                 }
649                 
650                 OS_AddEvent(lf);
651
652                 break;
653
654             }while((rulenode_pt = rulenode_pt->next) != NULL);
655
656             if(ut_str)
657             {
658                 /*setup exit code if we are doing unit testing*/
659                 char holder[1024];
660                 holder[1] = '\0';
661                 exit_code = 3;
662                 if(strcasecmp(ut_decoder_name, lf->decoder_info->name) == 0)
663                 {
664                     exit_code--;
665                     snprintf(holder, 1023, "%d", currently_rule->sigid);
666                     if(strcasecmp(ut_rulelevel, holder) == 0)
667                     {
668                         exit_code--;
669                         snprintf(holder, 1023, "%d", currently_rule->level);
670                         if(strcasecmp(ut_alertlevel, holder) == 0)
671                         {
672                             exit_code--;
673                             printf("%d\n",exit_code);
674                         }
675                     }
676                 }
677             }
678
679
680             /* Only clear the memory if the eventinfo was not
681              * added to the stateful memory 
682              * -- message is free inside clean event --
683              */
684             if(lf->generated_rule == NULL)
685                 Free_Eventinfo(lf);
686
687         }
688         else
689         {
690             exit(exit_code);   
691         }
692     }
693     exit(exit_code);
694     return;
695 }
696
697
698
699 /* EOF */
700