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 2) as published by the FSF - Free Software
17 #include "logcollector.h"
20 int update_fname(int i);
23 char *rand_keepalive_str(char *dst, int size)
25 static const char text[] = "abcdefghijklmnopqrstuvwxyz"
26 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
28 "!@#$%^&*()_+-=;'[],./?";
29 int i, len = rand() % (size - 10);
30 strncpy(dst, "--MARK--: ", 12);
31 for ( i = 10; i < len; ++i )
33 dst[i] = text[rand() % (sizeof text - 1)];
39 /** void LogCollectorStart() v0.4
40 * Handle file management.
42 void LogCollectorStart()
52 /* To check for inode changes */
59 struct timeval fp_timeout;
63 /* Checking if we are on vista. */
67 /* Reading vista descriptions. */
75 debug1("%s: DEBUG: Entering LogCollectorStart().", ARGV0);
78 /* Initializing each file and structure */
81 if(logff[i].file == NULL)
85 /* Removing duplicate entries. */
86 for(r = 0; r < i; r++)
88 if(logff[r].file && strcmp(logff[i].file, logff[r].file) == 0)
90 merror("%s: WARN: Duplicated log file given: '%s'.",
91 ARGV0, logff[i].file);
93 logff[i].command = NULL;
100 if(logff[i].file == NULL)
102 /* do nothing, duplicated entry. */
105 else if(strcmp(logff[i].logformat,"eventlog") == 0)
109 verbose(READING_EVTLOG, ARGV0, logff[i].file);
110 win_startel(logff[i].file);
113 logff[i].file = NULL;
114 logff[i].command = NULL;
118 else if(strcmp(logff[i].logformat, "command") == 0)
120 logff[i].file = NULL;
126 logff[i].read = (void *)read_command;
128 verbose("%s: INFO: Monitoring output of command(%d): %s", ARGV0, logff[i].ign, logff[i].command);
132 os_strdup(logff[i].command, logff[i].alias);
137 merror("%s: ERROR: Missing command argument. Ignoring it.",
141 else if(strcmp(logff[i].logformat, "full_command") == 0)
143 logff[i].file = NULL;
148 logff[i].read = (void *)read_fullcommand;
150 verbose("%s: INFO: Monitoring full output of command(%d): %s", ARGV0, logff[i].ign, logff[i].command);
153 os_strdup(logff[i].command, logff[i].alias);
157 merror("%s: ERROR: Missing command argument. Ignoring it.",
164 logff[i].command = NULL;
167 /* Initializing the files */
170 /* Day must be zero for all files to be initialized */
174 handle_file(i, 1, 1);
178 ErrorExit(PARSE_ERROR, ARGV0, logff[i].ffile);
184 handle_file(i, 1, 1);
187 verbose(READING_FILE, ARGV0, logff[i].file);
189 /* Getting the log type */
190 if(strcmp("snort-full", logff[i].logformat) == 0)
192 logff[i].read = (void *)read_snortfull;
194 else if(strcmp("nmapg", logff[i].logformat) == 0)
196 logff[i].read = (void *)read_nmapg;
198 else if(strcmp("mysql_log", logff[i].logformat) == 0)
200 logff[i].read = (void *)read_mysql_log;
202 else if(strcmp("mssql_log", logff[i].logformat) == 0)
204 logff[i].read = (void *)read_mssql_log;
206 else if(strcmp("postgresql_log", logff[i].logformat) == 0)
208 logff[i].read = (void *)read_postgresql_log;
210 else if(strcmp("djb-multilog", logff[i].logformat) == 0)
212 if(!init_djbmultilog(i))
214 merror(INV_MULTILOG, ARGV0, logff[i].file);
220 logff[i].file = NULL;
222 logff[i].read = (void *)read_djbmultilog;
224 else if(logff[i].logformat[0] >= '0' && logff[i].logformat[0] <= '9')
226 logff[i].read = (void *)read_multiline;
230 logff[i].read = (void *)read_syslog;
233 /* More tweaks for Windows. For some reason IIS places
234 * some wierd characters at the end of the files and getc
235 * always returns 0 (even after clearerr).
240 logff[i].read(i, &r, 1);
248 while(logff[i].alias[ii] != '\0')
250 if(logff[i].alias[ii] == ':')
252 logff[i].alias[ii] = '\\';
260 /* Start up message */
261 verbose(STARTUP_MSG, ARGV0, (int)getpid());
277 fp_timeout.tv_sec = loop_timeout;
278 fp_timeout.tv_usec = 0;
280 /* Waiting for the select timeout */
281 if ((r = select(0, NULL, NULL, NULL, &fp_timeout)) < 0)
283 merror(SELECT_ERROR, ARGV0);
288 ErrorExit(SYSTEM_ERROR, ARGV0);
294 /* Windows don't like select that way */
295 sleep(loop_timeout + 2);
298 /* Check for messages in the event viewer */
305 /* Checking which file is available */
306 for(i = 0; i <= max_file; i++)
310 /* Run the command. */
311 if(logff[i].command && (f_check %2))
314 if((curr_time - logff[i].size) >= logff[i].ign)
316 logff[i].size = curr_time;
317 logff[i].read(i, &r, 0);
323 /* Windows with IIS logs is very strange.
324 * For some reason it always returns 0 (not EOF)
325 * the fgetc. To solve this problem, we always
326 * pass it to the function pointer directly.
329 /* We check for the end of file. If is returns EOF,
330 * we don't attempt to read it.
332 if((r = fgetc(logff[i].fp)) == EOF)
334 clearerr(logff[i].fp);
339 /* If it is not EOF, we need to return the read character */
340 ungetc(r, logff[i].fp);
344 /* Finally, send to the function pointer to read it */
345 logff[i].read(i, &r, 0);
348 /* Checking for error */
349 if(!ferror(logff[i].fp))
352 clearerr(logff[i].fp);
360 /* If ferror is set */
363 merror(FREAD_ERROR, ARGV0, logff[i].file);
365 if(fseek(logff[i].fp, 0, SEEK_END) < 0)
372 merror(FSEEK_ERROR, ARGV0, logff[i].file);
375 /* Closing the file */
380 CloseHandle(logff[i].h);
386 /* Trying to open it again */
387 if(handle_file(i, 1, 1) != 0)
394 logff[i].read(i, &r, 1);
398 /* Increase the error count */
400 clearerr(logff[i].fp);
405 /* Only check bellow if check > VCHECK_FILES */
406 if(f_check <= VCHECK_FILES)
410 /* Send keep alive message */
412 rand_keepalive_str(keepalive, 700);
413 SendMSG(logr_queue, keepalive, "ossec-keepalive", LOCALFILE_MQ);
416 /* Zeroing f_check */
420 /* Checking if any file has been renamed/removed */
421 for(i = 0; i <= max_file; i++)
423 /* These are the windows logs or ignored files */
428 /* Files with date -- check for day change */
437 CloseHandle(logff[i].h);
441 handle_file(i, 0, 1);
445 /* Variable file name */
446 else if(!logff[i].fp)
448 handle_file(i, 0, 0);
454 /* Check for file change -- if the file is open already */
458 if(stat(logff[i].file, &tmp_stat) == -1)
463 merror(FILE_ERROR, ARGV0, logff[i].file);
467 BY_HANDLE_FILE_INFORMATION lpFileInformation;
470 h1 = CreateFile(logff[i].file, GENERIC_READ,
471 FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
472 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
473 if(h1 == INVALID_HANDLE_VALUE)
476 CloseHandle(logff[i].h);
478 merror(FILE_ERROR, ARGV0, logff[i].file);
480 else if(GetFileInformationByHandle(h1, &lpFileInformation) == 0)
483 CloseHandle(logff[i].h);
486 merror(FILE_ERROR, ARGV0, logff[i].file);;
492 else if(logff[i].fd != (lpFileInformation.nFileIndexLow + lpFileInformation.nFileIndexHigh))
494 else if(logff[i].fd != tmp_stat.st_ino)
497 char msg_alert[512 +1];
499 snprintf(msg_alert, 512, "ossec: File rotated (inode "
503 /* Send message about log rotated */
504 SendMSG(logr_queue, msg_alert,
505 "ossec-logcollector", LOCALFILE_MQ);
507 debug1("%s: DEBUG: File inode changed. %s",
508 ARGV0, logff[i].file);
513 CloseHandle(logff[i].h);
518 handle_file(i, 0, 1);
522 else if(logff[i].size > (lpFileInformation.nFileSizeHigh + lpFileInformation.nFileSizeLow))
524 else if(logff[i].size > tmp_stat.st_size)
527 char msg_alert[512 +1];
529 snprintf(msg_alert, 512, "ossec: File size reduced "
530 "(inode remained): '%s'.",
533 /* Send message about log rotated */
534 SendMSG(logr_queue, msg_alert,
535 "ossec-logcollector", LOCALFILE_MQ);
537 debug1("%s: DEBUG: File size reduced. %s",
538 ARGV0, logff[i].file);
541 /* Fixing size so we don't alert more than once */
542 logff[i].size = tmp_stat.st_size;
545 /* Getting new file. */
549 CloseHandle(logff[i].h);
554 handle_file(i, 1, 1);
565 /* Too many errors for the file */
566 if(logff[i].ign > open_file_attempts)
568 /* 999 Maximum ignore */
569 if(logff[i].ign == 999)
574 merror(LOGC_FILE_ERROR, ARGV0, logff[i].file);
579 CloseHandle(logff[i].h);
586 /* If the file has a variable date, ignore it for
591 /* Variable log files should always be attempted
594 //logff[i].file = NULL;
601 /* File not opened */
604 if(logff[i].ign >= 999)
608 /* Try for a few times to open the file */
609 if(handle_file(i, 1, 1) < 0)
622 /**int update_fname(int i): updates file name */
623 int update_fname(int i)
626 time_t __ctime = time(0);
628 char lfile[OS_FLSIZE + 1];
632 p = localtime(&__ctime);
636 if(p->tm_mday == _cday)
642 lfile[OS_FLSIZE] = '\0';
643 ret = strftime(lfile, OS_FLSIZE, logff[i].ffile, p);
646 ErrorExit(PARSE_ERROR, ARGV0, logff[i].ffile);
650 /* Update the file name */
651 if(strcmp(lfile, logff[i].file) != 0)
653 os_free(logff[i].file);
655 os_strdup(lfile, logff[i].file);
657 verbose(VAR_LOG_MON, ARGV0, logff[i].file);
659 /* Setting cday to zero because other files may need
671 /* handle_file: Open, get the fileno, seek to the end and update mtime */
672 int handle_file(int i, int do_fseek, int do_log)
677 /* We must be able to open the file, fseek and get the
678 * time of change from it.
681 logff[i].fp = fopen(logff[i].file, "r");
686 merror(FOPEN_ERROR, ARGV0, logff[i].file);
690 /* Getting inode number for fp */
691 fd = fileno(logff[i].fp);
692 if(fstat(fd, &stat_fd) == -1)
694 merror(FILE_ERROR,ARGV0,logff[i].file);
700 logff[i].fd = stat_fd.st_ino;
701 logff[i].size = stat_fd.st_size;
705 BY_HANDLE_FILE_INFORMATION lpFileInformation;
708 logff[i].h = CreateFile(logff[i].file, GENERIC_READ,
709 FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
710 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
711 if(logff[i].h == INVALID_HANDLE_VALUE)
715 merror(FOPEN_ERROR, ARGV0, logff[i].file);
719 fd = _open_osfhandle((long)logff[i].h, 0);
722 merror(FOPEN_ERROR, ARGV0, logff[i].file);
723 CloseHandle(logff[i].h);
726 logff[i].fp = _fdopen(fd, "r");
727 if(logff[i].fp == NULL)
729 merror(FOPEN_ERROR, ARGV0, logff[i].file);
730 CloseHandle(logff[i].h);
735 /* On windows, we also need the real inode, which is the combination
736 * of the index low + index high numbers.
738 if(GetFileInformationByHandle(logff[i].h, &lpFileInformation) == 0)
740 merror("%s: Unable to get file information by handle.", ARGV0);
742 CloseHandle(logff[i].h);
747 logff[i].fd = (lpFileInformation.nFileIndexLow + lpFileInformation.nFileIndexHigh);
748 logff[i].size = (lpFileInformation.nFileSizeHigh + lpFileInformation.nFileSizeLow);
753 /* Only seek the end of the file if set to. */
754 if(do_fseek == 1 && S_ISREG(stat_fd.st_mode))
756 /* Windows and fseek causes some weird issues.. */
758 if(fseek(logff[i].fp, 0, SEEK_END) < 0)
760 merror(FSEEK_ERROR, ARGV0,logff[i].file);
769 /* Setting ignore to zero */