-/* @(#) $Id$ */
+/* @(#) $Id: ./src/analysisd/analysisd.c, 2012/07/26 dcid Exp $
+ */
-/* Copyright (C) 2010 Trend Micro Inc.
+/* Copyright (C) 2010-2012 Trend Micro Inc.
* All rights reserved.
*
* This program is a free software; you can redistribute it
* 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
*/
/* Part of the OSSEC
* Available at http://www.ossec.net
*/
-
+
/* ossec-analysisd.
* Responsible for correlation and log decoding.
#include "prelude.h"
#endif
+#ifdef ZEROMQ_OUTPUT
+#include "zeromq_output.h"
+#endif
/** Global data **/
int DecodeSyscheck(Eventinfo *lf);
int DecodeRootcheck(Eventinfo *lf);
int DecodeHostinfo(Eventinfo *lf);
-
+
/* For Decoders */
int ReadDecodeXML(char *file);
/** int main(int argc, char **argv)
*/
-#ifndef TESTRULE
+#ifndef TESTRULE
int main(int argc, char **argv)
#else
int main_analysisd(int argc, char **argv)
#endif
{
int c = 0, m_queue = 0, test_config = 0,run_foreground = 0;
+ int debug_level = 0;
char *dir = DEFAULTDIR;
char *user = USER;
char *group = GROUPGLOBAL;
break;
case 'd':
nowDebug();
+ debug_level = 1;
break;
case 'f':
run_foreground = 1;
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 't':
- test_config = 1;
+ test_config = 1;
break;
default:
help(ARGV0);
}
+ /* Check current debug_level
+ * Command line setting takes precedence
+ */
+ if (debug_level == 0)
+ {
+ /* Getting debug level */
+ debug_level = getDefine_Int("analysisd", "debug", 0, 2);
+ while(debug_level != 0)
+ {
+ nowDebug();
+ debug_level--;
+ }
+ }
+
/* Starting daemon */
debug1(STARTED_MSG,ARGV0);
DEBUG_MSG("%s: DEBUG: Starting on debug mode - %d ", ARGV0, (int)time(0));
-
+
/*Check if the user/group given are valid */
uid = Privsep_GetUser(user);
gid = Privsep_GetGroup(group);
/* Found user */
debug1(FOUND_USER, ARGV0);
-
+
/* Initializing Active response */
AR_Init();
if(AR_ReadConfig(test_config, cfg) < 0)
ErrorExit(CONFIG_ERROR,ARGV0, cfg);
}
debug1(ASINIT, ARGV0);
-
-
+
+
/* Reading configuration file */
if(GlobalConf(cfg) < 0)
{
}
debug1(READ_CONFIG, ARGV0);
-
+
/* Fixing Config.ar */
Config.ar = ar_flag;
if(Config.ar == -1)
Config.ar = 0;
-
-
+
+
/* 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
{
if(_ltmp)
*_ltmp = '\0';
}
-
+
/* going on Daemon mode */
- if(!test_config || !run_foreground)
+ if(!test_config && !run_foreground)
{
nowDaemon();
goDaemon();
}
-
+
/* Starting prelude */
#ifdef PRELUDE
}
#endif
+ /* Starting zeromq */
+ #ifdef ZEROMQ_OUTPUT
+ if(Config.zeromq_output)
+ {
+ zeromq_output_start(Config.zeromq_output_uri, argc, argv);
+ }
+ #endif
/* Opening the Picviz socket */
if(Config.picviz)
nowChroot();
-
-
+
+
/*
- * Anonymous Section: Load rules, decoders, and lists
+ * 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.
+ * are created with blank database structs, and need to be filled in after
+ * completion of all rules and lists.
*/
{
{
/* Initializing the decoders list */
OS_CreateOSDecoderList();
- if(!Config.decoders)
+ if(!Config.decoders)
{ /* Legacy loading */
/* Reading decoders */
if(!ReadDecodeXML(XML_DECODER))
verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
if(!ReadDecodeXML(*decodersfiles))
ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
-
- free(*decodersfiles);
- decodersfiles++;
+
+ free(*decodersfiles);
+ decodersfiles++;
}
}
}
{ /* Load Lists */
/* Initializing the lists of list struct */
- Lists_OP_CreateLists();
+ Lists_OP_CreateLists();
/* Load each list into list struct */
{
char **listfiles;
verbose("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
if(Rules_OP_ReadRules(*rulesfiles) < 0)
ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
-
- free(*rulesfiles);
- 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
+ * 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;
total_rules = _setlevels(tmp_node, 0);
if(!test_config)
- verbose("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
+ verbose("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
}
AddHash_Rule(tmp_node);
}
-
-
+
+
/* Ignored files on syscheck */
{
char **files;
{
if(!test_config)
verbose("%s: INFO: Ignoring file: '%s'", ARGV0, *files);
- files++;
+ files++;
}
}
"log_fw",
0, 1);
-
+
/* Success on the configuration test */
if(test_config)
exit(0);
-
+
/* Verbose message */
debug1(PRIVSEP_MSG, ARGV0, dir, user);
StartSIG(ARGV0);
- /* Setting the user */
+ /* Setting the user */
if(Privsep_SetUser(uid) < 0)
ErrorExit(SETUID_ERROR,ARGV0,user);
-
-
+
+
/* Creating the PID file */
if(CreatePID(ARGV0, getpid()) < 0)
ErrorExit(PID_ERROR,ARGV0);
if(Config.hostname_white_list == NULL)
{
if(Config.ar)
- verbose("%s: INFO: No Hostname in the white list for active reponse.",
+ verbose("%s: INFO: No Hostname in the white list for active reponse.",
ARGV0);
}
else
{
int wlc = 0;
OSMatch **wl;
-
+
wl = Config.hostname_white_list;
while(*wl)
{
/* Going to main loop */
OS_ReadMSG(m_queue);
- if (Config.picviz)
+ if (Config.picviz)
{
OS_PicvizClose();
}
exit(0);
-
+
}
* Main function. Receives the messages(events)
* and analyze them all.
*/
-#ifndef TESTRULE
+#ifndef TESTRULE
void OS_ReadMSG(int m_queue)
#else
void OS_ReadMSG_analysisd(int m_queue)
Eventinfo *lf;
RuleInfo *stats_rule;
-
+
/* Null to global currently pointers */
currently_rule = NULL;
/* Initializing Rootcheck */
RootcheckInit();
-
-
+
+
/* Initializing host info */
HostinfoInit();
-
-
+
+
/* Creating the event list */
OS_CreateEventList(Config.memorysize);
{
ErrorExit(FTS_LIST_ERROR, ARGV0);
}
-
+
/* 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)
{
verbose(CONN_TO, ARGV0, ARQUEUE, "active-response");
}
}
-
+
#else
/* Only for LOCAL_ONLY installs */
if(Config.ar & REMOTE_AR)
}
}
#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)
{
/* Doing some cleanup */
memset(msg, '\0', OS_MAXSTR +1);
-
-
+
+
/* Initializing the logs */
{
lf = (Eventinfo *)calloc(1,sizeof(Eventinfo));
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)))
{
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)
{
/* Msg cleaned */
DEBUG_MSG("%s: DEBUG: Msg cleanup: %s ", ARGV0, lf->log);
-
+
/* Currently rule must be null in here */
currently_rule = NULL;
prev_year = lf->year;
}
}
-
-
+
+
/* Incrementing number of events received */
hourly_events++;
if(msg[0] == SYSCHECK_MQ)
{
hourly_syscheck++;
-
+
if(!DecodeSyscheck(lf))
{
/* We don't process syscheck events further */
DecodeEvent(lf);
}
-
+
/* Firewall event */
if(lf->decoder_info->type == FIREWALL)
/* If we could not get any information from
* the log, just ignore it
*/
- hourly_firewall++;
+ hourly_firewall++;
if(Config.logfw)
{
if(!FW_Log(lf))
{
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;
if(stats_rule->alert_opts & DO_LOGALERT)
{
__crt_ftell = ftell(_aflog);
- OS_Log(lf);
+ if(Config.custom_alert_output)
+ {
+ OS_CustomLog(lf,Config.custom_alert_output_format);
+ }
+ else
+ {
+ OS_Log(lf);
+ }
+
}
/* Checking the rules */
- DEBUG_MSG("%s: DEBUG: Checking the rules - %d ",
+ DEBUG_MSG("%s: DEBUG: Checking the rules - %d ",
ARGV0, lf->decoder_info->type);
-
+
/* Looping all the rules */
rulenode_pt = OS_GetFirstRule();
- if(!rulenode_pt)
+ if(!rulenode_pt)
{
ErrorExit("%s: Rules in an inconsistent state. Exiting.",
ARGV0);
{
if(!lf->generated_rule)
{
- goto CLMEM;
+ 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 !=
+ else if(rulenode_pt->ruleinfo->category !=
lf->decoder_info->type)
{
continue;
}
/* Checking each rule. */
- else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
+ else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
== NULL)
{
continue;
}
- /* Checking ignore time */
+ /* Checking ignore time */
if(currently_rule->ignore_time)
{
if(currently_rule->time_ignored == 0)
* 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;
/* Pointer to the rule that generated it */
lf->generated_rule = currently_rule;
-
+
/* Checking if we should ignore it */
if(currently_rule->ckignore && IGnore(lf))
{
lf->generated_rule = NULL;
break;
}
-
-
+
+
/* Checking if we need to add to ignore list */
if(currently_rule->ignore)
{
if(currently_rule->alert_opts & DO_LOGALERT)
{
__crt_ftell = ftell(_aflog);
- OS_Log(lf);
+
+ if(Config.custom_alert_output)
+ {
+ OS_CustomLog(lf,Config.custom_alert_output_format);
+ }
+ else
+ {
+ OS_Log(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)
do_ar = 1;
if((*rule_ar)->ar_cmd->expect & USERNAME)
{
- if(!lf->dstuser ||
+ if(!lf->dstuser ||
!OS_PRegex(lf->dstuser,"^[a-zA-Z._0-9@?-]*$"))
{
if(lf->dstuser)
do_ar = 0;
}
}
+ if((*rule_ar)->ar_cmd->expect & FILENAME)
+ {
+ if(!lf->filename)
+ {
+ do_ar = 0;
+ }
+ }
if(do_ar)
{
}
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);
i++;
}
}
-
+
OS_AddEvent(lf);
break;
/* Cleaning the memory */
CLMEM:
-
+
/* 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)
* status,
*/
RuleInfo *currently_rule = curr_node->ruleinfo;
-
-
+
+
/* Can't be null */
if(!currently_rule)
{
merror("%s: Inconsistent state. currently rule NULL", ARGV0);
return(NULL);
}
-
+
#ifdef TESTRULE
if(full_output && !alert_only)
print_out(" Trying rule: %d - %s", currently_rule->sigid,
currently_rule->comment);
#endif
-
-
+
+
/* Checking if any decoder pre-matched here */
- if(currently_rule->decoded_as &&
+ if(currently_rule->decoded_as &&
currently_rule->decoded_as != lf->decoder_info->id)
{
return(NULL);
}
-
-
+
+
/* Checking program name */
if(currently_rule->program_name)
{
if(!lf->program_name)
return(NULL);
- if(!OSMatch_Execute(lf->program_name,
- lf->p_name_size,
+ if(!OSMatch_Execute(lf->program_name,
+ lf->p_name_size,
currently_rule->program_name))
return(NULL);
}
{
return(NULL);
}
-
+
if(!OSMatch_Execute(lf->id,
strlen(lf->id),
currently_rule->id))
#endif
}
-
+
/* Checking if any word to match exists */
if(currently_rule->match)
{
if(!OSMatch_Execute(lf->log, lf->size, currently_rule->match))
return(NULL);
- }
+ }
+
-
/* Checking if exist any regex for this rule */
if(currently_rule->regex)
{
if(!OSRegex_Execute(lf->log, currently_rule->regex))
return(NULL);
}
-
-
+
+
/* Checking for actions */
if(currently_rule->action)
{
return(NULL);
}
-
+
/* Checking for the url */
if(currently_rule->url)
{
{
return(NULL);
}
-
+
if(!OSMatch_Execute(lf->url, strlen(lf->url), currently_rule->url))
{
return(NULL);
{
return(NULL);
}
-
+
if(!OSMatch_Execute(lf->srcport,
strlen(lf->srcport),
currently_rule->srcport))
{
return(NULL);
}
-
+
if(!OSMatch_Execute(lf->dstport,
strlen(lf->dstport),
currently_rule->dstport))
#endif
}
} /* END PACKET_INFO */
-
+
/* Extra information from event */
if(currently_rule->alert_opts & DO_EXTRAINFO)
}
}
-
+
/* If it is a context rule, search for it */
if(currently_rule->context == 1)
{
if(full_output && !alert_only)
print_out(" *Rule %d matched.", currently_rule->sigid);
#endif
-
-
+
+
/* Search for dependent rules */
if(curr_node->child)
{
RuleNode *child_node = curr_node->child;
RuleInfo *child_rule = NULL;
-
+
#ifdef TESTRULE
if(full_output && !alert_only)
print_out(" *Trying child rules.");
#endif
-
+
while(child_node)
{
child_rule = OS_CheckIfRuleMatch(lf, child_node);
{
return(child_rule);
}
-
+
child_node = child_node->next;
}
}
-
+
/* If we are set to no alert, keep going */
if(currently_rule->alert_opts & NO_ALERT)
{
return(NULL);
}
-
+
hourly_alerts++;
currently_rule->firedtimes++;
{
if(curr_node->ruleinfo->firedtimes)
{
- fprintf(flog, "%d-%d-%d-%d\n",
- thishour,
+ fprintf(flog, "%d-%d-%d-%d\n",
+ thishour,
curr_node->ruleinfo->sigid,
curr_node->ruleinfo->level,
curr_node->ruleinfo->firedtimes);
curr_node->ruleinfo->firedtimes = 0;
}
-
+
if(curr_node->child)
{
RuleNode *child_node = curr_node->child;
/* Looping on all the rules and printing the stats from them */
do
{
- LoopRule(rulenode_pt, flog);
+ LoopRule(rulenode_pt, flog);
}while((rulenode_pt = rulenode_pt->next) != NULL);
hourly_events = 0;
hourly_syscheck = 0;
hourly_firewall = 0;
-
+
fclose(flog);
}