/** void LogCollectorStart() v0.4 * Handle file management. */ void LogCollectorStart() { int i = 0, r = 0; int max_file = 0; int f_check = 0; time_t curr_time = 0; char keepalive[1024]; /* To check for inode changes */ struct stat tmp_stat; #ifndef WIN32 int int_error = 0; struct timeval fp_timeout; #else /* Checking if we are on vista. */ checkVista(); /* Reading vista descriptions. */ if(isVista) { win_read_vista_sec(); } #endif debug1("%s: DEBUG: Entering LogCollectorStart().", ARGV0); /* Initializing each file and structure */ for(i = 0;;i++) { if(logff[i].file == NULL) break; /* Removing duplicate entries. */ for(r = 0; r < i; r++) { if(logff[r].file && strcmp(logff[i].file, logff[r].file) == 0) { merror("%s: WARN: Duplicated log file given: '%s'.", ARGV0, logff[i].file); logff[i].file = NULL; logff[i].command = NULL; logff[i].fp = NULL; break; } } if(logff[i].file == NULL) { /* do nothing, duplicated entry. */ } else if(strcmp(logff[i].logformat,"eventlog") == 0) { #ifdef WIN32 verbose(READING_EVTLOG, ARGV0, logff[i].file); win_startel(logff[i].file); #endif logff[i].file = NULL; logff[i].command = NULL; logff[i].fp = NULL; } else if(strcmp(logff[i].logformat, "eventchannel") == 0) { #ifdef WIN32 #ifdef EVENTCHANNEL_SUPPORT verbose(READING_EVTLOG, ARGV0, logff[i].file); win_start_event_channel(logff[i].file, logff[i].future, logff[i].query); #else merror("%s: WARN: eventchannel not available on this version of OSSEC", ARGV0); #endif #endif logff[i].file = NULL; logff[i].command = NULL; logff[i].fp = NULL; } else if(strcmp(logff[i].logformat, "command") == 0) { logff[i].file = NULL; logff[i].fp = NULL; logff[i].size = 0; if(logff[i].command) { logff[i].read = read_command; verbose("%s: INFO: Monitoring output of command(%d): %s", ARGV0, logff[i].ign, logff[i].command); if(!logff[i].alias) { os_strdup(logff[i].command, logff[i].alias); } } else { merror("%s: ERROR: Missing command argument. Ignoring it.", ARGV0); } } else if(strcmp(logff[i].logformat, "full_command") == 0) { logff[i].file = NULL; logff[i].fp = NULL; logff[i].size = 0; if(logff[i].command) { logff[i].read = read_fullcommand; verbose("%s: INFO: Monitoring full output of command(%d): %s", ARGV0, logff[i].ign, logff[i].command); if(!logff[i].alias) os_strdup(logff[i].command, logff[i].alias); } else { merror("%s: ERROR: Missing command argument. Ignoring it.", ARGV0); } } else { logff[i].command = NULL; /* Initializing the files */ if(logff[i].ffile) { /* Day must be zero for all files to be initialized */ _cday = 0; if(update_fname(i)) { handle_file(i, 1, 1); } else { ErrorExit(PARSE_ERROR, ARGV0, logff[i].ffile); } } else { handle_file(i, 1, 1); } verbose(READING_FILE, ARGV0, logff[i].file); /* Getting the log type */ if(strcmp("snort-full", logff[i].logformat) == 0) { logff[i].read = read_snortfull; } #ifndef WIN32 if(strcmp("ossecalert", logff[i].logformat) == 0) { logff[i].read = read_ossecalert; } #endif else if(strcmp("nmapg", logff[i].logformat) == 0) { logff[i].read = read_nmapg; } else if(strcmp("mysql_log", logff[i].logformat) == 0) { logff[i].read = read_mysql_log; } else if(strcmp("mssql_log", logff[i].logformat) == 0) { logff[i].read = read_mssql_log; } else if(strcmp("postgresql_log", logff[i].logformat) == 0) { logff[i].read = read_postgresql_log; } else if(strcmp("djb-multilog", logff[i].logformat) == 0) { if(!init_djbmultilog(i)) { merror(INV_MULTILOG, ARGV0, logff[i].file); if(logff[i].fp) { fclose(logff[i].fp); logff[i].fp = NULL; } logff[i].file = NULL; } logff[i].read = read_djbmultilog; } else if(logff[i].logformat[0] >= '0' && logff[i].logformat[0] <= '9') { logff[i].read = read_multiline; } else { logff[i].read = read_syslog; } /* More tweaks for Windows. For some reason IIS places * some wierd characters at the end of the files and getc * always returns 0 (even after clearerr). */ #ifdef WIN32 if(logff[i].fp) { logff[i].read(i, &r, 1); } #endif } if(logff[i].alias) { int ii = 0; while(logff[i].alias[ii] != '\0') { if(logff[i].alias[ii] == ':') { logff[i].alias[ii] = '\\'; } ii++; } } } /* Start up message */ verbose(STARTUP_MSG, ARGV0, (int)getpid()); max_file = i -1; /* Cannot be zero */ if(max_file < 0) { max_file = 0; } /* Daemon loop */ while(1) { #ifndef WIN32 fp_timeout.tv_sec = loop_timeout; fp_timeout.tv_usec = 0; /* Waiting for the select timeout */ if ((r = select(0, NULL, NULL, NULL, &fp_timeout)) < 0) { merror(SELECT_ERROR, ARGV0, errno, strerror(errno)); int_error++; if(int_error >= 5) { ErrorExit(SYSTEM_ERROR, ARGV0); } continue; } #else /* Windows don't like select that way */ sleep(loop_timeout + 2); /* Check for messages in the event viewer */ win_readel(); #endif f_check++; /* Checking which file is available */ for(i = 0; i <= max_file; i++) { if(!logff[i].fp) { /* Run the command. */ if(logff[i].command && (f_check %2)) { curr_time = time(0); if((curr_time - logff[i].size) >= logff[i].ign) { logff[i].size = curr_time; logff[i].read(i, &r, 0); } } continue; } /* Windows with IIS logs is very strange. * For some reason it always returns 0 (not EOF) * the fgetc. To solve this problem, we always * pass it to the function pointer directly. */ #ifndef WIN32 /* We check for the end of file. If is returns EOF, * we don't attempt to read it. */ if((r = fgetc(logff[i].fp)) == EOF) { clearerr(logff[i].fp); continue; } /* If it is not EOF, we need to return the read character */ ungetc(r, logff[i].fp); #endif /* Finally, send to the function pointer to read it */ logff[i].read(i, &r, 0); /* Checking for error */ if(!ferror(logff[i].fp)) { /* Clearing EOF */ clearerr(logff[i].fp); /* Parsing error */ if(r != 0) { logff[i].ign++; } } /* If ferror is set */ else { merror(FREAD_ERROR, ARGV0, logff[i].file, errno, strerror(errno)); #ifndef WIN32 if(fseek(logff[i].fp, 0, SEEK_END) < 0) #else if(1) #endif { #ifndef WIN32 merror(FSEEK_ERROR, ARGV0, logff[i].file, errno, strerror(errno)); #endif /* Closing the file */ if(logff[i].fp) { fclose(logff[i].fp); #ifdef WIN32 CloseHandle(logff[i].h); #endif } logff[i].fp = NULL; /* Trying to open it again */ if(handle_file(i, 1, 1) != 0) { logff[i].ign++; continue; } #ifdef WIN32 logff[i].read(i, &r, 1); #endif } /* Increase the error count */ logff[i].ign++; clearerr(logff[i].fp); } } /* Only check bellow if check > VCHECK_FILES */ if(f_check <= VCHECK_FILES) continue; /* Send keep alive message */ rand_keepalive_str(keepalive, 700); SendMSG(logr_queue, keepalive, "ossec-keepalive", LOCALFILE_MQ); /* Zeroing f_check */ f_check = 0; /* Checking if any file has been renamed/removed */ for(i = 0; i <= max_file; i++) { /* These are the windows logs or ignored files */ if(!logff[i].file) continue; /* Files with date -- check for day change */ if(logff[i].ffile) { if(update_fname(i)) { if(logff[i].fp) { fclose(logff[i].fp); #ifdef WIN32 CloseHandle(logff[i].h); #endif } logff[i].fp = NULL; handle_file(i, 0, 1); continue; } /* Variable file name */ else if(!logff[i].fp) { handle_file(i, 0, 0); continue; } } /* Check for file change -- if the file is open already */ if(logff[i].fp) { #ifndef WIN32 if(fstat(fileno(logff[i].fp), &tmp_stat) == -1) { fclose(logff[i].fp); logff[i].fp = NULL; merror(FSTAT_ERROR, ARGV0, logff[i].file, errno, strerror(errno)); } #else BY_HANDLE_FILE_INFORMATION lpFileInformation; HANDLE h1; h1 = CreateFile(logff[i].file, GENERIC_READ, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(h1 == INVALID_HANDLE_VALUE) { fclose(logff[i].fp); CloseHandle(logff[i].h); logff[i].fp = NULL; merror(FILE_ERROR, ARGV0, logff[i].file); } else if(GetFileInformationByHandle(h1, &lpFileInformation) == 0) { fclose(logff[i].fp); CloseHandle(logff[i].h); CloseHandle(h1); logff[i].fp = NULL; merror(FILE_ERROR, ARGV0, logff[i].file);; } #endif #ifdef WIN32 else if(logff[i].fd != (lpFileInformation.nFileIndexLow + lpFileInformation.nFileIndexHigh)) #else else if(logff[i].fd != tmp_stat.st_ino) #endif { char msg_alert[512 +1]; snprintf(msg_alert, 512, "ossec: File rotated (inode " "changed): '%s'.", logff[i].file); /* Send message about log rotated */ SendMSG(logr_queue, msg_alert, "ossec-logcollector", LOCALFILE_MQ); debug1("%s: DEBUG: File inode changed. %s", ARGV0, logff[i].file); fclose(logff[i].fp); #ifdef WIN32 CloseHandle(logff[i].h); CloseHandle(h1); #endif logff[i].fp = NULL; handle_file(i, 0, 1); continue; } #ifdef WIN32 else if(logff[i].size > (lpFileInformation.nFileSizeHigh + lpFileInformation.nFileSizeLow)) #else else if(logff[i].size > tmp_stat.st_size) #endif { char msg_alert[512 +1]; snprintf(msg_alert, 512, "ossec: File size reduced " "(inode remained): '%s'.", logff[i].file); /* Send message about log rotated */ SendMSG(logr_queue, msg_alert, "ossec-logcollector", LOCALFILE_MQ); debug1("%s: DEBUG: File size reduced. %s", ARGV0, logff[i].file); /* Fixing size so we don't alert more than once */ logff[i].size = tmp_stat.st_size; /* Getting new file. */ fclose(logff[i].fp); #ifdef WIN32 CloseHandle(logff[i].h); CloseHandle(h1); #endif logff[i].fp = NULL; handle_file(i, 1, 1); } #ifdef WIN32 else { CloseHandle(h1); } #endif } /* Too many errors for the file */ if(logff[i].ign > open_file_attempts) { /* 999 Maximum ignore */ if(logff[i].ign == 999) { continue; } merror(LOGC_FILE_ERROR, ARGV0, logff[i].file); if(logff[i].fp) { fclose(logff[i].fp); #ifdef WIN32 CloseHandle(logff[i].h); #endif } logff[i].fp = NULL; /* If the file has a variable date, ignore it for * today only. */ if(!logff[i].ffile) { /* Variable log files should always be attempted * to be open... */ //logff[i].file = NULL; } logff[i].ign = 999; continue; } /* File not opened */ if(!logff[i].fp) { if(logff[i].ign >= 999) continue; else { /* Try for a few times to open the file */ if(handle_file(i, 1, 1) < 0) { logff[i].ign++; } continue; } } } } }
/** void HandleSyslog() v0.2 * Handle syslog connections */ void HandleSyslog() { char buffer[OS_SIZE_1024 +2]; char srcip[IPSIZE +1]; char *buffer_pt = NULL; int recv_b; struct sockaddr_in peer_info; socklen_t peer_size; /* setting peer size */ peer_size = sizeof(peer_info); /* Initializing some variables */ memset(buffer, '\0', OS_SIZE_1024 +2); /* Connecting to the message queue * Exit if it fails. */ if((logr.m_queue = StartMQ(DEFAULTQUEUE,WRITE)) < 0) { ErrorExit(QUEUE_FATAL,ARGV0, DEFAULTQUEUE); } /* Infinite loop in here */ while(1) { /* Receiving message */ recv_b = recvfrom(logr.sock, buffer, OS_SIZE_1024, 0, (struct sockaddr *)&peer_info, &peer_size); /* Nothing received */ if(recv_b <= 0) continue; /* null terminating the message */ buffer[recv_b] = '\0'; /* Removing new line */ if(buffer[recv_b -1] == '\n') { buffer[recv_b -1] = '\0'; } /* Setting the source ip */ strncpy(srcip, inet_ntoa(peer_info.sin_addr), IPSIZE); srcip[IPSIZE] = '\0'; /* Removing syslog header */ if(buffer[0] == '<') { buffer_pt = strchr(buffer+1, '>'); if(buffer_pt) { buffer_pt++; } else { buffer_pt = buffer; } } else { buffer_pt = buffer; } /* Checking if IP is allowed here */ if(OS_IPNotAllowed(srcip)) { merror(DENYIP_WARN,ARGV0,srcip); } else if(SendMSG(logr.m_queue, buffer_pt, srcip, SYSLOG_MQ) < 0) { merror(QUEUE_ERROR,ARGV0,DEFAULTQUEUE, strerror(errno)); if((logr.m_queue = StartMQ(DEFAULTQUEUE,READ)) < 0) { ErrorExit(QUEUE_FATAL,ARGV0,DEFAULTQUEUE); } } } }
/* Read Output of commands */ void *read_fullcommand(int pos, int *rc, int drop_it) { size_t n = 0; size_t cmd_size = 0; char *p; char str[OS_MAXSTR + 1]; char strfinal[OS_MAXSTR + 1]; FILE *cmd_output; str[OS_MAXSTR] = '\0'; strfinal[OS_MAXSTR] = '\0'; *rc = 0; debug2("%s: DEBUG: Running full command '%s'", ARGV0, logff[pos].command); cmd_output = popen(logff[pos].command, "r"); if (!cmd_output) { merror("%s: ERROR: Unable to execute command: '%s'.", ARGV0, logff[pos].command); logff[pos].command = NULL; return (NULL); } snprintf(str, 256, "ossec: output: '%s':\n", (NULL != logff[pos].alias) ? logff[pos].alias : logff[pos].command); cmd_size = strlen(str); n = fread(str + cmd_size, 1, OS_MAXSTR - OS_LOG_HEADER - 256, cmd_output); if (n > 0) { str[cmd_size + n] = '\0'; /* Get the last occurrence of \n */ if ((p = strrchr(str, '\n')) != NULL) { *p = '\0'; } debug2("%s: DEBUG: Reading command message: '%s'", ARGV0, str); /* Remove empty lines */ n = 0; p = str; while (*p != '\0') { if (p[0] == '\r') { p++; continue; } if (p[0] == '\n' && p[1] == '\n') { p++; } strfinal[n] = *p; n++; p++; } strfinal[n] = '\0'; /* Send message to queue */ if (drop_it == 0) { if (SendMSG(logr_queue, strfinal, (NULL != logff[pos].alias) ? logff[pos].alias : logff[pos].command, LOCALFILE_MQ) < 0) { merror(QUEUE_SEND, ARGV0); if ((logr_queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) { ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH); } } } } pclose(cmd_output); return (NULL); }
/** void HandleSecure() v0.3 * Handle the secure connections */ void HandleSecure() { int agentid; char buffer[OS_MAXSTR +1]; char cleartext_msg[OS_MAXSTR +1]; char srcip[IPSIZE +1]; char *tmp_msg; char srcmsg[OS_FLSIZE +1]; int recv_b; struct sockaddr_in peer_info; socklen_t peer_size; /* Send msg init */ send_msg_init(); /* Initializing key mutex. */ keyupdate_init(); /* Initializing manager */ manager_init(0); /* Creating Ar forwarder thread */ if(CreateThread(AR_Forward, (void *)NULL) != 0) { ErrorExit(THREAD_ERROR, ARGV0); } /* Creating wait_for_msgs thread */ if(CreateThread(wait_for_msgs, (void *)NULL) != 0) { ErrorExit(THREAD_ERROR, ARGV0); } /* Connecting to the message queue * Exit if it fails. */ if((logr.m_queue = StartMQ(DEFAULTQUEUE,WRITE)) < 0) { ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQUEUE); } verbose(AG_AX_AGENTS, ARGV0, MAX_AGENTS); /* Reading authentication keys */ verbose(ENC_READ, ARGV0); OS_ReadKeys(&keys); debug1("%s: DEBUG: OS_StartCounter.", ARGV0); OS_StartCounter(&keys); debug1("%s: DEBUG: OS_StartCounter completed.", ARGV0); /* setting up peer size */ peer_size = sizeof(peer_info); logr.peer_size = sizeof(peer_info); /* Initializing some variables */ memset(buffer, '\0', OS_MAXSTR +1); memset(cleartext_msg, '\0', OS_MAXSTR +1); memset(srcmsg, '\0', OS_FLSIZE +1); tmp_msg = NULL; /* loop in here */ while(1) { /* Receiving message */ recv_b = recvfrom(logr.sock, buffer, OS_MAXSTR, 0, (struct sockaddr *)&peer_info, &peer_size); /* Nothing received */ if(recv_b <= 0) { continue; } /* Setting the source ip */ strncpy(srcip, inet_ntoa(peer_info.sin_addr), IPSIZE); srcip[IPSIZE] = '\0'; /* Getting a valid agentid */ if(buffer[0] == '!') { tmp_msg = buffer; tmp_msg++; /* We need to make sure that we have a valid id * and that we reduce the recv buffer size. */ while(isdigit((int)*tmp_msg)) { tmp_msg++; recv_b--; } if(*tmp_msg != '!') { merror(ENCFORMAT_ERROR, __local_name, srcip); continue; } *tmp_msg = '\0'; tmp_msg++; recv_b-=2; agentid = OS_IsAllowedDynamicID(&keys, buffer +1, srcip); if(agentid == -1) { if(check_keyupdate()) { agentid = OS_IsAllowedDynamicID(&keys, buffer +1, srcip); if(agentid == -1) { merror(ENC_IP_ERROR, ARGV0, srcip); continue; } } else { merror(ENC_IP_ERROR, ARGV0, srcip); continue; } } } else { agentid = OS_IsAllowedIP(&keys, srcip); if(agentid < 0) { if(check_keyupdate()) { agentid = OS_IsAllowedIP(&keys, srcip); if(agentid == -1) { merror(DENYIP_WARN,ARGV0,srcip); continue; } } else { merror(DENYIP_WARN,ARGV0,srcip); continue; } } tmp_msg = buffer; } /* Decrypting the message */ tmp_msg = ReadSecMSG(&keys, tmp_msg, cleartext_msg, agentid, recv_b -1); if(tmp_msg == NULL) { /* If duplicated, a warning was already generated */ continue; } /* Check if it is a control message */ if(IsValidHeader(tmp_msg)) { /* We need to save the peerinfo if it is a control msg */ memcpy(&keys.keyentries[agentid]->peer_info, &peer_info, peer_size); keys.keyentries[agentid]->rcvd = time(0); save_controlmsg(agentid, tmp_msg); continue; } /* Generating srcmsg */ snprintf(srcmsg, OS_FLSIZE,"(%s) %s",keys.keyentries[agentid]->name, keys.keyentries[agentid]->ip->ip); /* If we can't send the message, try to connect to the * socket again. If it not exit. */ if(SendMSG(logr.m_queue, tmp_msg, srcmsg, SECURE_MQ) < 0) { merror(QUEUE_ERROR, ARGV0, DEFAULTQUEUE, strerror(errno)); if((logr.m_queue = StartMQ(DEFAULTQUEUE, WRITE)) < 0) { ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQUEUE); } } } }
void Monitord() { time_t tm; struct tm *p; int today = 0; int thismonth = 0; int thisyear = 0; char str[OS_SIZE_1024 + 1]; /* Wait a few seconds to settle */ sleep(10); memset(str, '\0', OS_SIZE_1024 + 1); /* Get current time before starting */ tm = time(NULL); p = localtime(&tm); today = p->tm_mday; thismonth = p->tm_mon; thisyear = p->tm_year + 1900; /* Connect to the message queue or exit */ if ((mond.a_queue = StartMQ(DEFAULTQUEUE, WRITE)) < 0) { ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQUEUE); } /* Send startup message */ snprintf(str, OS_SIZE_1024 - 1, OS_AD_STARTED); if (SendMSG(mond.a_queue, str, ARGV0, LOCALFILE_MQ) < 0) { merror(QUEUE_SEND, ARGV0); } /* Main monitor loop */ while (1) { tm = time(NULL); p = localtime(&tm); /* Check for unavailable agents */ if (mond.monitor_agents) { monitor_agents(); } /* Day changed, deal with log files */ if (today != p->tm_mday) { /* Generate reports */ generate_reports(today, thismonth, thisyear, p); manage_files(today, thismonth, thisyear); today = p->tm_mday; thismonth = p->tm_mon; thisyear = p->tm_year + 1900; } /* We only check every two minutes */ sleep(120); } }