new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / analysisd / testrule.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights 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 #ifdef ARGV0
11 #undef ARGV0
12 #define ARGV0 "ossec-testrule"
13 #endif
14
15 #include "shared.h"
16 #include "alerts/alerts.h"
17 #include "alerts/getloglocation.h"
18 #include "os_execd/execd.h"
19 #include "os_regex/os_regex.h"
20 #include "os_net/os_net.h"
21 #include "active-response.h"
22 #include "config.h"
23 #include "rules.h"
24 #include "stats.h"
25 #include "eventinfo.h"
26 #include "accumulator.h"
27 #include "analysisd.h"
28 #include "fts.h"
29 #include "cleanevent.h"
30
31 /** Internal Functions **/
32 void OS_ReadMSG(char *ut_str);
33
34 /* Analysisd function */
35 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
36
37 void DecodeEvent(Eventinfo *lf);
38
39 /* Print help statement */
40 __attribute__((noreturn))
41 static void help_logtest(void)
42 {
43     print_header();
44     print_out("  %s: -[Vhdtva] [-c config] [-D dir] [-U rule:alert:decoder]", ARGV0);
45     print_out("    -V          Version and license message");
46     print_out("    -h          This help message");
47     print_out("    -d          Execute in debug mode. This parameter");
48     print_out("                can be specified multiple times");
49     print_out("                to increase the debug level.");
50     print_out("    -t          Test configuration");
51     print_out("    -a          Alerts output");
52     print_out("    -v          Verbose (full) output/rule debugging");
53     print_out("    -c <config> Configuration file to use (default: %s)", DEFAULTCPATH);
54     print_out("    -D <dir>    Directory to chroot into (default: %s)", DEFAULTDIR);
55     print_out("    -U <rule:alert:decoder>  Unit test. Refer to contrib/ossec-testing/runtests.py");
56     print_out(" ");
57     exit(1);
58 }
59
60 int main(int argc, char **argv)
61 {
62     int test_config = 0;
63     int c = 0;
64     char *ut_str = NULL;
65     const char *dir = DEFAULTDIR;
66     const char *cfg = DEFAULTCPATH;
67     const char *user = USER;
68     const char *group = GROUPGLOBAL;
69     uid_t uid;
70     gid_t gid;
71     int quiet = 0;
72
73     /* Set the name */
74     OS_SetName(ARGV0);
75
76     thishour = 0;
77     today = 0;
78     prev_year = 0;
79     full_output = 0;
80     alert_only = 0;
81
82     active_responses = NULL;
83     memset(prev_month, '\0', 4);
84
85 #ifdef LIBGEOIP_ENABLED
86     geoipdb = NULL;
87 #endif
88
89     while ((c = getopt(argc, argv, "VatvdhU:D:c:q")) != -1) {
90         switch (c) {
91             case 'V':
92                 print_version();
93                 break;
94             case 't':
95                 test_config = 1;
96                 break;
97             case 'h':
98                 help_logtest();
99                 break;
100             case 'd':
101                 nowDebug();
102                 break;
103             case 'U':
104                 if (!optarg) {
105                     ErrorExit("%s: -U needs an argument", ARGV0);
106                 }
107                 ut_str = optarg;
108                 break;
109             case 'D':
110                 if (!optarg) {
111                     ErrorExit("%s: -D needs an argument", ARGV0);
112                 }
113                 dir = optarg;
114                 break;
115             case 'c':
116                 if (!optarg) {
117                     ErrorExit("%s: -c needs an argument", ARGV0);
118                 }
119                 cfg = optarg;
120                 break;
121             case 'a':
122                 alert_only = 1;
123                 break;
124             case 'q':
125                 quiet = 1;
126                 break;
127             case 'v':
128                 full_output = 1;
129                 break;
130             default:
131                 help_logtest();
132                 break;
133         }
134     }
135
136     /* Read configuration file */
137     if (GlobalConf(cfg) < 0) {
138         ErrorExit(CONFIG_ERROR, ARGV0, cfg);
139     }
140
141     debug1(READ_CONFIG, ARGV0);
142
143 #ifdef LIBGEOIP_ENABLED
144     Config.geoip_jsonout = getDefine_Int("analysisd", "geoip_jsonout", 0, 1);
145
146     /* Opening GeoIP DB */
147     if(Config.geoipdb_file) {
148         geoipdb = GeoIP_open(Config.geoipdb_file, GEOIP_INDEX_CACHE);
149         if (geoipdb == NULL)
150         {
151             merror("%s: Unable to open GeoIP database from: %s (disabling GeoIP).", ARGV0, Config.geoipdb_file);
152         }
153     }
154 #endif
155
156     /* Get server hostname */
157     memset(__shost, '\0', 512);
158     if (gethostname(__shost, 512 - 1) != 0) {
159         strncpy(__shost, OSSEC_SERVER, 512 - 1);
160     } else {
161         char *_ltmp;
162
163         /* Remove domain part if available */
164         _ltmp = strchr(__shost, '.');
165         if (_ltmp) {
166             *_ltmp = '\0';
167         }
168     }
169
170     /* Check if the user/group given are valid */
171     uid = Privsep_GetUser(user);
172     gid = Privsep_GetGroup(group);
173     if (uid == (uid_t) - 1 || gid == (gid_t) - 1) {
174         ErrorExit(USER_ERROR, ARGV0, user, group);
175     }
176
177     /* Set the group */
178     if (Privsep_SetGroup(gid) < 0) {
179         ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
180     }
181
182     /* Chroot */
183     if (Privsep_Chroot(dir) < 0) {
184         ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
185     }
186     nowChroot();
187
188     Config.decoder_order_size = (size_t)getDefine_Int("analysisd", "decoder_order_size", 8, MAX_DECODER_ORDER_SIZE);
189
190
191     /*
192      * Anonymous Section: Load rules, decoders, and lists
193      *
194      * As lists require two pass loading of rules that make use of list lookups
195      * are created with blank database structs, and need to be filled in after
196      * completion of all rules and lists.
197      */
198     {
199         {
200             /* Load decoders */
201             /* Initialize the decoders list */
202             OS_CreateOSDecoderList();
203
204             if (!Config.decoders) {
205                 /* Legacy loading */
206                 /* Read decoders */
207                 if (!ReadDecodeXML("etc/decoder.xml")) {
208                     ErrorExit(CONFIG_ERROR, ARGV0,  XML_DECODER);
209                 }
210
211                 /* Read local ones */
212                 c = ReadDecodeXML("etc/local_decoder.xml");
213                 if (!c) {
214                     if ((c != -2)) {
215                         ErrorExit(CONFIG_ERROR, ARGV0,  XML_LDECODER);
216                     }
217                 } else {
218                     verbose("%s: INFO: Reading local decoder file.", ARGV0);
219                 }
220             } else {
221                 /* New loaded based on file specified in ossec.conf */
222                 char **decodersfiles;
223                 decodersfiles = Config.decoders;
224                 while ( decodersfiles && *decodersfiles) {
225
226                     if(!quiet) {
227                         verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
228                     }
229                     if (!ReadDecodeXML(*decodersfiles)) {
230                         ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
231                     }
232
233                     free(*decodersfiles);
234                     decodersfiles++;
235                 }
236             }
237
238             /* Load decoders */
239             SetDecodeXML();
240         }
241         {
242             /* Load Lists */
243             /* Initialize the lists of list struct */
244             Lists_OP_CreateLists();
245             /* Load each list into list struct */
246             {
247                 char **listfiles;
248                 listfiles = Config.lists;
249                 while (listfiles && *listfiles) {
250                     verbose("%s: INFO: Reading the lists file: '%s'", ARGV0, *listfiles);
251                     if (Lists_OP_LoadList(*listfiles) < 0) {
252                         ErrorExit(LISTS_ERROR, ARGV0, *listfiles);
253                     }
254                     free(*listfiles);
255                     listfiles++;
256                 }
257                 free(Config.lists);
258                 Config.lists = NULL;
259             }
260         }
261         {
262             /* Load Rules */
263             /* Create the rules list */
264             Rules_OP_CreateRules();
265
266             /* Read the rules */
267             {
268                 char **rulesfiles;
269                 rulesfiles = Config.includes;
270                 while (rulesfiles && *rulesfiles) {
271                     debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
272                     if (Rules_OP_ReadRules(*rulesfiles) < 0) {
273                         ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
274                     }
275
276                     free(*rulesfiles);
277                     rulesfiles++;
278                 }
279
280                 free(Config.includes);
281                 Config.includes = NULL;
282             }
283
284             /* Find all rules with that require list lookups and attache the
285              * the correct list struct to the rule.  This keeps rules from
286              * having to search thought the list of lists for the correct file
287              * during rule evaluation.
288              */
289             OS_ListLoadRules();
290         }
291     }
292
293     /* Fix the levels/accuracy */
294     {
295         int total_rules;
296         RuleNode *tmp_node = OS_GetFirstRule();
297
298         total_rules = _setlevels(tmp_node, 0);
299         debug1("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
300     }
301
302     /* Creating a rules hash (for reading alerts from other servers) */
303     {
304         RuleNode *tmp_node = OS_GetFirstRule();
305         Config.g_rules_hash = OSHash_Create();
306         if (!Config.g_rules_hash) {
307             ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
308         }
309         AddHash_Rule(tmp_node);
310     }
311
312     if (test_config == 1) {
313         exit(0);
314     }
315
316     /* Set the user */
317     if (Privsep_SetUser(uid) < 0) {
318         ErrorExit(SETUID_ERROR, ARGV0, user, errno, strerror(errno));
319     }
320
321     /* Start up message */
322     verbose(STARTUP_MSG, ARGV0, getpid());
323
324     /* Going to main loop */
325     OS_ReadMSG(ut_str);
326
327     exit(0);
328 }
329
330 /* Receive the messages (events) and analyze them */
331 __attribute__((noreturn))
332 void OS_ReadMSG(char *ut_str)
333 {
334     char msg[OS_MAXSTR + 1];
335     int exit_code = 0;
336     char *ut_alertlevel = NULL;
337     char *ut_rulelevel = NULL;
338     char *ut_decoder_name = NULL;
339
340     if (ut_str) {
341         /* XXX Break apart string */
342         ut_rulelevel = ut_str;
343         ut_alertlevel =  strchr(ut_rulelevel, ':');
344         if (!ut_alertlevel) {
345             ErrorExit("%s: -U requires the matching format to be "
346                       "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
347         } else {
348             *ut_alertlevel = '\0';
349             ut_alertlevel++;
350         }
351         ut_decoder_name = strchr(ut_alertlevel, ':');
352         if (!ut_decoder_name) {
353             ErrorExit("%s: -U requires the matching format to be "
354                       "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
355         } else {
356             *ut_decoder_name = '\0';
357             ut_decoder_name++;
358         }
359     }
360
361     RuleInfoDetail *last_info_detail;
362     Eventinfo *lf;
363
364     /* Null global pointer to current rule */
365     currently_rule = NULL;
366
367     /* Create the event list */
368     OS_CreateEventList(Config.memorysize);
369
370     /* Initiate the FTS list */
371     if (!FTS_Init()) {
372         ErrorExit(FTS_LIST_ERROR, ARGV0);
373     }
374
375     /* Initialize the Accumulator */
376     if (!Accumulate_Init()) {
377         merror("accumulator: ERROR: Initialization failed");
378         exit(1);
379     }
380
381     __crt_ftell = 1;
382
383     /* Get current time before starting */
384     c_time = time(NULL);
385
386     /* Do some cleanup */
387     memset(msg, '\0', OS_MAXSTR + 1);
388
389     if (!alert_only) {
390         print_out("%s: Type one log per line.\n", ARGV0);
391     }
392
393     /* Daemon loop */
394     while (1) {
395         lf = (Eventinfo *)calloc(1, sizeof(Eventinfo));
396         os_calloc(Config.decoder_order_size, sizeof(char*), lf->fields);
397
398
399         /* This shouldn't happen */
400         if (lf == NULL) {
401             ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
402         }
403
404         /* Fix the msg */
405         snprintf(msg, 15, "1:stdin:");
406
407         /* Receive message from queue */
408         if (fgets(msg + 8, OS_MAXSTR - 8, stdin)) {
409             RuleNode *rulenode_pt;
410
411             /* Get the time we received the event */
412             c_time = time(NULL);
413
414             /* Remov newline */
415             if (msg[strlen(msg) - 1] == '\n') {
416                 msg[strlen(msg) - 1] = '\0';
417             }
418
419             /* Make sure we ignore blank lines */
420             if (strlen(msg) < 10) {
421                 continue;
422             }
423
424             if (!alert_only) {
425                 print_out("\n");
426             }
427
428             /* Default values for the log info */
429             Zero_Eventinfo(lf);
430
431             /* Clean the msg appropriately */
432             if (OS_CleanMSG(msg, lf) < 0) {
433                 merror(IMSG_ERROR, ARGV0, msg);
434
435                 Free_Eventinfo(lf);
436
437                 continue;
438             }
439
440             /* Current rule must be null in here */
441             currently_rule = NULL;
442
443             /***  Run decoders ***/
444             /* Get log size */
445             lf->size = strlen(lf->log);
446
447             /* Decode event */
448             DecodeEvent(lf);
449
450             /* Run accumulator */
451             if ( lf->decoder_info->accumulate == 1 ) {
452                 print_out("\n**ACCUMULATOR: LEVEL UP!!**\n");
453                 lf = Accumulate(lf);
454             }
455
456             /* Loop over all the rules */
457             rulenode_pt = OS_GetFirstRule();
458             if (!rulenode_pt) {
459                 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
460                           ARGV0);
461             }
462
463 #ifdef TESTRULE
464             if (full_output && !alert_only) {
465                 print_out("\n**Rule debugging:");
466             }
467 #endif
468
469             do {
470                 if (lf->decoder_info->type == OSSEC_ALERT) {
471                     if (!lf->generated_rule) {
472                         break;
473                     }
474
475                     /* Process the alert */
476                     currently_rule = lf->generated_rule;
477                 }
478
479                 /* The categories must match */
480                 else if (rulenode_pt->ruleinfo->category !=
481                          lf->decoder_info->type) {
482                     continue;
483                 }
484
485                 /* Check each rule */
486                 else if ((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
487                          == NULL) {
488                     continue;
489                 }
490
491 #ifdef TESTRULE
492                 if (!alert_only) {
493                     const char *(ruleinfodetail_text[]) = {"Text", "Link", "CVE", "OSVDB", "BUGTRACKID"};
494                     print_out("\n**Phase 3: Completed filtering (rules).");
495                     print_out("       Rule id: '%d'", currently_rule->sigid);
496                     print_out("       Level: '%d'", currently_rule->level);
497                     print_out("       Description: '%s'", currently_rule->comment);
498                     for (last_info_detail = currently_rule->info_details; last_info_detail != NULL; last_info_detail = last_info_detail->next) {
499                         print_out("       Info - %s: '%s'", ruleinfodetail_text[last_info_detail->type], last_info_detail->data);
500                     }
501                 }
502 #endif
503
504                 /* Ignore level 0 */
505                 if (currently_rule->level == 0) {
506                     break;
507                 }
508
509                 /* Check ignore time */
510                 if (currently_rule->ignore_time) {
511                     if (currently_rule->time_ignored == 0) {
512                         currently_rule->time_ignored = lf->time;
513                     }
514                     /* If the current time - the time the rule was ignored
515                      * is less than the time it should be ignored,
516                      * do not alert again
517                      */
518                     else if ((lf->time - currently_rule->time_ignored)
519                              < currently_rule->ignore_time) {
520                         break;
521                     } else {
522                         currently_rule->time_ignored = 0;
523                     }
524                 }
525
526                 /* Pointer to the rule that generated it */
527                 lf->generated_rule = currently_rule;
528
529
530                 /* Check if we should ignore it */
531                 if (currently_rule->ckignore && IGnore(lf)) {
532                     lf->generated_rule = NULL;
533                     break;
534                 }
535
536                 /* Check if we need to add to ignore list */
537                 if (currently_rule->ignore) {
538                     AddtoIGnore(lf);
539                 }
540
541                 /* Log the alert if configured to */
542                 if (currently_rule->alert_opts & DO_LOGALERT) {
543                     if (alert_only) {
544                         OS_LogOutput(lf);
545                         __crt_ftell++;
546                     } else {
547                         print_out("**Alert to be generated.\n\n");
548                     }
549                 }
550
551                 /* Copy the structure to the state memory of if_matched_sid */
552                 if (currently_rule->sid_prev_matched) {
553                     if (!OSList_AddData(currently_rule->sid_prev_matched, lf)) {
554                         merror("%s: Unable to add data to sig list.", ARGV0);
555                     } else {
556                         lf->sid_node_to_delete =
557                             currently_rule->sid_prev_matched->last_node;
558                     }
559                 }
560
561                 /* Group list */
562                 else if (currently_rule->group_prev_matched) {
563                     unsigned int i = 0;
564
565                     while (i < currently_rule->group_prev_matched_sz) {
566                         if (!OSList_AddData(
567                                     currently_rule->group_prev_matched[i],
568                                     lf)) {
569                             merror("%s: Unable to add data to grp list.", ARGV0);
570                         }
571                         i++;
572                     }
573                 }
574
575                 OS_AddEvent(lf);
576                 break;
577
578             } while ((rulenode_pt = rulenode_pt->next) != NULL);
579
580             if (ut_str) {
581                 /* Set up exit code if we are doing unit testing */
582                 char holder[1024];
583                 holder[1] = '\0';
584                 exit_code = 3;
585                 print_out("lf->decoder_info->name: '%s'", lf->decoder_info->name);
586                 print_out("ut_decoder_name       : '%s'", ut_decoder_name);
587                 if (lf->decoder_info->name != NULL && strcasecmp(ut_decoder_name, lf->decoder_info->name) == 0) {
588                     exit_code--;
589
590                     if (!currently_rule) {
591                         merror("%s: currently_rule not set!", ARGV0);
592                         exit(-1);
593                     }
594                     snprintf(holder, 1023, "%d", currently_rule->sigid);
595                     if (strcasecmp(ut_rulelevel, holder) == 0) {
596                         exit_code--;
597                         snprintf(holder, 1023, "%d", currently_rule->level);
598                         if (strcasecmp(ut_alertlevel, holder) == 0) {
599                             exit_code--;
600                             printf("%d\n", exit_code);
601                         }
602                     }
603                 } else if (lf->decoder_info->name != NULL) {
604                     print_out("decoder matched : '%s'", lf->decoder_info->name);
605                     print_out("decoder expected: '%s'", ut_decoder_name);
606                 } else {
607                     print_out("decoder matched : 'NULL'");
608                 }
609             }
610
611             /* Only clear the memory if the eventinfo was not
612              * added to the stateful memory
613              * -- message is free inside clean event --
614              */
615             if (lf->generated_rule == NULL) {
616                 Free_Eventinfo(lf);
617             }
618
619         } else {
620             exit(exit_code);
621         }
622     }
623     exit(exit_code);
624 }