X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?a=blobdiff_plain;ds=sidebyside;f=src%2Fanalysisd%2Ftestrule.c;h=d2f5b2544c7e80549239809c36057f55bf195a0b;hb=6ef2f786c6c8ead94841b5f93baf9f43421f08c8;hp=db769f771f6dcf57ee591644c161f9d5d53f9a99;hpb=914feba5d54f979cd5d7e69c349c3d01f630042a;p=ossec-hids.git diff --git a/src/analysisd/testrule.c b/src/analysisd/testrule.c index db769f7..d2f5b25 100755 --- a/src/analysisd/testrule.c +++ b/src/analysisd/testrule.c @@ -1,14 +1,15 @@ -/* @(#) $Id: testrule.c,v 1.7 2009/08/25 11:30:57 dcid Exp $ */ +/* @(#) $Id: ./src/analysisd/testrule.c, 2012/07/23 dcid Exp $ + */ /* Copyright (C) 2009 Trend Micro Inc. * All rights reserved. * * This program is a free software; you can redistribute it * and/or modify it under the terms of the GNU General Public - * License (version 3) as published by the FSF - Free Software + * License (version 2) as published by the FSF - Free Software * Foundation. * - * License details at the LICENSE file included with OSSEC or + * License details at the LICENSE file included with OSSEC or * online at: http://www.ossec.net/en/licensing.html */ @@ -16,7 +17,7 @@ /* Part of the OSSEC * Available at http://www.ossec.net */ - + /* ossec-analysisd. * Responsible for correlation and log decoding. @@ -27,6 +28,8 @@ #define ARGV0 "ossec-testrule" #endif + + #include "shared.h" #include "alerts/alerts.h" @@ -42,13 +45,14 @@ #include "config.h" #include "rules.h" #include "stats.h" + #include "eventinfo.h" #include "analysisd.h" /** Internal Functions **/ -void OS_ReadMSG(int m_queue); +void OS_ReadMSG(int m_queue, char *ut_str); RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node); @@ -60,6 +64,7 @@ int GlobalConf(char * cfgfile); /* For rules */ void Rules_OP_CreateRules(); +void Lists_OP_CreateLists(); int Rules_OP_ReadRules(char * cfgfile); int _setlevels(RuleNode *node, int nnode); int AddHash_Rule(RuleNode *node); @@ -88,13 +93,38 @@ int ReadDecodeXML(char *file); int SetDecodeXML(); +void logtest_help(const char *prog) +{ + print_out(" "); + print_out("%s %s - %s (%s)", __name, __version, __author, __contact); + print_out("%s", __site); + print_out(" "); + print_out(" %s: -[Vatfdh] [-U ut_str] [-u user] [-g group] [-c config] [-D dir]", prog); + print_out(" -V Version and license message"); + print_out(" -a Alerts output"); + print_out(" -t Test configuration"); + print_out(" -v Verbose (full) output/rule debugging"); + print_out(" -d Execute in debug mode"); + print_out(" -h This help message"); + print_out(" -U Unit test. Refer to contrib/ossec-testing/runtests.py"); + print_out(" -u Run as 'user'"); + print_out(" -g Run as 'group'"); + print_out(" -c Read the 'config' file"); + print_out(" -D Chroot to 'dir'"); + print_out(" "); + exit(1); +} + /** int main(int argc, char **argv) */ int main(int argc, char **argv) { + int t_config = 0; int c = 0, m_queue = 0; + char *ut_str = NULL; + char *dir = DEFAULTDIR; char *user = USER; char *group = GROUPGLOBAL; @@ -108,20 +138,30 @@ int main(int argc, char **argv) today = 0; prev_year = 0; full_output = 0; + alert_only = 0; + active_responses = NULL; memset(prev_month, '\0', 4); - while((c = getopt(argc, argv, "Vfdhu:g:D:c:")) != -1){ + while((c = getopt(argc, argv, "VatvdhU:u:g:D:c:")) != -1){ switch(c){ case 'V': print_version(); break; + case 't': + t_config = 1; + break; case 'h': - help(ARGV0); + logtest_help(ARGV0); break; case 'd': nowDebug(); break; + case 'U': + if(!optarg) + ErrorExit("%s: -U needs an argument",ARGV0); + ut_str = optarg; + break; case 'u': if(!optarg) ErrorExit("%s: -u needs an argument",ARGV0); @@ -136,22 +176,28 @@ int main(int argc, char **argv) if(!optarg) ErrorExit("%s: -D needs an argument",ARGV0); dir = optarg; + break; case 'c': if(!optarg) ErrorExit("%s: -c needs an argument",ARGV0); cfg = optarg; break; - case 'f': - full_output = 1; + case 'a': + alert_only = 1; + break; + case 'v': + full_output = 1; break; default: - help(ARGV0); + logtest_help(ARGV0); break; } } + + /* Reading configuration file */ if(GlobalConf(cfg) < 0) { @@ -159,14 +205,14 @@ int main(int argc, char **argv) } debug1(READ_CONFIG, ARGV0); - - + + /* Getting servers hostname */ memset(__shost, '\0', 512); if(gethostname(__shost, 512 -1) != 0) { - strncpy(__shost, OSSEC_SERVER, 512 -1); + strncpy(__shost, OSSEC_SERVER, 512 -1); } else { @@ -177,60 +223,121 @@ int main(int argc, char **argv) if(_ltmp) *_ltmp = '\0'; } - + if(chdir(dir) != 0) ErrorExit(CHROOT_ERROR,ARGV0,dir); - - /* Reading decoders */ - OS_CreateOSDecoderList(); - if(!ReadDecodeXML("etc/decoder.xml")) + /* + * Anonymous Section: Load rules, decoders, and lists + * + * As lists require two pass loading of rules that make use of list lookups + * are created with blank database structs, and need to be filled in after + * completion of all rules and lists. + */ { - ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER); - } + { /* Lad decders */ + /* Initializing the decoders list */ + OS_CreateOSDecoderList(); + + if(!Config.decoders) + { /* Legacy loading */ + /* Reading decoders */ + if(!ReadDecodeXML("etc/decoder.xml")) + { + ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER); + } - c = ReadDecodeXML("etc/local_decoder.xml"); - if(!c) - { - if((c != -2)) - ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER); - } - SetDecodeXML(); + /* Reading local ones. */ + c = ReadDecodeXML("etc/local_decoder.xml"); + if(!c) + { + if((c != -2)) + ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER); + } + else + { + verbose("%s: INFO: Reading local decoder file.", ARGV0); + } + } + else + { /* New loaded based on file speified in ossec.conf */ + char **decodersfiles; + decodersfiles = Config.decoders; + while( decodersfiles && *decodersfiles) + { - - /* Creating the rules list */ - Rules_OP_CreateRules(); + verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles); + if(!ReadDecodeXML(*decodersfiles)) + ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles); - - /* Reading the rules */ - { - char **rulesfiles; - rulesfiles = Config.includes; - while(rulesfiles && *rulesfiles) - { - debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles); - if(Rules_OP_ReadRules(*rulesfiles) < 0) - ErrorExit(RULES_ERROR, ARGV0, *rulesfiles); - - free(*rulesfiles); - rulesfiles++; + free(*decodersfiles); + decodersfiles++; + } + } + + /* Load decoders */ + SetDecodeXML(); + } + { /* Load Lists */ + /* Initializing the lists of list struct */ + Lists_OP_CreateLists(); + /* Load each list into list struct */ + { + char **listfiles; + listfiles = Config.lists; + while(listfiles && *listfiles) + { + verbose("%s: INFO: Reading the lists file: '%s'", ARGV0, *listfiles); + if(Lists_OP_LoadList(*listfiles) < 0) + ErrorExit(LISTS_ERROR, ARGV0, *listfiles); + free(*listfiles); + listfiles++; + } + free(Config.lists); + Config.lists = NULL; + } } + { /* Load Rules */ + /* Creating the rules list */ + Rules_OP_CreateRules(); - free(Config.includes); - Config.includes = NULL; + /* Reading the rules */ + { + char **rulesfiles; + rulesfiles = Config.includes; + while(rulesfiles && *rulesfiles) + { + debug1("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles); + if(Rules_OP_ReadRules(*rulesfiles) < 0) + ErrorExit(RULES_ERROR, ARGV0, *rulesfiles); + + free(*rulesfiles); + rulesfiles++; + } + + free(Config.includes); + Config.includes = NULL; + } + + /* Find all rules with that require list lookups and attache the + * the correct list struct to the rule. This keeps rules from having to + * search thought the list of lists for the correct file during rule evaluation. + */ + OS_ListLoadRules(); + } } - - + + /* Fixing the levels/accuracy */ { int total_rules; RuleNode *tmp_node = OS_GetFirstRule(); total_rules = _setlevels(tmp_node, 0); - debug1("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules); + debug1("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules); } @@ -246,17 +353,22 @@ int main(int argc, char **argv) } - + if(t_config == 1) + { + exit(0); + } + + /* Start up message */ verbose(STARTUP_MSG, ARGV0, getpid()); /* Going to main loop */ - OS_ReadMSG(m_queue); + OS_ReadMSG(m_queue, ut_str); exit(0); - + } @@ -265,10 +377,44 @@ int main(int argc, char **argv) * Main function. Receives the messages(events) * and analyze them all. */ -void OS_ReadMSG(int m_queue) +void OS_ReadMSG(int m_queue, char *ut_str) { int i; char msg[OS_MAXSTR +1]; + int exit_code = 0; + char *ut_alertlevel = NULL; + char *ut_rulelevel = NULL; + char *ut_decoder_name = NULL; + + if(ut_str) + { + /* XXX Break apart string */ + ut_rulelevel = ut_str; + ut_alertlevel = strchr(ut_rulelevel, ':'); + if(!ut_alertlevel) + { + ErrorExit("%s: -U requires the matching format to be " + "\"::\"", ARGV0); + } + else + { + *ut_alertlevel = '\0'; + ut_alertlevel++; + } + ut_decoder_name = strchr(ut_alertlevel, ':'); + if(!ut_decoder_name) + { + ErrorExit("%s: -U requires the matching format to be " + "\"::\"", ARGV0); + } + else + { + *ut_decoder_name = '\0'; + ut_decoder_name++; + } + } + + RuleInfoDetail *last_info_detail; Eventinfo *lf; @@ -285,7 +431,9 @@ void OS_ReadMSG(int m_queue) { ErrorExit(FTS_LIST_ERROR, ARGV0); } - + + + __crt_ftell = 1; /* Getting currently time before starting */ @@ -294,16 +442,17 @@ void OS_ReadMSG(int m_queue) /* Doing some cleanup */ memset(msg, '\0', OS_MAXSTR +1); - + + if(!alert_only) print_out("%s: Type one log per line.\n", ARGV0); - - + + /* Daemon loop */ while(1) { lf = (Eventinfo *)calloc(1,sizeof(Eventinfo)); - + /* This shouldn't happen .. */ if(lf == NULL) { @@ -312,12 +461,12 @@ void OS_ReadMSG(int m_queue) /* Fixing the msg. */ - strncpy(msg, "1:a:", 5); - - - + snprintf(msg, 15, "1:stdin:"); + + + /* Receive message from queue */ - if(fgets(msg +4, OS_MAXSTR, stdin)) + if(fgets(msg +8, OS_MAXSTR, stdin)) { RuleNode *rulenode_pt; @@ -331,14 +480,14 @@ void OS_ReadMSG(int m_queue) /* Make sure we ignore blank lines. */ - if(strlen(msg) < 6) + if(strlen(msg) < 10) { continue; } - - - print_out("\n"); - + + + if(!alert_only)print_out("\n"); + /* Default values for the log info */ Zero_Eventinfo(lf); @@ -367,19 +516,19 @@ void OS_ReadMSG(int m_queue) /* Decoding event. */ DecodeEvent(lf); - + /* Looping all the rules */ rulenode_pt = OS_GetFirstRule(); - if(!rulenode_pt) + if(!rulenode_pt) { ErrorExit("%s: Rules in an inconsistent state. Exiting.", ARGV0); } - + #ifdef TESTRULE - if(full_output) + if(full_output && !alert_only) print_out("\n**Rule debugging:"); #endif @@ -396,9 +545,9 @@ void OS_ReadMSG(int m_queue) /* We go ahead in here and process the alert. */ currently_rule = lf->generated_rule; } - + /* The categories must match */ - else if(rulenode_pt->ruleinfo->category != + else if(rulenode_pt->ruleinfo->category != lf->decoder_info->type) { continue; @@ -406,19 +555,27 @@ void OS_ReadMSG(int m_queue) /* Checking each rule. */ - else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt)) + else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt)) == NULL) { continue; } #ifdef TESTRULE + if(!alert_only) + { + char *(ruleinfodetail_text[])={"Text","Link","CVE","OSVDB","BUGTRACKID"}; print_out("\n**Phase 3: Completed filtering (rules)."); print_out(" Rule id: '%d'", currently_rule->sigid); print_out(" Level: '%d'", currently_rule->level); print_out(" Description: '%s'",currently_rule->comment); + for (last_info_detail = currently_rule->info_details; last_info_detail != NULL; last_info_detail = last_info_detail->next) + { + print_out(" Info - %s: '%s'", ruleinfodetail_text[last_info_detail->type], last_info_detail->data); + } + } #endif - + /* Ignore level 0 */ @@ -428,7 +585,7 @@ void OS_ReadMSG(int m_queue) } - /* Checking ignore time */ + /* Checking ignore time */ if(currently_rule->ignore_time) { if(currently_rule->time_ignored == 0) @@ -439,7 +596,7 @@ void OS_ReadMSG(int m_queue) * is less than the time it should be ignored, * leave (do not alert again). */ - else if((lf->time - currently_rule->time_ignored) + else if((lf->time - currently_rule->time_ignored) < currently_rule->ignore_time) { break; @@ -453,7 +610,7 @@ void OS_ReadMSG(int m_queue) /* Pointer to the rule that generated it */ lf->generated_rule = currently_rule; - + /* Checking if we should ignore it */ if(currently_rule->ckignore && IGnore(lf)) { @@ -461,7 +618,7 @@ void OS_ReadMSG(int m_queue) lf->generated_rule = NULL; break; } - + /* Checking if we need to add to ignore list */ if(currently_rule->ignore) { @@ -472,7 +629,15 @@ void OS_ReadMSG(int m_queue) /* Log the alert if configured to ... */ if(currently_rule->alert_opts & DO_LOGALERT) { - print_out("**Alert to be generated.\n\n"); + if(alert_only) + { + OS_LogOutput(lf); + __crt_ftell++; + } + else + { + print_out("**Alert to be generated.\n\n"); + } } @@ -485,19 +650,19 @@ void OS_ReadMSG(int m_queue) } else { - lf->sid_node_to_delete = + lf->sid_node_to_delete = currently_rule->sid_prev_matched->last_node; } } /* Group list */ else if(currently_rule->group_prev_matched) { - i = 0; - + i = 0; + while(i < currently_rule->group_prev_matched_sz) { if(!OSList_AddData( - currently_rule->group_prev_matched[i], + currently_rule->group_prev_matched[i], lf)) { merror("%s: Unable to add data to grp list.",ARGV0); @@ -505,16 +670,39 @@ void OS_ReadMSG(int m_queue) i++; } } - + OS_AddEvent(lf); break; }while((rulenode_pt = rulenode_pt->next) != NULL); + if(ut_str) + { + /*setup exit code if we are doing unit testing*/ + char holder[1024]; + holder[1] = '\0'; + exit_code = 3; + if(lf->decoder_info->name != NULL && strcasecmp(ut_decoder_name, lf->decoder_info->name) == 0) + { + exit_code--; + snprintf(holder, 1023, "%d", currently_rule->sigid); + if(strcasecmp(ut_rulelevel, holder) == 0) + { + exit_code--; + snprintf(holder, 1023, "%d", currently_rule->level); + if(strcasecmp(ut_alertlevel, holder) == 0) + { + exit_code--; + printf("%d\n",exit_code); + } + } + } + } + /* Only clear the memory if the eventinfo was not - * added to the stateful memory + * added to the stateful memory * -- message is free inside clean event -- */ if(lf->generated_rule == NULL) @@ -523,12 +711,14 @@ void OS_ReadMSG(int m_queue) } else { - exit(0); + exit(exit_code); } } + exit(exit_code); return; } /* EOF */ +