1 /* @(#) $Id: ./src/analysisd/testrule.c, 2012/07/23 dcid Exp $
4 /* Copyright (C) 2009 Trend Micro Inc.
7 * This program is a free software; you can redistribute it
8 * and/or modify it under the terms of the GNU General Public
9 * License (version 2) as published by the FSF - Free Software
12 * License details at the LICENSE file included with OSSEC or
13 * online at: http://www.ossec.net/en/licensing.html
18 * Available at http://www.ossec.net
23 * Responsible for correlation and log decoding.
28 #define ARGV0 "ossec-testrule"
35 #include "alerts/alerts.h"
36 #include "alerts/getloglocation.h"
37 #include "os_execd/execd.h"
39 #include "os_regex/os_regex.h"
40 #include "os_net/os_net.h"
44 #include "active-response.h"
49 #include "eventinfo.h"
50 #include "analysisd.h"
54 /** Internal Functions **/
55 void OS_ReadMSG(int m_queue, char *ut_str);
56 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
59 /** External functions prototypes (only called here) **/
62 int GlobalConf(char * cfgfile);
66 void Rules_OP_CreateRules();
67 void Lists_OP_CreateLists();
68 int Rules_OP_ReadRules(char * cfgfile);
69 int _setlevels(RuleNode *node, int nnode);
70 int AddHash_Rule(RuleNode *node);
74 int OS_CleanMSG(char *msg, Eventinfo *lf);
79 int AddtoIGnore(Eventinfo *lf);
80 int IGnore(Eventinfo *lf);
84 void DecodeEvent(Eventinfo *lf);
88 int ReadDecodeXML(char *file);
92 void logtest_help(const char *prog)
95 print_out("%s %s - %s (%s)", __ossec_name, __version, __author, __contact);
96 print_out("%s", __site);
98 print_out(" %s: -[Vatfdh] [-U ut_str] [-u user] [-g group] [-c config] [-D dir]", prog);
99 print_out(" -V Version and license message");
100 print_out(" -a Alerts output");
101 print_out(" -t Test configuration");
102 print_out(" -v Verbose (full) output/rule debugging");
103 print_out(" -d Execute in debug mode");
104 print_out(" -h This help message");
105 print_out(" -U <rule:alert:decoder> Unit test. Refer to contrib/ossec-testing/runtests.py");
106 print_out(" -u <user> Run as 'user'");
107 print_out(" -g <group> Run as 'group'");
108 print_out(" -c <config> Read the 'config' file");
109 print_out(" -D <dir> Chroot to 'dir'");
116 /** int main(int argc, char **argv)
118 int main(int argc, char **argv)
121 int c = 0, m_queue = 0;
124 char *dir = DEFAULTDIR;
125 // TODO: delete or implement
126 char *user __attribute__((unused)) = USER;
127 // TODO: delete or implement
128 char *group __attribute__((unused)) = GROUPGLOBAL;
130 char *cfg = DEFAULTCPATH;
132 /* Setting the name */
141 active_responses = NULL;
142 memset(prev_month, '\0', 4);
144 while((c = getopt(argc, argv, "VatvdhU:u:g:D:c:")) != -1){
160 ErrorExit("%s: -U needs an argument",ARGV0);
165 ErrorExit("%s: -u needs an argument",ARGV0);
170 ErrorExit("%s: -g needs an argument",ARGV0);
175 ErrorExit("%s: -D needs an argument",ARGV0);
180 ErrorExit("%s: -c needs an argument",ARGV0);
199 /* Reading configuration file */
200 if(GlobalConf(cfg) < 0)
202 ErrorExit(CONFIG_ERROR,ARGV0, cfg);
205 debug1(READ_CONFIG, ARGV0);
209 /* Getting servers hostname */
210 memset(__shost, '\0', 512);
211 if(gethostname(__shost, 512 -1) != 0)
213 strncpy(__shost, OSSEC_SERVER, 512 -1);
219 /* Remove domain part if available */
220 _ltmp = strchr(__shost, '.');
228 ErrorExit(CHROOT_ERROR,ARGV0,dir);
232 * Anonymous Section: Load rules, decoders, and lists
234 * As lists require two pass loading of rules that make use of list lookups
235 * are created with blank database structs, and need to be filled in after
236 * completion of all rules and lists.
240 /* Initializing the decoders list */
241 OS_CreateOSDecoderList();
244 { /* Legacy loading */
245 /* Reading decoders */
246 if(!ReadDecodeXML("etc/decoder.xml"))
248 ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER);
251 /* Reading local ones. */
252 c = ReadDecodeXML("etc/local_decoder.xml");
256 ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER);
260 verbose("%s: INFO: Reading local decoder file.", ARGV0);
264 { /* New loaded based on file speified in ossec.conf */
265 char **decodersfiles;
266 decodersfiles = Config.decoders;
267 while( decodersfiles && *decodersfiles)
270 verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
271 if(!ReadDecodeXML(*decodersfiles))
272 ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
274 free(*decodersfiles);
283 /* Initializing the lists of list struct */
284 Lists_OP_CreateLists();
285 /* Load each list into list struct */
288 listfiles = Config.lists;
289 while(listfiles && *listfiles)
291 verbose("%s: INFO: Reading the lists file: '%s'", ARGV0, *listfiles);
292 if(Lists_OP_LoadList(*listfiles) < 0)
293 ErrorExit(LISTS_ERROR, ARGV0, *listfiles);
302 /* Creating the rules list */
303 Rules_OP_CreateRules();
305 /* Reading the rules */
308 rulesfiles = Config.includes;
309 while(rulesfiles && *rulesfiles)
311 debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
312 if(Rules_OP_ReadRules(*rulesfiles) < 0)
313 ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
319 free(Config.includes);
320 Config.includes = NULL;
323 /* Find all rules with that require list lookups and attache the
324 * the correct list struct to the rule. This keeps rules from having to
325 * search thought the list of lists for the correct file during rule evaluation.
332 /* Fixing the levels/accuracy */
335 RuleNode *tmp_node = OS_GetFirstRule();
337 total_rules = _setlevels(tmp_node, 0);
338 debug1("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
342 /* Creating a rules hash (for reading alerts from other servers). */
344 RuleNode *tmp_node = OS_GetFirstRule();
345 Config.g_rules_hash = OSHash_Create();
346 if(!Config.g_rules_hash)
348 ErrorExit(MEM_ERROR, ARGV0);
350 AddHash_Rule(tmp_node);
360 /* Start up message */
361 verbose(STARTUP_MSG, ARGV0, getpid());
364 /* Going to main loop */
365 OS_ReadMSG(m_queue, ut_str);
375 * Main function. Receives the messages(events)
376 * and analyze them all.
378 void OS_ReadMSG(int m_queue, char *ut_str)
381 char msg[OS_MAXSTR +1];
383 char *ut_alertlevel = NULL;
384 char *ut_rulelevel = NULL;
385 char *ut_decoder_name = NULL;
389 /* XXX Break apart string */
390 ut_rulelevel = ut_str;
391 ut_alertlevel = strchr(ut_rulelevel, ':');
394 ErrorExit("%s: -U requires the matching format to be "
395 "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
399 *ut_alertlevel = '\0';
402 ut_decoder_name = strchr(ut_alertlevel, ':');
405 ErrorExit("%s: -U requires the matching format to be "
406 "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
410 *ut_decoder_name = '\0';
415 RuleInfoDetail *last_info_detail;
419 /* Null to global currently pointers */
420 currently_rule = NULL;
423 /* Creating the event list */
424 OS_CreateEventList(Config.memorysize);
427 /* Initiating the FTS list */
430 ErrorExit(FTS_LIST_ERROR, ARGV0);
437 /* Getting currently time before starting */
441 /* Doing some cleanup */
442 memset(msg, '\0', OS_MAXSTR +1);
446 print_out("%s: Type one log per line.\n", ARGV0);
452 lf = (Eventinfo *)calloc(1,sizeof(Eventinfo));
454 /* This shouldn't happen .. */
457 ErrorExit(MEM_ERROR,ARGV0);
461 /* Fixing the msg. */
462 snprintf(msg, 15, "1:stdin:");
466 /* Receive message from queue */
467 if(fgets(msg +8, OS_MAXSTR -8, stdin))
469 RuleNode *rulenode_pt;
471 /* Getting the time we received the event */
475 /* Removing new line. */
476 if(msg[strlen(msg) -1] == '\n')
477 msg[strlen(msg) -1] = '\0';
480 /* Make sure we ignore blank lines. */
487 if(!alert_only)print_out("\n");
490 /* Default values for the log info */
494 /* Clean the msg appropriately */
495 if(OS_CleanMSG(msg, lf) < 0)
497 merror(IMSG_ERROR,ARGV0,msg);
505 /* Currently rule must be null in here */
506 currently_rule = NULL;
509 /*** Running decoders ***/
511 /* Getting log size */
512 lf->size = strlen(lf->log);
515 /* Decoding event. */
519 /* Looping all the rules */
520 rulenode_pt = OS_GetFirstRule();
523 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
529 if(full_output && !alert_only)
530 print_out("\n**Rule debugging:");
536 if(lf->decoder_info->type == OSSEC_ALERT)
538 if(!lf->generated_rule)
543 /* We go ahead in here and process the alert. */
544 currently_rule = lf->generated_rule;
547 /* The categories must match */
548 else if(rulenode_pt->ruleinfo->category !=
549 lf->decoder_info->type)
555 /* Checking each rule. */
556 else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
565 char *(ruleinfodetail_text[])={"Text","Link","CVE","OSVDB","BUGTRACKID"};
566 print_out("\n**Phase 3: Completed filtering (rules).");
567 print_out(" Rule id: '%d'", currently_rule->sigid);
568 print_out(" Level: '%d'", currently_rule->level);
569 print_out(" Description: '%s'",currently_rule->comment);
570 for (last_info_detail = currently_rule->info_details; last_info_detail != NULL; last_info_detail = last_info_detail->next)
572 print_out(" Info - %s: '%s'", ruleinfodetail_text[last_info_detail->type], last_info_detail->data);
580 if(currently_rule->level == 0)
586 /* Checking ignore time */
587 if(currently_rule->ignore_time)
589 if(currently_rule->time_ignored == 0)
591 currently_rule->time_ignored = lf->time;
593 /* If the currently time - the time the rule was ignored
594 * is less than the time it should be ignored,
595 * leave (do not alert again).
597 else if((lf->time - currently_rule->time_ignored)
598 < currently_rule->ignore_time)
604 currently_rule->time_ignored = 0;
608 /* Pointer to the rule that generated it */
609 lf->generated_rule = currently_rule;
612 /* Checking if we should ignore it */
613 if(currently_rule->ckignore && IGnore(lf))
616 lf->generated_rule = NULL;
620 /* Checking if we need to add to ignore list */
621 if(currently_rule->ignore)
627 /* Log the alert if configured to ... */
628 if(currently_rule->alert_opts & DO_LOGALERT)
637 print_out("**Alert to be generated.\n\n");
642 /* Copy the structure to the state memory of if_matched_sid */
643 if(currently_rule->sid_prev_matched)
645 if(!OSList_AddData(currently_rule->sid_prev_matched, lf))
647 merror("%s: Unable to add data to sig list.", ARGV0);
651 lf->sid_node_to_delete =
652 currently_rule->sid_prev_matched->last_node;
656 else if(currently_rule->group_prev_matched)
660 while(i < currently_rule->group_prev_matched_sz)
663 currently_rule->group_prev_matched[i],
666 merror("%s: Unable to add data to grp list.",ARGV0);
676 }while((rulenode_pt = rulenode_pt->next) != NULL);
680 /*setup exit code if we are doing unit testing*/
684 if(lf->decoder_info->name != NULL && strcasecmp(ut_decoder_name, lf->decoder_info->name) == 0)
687 snprintf(holder, 1023, "%d", currently_rule->sigid);
688 if(strcasecmp(ut_rulelevel, holder) == 0)
691 snprintf(holder, 1023, "%d", currently_rule->level);
692 if(strcasecmp(ut_alertlevel, holder) == 0)
695 printf("%d\n",exit_code);
702 /* Only clear the memory if the eventinfo was not
703 * added to the stateful memory
704 * -- message is free inside clean event --
706 if(lf->generated_rule == NULL)