-/* @(#) $Id: analysisd.c,v 1.149 2009/11/20 16:11:46 dcid Exp $ */
+/* @(#) $Id: ./src/analysisd/analysisd.c, 2012/07/26 dcid Exp $
+ */
-/* Copyright (C) 2009 Trend Micro Inc.
+/* Copyright (C) 2010-2012 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
*/
/* Part of the OSSEC
* Available at http://www.ossec.net
*/
-
+
/* ossec-analysisd.
* Responsible for correlation and log decoding.
#include "config.h"
#include "rules.h"
#include "stats.h"
+
#include "eventinfo.h"
#include "analysisd.h"
/* 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);
int FTS(Eventinfo *lf);
int AddtoIGnore(Eventinfo *lf);
int IGnore(Eventinfo *lf);
+int doDiff(RuleInfo *currently_rule, Eventinfo *lf);
/* For decoders */
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)
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);
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
OS_PicvizOpen(Config.picviz_socket);
chown(Config.picviz_socket, uid, gid);
}
-
-
+
/* Setting the group */
if(Privsep_SetGroup(gid) < 0)
ErrorExit(SETGID_ERROR,ARGV0,group);
nowChroot();
-
-
- /* Initializing the list */
- OS_CreateOSDecoderList();
-
- /* Reading decoders */
- if(!ReadDecodeXML(XML_DECODER))
- {
- ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER);
- }
- /* Reading local ones. */
- c = ReadDecodeXML(XML_LDECODER);
- if(!c)
- {
- if((c != -2))
- ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER);
- }
- else
+ /*
+ * 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.
+ */
{
- if(!test_config)
- verbose("%s: INFO: Reading local decoder file.", ARGV0);
- }
- SetDecodeXML();
+ {
+ /* Initializing the decoders list */
+ OS_CreateOSDecoderList();
+
+ if(!Config.decoders)
+ { /* Legacy loading */
+ /* Reading decoders */
+ if(!ReadDecodeXML(XML_DECODER))
+ {
+ ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER);
+ }
-
- /* Creating the rules list */
- Rules_OP_CreateRules();
+ /* Reading local ones. */
+ c = ReadDecodeXML(XML_LDECODER);
+ if(!c)
+ {
+ if((c != -2))
+ ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER);
+ }
+ else
+ {
+ if(!test_config)
+ 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)
+ {
+ if(!test_config)
+ 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)
- {
- if(!test_config)
- verbose("%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)
+ {
+ if(!test_config)
+ verbose("%s: INFO: Reading loading 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();
+
+ /* Reading the rules */
+ {
+ char **rulesfiles;
+ rulesfiles = Config.includes;
+ while(rulesfiles && *rulesfiles)
+ {
+ if(!test_config)
+ verbose("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
+ if(Rules_OP_ReadRules(*rulesfiles) < 0)
+ ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
- free(Config.includes);
- Config.includes = NULL;
+ 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;
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);
-
+
/* 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;
/* 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)
{
{
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)
}
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)
+ 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))
return(NULL);
+ #ifdef CDBLOOKUP
+
+ #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);
}
+ #ifdef CDBLOOKUP
+
+ #endif
}
{
return(NULL);
}
+ #ifdef CDBLOOKUP
+
+ #endif
}
/* Checking for the dstip */
{
return(NULL);
}
+ #ifdef CDBLOOKUP
+
+ #endif
}
if(currently_rule->srcport)
{
return(NULL);
}
-
+
if(!OSMatch_Execute(lf->srcport,
strlen(lf->srcport),
currently_rule->srcport))
{
return(NULL);
}
+ #ifdef CDBLOOKUP
+
+ #endif
}
if(currently_rule->dstport)
{
{
return(NULL);
}
-
+
if(!OSMatch_Execute(lf->dstport,
strlen(lf->dstport),
currently_rule->dstport))
{
return(NULL);
}
+ #ifdef CDBLOOKUP
+
+ #endif
}
} /* END PACKET_INFO */
-
+
/* Extra information from event */
if(currently_rule->alert_opts & DO_EXTRAINFO)
return(NULL);
}
else
+ #ifdef CDBLOOKUP
+
+ #endif
{
/* no user set */
return(NULL);
currently_rule->status))
return(NULL);
}
+
+
+ /* Do diff check. */
+ if(currently_rule->context_opts & SAME_DODIFF)
+ {
+ if(!doDiff(currently_rule, lf))
+ {
+ return(NULL);
+ }
+ }
}
-
/* Checking for the FTS flag */
if(currently_rule->alert_opts & DO_FTS)
{
}
}
-
+ /* List lookups */
+ if(currently_rule->lists != NULL)
+ {
+ ListRule *list_holder=currently_rule->lists;
+ while(list_holder)
+ {
+ switch(list_holder->field)
+ {
+ case RULE_SRCIP:
+ if(!lf->srcip)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->srcip))
+ return(NULL);
+ break;
+ case RULE_SRCPORT:
+ if(!lf->srcport)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->srcport))
+ return(NULL);
+ break;
+ case RULE_DSTIP:
+ if(!lf->dstip)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->dstip))
+ return(NULL);
+ break;
+ case RULE_DSTPORT:
+ if(!lf->dstport)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->dstport))
+ return(NULL);
+ break;
+ case RULE_USER:
+ if(lf->srcuser)
+ {
+ if(!OS_DBSearch(list_holder,lf->srcuser))
+ return(NULL);
+ }
+ else if(lf->dstuser)
+ {
+ if(!OS_DBSearch(list_holder,lf->dstuser))
+ return(NULL);
+ }
+ else
+ {
+ return(NULL);
+ }
+ break;
+ case RULE_URL:
+ if(!lf->url)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->url))
+ return(NULL);
+ break;
+ case RULE_ID:
+ if(!lf->id)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->id))
+ return(NULL);
+ break;
+ case RULE_HOSTNAME:
+ if(!lf->hostname)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->hostname))
+ return(NULL);
+ break;
+ case RULE_PROGRAM_NAME:
+ if(!lf->program_name)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->program_name))
+ return(NULL);
+ break;
+ case RULE_STATUS:
+ if(!lf->status)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->status))
+ return(NULL);
+ break;
+ case RULE_ACTION:
+ if(!lf->action)
+ return(NULL);
+ if(!OS_DBSearch(list_holder,lf->action))
+ return(NULL);
+ break;
+ default:
+ return(NULL);
+ }
+
+ list_holder = list_holder->next;
+ }
+ }
+
+
/* If it is a context rule, search for it */
if(currently_rule->context == 1)
{
}
#ifdef TESTRULE
- if(full_output)
+ 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)
+ 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);
}
/* EOF */
+