void OS_ReadMSG_analysisd(int m_queue) #endif { int i; char msg[OS_MAXSTR +1]; Eventinfo *lf; RuleInfo *stats_rule = NULL; /* Null to global currently pointers */ currently_rule = NULL; /* Initiating the logs */ OS_InitLog(); /* Initiating the integrity database */ SyscheckInit(); /* Initializing Rootcheck */ RootcheckInit(); /* Initializing host info */ HostinfoInit(); /* Creating the event list */ OS_CreateEventList(Config.memorysize); /* Initiating the FTS list */ if(!FTS_Init()) { ErrorExit(FTS_LIST_ERROR, ARGV0); } /* Initialize the Accumulator */ if(!Accumulate_Init()) { merror("accumulator: ERROR: Initialization failed"); exit(1); } /* Starting the active response queues */ if(Config.ar) { /* Waiting the ARQ to settle .. */ sleep(3); #ifndef LOCAL if(Config.ar & REMOTE_AR) { if((arq = StartMQ(ARQUEUE, WRITE)) < 0) { merror(ARQ_ERROR, ARGV0); /* If LOCAL_AR is set, keep it there */ if(Config.ar & LOCAL_AR) { Config.ar = 0; Config.ar|=LOCAL_AR; } else { Config.ar = 0; } } else { verbose(CONN_TO, ARGV0, ARQUEUE, "active-response"); } } #else /* Only for LOCAL_ONLY installs */ if(Config.ar & REMOTE_AR) { if(Config.ar & LOCAL_AR) { Config.ar = 0; Config.ar|=LOCAL_AR; } else { Config.ar = 0; } } #endif if(Config.ar & LOCAL_AR) { if((execdq = StartMQ(EXECQUEUE, WRITE)) < 0) { merror(ARQ_ERROR, ARGV0); /* If REMOTE_AR is set, keep it there */ if(Config.ar & REMOTE_AR) { Config.ar = 0; Config.ar|=REMOTE_AR; } else { Config.ar = 0; } } else { verbose(CONN_TO, ARGV0, EXECQUEUE, "exec"); } } } debug1("%s: DEBUG: Active response Init completed.", ARGV0); /* Getting currently time before starting */ c_time = time(NULL); /* Starting the hourly/weekly stats */ if(Start_Hour() < 0) Config.stats = 0; else { /* Initializing stats rules */ stats_rule = zerorulemember( STATS_MODULE, Config.stats, 0,0,0,0,0,0); if(!stats_rule) { ErrorExit(MEM_ERROR, ARGV0); } stats_rule->group = "stats,"; stats_rule->comment = "Excessive number of events (above normal)."; } /* Doing some cleanup */ memset(msg, '\0', OS_MAXSTR +1); /* Initializing the logs */ { lf = (Eventinfo *)calloc(1,sizeof(Eventinfo)); if(!lf) ErrorExit(MEM_ERROR, ARGV0); lf->year = prev_year; strncpy(lf->mon, prev_month, 3); lf->day = today; if(OS_GetLogLocation(lf) < 0) { ErrorExit("%s: Error allocating log files", ARGV0); } Free_Eventinfo(lf); } debug1("%s: DEBUG: Startup completed. Waiting for new messages..",ARGV0); if(Config.custom_alert_output) debug1("%s: INFO: Custom output found.!",ARGV0); /* Daemon loop */ while(1) { lf = (Eventinfo *)calloc(1,sizeof(Eventinfo)); /* This shouldn't happen .. */ if(lf == NULL) { ErrorExit(MEM_ERROR,ARGV0); } DEBUG_MSG("%s: DEBUG: Waiting for msgs - %d ", ARGV0, (int)time(0)); /* Receive message from queue */ if((i = OS_RecvUnix(m_queue, OS_MAXSTR, msg))) { RuleNode *rulenode_pt; /* Getting the time we received the event */ c_time = time(NULL); /* Default values for the log info */ Zero_Eventinfo(lf); /* Checking for a valid message. */ if(i < 4) { merror(IMSG_ERROR, ARGV0, msg); Free_Eventinfo(lf); continue; } /* Message before extracting header */ DEBUG_MSG("%s: DEBUG: Received msg: %s ", ARGV0, msg); /* Clean the msg appropriately */ if(OS_CleanMSG(msg, lf) < 0) { merror(IMSG_ERROR,ARGV0, msg); Free_Eventinfo(lf); continue; } /* Msg cleaned */ DEBUG_MSG("%s: DEBUG: Msg cleanup: %s ", ARGV0, lf->log); /* Currently rule must be null in here */ currently_rule = NULL; /** Checking the date/hour changes **/ /* Update the hour */ if(thishour != __crt_hour) { /* Search all the rules and print the number * of alerts that each one fired. */ DumpLogstats(); thishour = __crt_hour; /* Check if the date has changed */ if(today != lf->day) { if(Config.stats) { /* Update the hourly stats (done daily) */ Update_Hour(); } if(OS_GetLogLocation(lf) < 0) { ErrorExit("%s: Error allocating log files", ARGV0); } today = lf->day; strncpy(prev_month, lf->mon, 3); prev_year = lf->year; } } /* Incrementing number of events received */ hourly_events++; /*** Running decoders ***/ /* Integrity check from syscheck */ if(msg[0] == SYSCHECK_MQ) { hourly_syscheck++; if(!DecodeSyscheck(lf)) { /* We don't process syscheck events further */ goto CLMEM; } /* Getting log size */ lf->size = strlen(lf->log); } /* Rootcheck decoding */ else if(msg[0] == ROOTCHECK_MQ) { if(!DecodeRootcheck(lf)) { /* We don't process rootcheck events further */ goto CLMEM; } lf->size = strlen(lf->log); } /* Host information special decoder */ else if(msg[0] == HOSTINFO_MQ) { if(!DecodeHostinfo(lf)) { /* We don't process hostinfo events further */ goto CLMEM; } lf->size = strlen(lf->log); } /* Run the general Decoders */ else { /* Getting log size */ lf->size = strlen(lf->log); DecodeEvent(lf); } /* Run accumulator */ if( lf->decoder_info->accumulate == 1 ) { lf = Accumulate(lf); } /* Firewall event */ if(lf->decoder_info->type == FIREWALL) { /* If we could not get any information from * the log, just ignore it */ hourly_firewall++; if(Config.logfw) { if(!FW_Log(lf)) { goto CLMEM; } } } /* We only check if the last message is * duplicated on syslog. */ else if(lf->decoder_info->type == SYSLOG) { /* Checking if the message is duplicated */ if(LastMsg_Stats(lf->full_log) == 1) goto CLMEM; else LastMsg_Change(lf->full_log); } /* Stats checking */ if(Config.stats) { if(Check_Hour() == 1) { void *saved_rule = lf->generated_rule; char *saved_log; /* Saving previous log */ saved_log = lf->full_log; lf->generated_rule = stats_rule; lf->full_log = __stats_comment; /* alert for statistical analysis */ if(stats_rule->alert_opts & DO_LOGALERT) { __crt_ftell = ftell(_aflog); if(Config.custom_alert_output) { OS_CustomLog(lf,Config.custom_alert_output_format); } else { OS_Log(lf); } } /* Set lf to the old values */ lf->generated_rule = saved_rule; lf->full_log = saved_log; } } /* Checking the rules */ DEBUG_MSG("%s: DEBUG: Checking the rules - %d ", ARGV0, lf->decoder_info->type); /* Looping all the rules */ rulenode_pt = OS_GetFirstRule(); if(!rulenode_pt) { ErrorExit("%s: Rules in an inconsistent state. Exiting.", ARGV0); } do { if(lf->decoder_info->type == OSSEC_ALERT) { if(!lf->generated_rule) { goto CLMEM; } /* We go ahead in here and process the alert. */ currently_rule = lf->generated_rule; } /* The categories must match */ else if(rulenode_pt->ruleinfo->category != lf->decoder_info->type) { continue; } /* Checking each rule. */ else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt)) == NULL) { continue; } /* Ignore level 0 */ if(currently_rule->level == 0) { break; } /* Checking ignore time */ if(currently_rule->ignore_time) { if(currently_rule->time_ignored == 0) { currently_rule->time_ignored = lf->time; } /* If the currently time - the time the rule was ignored * is less than the time it should be ignored, * leave (do not alert again). */ else if((lf->time - currently_rule->time_ignored) < currently_rule->ignore_time) { break; } else { currently_rule->time_ignored = lf->time; } } /* Pointer to the rule that generated it */ lf->generated_rule = currently_rule; /* Checking if we should ignore it */ if(currently_rule->ckignore && IGnore(lf)) { /* Ignoring rule */ lf->generated_rule = NULL; break; } /* Checking if we need to add to ignore list */ if(currently_rule->ignore) { AddtoIGnore(lf); } /* Log the alert if configured to ... */ if(currently_rule->alert_opts & DO_LOGALERT) { __crt_ftell = ftell(_aflog); if(Config.custom_alert_output) { OS_CustomLog(lf,Config.custom_alert_output_format); } else { OS_Log(lf); } } /* Log to prelude */ #ifdef PRELUDE if(Config.prelude) { if(Config.prelude_log_level <= currently_rule->level) { OS_PreludeLog(lf); } } #endif /* Log to zeromq */ #ifdef ZEROMQ_OUTPUT if(Config.zeromq_output) { zeromq_output_event(lf); } #endif /* Log to Picviz */ if (Config.picviz) { OS_PicvizLog(lf); } /* Execute an active response */ if(currently_rule->ar) { int do_ar; active_response **rule_ar; rule_ar = currently_rule->ar; while(*rule_ar) { do_ar = 1; if((*rule_ar)->ar_cmd->expect & USERNAME) { if(!lf->dstuser || !OS_PRegex(lf->dstuser,"^[a-zA-Z._0-9@?-]*$")) { if(lf->dstuser) merror(CRAFTED_USER, ARGV0, lf->dstuser); do_ar = 0; } } if((*rule_ar)->ar_cmd->expect & SRCIP) { if(!lf->srcip || !OS_PRegex(lf->srcip, "^[a-zA-Z.:_0-9-]*$")) { if(lf->srcip) merror(CRAFTED_IP, ARGV0, lf->srcip); do_ar = 0; } } if((*rule_ar)->ar_cmd->expect & FILENAME) { if(!lf->filename) { do_ar = 0; } } if(do_ar) { OS_Exec(&execdq, &arq, lf, *rule_ar); } rule_ar++; } } /* Copy the structure to the state memory of if_matched_sid */ if(currently_rule->sid_prev_matched) { if(!OSList_AddData(currently_rule->sid_prev_matched, lf)) { merror("%s: Unable to add data to sig list.", ARGV0); } else { lf->sid_node_to_delete = currently_rule->sid_prev_matched->last_node; } } /* Group list */ else if(currently_rule->group_prev_matched) { i = 0; while(i < currently_rule->group_prev_matched_sz) { if(!OSList_AddData( currently_rule->group_prev_matched[i], lf)) { merror("%s: Unable to add data to grp list.",ARGV0); } i++; } } OS_AddEvent(lf); break; }while((rulenode_pt = rulenode_pt->next) != NULL); /* If configured to log all, do it */ if(Config.logall) OS_Store(lf); /* Cleaning the memory */ CLMEM: /* Only clear the memory if the eventinfo was not * added to the stateful memory * -- message is free inside clean event -- */ if(lf->generated_rule == NULL) Free_Eventinfo(lf); } else { free(lf); } } return; }
void OS_ReadMSG(char *ut_str) { 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 " "\"<rule_id>:<alert_level>:<decoder_name>\"", 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 " "\"<rule_id>:<alert_level>:<decoder_name>\"", ARGV0); } else { *ut_decoder_name = '\0'; ut_decoder_name++; } } RuleInfoDetail *last_info_detail; Eventinfo *lf; /* Null global pointer to current rule */ currently_rule = NULL; /* Create the event list */ OS_CreateEventList(Config.memorysize); /* Initiate the FTS list */ if (!FTS_Init()) { ErrorExit(FTS_LIST_ERROR, ARGV0); } /* Initialize the Accumulator */ if (!Accumulate_Init()) { merror("accumulator: ERROR: Initialization failed"); exit(1); } __crt_ftell = 1; /* Get current time before starting */ c_time = time(NULL); /* Do 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)); os_calloc(Config.decoder_order_size, sizeof(char*), lf->fields); /* This shouldn't happen */ if (lf == NULL) { ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno)); } /* Fix the msg */ snprintf(msg, 15, "1:stdin:"); /* Receive message from queue */ if (fgets(msg + 8, OS_MAXSTR - 8, stdin)) { RuleNode *rulenode_pt; /* Get the time we received the event */ c_time = time(NULL); /* Remov newline */ if (msg[strlen(msg) - 1] == '\n') { msg[strlen(msg) - 1] = '\0'; } /* Make sure we ignore blank lines */ if (strlen(msg) < 10) { continue; } if (!alert_only) { print_out("\n"); } /* Default values for the log info */ Zero_Eventinfo(lf); /* Clean the msg appropriately */ if (OS_CleanMSG(msg, lf) < 0) { merror(IMSG_ERROR, ARGV0, msg); Free_Eventinfo(lf); continue; } /* Current rule must be null in here */ currently_rule = NULL; /*** Run decoders ***/ /* Get log size */ lf->size = strlen(lf->log); /* Decode event */ DecodeEvent(lf); /* Run accumulator */ if ( lf->decoder_info->accumulate == 1 ) { print_out("\n**ACCUMULATOR: LEVEL UP!!**\n"); lf = Accumulate(lf); } /* Loop over all the rules */ rulenode_pt = OS_GetFirstRule(); if (!rulenode_pt) { ErrorExit("%s: Rules in an inconsistent state. Exiting.", ARGV0); } #ifdef TESTRULE if (full_output && !alert_only) { print_out("\n**Rule debugging:"); } #endif do { if (lf->decoder_info->type == OSSEC_ALERT) { if (!lf->generated_rule) { break; } /* Process the alert */ currently_rule = lf->generated_rule; } /* The categories must match */ else if (rulenode_pt->ruleinfo->category != lf->decoder_info->type) { continue; } /* Check each rule */ else if ((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt)) == NULL) { continue; } #ifdef TESTRULE if (!alert_only) { const 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 */ if (currently_rule->level == 0) { break; } /* Check ignore time */ if (currently_rule->ignore_time) { if (currently_rule->time_ignored == 0) { currently_rule->time_ignored = lf->time; } /* If the current time - the time the rule was ignored * is less than the time it should be ignored, * do not alert again */ else if ((lf->time - currently_rule->time_ignored) < currently_rule->ignore_time) { break; } else { currently_rule->time_ignored = 0; } } /* Pointer to the rule that generated it */ lf->generated_rule = currently_rule; /* Check if we should ignore it */ if (currently_rule->ckignore && IGnore(lf)) { lf->generated_rule = NULL; break; } /* Check if we need to add to ignore list */ if (currently_rule->ignore) { AddtoIGnore(lf); } /* Log the alert if configured to */ if (currently_rule->alert_opts & DO_LOGALERT) { if (alert_only) { OS_LogOutput(lf); __crt_ftell++; } else { print_out("**Alert to be generated.\n\n"); } } /* Copy the structure to the state memory of if_matched_sid */ if (currently_rule->sid_prev_matched) { if (!OSList_AddData(currently_rule->sid_prev_matched, lf)) { merror("%s: Unable to add data to sig list.", ARGV0); } else { lf->sid_node_to_delete = currently_rule->sid_prev_matched->last_node; } } /* Group list */ else if (currently_rule->group_prev_matched) { unsigned int i = 0; while (i < currently_rule->group_prev_matched_sz) { if (!OSList_AddData( currently_rule->group_prev_matched[i], lf)) { merror("%s: Unable to add data to grp list.", ARGV0); } i++; } } OS_AddEvent(lf); break; } while ((rulenode_pt = rulenode_pt->next) != NULL); if (ut_str) { /* Set up exit code if we are doing unit testing */ char holder[1024]; holder[1] = '\0'; exit_code = 3; print_out("lf->decoder_info->name: '%s'", lf->decoder_info->name); print_out("ut_decoder_name : '%s'", ut_decoder_name); if (lf->decoder_info->name != NULL && strcasecmp(ut_decoder_name, lf->decoder_info->name) == 0) { exit_code--; if (!currently_rule) { merror("%s: currently_rule not set!", ARGV0); exit(-1); } 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); } } } else if (lf->decoder_info->name != NULL) { print_out("decoder matched : '%s'", lf->decoder_info->name); print_out("decoder expected: '%s'", ut_decoder_name); } else { print_out("decoder matched : 'NULL'"); } } /* Only clear the memory if the eventinfo was not * added to the stateful memory * -- message is free inside clean event -- */ if (lf->generated_rule == NULL) { Free_Eventinfo(lf); } } else { exit(exit_code); } } exit(exit_code); }