1 /* @(#) $Id: analysisd.c,v 1.149 2009/11/20 16:11:46 dcid Exp $ */
3 /* Copyright (C) 2009 Trend Micro Inc.
6 * This program is a free software; you can redistribute it
7 * and/or modify it under the terms of the GNU General Public
8 * License (version 3) as published by the FSF - Free Software
11 * License details at the LICENSE file included with OSSEC or
12 * online at: http://www.ossec.net/en/licensing.html
17 * Available at http://www.ossec.net
22 * Responsible for correlation and log decoding.
26 #define ARGV0 "ossec-analysisd"
31 #include "alerts/alerts.h"
32 #include "alerts/getloglocation.h"
33 #include "os_execd/execd.h"
35 #include "os_regex/os_regex.h"
36 #include "os_net/os_net.h"
40 #include "active-response.h"
44 #include "eventinfo.h"
45 #include "analysisd.h"
59 /* active response queue */
63 /** Internal Functions **/
64 void OS_ReadMSG(int m_queue);
65 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
68 /** External functions prototypes (only called here) **/
71 int GlobalConf(char * cfgfile);
75 void Rules_OP_CreateRules();
76 int Rules_OP_ReadRules(char * cfgfile);
77 int _setlevels(RuleNode *node, int nnode);
78 int AddHash_Rule(RuleNode *node);
82 int OS_CleanMSG(char *msg, Eventinfo *lf);
87 int FTS(Eventinfo *lf);
88 int AddtoIGnore(Eventinfo *lf);
89 int IGnore(Eventinfo *lf);
93 void DecodeEvent(Eventinfo *lf);
94 int DecodeSyscheck(Eventinfo *lf);
95 int DecodeRootcheck(Eventinfo *lf);
96 int DecodeHostinfo(Eventinfo *lf);
100 int ReadDecodeXML(char *file);
104 /* For syscheckd (integrity checking) */
106 void RootcheckInit();
112 int Check_Hour(Eventinfo *lf);
123 /** int main(int argc, char **argv)
126 int main(int argc, char **argv)
128 int main_analysisd(int argc, char **argv)
131 int c = 0, m_queue = 0, test_config = 0,run_foreground = 0;
132 char *dir = DEFAULTDIR;
134 char *group = GROUPGLOBAL;
137 char *cfg = DEFAULTCPATH;
139 /* Setting the name */
145 memset(prev_month, '\0', 4);
151 while((c = getopt(argc, argv, "Vtdhfu:g:D:c:")) != -1){
167 ErrorExit("%s: -u needs an argument",ARGV0);
172 ErrorExit("%s: -g needs an argument",ARGV0);
177 ErrorExit("%s: -D needs an argument",ARGV0);
181 ErrorExit("%s: -c needs an argument",ARGV0);
195 /* Starting daemon */
196 debug1(STARTED_MSG,ARGV0);
197 DEBUG_MSG("%s: DEBUG: Starting on debug mode - %d ", ARGV0, (int)time(0));
200 /*Check if the user/group given are valid */
201 uid = Privsep_GetUser(user);
202 gid = Privsep_GetGroup(group);
203 if((uid < 0)||(gid < 0))
204 ErrorExit(USER_ERROR,ARGV0,user,group);
208 debug1(FOUND_USER, ARGV0);
211 /* Initializing Active response */
213 if(AR_ReadConfig(test_config, cfg) < 0)
215 ErrorExit(CONFIG_ERROR,ARGV0, cfg);
217 debug1(ASINIT, ARGV0);
220 /* Reading configuration file */
221 if(GlobalConf(cfg) < 0)
223 ErrorExit(CONFIG_ERROR,ARGV0, cfg);
226 debug1(READ_CONFIG, ARGV0);
229 /* Fixing Config.ar */
235 /* Getting servers hostname */
236 memset(__shost, '\0', 512);
237 if(gethostname(__shost, 512 -1) != 0)
239 strncpy(__shost, OSSEC_SERVER, 512 -1);
245 /* Remove domain part if available */
246 _ltmp = strchr(__shost, '.');
251 /* going on Daemon mode */
252 if(!test_config || !run_foreground)
259 /* Starting prelude */
263 prelude_start(Config.prelude_profile, argc, argv);
268 /* Opening the Picviz socket */
271 OS_PicvizOpen(Config.picviz_socket);
272 chown(Config.picviz_socket, uid, gid);
276 /* Setting the group */
277 if(Privsep_SetGroup(gid) < 0)
278 ErrorExit(SETGID_ERROR,ARGV0,group);
281 if(Privsep_Chroot(dir) < 0)
282 ErrorExit(CHROOT_ERROR,ARGV0,dir);
289 /* Initializing the list */
290 OS_CreateOSDecoderList();
293 /* Reading decoders */
294 if(!ReadDecodeXML(XML_DECODER))
296 ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER);
299 /* Reading local ones. */
300 c = ReadDecodeXML(XML_LDECODER);
304 ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER);
309 verbose("%s: INFO: Reading local decoder file.", ARGV0);
314 /* Creating the rules list */
315 Rules_OP_CreateRules();
318 /* Reading the rules */
321 rulesfiles = Config.includes;
322 while(rulesfiles && *rulesfiles)
325 verbose("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
326 if(Rules_OP_ReadRules(*rulesfiles) < 0)
327 ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
333 free(Config.includes);
334 Config.includes = NULL;
338 /* Fixing the levels/accuracy */
341 RuleNode *tmp_node = OS_GetFirstRule();
343 total_rules = _setlevels(tmp_node, 0);
345 verbose("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
350 /* Creating a rules hash (for reading alerts from other servers). */
352 RuleNode *tmp_node = OS_GetFirstRule();
353 Config.g_rules_hash = OSHash_Create();
354 if(!Config.g_rules_hash)
356 ErrorExit(MEM_ERROR, ARGV0);
358 AddHash_Rule(tmp_node);
363 /* Ignored files on syscheck */
366 files = Config.syscheck_ignore;
367 while(files && *files)
370 verbose("%s: INFO: Ignoring file: '%s'", ARGV0, *files);
376 /* Checking if log_fw is enabled. */
377 Config.logfw = getDefine_Int("analysisd",
382 /* Success on the configuration test */
387 /* Verbose message */
388 debug1(PRIVSEP_MSG, ARGV0, dir, user);
391 /* Signal manipulation */
395 /* Setting the user */
396 if(Privsep_SetUser(uid) < 0)
397 ErrorExit(SETUID_ERROR,ARGV0,user);
400 /* Creating the PID file */
401 if(CreatePID(ARGV0, getpid()) < 0)
402 ErrorExit(PID_ERROR,ARGV0);
405 /* Setting the queue */
406 if((m_queue = StartMQ(DEFAULTQUEUE,READ)) < 0)
407 ErrorExit(QUEUE_ERROR, ARGV0, DEFAULTQUEUE, strerror(errno));
411 if(Config.white_list == NULL)
414 verbose("%s: INFO: No IP in the white list for active reponse.", ARGV0);
422 wl = Config.white_list;
425 verbose("%s: INFO: White listing IP: '%s'",ARGV0, (*wl)->ip);
428 verbose("%s: INFO: %d IPs in the white list for active response.",
433 /* Hostname White list */
434 if(Config.hostname_white_list == NULL)
437 verbose("%s: INFO: No Hostname in the white list for active reponse.",
447 wl = Config.hostname_white_list;
450 char **tmp_pts = (*wl)->patterns;
453 verbose("%s: INFO: White listing Hostname: '%s'",ARGV0,*tmp_pts);
459 verbose("%s: INFO: %d Hostname(s) in the white list for active response.",
465 /* Start up message */
466 verbose(STARTUP_MSG, ARGV0, (int)getpid());
469 /* Going to main loop */
484 * Main function. Receives the messages(events)
485 * and analyze them all.
488 void OS_ReadMSG(int m_queue)
490 void OS_ReadMSG_analysisd(int m_queue)
494 char msg[OS_MAXSTR +1];
497 RuleInfo *stats_rule;
500 /* Null to global currently pointers */
501 currently_rule = NULL;
503 /* Initiating the logs */
507 /* Initiating the integrity database */
511 /* Initializing Rootcheck */
515 /* Initializing host info */
519 /* Creating the event list */
520 OS_CreateEventList(Config.memorysize);
523 /* Initiating the FTS list */
526 ErrorExit(FTS_LIST_ERROR, ARGV0);
530 /* Starting the active response queues */
533 /* Waiting the ARQ to settle .. */
538 if(Config.ar & REMOTE_AR)
540 if((arq = StartMQ(ARQUEUE, WRITE)) < 0)
542 merror(ARQ_ERROR, ARGV0);
544 /* If LOCAL_AR is set, keep it there */
545 if(Config.ar & LOCAL_AR)
557 verbose(CONN_TO, ARGV0, ARQUEUE, "active-response");
562 /* Only for LOCAL_ONLY installs */
563 if(Config.ar & REMOTE_AR)
565 if(Config.ar & LOCAL_AR)
577 if(Config.ar & LOCAL_AR)
579 if((execdq = StartMQ(EXECQUEUE, WRITE)) < 0)
581 merror(ARQ_ERROR, ARGV0);
583 /* If REMOTE_AR is set, keep it there */
584 if(Config.ar & REMOTE_AR)
587 Config.ar|=REMOTE_AR;
596 verbose(CONN_TO, ARGV0, EXECQUEUE, "exec");
600 debug1("%s: DEBUG: Active response Init completed.", ARGV0);
603 /* Getting currently time before starting */
607 /* Starting the hourly/weekly stats */
612 /* Initializing stats rules */
613 stats_rule = zerorulemember(
620 ErrorExit(MEM_ERROR, ARGV0);
622 stats_rule->group = "stats,";
623 stats_rule->comment = "Excessive number of events (above normal).";
627 /* Doing some cleanup */
628 memset(msg, '\0', OS_MAXSTR +1);
631 /* Initializing the logs */
633 lf = (Eventinfo *)calloc(1,sizeof(Eventinfo));
635 ErrorExit(MEM_ERROR, ARGV0);
636 lf->year = prev_year;
637 strncpy(lf->mon, prev_month, 3);
640 if(OS_GetLogLocation(lf) < 0)
642 ErrorExit("%s: Error allocating log files", ARGV0);
649 debug1("%s: DEBUG: Startup completed. Waiting for new messages..",ARGV0);
655 lf = (Eventinfo *)calloc(1,sizeof(Eventinfo));
657 /* This shouldn't happen .. */
660 ErrorExit(MEM_ERROR,ARGV0);
663 DEBUG_MSG("%s: DEBUG: Waiting for msgs - %d ", ARGV0, (int)time(0));
666 /* Receive message from queue */
667 if((i = OS_RecvUnix(m_queue, OS_MAXSTR, msg)))
669 RuleNode *rulenode_pt;
671 /* Getting the time we received the event */
675 /* Default values for the log info */
679 /* Checking for a valid message. */
682 merror(IMSG_ERROR, ARGV0, msg);
688 /* Message before extracting header */
689 DEBUG_MSG("%s: DEBUG: Received msg: %s ", ARGV0, msg);
692 /* Clean the msg appropriately */
693 if(OS_CleanMSG(msg, lf) < 0)
695 merror(IMSG_ERROR,ARGV0, msg);
702 DEBUG_MSG("%s: DEBUG: Msg cleanup: %s ", ARGV0, lf->log);
705 /* Currently rule must be null in here */
706 currently_rule = NULL;
709 /** Checking the date/hour changes **/
711 /* Update the hour */
712 if(thishour != __crt_hour)
714 /* Search all the rules and print the number
715 * of alerts that each one fired.
718 thishour = __crt_hour;
720 /* Check if the date has changed */
725 /* Update the hourly stats (done daily) */
729 if(OS_GetLogLocation(lf) < 0)
731 ErrorExit("%s: Error allocating log files", ARGV0);
735 strncpy(prev_month, lf->mon, 3);
736 prev_year = lf->year;
741 /* Incrementing number of events received */
745 /*** Running decoders ***/
747 /* Integrity check from syscheck */
748 if(msg[0] == SYSCHECK_MQ)
752 if(!DecodeSyscheck(lf))
754 /* We don't process syscheck events further */
758 /* Getting log size */
759 lf->size = strlen(lf->log);
762 /* Rootcheck decoding */
763 else if(msg[0] == ROOTCHECK_MQ)
765 if(!DecodeRootcheck(lf))
767 /* We don't process rootcheck events further */
770 lf->size = strlen(lf->log);
773 /* Host information special decoder */
774 else if(msg[0] == HOSTINFO_MQ)
776 if(!DecodeHostinfo(lf))
778 /* We don't process hostinfo events further */
781 lf->size = strlen(lf->log);
784 /* Run the general Decoders */
787 /* Getting log size */
788 lf->size = strlen(lf->log);
795 if(lf->decoder_info->type == FIREWALL)
797 /* If we could not get any information from
798 * the log, just ignore it
811 /* We only check if the last message is
812 * duplicated on syslog.
814 else if(lf->decoder_info->type == SYSLOG)
816 /* Checking if the message is duplicated */
817 if(LastMsg_Stats(lf->full_log) == 1)
820 LastMsg_Change(lf->full_log);
827 if(Check_Hour(lf) == 1)
829 void *saved_rule = lf->generated_rule;
832 /* Saving previous log */
833 saved_log = lf->full_log;
835 lf->generated_rule = stats_rule;
836 lf->full_log = __stats_comment;
839 /* alert for statistical analysis */
840 if(stats_rule->alert_opts & DO_LOGALERT)
842 __crt_ftell = ftell(_aflog);
847 /* Set lf to the old values */
848 lf->generated_rule = saved_rule;
849 lf->full_log = saved_log;
854 /* Checking the rules */
855 DEBUG_MSG("%s: DEBUG: Checking the rules - %d ",
856 ARGV0, lf->decoder_info->type);
859 /* Looping all the rules */
860 rulenode_pt = OS_GetFirstRule();
863 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
870 if(lf->decoder_info->type == OSSEC_ALERT)
872 if(!lf->generated_rule)
877 /* We go ahead in here and process the alert. */
878 currently_rule = lf->generated_rule;
881 /* The categories must match */
882 else if(rulenode_pt->ruleinfo->category !=
883 lf->decoder_info->type)
888 /* Checking each rule. */
889 else if((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
897 if(currently_rule->level == 0)
903 /* Checking ignore time */
904 if(currently_rule->ignore_time)
906 if(currently_rule->time_ignored == 0)
908 currently_rule->time_ignored = lf->time;
910 /* If the currently time - the time the rule was ignored
911 * is less than the time it should be ignored,
912 * leave (do not alert again).
914 else if((lf->time - currently_rule->time_ignored)
915 < currently_rule->ignore_time)
921 currently_rule->time_ignored = lf->time;
926 /* Pointer to the rule that generated it */
927 lf->generated_rule = currently_rule;
930 /* Checking if we should ignore it */
931 if(currently_rule->ckignore && IGnore(lf))
934 lf->generated_rule = NULL;
939 /* Checking if we need to add to ignore list */
940 if(currently_rule->ignore)
946 /* Log the alert if configured to ... */
947 if(currently_rule->alert_opts & DO_LOGALERT)
949 __crt_ftell = ftell(_aflog);
958 if(Config.prelude_log_level <= currently_rule->level)
973 /* Execute an active response */
974 if(currently_rule->ar)
977 active_response **rule_ar;
979 rule_ar = currently_rule->ar;
984 if((*rule_ar)->ar_cmd->expect & USERNAME)
987 !OS_PRegex(lf->dstuser,"^[a-zA-Z._0-9@?-]*$"))
990 merror(CRAFTED_USER, ARGV0, lf->dstuser);
994 if((*rule_ar)->ar_cmd->expect & SRCIP)
997 !OS_PRegex(lf->srcip, "^[a-zA-Z.:_0-9-]*$"))
1000 merror(CRAFTED_IP, ARGV0, lf->srcip);
1007 OS_Exec(&execdq, &arq, lf, *rule_ar);
1014 /* Copy the structure to the state memory of if_matched_sid */
1015 if(currently_rule->sid_prev_matched)
1017 if(!OSList_AddData(currently_rule->sid_prev_matched, lf))
1019 merror("%s: Unable to add data to sig list.", ARGV0);
1023 lf->sid_node_to_delete =
1024 currently_rule->sid_prev_matched->last_node;
1028 else if(currently_rule->group_prev_matched)
1032 while(i < currently_rule->group_prev_matched_sz)
1035 currently_rule->group_prev_matched[i],
1038 merror("%s: Unable to add data to grp list.",ARGV0);
1048 }while((rulenode_pt = rulenode_pt->next) != NULL);
1051 /* If configured to log all, do it */
1056 /* Cleaning the memory */
1060 /* Only clear the memory if the eventinfo was not
1061 * added to the stateful memory
1062 * -- message is free inside clean event --
1064 if(lf->generated_rule == NULL)
1077 /* CheckIfRuleMatch v0.1
1078 * Will check if the currently_rule matches the event information
1080 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node)
1085 * word match (fast regex),
1100 RuleInfo *currently_rule = curr_node->ruleinfo;
1106 merror("%s: Inconsistent state. currently rule NULL", ARGV0);
1113 print_out(" Trying rule: %d - %s", currently_rule->sigid,
1114 currently_rule->comment);
1118 /* Checking if any decoder pre-matched here */
1119 if(currently_rule->decoded_as &&
1120 currently_rule->decoded_as != lf->decoder_info->id)
1127 /* Checking program name */
1128 if(currently_rule->program_name)
1130 if(!lf->program_name)
1133 if(!OSMatch_Execute(lf->program_name,
1135 currently_rule->program_name))
1140 /* Checking for the id */
1141 if(currently_rule->id)
1148 if(!OSMatch_Execute(lf->id,
1150 currently_rule->id))
1155 /* Checking if any word to match exists */
1156 if(currently_rule->match)
1158 if(!OSMatch_Execute(lf->log, lf->size, currently_rule->match))
1164 /* Checking if exist any regex for this rule */
1165 if(currently_rule->regex)
1167 if(!OSRegex_Execute(lf->log, currently_rule->regex))
1172 /* Checking for actions */
1173 if(currently_rule->action)
1178 if(strcmp(currently_rule->action,lf->action) != 0)
1183 /* Checking for the url */
1184 if(currently_rule->url)
1191 if(!OSMatch_Execute(lf->url, strlen(lf->url), currently_rule->url))
1199 /* Getting tcp/ip packet information */
1200 if(currently_rule->alert_opts & DO_PACKETINFO)
1202 /* Checking for the srcip */
1203 if(currently_rule->srcip)
1210 if(!OS_IPFoundList(lf->srcip, currently_rule->srcip))
1216 /* Checking for the dstip */
1217 if(currently_rule->dstip)
1224 if(!OS_IPFoundList(lf->dstip, currently_rule->dstip))
1230 if(currently_rule->srcport)
1237 if(!OSMatch_Execute(lf->srcport,
1238 strlen(lf->srcport),
1239 currently_rule->srcport))
1244 if(currently_rule->dstport)
1251 if(!OSMatch_Execute(lf->dstport,
1252 strlen(lf->dstport),
1253 currently_rule->dstport))
1258 } /* END PACKET_INFO */
1261 /* Extra information from event */
1262 if(currently_rule->alert_opts & DO_EXTRAINFO)
1264 /* Checking compiled rule. */
1265 if(currently_rule->compiled_rule)
1267 if(!currently_rule->compiled_rule(lf))
1274 /* Checking if exist any user to match */
1275 if(currently_rule->user)
1279 if(!OSMatch_Execute(lf->dstuser,
1280 strlen(lf->dstuser),
1281 currently_rule->user))
1284 else if(lf->srcuser)
1286 if(!OSMatch_Execute(lf->srcuser,
1287 strlen(lf->srcuser),
1288 currently_rule->user))
1299 /* Checking if any rule related to the size exist */
1300 if(currently_rule->maxsize)
1302 if(lf->size < currently_rule->maxsize)
1307 /* Checking if we are in the right time */
1308 if(currently_rule->day_time)
1310 if(!OS_IsonTime(lf->hour, currently_rule->day_time))
1317 /* Checking week day */
1318 if(currently_rule->week_day)
1320 if(!OS_IsonDay(__crt_wday, currently_rule->week_day))
1327 /* Getting extra data */
1328 if(currently_rule->extra_data)
1333 if(!OSMatch_Execute(lf->data,
1335 currently_rule->extra_data))
1340 /* Checking hostname */
1341 if(currently_rule->hostname)
1346 if(!OSMatch_Execute(lf->hostname,
1347 strlen(lf->hostname),
1348 currently_rule->hostname))
1353 /* Checking for status */
1354 if(currently_rule->status)
1359 if(!OSMatch_Execute(lf->status,
1361 currently_rule->status))
1367 /* Checking for the FTS flag */
1368 if(currently_rule->alert_opts & DO_FTS)
1371 if(lf->decoder_info->fts)
1373 if(lf->decoder_info->fts & FTS_DONE)
1375 /* We already did the fts in here. */
1389 /* If it is a context rule, search for it */
1390 if(currently_rule->context == 1)
1392 if(!currently_rule->event_search(lf, currently_rule))
1398 print_out(" *Rule %d matched.", currently_rule->sigid);
1402 /* Search for dependent rules */
1403 if(curr_node->child)
1405 RuleNode *child_node = curr_node->child;
1406 RuleInfo *child_rule = NULL;
1410 print_out(" *Trying child rules.");
1415 child_rule = OS_CheckIfRuleMatch(lf, child_node);
1416 if(child_rule != NULL)
1421 child_node = child_node->next;
1426 /* If we are set to no alert, keep going */
1427 if(currently_rule->alert_opts & NO_ALERT)
1434 currently_rule->firedtimes++;
1436 return(currently_rule); /* Matched */
1440 /** void LoopRule(RuleNode *curr_node);
1441 * Update each rule and print it to the logs.
1443 void LoopRule(RuleNode *curr_node, FILE *flog)
1445 if(curr_node->ruleinfo->firedtimes)
1447 fprintf(flog, "%d-%d-%d-%d\n",
1449 curr_node->ruleinfo->sigid,
1450 curr_node->ruleinfo->level,
1451 curr_node->ruleinfo->firedtimes);
1452 curr_node->ruleinfo->firedtimes = 0;
1455 if(curr_node->child)
1457 RuleNode *child_node = curr_node->child;
1461 LoopRule(child_node, flog);
1462 child_node = child_node->next;
1469 /** void DumpLogstats();
1470 * Dump the hourly stats about each rule.
1474 RuleNode *rulenode_pt;
1475 char logfile[OS_FLSIZE +1];
1478 /* Opening log file */
1479 snprintf(logfile, OS_FLSIZE, "%s/%d/", STATSAVED, prev_year);
1480 if(IsDir(logfile) == -1)
1481 if(mkdir(logfile,0770) == -1)
1483 merror(MKDIR_ERROR, ARGV0, logfile);
1487 snprintf(logfile,OS_FLSIZE,"%s/%d/%s", STATSAVED, prev_year,prev_month);
1489 if(IsDir(logfile) == -1)
1490 if(mkdir(logfile,0770) == -1)
1492 merror(MKDIR_ERROR,ARGV0,logfile);
1497 /* Creating the logfile name */
1498 snprintf(logfile,OS_FLSIZE,"%s/%d/%s/ossec-%s-%02d.log",
1505 flog = fopen(logfile, "a");
1508 merror(FOPEN_ERROR, ARGV0, logfile);
1512 rulenode_pt = OS_GetFirstRule();
1516 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
1520 /* Looping on all the rules and printing the stats from them */
1523 LoopRule(rulenode_pt, flog);
1524 }while((rulenode_pt = rulenode_pt->next) != NULL);
1527 /* Print total for the hour */
1528 fprintf(flog, "%d--%d--%d--%d--%d\n\n",
1530 hourly_alerts, hourly_events, hourly_syscheck,hourly_firewall);
1533 hourly_syscheck = 0;
1534 hourly_firewall = 0;