END_TEST START_TEST(test_unixinvalidsockets) { char buffer[BUFFERSIZE]; ck_assert_int_eq(OS_SendUnix(-1, SENDSTRING, strlen(SENDSTRING)), OS_SOCKTERR); ck_assert_int_eq(OS_RecvUnix(-1, BUFFERSIZE, buffer), 0); }
END_TEST START_TEST(test_unix) { int fd; /* create socket path */ char socket_path[256]; strncpy(socket_path, "/tmp/tmp_file-XXXXXX", 256); fd = mkstemp(socket_path); close(fd); int server_socket, client_socket; const int msg_size = 2048; char buffer[BUFFERSIZE]; ck_assert_int_ge((server_socket = OS_BindUnixDomain(socket_path, 0660, msg_size)), 0); ck_assert_int_ge(OS_getsocketsize(server_socket), msg_size); ck_assert_int_ge((client_socket = OS_ConnectUnixDomain(socket_path, msg_size)), 0); ck_assert_int_eq(OS_SendUnix(client_socket, SENDSTRING, 5), 0); ck_assert_int_eq(OS_RecvUnix(server_socket, BUFFERSIZE, buffer), 5); ck_assert_str_eq(buffer, "Hello"); ck_assert_int_eq(OS_SendUnix(client_socket, SENDSTRING, 0), 0); ck_assert_int_eq(OS_RecvUnix(server_socket, BUFFERSIZE, buffer), strlen(SENDSTRING) + 1); ck_assert_str_eq(buffer, SENDSTRING); OS_CloseSocket(client_socket); OS_CloseSocket(server_socket); unlink(socket_path); }
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 *AR_Forward(void *arg) v0.1 * Start of a new thread. Only returns * on unrecoverable errors. */ void *AR_Forward(void *arg) { int i = 0; int arq = 0; int agent_id = 0; int ar_location = 0; char msg_to_send[OS_SIZE_1024 +1]; char msg[OS_SIZE_1024 +1]; char *location = NULL; char *ar_location_str = NULL; char *ar_agent_id = NULL; char *tmp_str = NULL; /* Creating the unix queue */ if((arq = StartMQ(ARQUEUE, READ)) < 0) { ErrorExit(QUEUE_ERROR, ARGV0, ARQUEUE, strerror(errno)); } memset(msg, '\0', OS_SIZE_1024 +1); /* Daemon loop */ while(1) { if(OS_RecvUnix(arq, OS_SIZE_1024, msg)) { /* Always zeroing the location */ ar_location = 0; /* Getting the location */ location = msg; /* Location is going to be the agent name */ tmp_str = strchr(msg, ')'); if(!tmp_str) { merror(EXECD_INV_MSG, ARGV0, msg); continue; } *tmp_str = '\0'; /* Going after the ')' and space */ tmp_str += 2; /* Extracting the source ip */ tmp_str = strchr(tmp_str, ' '); if(!tmp_str) { merror(EXECD_INV_MSG, ARGV0, msg); continue; } tmp_str++; location++; /* Setting ar_location */ ar_location_str = tmp_str; if(*tmp_str == ALL_AGENTS_C) { ar_location|=ALL_AGENTS; } tmp_str++; if(*tmp_str == REMOTE_AGENT_C) { ar_location|=REMOTE_AGENT; } else if(*tmp_str == NO_AR_C) { ar_location|=NO_AR_MSG; } tmp_str++; if(*tmp_str == SPECIFIC_AGENT_C) { ar_location|=SPECIFIC_AGENT; } /*** Extracting the active response location ***/ tmp_str = strchr(ar_location_str, ' '); if(!tmp_str) { merror(EXECD_INV_MSG, ARGV0, msg); continue; } *tmp_str = '\0'; tmp_str++; /*** Extracting the agent id */ ar_agent_id = tmp_str; tmp_str = strchr(tmp_str, ' '); if(!tmp_str) { merror(EXECD_INV_MSG, ARGV0, msg); continue; } *tmp_str = '\0'; tmp_str++; /*** Creating the new message ***/ if(ar_location & NO_AR_MSG) { snprintf(msg_to_send, OS_SIZE_1024, "%s%s", CONTROL_HEADER, tmp_str); } else { snprintf(msg_to_send, OS_SIZE_1024, "%s%s%s", CONTROL_HEADER, EXECD_HEADER, tmp_str); } /* Lock use of keys */ key_lock(); /* Sending to ALL agents */ if(ar_location & ALL_AGENTS) { for(i = 0;i< keys.keysize; i++) { send_msg(i, msg_to_send); } } /* Send to the remote agent that generated the event */ else if((ar_location & REMOTE_AGENT) && (location != NULL)) { agent_id = OS_IsAllowedName(&keys, location); if(agent_id < 0) { key_unlock(); merror(AR_NOAGENT_ERROR, ARGV0, location); continue; } send_msg(agent_id, msg_to_send); } /* Send to a pre-defined agent */ else if(ar_location & SPECIFIC_AGENT) { ar_location++; agent_id = OS_IsAllowedID(&keys, ar_agent_id); if(agent_id < 0) { key_unlock(); merror(AR_NOAGENT_ERROR, ARGV0, ar_agent_id); continue; } send_msg(agent_id, msg_to_send); } /* Lock use of keys */ key_unlock(); } } }
/** void ExecdStart(int q) v0.2 * Main function on the execd. Does all the data receiving ,etc. */ static void ExecdStart(int q) { int i, childcount = 0; time_t curr_time; char buffer[OS_MAXSTR + 1]; char *tmp_msg = NULL; char *name; char *command; char *cmd_args[MAX_ARGS +2]; /* Select */ fd_set fdset; struct timeval socket_timeout; /* Clearing the buffer */ memset(buffer, '\0', OS_MAXSTR +1); /* Initializing the cmd arguments */ for(i = 0; i<= MAX_ARGS +1; i++) { cmd_args[i] = NULL; } /* Creating list for timeout */ timeout_list = OSList_Create(); if(!timeout_list) { ErrorExit(LIST_ERROR, ARGV0); } if(repeated_offenders_timeout[0] != 0) { repeated_hash = OSHash_Create(); } else { repeated_hash = NULL; } /* Main loop. */ while(1) { int timeout_value; int added_before = 0; char **timeout_args; timeout_data *timeout_entry; /* Cleaning up any child. */ while (childcount) { int wp; wp = waitpid((pid_t) -1, NULL, WNOHANG); if (wp < 0) { merror(WAITPID_ERROR, ARGV0, errno, strerror(errno)); break; } /* if = 0, we still need to wait for the child process */ else if (wp == 0) { break; } /* Child completed if wp > 0 */ else { childcount--; } } /* Getting currently time */ curr_time = time(0); /* Checking if there is any timeouted command to execute. */ timeout_node = OSList_GetFirstNode(timeout_list); while(timeout_node) { timeout_data *list_entry; list_entry = (timeout_data *)timeout_node->data; /* Timeouted */ if((curr_time - list_entry->time_of_addition) > list_entry->time_to_block) { ExecCmd(list_entry->command); /* Deletecurrently node already sets the pointer to next */ OSList_DeleteCurrentlyNode(timeout_list); timeout_node = OSList_GetCurrentlyNode(timeout_list); /* Clearing the memory */ FreeTimeoutEntry(list_entry); childcount++; } else { timeout_node = OSList_GetNextNode(timeout_list); } } /* Setting timeout to EXECD_TIMEOUT */ socket_timeout.tv_sec = EXECD_TIMEOUT; socket_timeout.tv_usec= 0; /* Setting FD values */ FD_ZERO(&fdset); FD_SET(q, &fdset); /* Adding timeout */ if(select(q+1, &fdset, NULL, NULL, &socket_timeout) == 0) { /* Timeout .. */ continue; } /* Checking for error */ if(!FD_ISSET(q, &fdset)) { merror(SELECT_ERROR, ARGV0, errno, strerror(errno)); continue; } /* Receiving the message */ if(OS_RecvUnix(q, OS_MAXSTR, buffer) == 0) { merror(QUEUE_ERROR, ARGV0, EXECQUEUEPATH, strerror(errno)); continue; } /* Currently time */ curr_time = time(0); /* Getting application name */ name = buffer; /* Zeroing the name */ tmp_msg = strchr(buffer, ' '); if(!tmp_msg) { merror(EXECD_INV_MSG, ARGV0, buffer); continue; } *tmp_msg = '\0'; tmp_msg++; /* Getting the command to execute (valid name) */ command = GetCommandbyName(name, &timeout_value); if(!command) { ReadExecConfig(); command = GetCommandbyName(name, &timeout_value); if(!command) { merror(EXEC_INV_NAME, ARGV0, name); continue; } } /* Command not present. */ if(command[0] == '\0') continue; /* Allocating memory for the timeout argument */ os_calloc(MAX_ARGS+2, sizeof(char *), timeout_args); /* Adding initial variables to the cmd_arg and to the timeout cmd */ cmd_args[0] = command; cmd_args[1] = ADD_ENTRY; os_strdup(command, timeout_args[0]); os_strdup(DELETE_ENTRY, timeout_args[1]); cmd_args[2] = NULL; timeout_args[2] = NULL; /* Getting the arguments. */ i = 2; while(i < (MAX_ARGS -1)) { cmd_args[i] = tmp_msg; cmd_args[i+1] = NULL; tmp_msg = strchr(tmp_msg, ' '); if(!tmp_msg) { timeout_args[i] = strdup(cmd_args[i]); timeout_args[i+1] = NULL; break; } *tmp_msg = '\0'; tmp_msg++; timeout_args[i] = strdup(cmd_args[i]); timeout_args[i+1] = NULL; i++; } /* Check this command was already executed. */ timeout_node = OSList_GetFirstNode(timeout_list); added_before = 0; /* Checking for the username and ip argument */ if(!timeout_args[2] || !timeout_args[3]) { added_before = 1; merror("%s: Invalid number of arguments.", ARGV0); } while(timeout_node) { timeout_data *list_entry; list_entry = (timeout_data *)timeout_node->data; if((strcmp(list_entry->command[3], timeout_args[3]) == 0) && (strcmp(list_entry->command[0], timeout_args[0]) == 0)) { /* Means we executed this command before * and we don't need to add it again. */ added_before = 1; /* updating the timeout */ list_entry->time_of_addition = curr_time; if(repeated_offenders_timeout[0] != 0 && repeated_hash != NULL && strncmp(timeout_args[3],"-", 1) != 0) { char *ntimes = NULL; char rkey[256]; rkey[255] = '\0'; snprintf(rkey, 255, "%s%s", list_entry->command[0], timeout_args[3]); if((ntimes = (char *) OSHash_Get(repeated_hash, rkey))) { int ntimes_int = 0; int i2 = 0; int new_timeout = 0; ntimes_int = atoi(ntimes); while(repeated_offenders_timeout[i2] != 0) { i2++; } if(ntimes_int >= i2) { new_timeout = repeated_offenders_timeout[i2 - 1]*60; } else { free(ntimes); // In hash_op.c, data belongs to caller os_calloc(10, sizeof(char), ntimes); new_timeout = repeated_offenders_timeout[ntimes_int]*60; ntimes_int++; snprintf(ntimes, 9, "%d", ntimes_int); OSHash_Update(repeated_hash,rkey,ntimes); } list_entry->time_to_block = new_timeout; } } break; } /* Continue with the next entry in timeout list*/ timeout_node = OSList_GetNextNode(timeout_list); } /* If it wasn't added before, do it now */ if(!added_before) { /* executing command */ ExecCmd(cmd_args); /* We don't need to add to the list if the timeout_value == 0 */ if(timeout_value) { char *ntimes; char rkey[256]; rkey[255] = '\0'; snprintf(rkey, 255, "%s%s", timeout_args[0], timeout_args[3]); if(repeated_hash != NULL) { if((ntimes = (char *) OSHash_Get(repeated_hash, rkey))) { int ntimes_int = 0; int i2 = 0; int new_timeout = 0; ntimes_int = atoi(ntimes); while(repeated_offenders_timeout[i2] != 0) { i2++; } if(ntimes_int >= i2) { new_timeout = repeated_offenders_timeout[i2 - 1]*60; } else { os_calloc(10, sizeof(char), ntimes); new_timeout = repeated_offenders_timeout[ntimes_int]*60; ntimes_int++; snprintf(ntimes, 9, "%d", ntimes_int); OSHash_Update(repeated_hash, rkey, ntimes); } timeout_value = new_timeout; } else { /* Adding to the repeated offenders list. */ OSHash_Add(repeated_hash, rkey, strdup("0")); } } /* Creating the timeout entry */ os_calloc(1, sizeof(timeout_data), timeout_entry); timeout_entry->command = timeout_args; timeout_entry->time_of_addition = curr_time; timeout_entry->time_to_block = timeout_value; /* Adding command to the timeout list */ if(!OSList_AddData(timeout_list, timeout_entry)) { merror(LIST_ADD_ERROR, ARGV0); FreeTimeoutEntry(timeout_entry); } } /* If no timeout, we still need to free it in here */ else { char **ss_ta = timeout_args; while(*timeout_args) { os_free(*timeout_args); *timeout_args = NULL; timeout_args++; } os_free(ss_ta); } childcount++; } /* We didn't add it to the timeout list */ else { char **ss_ta = timeout_args; /* Clear the timeout arguments */ while(*timeout_args) { os_free(*timeout_args); *timeout_args = NULL; timeout_args++; } os_free(ss_ta); } /* Some cleanup */ while(i > 0) { cmd_args[i] = NULL; i--; } } }