1 /* @(#) $Id: logcollector.c,v 1.59 2009/11/03 21:07:32 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
17 #include "logcollector.h"
20 int update_fname(int i);
23 /** void LogCollectorStart() v0.4
24 * Handle file management.
26 void LogCollectorStart()
32 /* To check for inode changes */
39 struct timeval fp_timeout;
43 /* Checking if we are on vista. */
47 /* Reading vista descriptions. */
55 debug1("%s: DEBUG: Entering LogCollectorStart().", ARGV0);
58 /* Initializing each file and structure */
61 if(logff[i].file == NULL)
65 /* Removing duplicate entries. */
66 for(r = 0; r < i; r++)
68 if(logff[r].file && strcmp(logff[i].file, logff[r].file) == 0)
70 merror("%s: WARN: Duplicated log file given: '%s'.",
71 ARGV0, logff[i].file);
73 logff[i].command = NULL;
80 if(logff[i].file == NULL)
82 /* do nothing, duplicated entry. */
85 else if(strcmp(logff[i].logformat,"eventlog") == 0)
89 verbose(READING_EVTLOG, ARGV0, logff[i].file);
90 win_startel(logff[i].file);
94 logff[i].command = NULL;
98 else if(strcmp(logff[i].logformat, "command") == 0)
100 logff[i].file = NULL;
105 logff[i].read = (void *)read_command;
109 merror("%s: ERROR: Missing command argument. Ignoring it.",
116 logff[i].command = NULL;
119 /* Initializing the files */
122 /* Day must be zero for all files to be initialized */
126 handle_file(i, 1, 1);
130 ErrorExit(PARSE_ERROR, ARGV0, logff[i].ffile);
136 handle_file(i, 1, 1);
139 verbose(READING_FILE, ARGV0, logff[i].file);
141 /* Getting the log type */
142 if(strcmp("snort-full", logff[i].logformat) == 0)
144 logff[i].read = (void *)read_snortfull;
146 else if(strcmp("nmapg", logff[i].logformat) == 0)
148 logff[i].read = (void *)read_nmapg;
150 else if(strcmp("mysql_log", logff[i].logformat) == 0)
152 logff[i].read = (void *)read_mysql_log;
154 else if(strcmp("mssql_log", logff[i].logformat) == 0)
156 logff[i].read = (void *)read_mssql_log;
158 else if(strcmp("postgresql_log", logff[i].logformat) == 0)
160 logff[i].read = (void *)read_postgresql_log;
162 else if(strcmp("djb-multilog", logff[i].logformat) == 0)
164 if(!init_djbmultilog(i))
166 merror(INV_MULTILOG, ARGV0, logff[i].file);
172 logff[i].file = NULL;
174 logff[i].read = (void *)read_djbmultilog;
178 logff[i].read = (void *)read_syslog;
181 /* More tweaks for Windows. For some reason IIS places
182 * some wierd characters at the end of the files and getc
183 * always returns 0 (even after clearerr).
188 logff[i].read(i, &r, 1);
195 /* Start up message */
196 verbose(STARTUP_MSG, ARGV0, (int)getpid());
212 fp_timeout.tv_sec = loop_timeout;
213 fp_timeout.tv_usec = 0;
215 /* Waiting for the select timeout */
216 if ((r = select(0, NULL, NULL, NULL, &fp_timeout)) < 0)
218 merror(SELECT_ERROR, ARGV0);
223 ErrorExit(SYSTEM_ERROR, ARGV0);
229 /* Windows don't like select that way */
230 sleep(loop_timeout + 2);
233 /* Check for messages in the event viewer */
240 /* Checking which file is available */
241 for(i = 0; i <= max_file; i++)
245 /* Run the command. */
246 if((f_check == VCHECK_FILES) && logff[i].command)
248 logff[i].read(i, &r, 0);
253 /* Windows with IIS logs is very strange.
254 * For some reason it always returns 0 (not EOF)
255 * the fgetc. To solve this problem, we always
256 * pass it to the function pointer directly.
259 /* We check for the end of file. If is returns EOF,
260 * we don't attempt to read it.
262 if((r = fgetc(logff[i].fp)) == EOF)
264 clearerr(logff[i].fp);
269 /* If it is not EOF, we need to return the read character */
270 ungetc(r, logff[i].fp);
274 /* Finally, send to the function pointer to read it */
275 logff[i].read(i, &r, 0);
278 /* Checking for error */
279 if(!ferror(logff[i].fp))
282 clearerr(logff[i].fp);
290 /* If ferror is set */
293 merror(FREAD_ERROR, ARGV0, logff[i].file);
295 if(fseek(logff[i].fp, 0, SEEK_END) < 0)
302 merror(FSEEK_ERROR, ARGV0, logff[i].file);
305 /* Closing the file */
310 CloseHandle(logff[i].h);
316 /* Trying to open it again */
317 if(handle_file(i, 1, 1) != 0)
324 logff[i].read(i, &r, 1);
328 /* Increase the error count */
330 clearerr(logff[i].fp);
335 /* Only check bellow if check > VCHECK_FILES */
336 if(f_check <= VCHECK_FILES)
340 /* Send keep alive message */
341 SendMSG(logr_queue, "--MARK--", "ossec-keepalive", LOCALFILE_MQ);
344 /* Zeroing f_check */
348 /* Checking if any file has been renamed/removed */
349 for(i = 0; i <= max_file; i++)
351 /* These are the windows logs or ignored files */
356 /* Files with date -- check for day change */
365 CloseHandle(logff[i].h);
369 handle_file(i, 0, 1);
373 /* Variable file name */
374 else if(!logff[i].fp)
376 handle_file(i, 0, 0);
382 /* Check for file change -- if the file is open already */
386 if(stat(logff[i].file, &tmp_stat) == -1)
391 merror(FILE_ERROR, ARGV0, logff[i].file);
395 BY_HANDLE_FILE_INFORMATION lpFileInformation;
398 h1 = CreateFile(logff[i].file, GENERIC_READ,
399 FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
400 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
401 if(h1 == INVALID_HANDLE_VALUE)
404 CloseHandle(logff[i].h);
406 merror(FILE_ERROR, ARGV0, logff[i].file);
408 else if(GetFileInformationByHandle(h1, &lpFileInformation) == 0)
411 CloseHandle(logff[i].h);
414 merror(FILE_ERROR, ARGV0, logff[i].file);;
420 else if(logff[i].fd != (lpFileInformation.nFileIndexLow + lpFileInformation.nFileIndexHigh))
422 else if(logff[i].fd != tmp_stat.st_ino)
425 char msg_alert[512 +1];
427 snprintf(msg_alert, 512, "ossec: File rotated (inode "
431 /* Send message about log rotated */
432 SendMSG(logr_queue, msg_alert,
433 "ossec-logcollector", LOCALFILE_MQ);
435 debug1("%s: DEBUG: File inode changed. %s",
436 ARGV0, logff[i].file);
441 CloseHandle(logff[i].h);
446 handle_file(i, 0, 1);
450 else if(logff[i].size > (lpFileInformation.nFileSizeHigh + lpFileInformation.nFileSizeLow))
452 else if(logff[i].size > tmp_stat.st_size)
455 char msg_alert[512 +1];
457 snprintf(msg_alert, 512, "ossec: File size reduced "
458 "(inode remained): '%s'.",
461 /* Send message about log rotated */
462 SendMSG(logr_queue, msg_alert,
463 "ossec-logcollector", LOCALFILE_MQ);
465 debug1("%s: DEBUG: File size reduced. %s",
466 ARGV0, logff[i].file);
469 /* Fixing size so we don't alert more than once */
470 logff[i].size = tmp_stat.st_size;
473 /* Getting new file. */
477 CloseHandle(logff[i].h);
482 handle_file(i, 1, 1);
493 /* Too many errors for the file */
494 if(logff[i].ign > open_file_attempts)
496 /* 999 Maximum ignore */
497 if(logff[i].ign == 999)
502 merror(LOGC_FILE_ERROR, ARGV0, logff[i].file);
507 CloseHandle(logff[i].h);
514 /* If the file has a variable date, ignore it for
519 /* Variable log files should always be attempted
522 //logff[i].file = NULL;
529 /* File not opened */
532 if(logff[i].ign >= 999)
536 /* Try for a few times to open the file */
537 if(handle_file(i, 1, 1) < 0)
550 /**int update_fname(int i): updates file name */
551 int update_fname(int i)
554 time_t __ctime = time(0);
556 char lfile[OS_FLSIZE + 1];
560 p = localtime(&__ctime);
564 if(p->tm_mday == _cday)
570 lfile[OS_FLSIZE] = '\0';
571 ret = strftime(lfile, OS_FLSIZE, logff[i].ffile, p);
574 ErrorExit(PARSE_ERROR, ARGV0, logff[i].ffile);
578 /* Update the file name */
579 if(strcmp(lfile, logff[i].file) != 0)
581 os_free(logff[i].file);
583 os_strdup(lfile, logff[i].file);
585 verbose(VAR_LOG_MON, ARGV0, logff[i].file);
587 /* Setting cday to zero because other files may need
599 /* handle_file: Open, get the fileno, seek to the end and update mtime */
600 int handle_file(int i, int do_fseek, int do_log)
605 /* We must be able to open the file, fseek and get the
606 * time of change from it.
609 logff[i].fp = fopen(logff[i].file, "r");
614 merror(FOPEN_ERROR, ARGV0, logff[i].file);
618 /* Getting inode number for fp */
619 fd = fileno(logff[i].fp);
620 if(fstat(fd, &stat_fd) == -1)
622 merror(FILE_ERROR,ARGV0,logff[i].file);
628 logff[i].fd = stat_fd.st_ino;
629 logff[i].size = stat_fd.st_size;
633 BY_HANDLE_FILE_INFORMATION lpFileInformation;
636 logff[i].h = CreateFile(logff[i].file, GENERIC_READ,
637 FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
638 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
639 if(logff[i].h == INVALID_HANDLE_VALUE)
643 merror(FOPEN_ERROR, ARGV0, logff[i].file);
647 fd = _open_osfhandle((long)logff[i].h, 0);
650 merror(FOPEN_ERROR, ARGV0, logff[i].file);
651 CloseHandle(logff[i].h);
654 logff[i].fp = _fdopen(fd, "r");
655 if(logff[i].fp == NULL)
657 merror(FOPEN_ERROR, ARGV0, logff[i].file);
658 CloseHandle(logff[i].h);
663 /* On windows, we also need the real inode, which is the combination
664 * of the index low + index high numbers.
666 if(GetFileInformationByHandle(logff[i].h, &lpFileInformation) == 0)
668 merror("%s: Unable to get file information by handle.", ARGV0);
670 CloseHandle(logff[i].h);
675 logff[i].fd = (lpFileInformation.nFileIndexLow + lpFileInformation.nFileIndexHigh);
676 logff[i].size = (lpFileInformation.nFileSizeHigh + lpFileInformation.nFileSizeLow);
681 /* Only seek the end of the file if set to. */
682 if(do_fseek == 1 && S_ISREG(stat_fd.st_mode))
684 /* Windows and fseek causes some weird issues.. */
686 if(fseek(logff[i].fp, 0, SEEK_END) < 0)
688 merror(FSEEK_ERROR, ARGV0,logff[i].file);
697 /* Setting ignore to zero */