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 FTS(Eventinfo *lf);
80 int AddtoIGnore(Eventinfo *lf);
81 int IGnore(Eventinfo *lf);
85 void DecodeEvent(Eventinfo *lf);
86 int DecodeSyscheck(Eventinfo *lf);
87 int DecodeRootcheck(Eventinfo *lf);
88 int DecodeHostinfo(Eventinfo *lf);
92 int ReadDecodeXML(char *file);
96 void logtest_help(const char *prog)
99 print_out("%s %s - %s (%s)", __name, __version, __author, __contact);
100 print_out("%s", __site);
102 print_out(" %s: -[Vatfdh] [-U ut_str] [-u user] [-g group] [-c config] [-D dir]", prog);
103 print_out(" -V Version and license message");
104 print_out(" -a Alerts output");
105 print_out(" -t Test configuration");
106 print_out(" -v Verbose (full) output/rule debugging");
107 print_out(" -d Execute in debug mode");
108 print_out(" -h This help message");
109 print_out(" -U <rule:alert:decoder> Unit test. Refer to contrib/ossec-testing/runtests.py");
110 print_out(" -u <user> Run as 'user'");
111 print_out(" -g <group> Run as 'group'");
112 print_out(" -c <config> Read the 'config' file");
113 print_out(" -D <dir> Chroot to 'dir'");
120 /** int main(int argc, char **argv)
122 int main(int argc, char **argv)
125 int c = 0, m_queue = 0;
128 char *dir = DEFAULTDIR;
130 char *group = GROUPGLOBAL;
132 char *cfg = DEFAULTCPATH;
134 /* Setting the name */
143 active_responses = NULL;
144 memset(prev_month, '\0', 4);
146 while((c = getopt(argc, argv, "VatvdhU:u:g:D:c:")) != -1){
162 ErrorExit("%s: -U needs an argument",ARGV0);
167 ErrorExit("%s: -u needs an argument",ARGV0);
172 ErrorExit("%s: -g needs an argument",ARGV0);
177 ErrorExit("%s: -D needs an argument",ARGV0);
182 ErrorExit("%s: -c needs an argument",ARGV0);
201 /* Reading configuration file */
202 if(GlobalConf(cfg) < 0)
204 ErrorExit(CONFIG_ERROR,ARGV0, cfg);
207 debug1(READ_CONFIG, ARGV0);
211 /* Getting servers hostname */
212 memset(__shost, '\0', 512);
213 if(gethostname(__shost, 512 -1) != 0)
215 strncpy(__shost, OSSEC_SERVER, 512 -1);
221 /* Remove domain part if available */
222 _ltmp = strchr(__shost, '.');
230 ErrorExit(CHROOT_ERROR,ARGV0,dir);
234 * Anonymous Section: Load rules, decoders, and lists
236 * As lists require two pass loading of rules that make use of list lookups
237 * are created with blank database structs, and need to be filled in after
238 * completion of all rules and lists.
242 /* Initializing the decoders list */
243 OS_CreateOSDecoderList();
246 { /* Legacy loading */
247 /* Reading decoders */
248 if(!ReadDecodeXML("etc/decoder.xml"))
250 ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER);
253 /* Reading local ones. */
254 c = ReadDecodeXML("etc/local_decoder.xml");
258 ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER);
262 verbose("%s: INFO: Reading local decoder file.", ARGV0);
266 { /* New loaded based on file speified in ossec.conf */
267 char **decodersfiles;
268 decodersfiles = Config.decoders;
269 while( decodersfiles && *decodersfiles)
272 verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
273 if(!ReadDecodeXML(*decodersfiles))
274 ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
276 free(*decodersfiles);
285 /* Initializing the lists of list struct */
286 Lists_OP_CreateLists();
287 /* Load each list into list struct */
290 listfiles = Config.lists;
291 while(listfiles && *listfiles)
293 verbose("%s: INFO: Reading the lists file: '%s'", ARGV0, *listfiles);
294 if(Lists_OP_LoadList(*listfiles) < 0)
295 ErrorExit(LISTS_ERROR, ARGV0, *listfiles);
304 /* Creating the rules list */
305 Rules_OP_CreateRules();
307 /* Reading the rules */
310 rulesfiles = Config.includes;
311 while(rulesfiles && *rulesfiles)
313 debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
314 if(Rules_OP_ReadRules(*rulesfiles) < 0)
315 ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
321 free(Config.includes);
322 Config.includes = NULL;
325 /* Find all rules with that require list lookups and attache the
326 * the correct list struct to the rule. This keeps rules from having to
327 * search thought the list of lists for the correct file during rule evaluation.
334 /* Fixing the levels/accuracy */
337 RuleNode *tmp_node = OS_GetFirstRule();
339 total_rules = _setlevels(tmp_node, 0);
340 debug1("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
344 /* Creating a rules hash (for reading alerts from other servers). */
346 RuleNode *tmp_node = OS_GetFirstRule();
347 Config.g_rules_hash = OSHash_Create();
348 if(!Config.g_rules_hash)
350 ErrorExit(MEM_ERROR, ARGV0);
352 AddHash_Rule(tmp_node);
362 /* Start up message */
363 verbose(STARTUP_MSG, ARGV0, getpid());
366 /* Going to main loop */
367 OS_ReadMSG(m_queue, ut_str);
377 * Main function. Receives the messages(events)
378 * and analyze them all.
380 void OS_ReadMSG(int m_queue, char *ut_str)
383 char msg[OS_MAXSTR +1];
385 char *ut_alertlevel = NULL;
386 char *ut_rulelevel = NULL;
387 char *ut_decoder_name = NULL;
391 /* XXX Break apart string */
392 ut_rulelevel = ut_str;
393 ut_alertlevel = strchr(ut_rulelevel, ':');
396 ErrorExit("%s: -U requires the matching format to be "
397 "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
401 *ut_alertlevel = '\0';
404 ut_decoder_name = strchr(ut_alertlevel, ':');
407 ErrorExit("%s: -U requires the matching format to be "
408 "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0);
412 *ut_decoder_name = '\0';
417 RuleInfoDetail *last_info_detail;
421 /* Null to global currently pointers */
422 currently_rule = NULL;
425 /* Creating the event list */
426 OS_CreateEventList(Config.memorysize);
429 /* Initiating the FTS list */
432 ErrorExit(FTS_LIST_ERROR, ARGV0);
439 /* Getting currently time before starting */
443 /* Doing some cleanup */
444 memset(msg, '\0', OS_MAXSTR +1);
448 print_out("%s: Type one log per line.\n", ARGV0);
454 lf = (Eventinfo *)calloc(1,sizeof(Eventinfo));
456 /* This shouldn't happen .. */
459 ErrorExit(MEM_ERROR,ARGV0);
463 /* Fixing the msg. */
464 snprintf(msg, 15, "1:stdin:");
468 /* Receive message from queue */
469 if(fgets(msg +8, OS_MAXSTR, stdin))
471 RuleNode *rulenode_pt;
473 /* Getting the time we received the event */
477 /* Removing new line. */
478 if(msg[strlen(msg) -1] == '\n')
479 msg[strlen(msg) -1] = '\0';
482 /* Make sure we ignore blank lines. */
489 if(!alert_only)print_out("\n");
492 /* Default values for the log info */
496 /* Clean the msg appropriately */
497 if(OS_CleanMSG(msg, lf) < 0)
499 merror(IMSG_ERROR,ARGV0,msg);
507 /* Currently rule must be null in here */
508 currently_rule = NULL;
511 /*** Running decoders ***/
513 /* Getting log size */
514 lf->size = strlen(lf->log);
517 /* Decoding event. */
521 /* Looping all the rules */
522 rulenode_pt = OS_GetFirstRule();
525 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
531 if(full_output && !alert_only)
532 print_out("\n**Rule debugging:");
538 if(lf->decoder_info->type == OSSEC_ALERT)
540 if(!lf->generated_rule)
545 /* We go ahead in here and process the alert. */
546 currently_rule = lf->generated_rule;
549 /* The categories must match */
550 else if(rulenode_pt->ruleinfo->category !=
551 lf->decoder_info->type)
557 /* Checking each rule. */
558 else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
567 char *(ruleinfodetail_text[])={"Text","Link","CVE","OSVDB","BUGTRACKID"};
568 print_out("\n**Phase 3: Completed filtering (rules).");
569 print_out(" Rule id: '%d'", currently_rule->sigid);
570 print_out(" Level: '%d'", currently_rule->level);
571 print_out(" Description: '%s'",currently_rule->comment);
572 for (last_info_detail = currently_rule->info_details; last_info_detail != NULL; last_info_detail = last_info_detail->next)
574 print_out(" Info - %s: '%s'", ruleinfodetail_text[last_info_detail->type], last_info_detail->data);
582 if(currently_rule->level == 0)
588 /* Checking ignore time */
589 if(currently_rule->ignore_time)
591 if(currently_rule->time_ignored == 0)
593 currently_rule->time_ignored = lf->time;
595 /* If the currently time - the time the rule was ignored
596 * is less than the time it should be ignored,
597 * leave (do not alert again).
599 else if((lf->time - currently_rule->time_ignored)
600 < currently_rule->ignore_time)
606 currently_rule->time_ignored = 0;
610 /* Pointer to the rule that generated it */
611 lf->generated_rule = currently_rule;
614 /* Checking if we should ignore it */
615 if(currently_rule->ckignore && IGnore(lf))
618 lf->generated_rule = NULL;
622 /* Checking if we need to add to ignore list */
623 if(currently_rule->ignore)
629 /* Log the alert if configured to ... */
630 if(currently_rule->alert_opts & DO_LOGALERT)
639 print_out("**Alert to be generated.\n\n");
644 /* Copy the structure to the state memory of if_matched_sid */
645 if(currently_rule->sid_prev_matched)
647 if(!OSList_AddData(currently_rule->sid_prev_matched, lf))
649 merror("%s: Unable to add data to sig list.", ARGV0);
653 lf->sid_node_to_delete =
654 currently_rule->sid_prev_matched->last_node;
658 else if(currently_rule->group_prev_matched)
662 while(i < currently_rule->group_prev_matched_sz)
665 currently_rule->group_prev_matched[i],
668 merror("%s: Unable to add data to grp list.",ARGV0);
678 }while((rulenode_pt = rulenode_pt->next) != NULL);
682 /*setup exit code if we are doing unit testing*/
686 if(lf->decoder_info->name != NULL && strcasecmp(ut_decoder_name, lf->decoder_info->name) == 0)
689 snprintf(holder, 1023, "%d", currently_rule->sigid);
690 if(strcasecmp(ut_rulelevel, holder) == 0)
693 snprintf(holder, 1023, "%d", currently_rule->level);
694 if(strcasecmp(ut_alertlevel, holder) == 0)
697 printf("%d\n",exit_code);
704 /* Only clear the memory if the eventinfo was not
705 * added to the stateful memory
706 * -- message is free inside clean event --
708 if(lf->generated_rule == NULL)