source: trunk/src/sh_log_check.c@ 265

Last change on this file since 265 was 265, checked in by katerina, 15 years ago

Enhance logfile monitoring (tickets #183, #184, #185).

File size: 28.5 KB
Line 
1
2#include "config_xor.h"
3
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9
10#ifdef USE_LOGFILE_MONITOR
11
12#undef FIL__
13#define FIL__ _("sh_log_check.c")
14
15/* Debian/Ubuntu: libpcre3-dev */
16#ifdef HAVE_PCRE_PCRE_H
17#include <pcre/pcre.h>
18#else
19#include <pcre.h>
20#endif
21
22#include "samhain.h"
23#include "sh_pthread.h"
24#include "sh_utils.h"
25#include "sh_unix.h"
26#include "sh_string.h"
27#include "sh_log_check.h"
28#include "sh_log_evalrule.h"
29#include "sh_log_correlate.h"
30#include "sh_log_mark.h"
31#include "sh_log_repeat.h"
32
33/* List of supported logfile types, format is
34 * {
35 * "TYPE_CODE",
36 * Reader_Callback_Function,
37 * Parser_Callback_function,
38 * Evaluate_Callback_Function
39 * }
40 * If Reader_Callback_Function is NULL, the default (line-oriented
41 * text file) reader is used.
42 */
43struct sh_logfile_type sh_logtypes_def[] = {
44 { "SYSLOG", NULL, sh_parse_syslog, NULL },
45 { "SAMBA", sh_read_samba, sh_parse_samba, NULL },
46 { "APACHE", NULL, sh_parse_apache, sh_eval_fileinfo_apache },
47#if defined(HAVE_SYS_ACCT_H)
48 { "PACCT", sh_read_pacct, sh_parse_pacct, NULL },
49#endif
50};
51
52/* -------------------------- Internal Stuff -------------------------- */
53
54struct logfile_record {
55 dev_t device_id;
56 ino_t inode;
57 fpos_t offset;
58};
59
60static char * save_dir = NULL;
61
62static void * sh_dummy_path = NULL;
63
64static char * build_path (struct sh_logfile * record)
65{
66 size_t plen;
67 int retval;
68 char * path = NULL;
69
70 sh_dummy_path = (void *)&path;
71
72 if (!save_dir)
73 {
74 save_dir = sh_util_strdup(DEFAULT_PIDDIR);
75
76 SH_MUTEX_LOCK(mutex_thread_nolog);
77 retval = tf_trust_check (save_dir, SL_YESPRIV);
78 SH_MUTEX_UNLOCK(mutex_thread_nolog);
79
80 if (retval != 0)
81 {
82 return(NULL);
83 }
84 }
85
86 plen = strlen(save_dir);
87
88 if (SL_TRUE == sl_ok_adds(plen, 130))
89 {
90 plen += 130; /* 64 + 64 + 2 */
91 path = SH_ALLOC(plen);
92 (void) sl_snprintf(path, plen, "%s/%lu_%lu", save_dir,
93 (unsigned long) record->device_id,
94 (unsigned long) record->inode);
95 }
96
97 return path;
98}
99
100static void save_pos (struct sh_logfile * record)
101{
102 char * path;
103 FILE * fd;
104 struct logfile_record save_rec;
105
106 path = build_path(record);
107
108 if (path)
109 {
110 if (0 != sh_unix_check_piddir (path))
111 {
112 SH_FREE(path);
113 return;
114 }
115
116 fd = fopen(path, "wb");
117 if (fd)
118 {
119 save_rec.device_id = record->device_id;
120 save_rec.inode = record->inode;
121 memcpy(&(save_rec.offset), &(record->offset), sizeof(fpos_t));
122 if (1 != fwrite(&save_rec, sizeof(struct logfile_record), 1, fd))
123 {
124 (void) sl_fclose(FIL__, __LINE__, fd);
125 (void) remove(path);
126 }
127 else
128 {
129 (void) sl_fclose(FIL__, __LINE__, fd);
130 }
131 }
132 SH_FREE(path);
133 }
134 return;
135}
136
137static int read_pos (struct sh_logfile * record)
138{
139 int retval = 0;
140 char * path;
141 FILE * fd;
142 struct logfile_record save_rec;
143
144 path = build_path(record);
145
146 if (path)
147 {
148 fd = fopen(path, "rb");
149 if (fd)
150 {
151 if (1 == fread(&save_rec, sizeof(struct logfile_record), 1, fd))
152 {
153 if (save_rec.device_id == record->device_id &&
154 save_rec.inode == record->inode)
155 {
156 memcpy(&(record->offset),&(save_rec.offset),sizeof(fpos_t));
157 retval = 1;
158 }
159 }
160 (void) sl_fclose(FIL__, __LINE__, fd);
161 }
162 SH_FREE(path);
163 }
164 return retval;
165}
166
167/*@null@*/ static struct sh_logfile * sh_watched_logs = NULL;
168
169int sh_add_watch (const char * str)
170{
171 char * filename;
172
173 unsigned int i;
174 unsigned int defsize;
175 struct sh_logfile_type * log_type = NULL;
176 struct sh_logfile * thisfile;
177 struct stat buf;
178
179 unsigned int nfields = 3; /* logtype:path[:regex] */
180 size_t lengths[3];
181 char * new = sh_util_strdup(str);
182 char ** splits = split_array(new, &nfields, ':', lengths);
183
184 if (nfields < 2 || (lengths[0] == 0 || lengths[0] >= SH_MAX_LCODE_SIZE || lengths[1] == 0))
185 {
186 sh_string * msg = sh_string_new(0);
187 sh_string_add_from_char(msg, _("Format error: "));
188 sh_string_add_from_char(msg, str);
189
190 SH_MUTEX_LOCK(mutex_thread_nolog);
191 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
192 sh_string_str(msg),
193 _("sh_add_watch"));
194 SH_MUTEX_UNLOCK(mutex_thread_nolog);
195 sh_string_destroy(&msg);
196
197 SH_FREE(new);
198 return -2;
199 }
200
201 defsize =
202 (unsigned int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type));
203
204 for (i = 0; i < defsize; ++i)
205 {
206 if (0 == strcmp(splits[0], sh_logtypes_def[i].code))
207 {
208 log_type = &(sh_logtypes_def[i]);
209 break;
210 }
211 }
212
213 if (log_type == NULL)
214 {
215 sh_string * msg = sh_string_new(0);
216 sh_string_add_from_char(msg, _("Unsupported log type: "));
217 sh_string_add_from_char(msg, splits[0]);
218
219 SH_MUTEX_LOCK(mutex_thread_nolog);
220 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
221 sh_string_str(msg),
222 _("sh_add_watch"));
223 SH_MUTEX_UNLOCK(mutex_thread_nolog);
224 sh_string_destroy(&msg);
225
226 SH_FREE(new);
227 return -3;
228 }
229
230 if (splits[1][0] != '/')
231 {
232 sh_string * msg = sh_string_new(0);
233 sh_string_add_from_char(msg, _("Logfile path not absolute: "));
234 sh_string_add_from_char(msg, splits[1]);
235
236 SH_MUTEX_LOCK(mutex_thread_nolog);
237 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
238 sh_string_str(msg),
239 _("sh_add_watch"));
240 SH_MUTEX_UNLOCK(mutex_thread_nolog);
241 sh_string_destroy(&msg);
242
243 SH_FREE(new);
244 return -4;
245 }
246
247 filename = /*@i@*/sh_util_strdup(splits[1]);
248 thisfile = SH_ALLOC(sizeof(struct sh_logfile));
249
250 thisfile->filename = filename;
251 thisfile->flags = SH_LOGFILE_REWIND;
252 thisfile->inode = 0;
253 thisfile->device_id = 0;
254 thisfile->fp = NULL;
255 if (log_type->get_record)
256 thisfile->get_record = log_type->get_record;
257 else
258 thisfile->get_record = sh_default_reader;
259 thisfile->parse_record = log_type->parse_record;
260
261 /* An optional regex for parsing the file. The result
262 * 'fileinfo' should contain info about host/time position.
263 */
264 if (log_type->eval_fileinfo)
265 {
266 if (nfields == 3 && lengths[2] > 0)
267 {
268 thisfile->fileinfo = log_type->eval_fileinfo(splits[2]);
269
270 if (thisfile->fileinfo == NULL)
271 {
272 sh_string * msg = sh_string_new(0);
273 sh_string_add_from_char(msg, _("Logfile format description not recognized: "));
274 sh_string_add_from_char(msg, splits[2]);
275
276 SH_MUTEX_LOCK(mutex_thread_nolog);
277 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
278 sh_string_str(msg),
279 _("sh_add_watch"));
280 SH_MUTEX_UNLOCK(mutex_thread_nolog);
281 sh_string_destroy(&msg);
282
283 SH_FREE(filename);
284 SH_FREE(thisfile);
285 SH_FREE(new);
286 return -1;
287 }
288 }
289 else
290 {
291 sh_string * msg = sh_string_new(0);
292 sh_string_add_from_char(msg, _("Logfile format description missing: "));
293 sh_string_add_from_char(msg, splits[1]);
294
295 SH_MUTEX_LOCK(mutex_thread_nolog);
296 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
297 sh_string_str(msg),
298 _("sh_add_watch"));
299 SH_MUTEX_UNLOCK(mutex_thread_nolog);
300 sh_string_destroy(&msg);
301
302 SH_FREE(filename);
303 SH_FREE(thisfile);
304 SH_FREE(new);
305 return -1;
306 }
307 }
308 else
309 {
310 thisfile->fileinfo = NULL;
311 }
312 thisfile->next = sh_watched_logs;
313
314 /* Try reading saved offset. On success clear rewind flag.
315 */
316 if (0 == stat(thisfile->filename, &buf))
317 {
318 thisfile->inode = buf.st_ino;
319 thisfile->device_id = buf.st_dev;
320
321 if (0 != read_pos(thisfile))
322 {
323 thisfile->flags &= ~SH_LOGFILE_REWIND;
324 }
325 }
326
327 sh_watched_logs = thisfile;
328
329 SH_FREE(new);
330 return 0;
331}
332
333void sh_dump_watches()
334{
335 struct sh_logfile * thisfile;
336
337 while (sh_watched_logs)
338 {
339 thisfile = sh_watched_logs;
340 sh_watched_logs = thisfile->next;
341
342 save_pos(thisfile);
343
344 if (thisfile->fp)
345 sl_fclose(FIL__, __LINE__, thisfile->fp);
346 if (thisfile->filename)
347 SH_FREE(thisfile->filename);
348 SH_FREE(thisfile);
349 }
350 return;
351}
352
353/* This variable is not used anywhere. It only exist
354 * to assign &new to them, which keeps gcc from
355 * putting it into a register, and avoids the 'clobbered
356 * by longjmp' warning. And no, 'volatile' proved insufficient.
357 */
358static void * sh_dummy_thisfile = NULL;
359
360void sh_check_watches()
361{
362 static size_t count = 0;
363 struct sh_logrecord * logrecord;
364 struct sh_logfile * thisfile = sh_watched_logs;
365 sh_string * record = sh_string_new(0);
366 char * tmp;
367
368 /* Take the address to keep gcc from putting them into registers.
369 * Avoids the 'clobbered by longjmp' warning.
370 */
371 sh_dummy_thisfile = (void*) &thisfile;
372
373 while (thisfile)
374 {
375 SH_MUTEX_LOCK(mutex_thread_nolog);
376 tmp = sh_util_safe_name (thisfile->filename);
377 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKS,
378 tmp);
379 SH_FREE(tmp);
380 SH_MUTEX_UNLOCK(mutex_thread_nolog);
381
382 for (;;) {
383
384 record = thisfile->get_record(record, thisfile);
385
386 if (record)
387 {
388 logrecord = thisfile->parse_record(record, thisfile->fileinfo);
389 ++count;
390
391 if (logrecord)
392 {
393 logrecord->filename = thisfile->filename;
394
395 /* Don't report if 'init', just set file pointer
396 */
397 if (sh.flag.checkSum != SH_CHECK_INIT)
398 {
399 sh_eval_process_msg(logrecord);
400 }
401
402 if (logrecord->message)
403 sh_string_destroy(&(logrecord->message));
404 if (logrecord->host)
405 sh_string_destroy(&(logrecord->host));
406 if (logrecord->timestr)
407 sh_string_destroy(&(logrecord->timestr));
408 SH_FREE(logrecord);
409 }
410 }
411 else
412 {
413 record = sh_string_new(0);
414 break;
415 }
416 }
417
418 SH_MUTEX_LOCK(mutex_thread_nolog);
419 tmp = sh_util_safe_name (thisfile->filename);
420 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKE,
421 tmp, (unsigned long)count);
422 SH_FREE(tmp);
423 SH_MUTEX_UNLOCK(mutex_thread_nolog);
424
425 thisfile = thisfile->next;
426 }
427 sh_string_destroy(&record);
428 return;
429}
430
431/********************************************************
432 * Search rotated logfile
433 */
434#include <unistd.h>
435#include <libgen.h>
436#include <dirent.h>
437
438char * sh_rotated_log_search(const char * path, struct stat * buf)
439{
440
441 size_t size;
442 int i;
443 char * searchpath;
444 struct stat sbuf;
445 DIR * dp;
446 char * dname;
447 char * bname;
448
449 dname = sh_util_dirname(path);
450 bname = sh_util_basename(path);
451
452 size = strlen(dname) + strlen(bname) + 4;
453 searchpath = SH_ALLOC(size);
454
455 for (i = 0; i < 2; ++i)
456 {
457 snprintf(searchpath, size, "%s/%s.%1d", dname, bname, i);
458 if (0 == stat(searchpath, &sbuf) && sbuf.st_ino == buf->st_ino)
459 {
460 SH_FREE(dname);
461 SH_FREE(bname);
462 return searchpath;
463 }
464 }
465
466 SH_FREE(searchpath);
467
468 if (NULL != (dp = opendir(dname)))
469 {
470 struct dirent * de;
471
472 while (NULL != (de = readdir(dp)))
473 {
474 if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, ".."))
475 continue;
476
477 size = strlen(dname) + strlen(de->d_name) + 2;
478 searchpath = SH_ALLOC(size);
479 snprintf(searchpath, size, "%s/%s", dname, de->d_name);
480
481 if (0 == stat(searchpath, &sbuf) && sbuf.st_ino == buf->st_ino)
482 {
483 SH_FREE(dname);
484 SH_FREE(bname);
485 closedir(dp);
486 return searchpath;
487 }
488
489 SH_FREE(searchpath);
490 }
491 closedir(dp);
492 }
493
494 SH_FREE(dname);
495 SH_FREE(bname);
496
497 return NULL;
498}
499
500/* Open file, position at stored offset
501 */
502int sh_open_for_reader (struct sh_logfile * logfile)
503{
504 struct stat buf;
505 sh_string * filename;
506
507 /* check whether file exists, get inode to check for
508 * logfile rotation
509 */
510 if (0 != retry_stat(FIL__, __LINE__, logfile->filename, &buf))
511 {
512 char * tmp;
513
514 SH_MUTEX_LOCK(mutex_thread_nolog);
515 tmp = sh_util_safe_name (logfile->filename);
516 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_MISS,
517 tmp);
518 SH_FREE(tmp);
519 SH_MUTEX_UNLOCK(mutex_thread_nolog);
520
521 memset (&(logfile->offset), '\0', sizeof(fpos_t));
522 logfile->flags |= SH_LOGFILE_REWIND;
523 return 0;
524 }
525
526 filename = sh_string_new(0);
527 (void) sh_string_set_from_char (filename, logfile->filename);
528
529 /* detect and handle logfile rotation
530 */
531 if (logfile->inode != buf.st_ino && logfile->inode != 0)
532 {
533 /* Case 1) We have dealt with the moved file already.
534 * Clear the moved flag, set the rewind flag,
535 * fix logfile->inode.
536 */
537 if ((logfile->flags & SH_LOGFILE_MOVED) != 0)
538 {
539 /* done with rotated file, start with current file
540 */
541 memset (&(logfile->offset), '\0', sizeof(fpos_t));
542 logfile->flags |= SH_LOGFILE_REWIND;
543 logfile->flags &= ~SH_LOGFILE_MOVED;
544 logfile->inode = buf.st_ino;
545 logfile->device_id = buf.st_dev;
546 }
547
548 /* Case 2) Searching for rotated file.
549 * If found: set the moved flag, fix path for fopen.
550 * If not found: set the rewind flag, fix logfile->inode.
551 */
552 else
553 {
554 char *oldfile = sh_rotated_log_search(logfile->filename, &buf);
555
556 if (NULL != oldfile)
557 {
558 (void) sh_string_set_from_char (filename, oldfile);
559 SH_FREE(oldfile);
560 logfile->flags |= SH_LOGFILE_MOVED;
561 }
562 else
563 {
564 memset (&(logfile->offset), '\0', sizeof(fpos_t));
565 logfile->flags |= SH_LOGFILE_REWIND;
566 logfile->inode = buf.st_ino;
567 logfile->device_id = buf.st_dev;
568 }
569 }
570 }
571
572 /* open file
573 */
574 logfile->fp = fopen(filename->str, "r");
575 if (!logfile->fp)
576 {
577 char * tmp;
578
579 SH_MUTEX_LOCK(mutex_thread_nolog);
580 tmp = sh_util_safe_name (logfile->filename);
581 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EOPEN,
582 tmp);
583 SH_FREE(tmp);
584 SH_MUTEX_UNLOCK(mutex_thread_nolog);
585
586 sh_string_destroy(&filename);
587 return 0;
588 }
589
590 sh_string_destroy(&filename);
591
592 if ((logfile->flags & SH_LOGFILE_REWIND) != 0)
593 {
594 rewind(logfile->fp);
595 fgetpos(logfile->fp, &(logfile->offset));
596 logfile->flags &= ~SH_LOGFILE_REWIND;
597 }
598 else
599 {
600 /* file too short
601 */
602 if (0 != fsetpos(logfile->fp, &(logfile->offset)))
603 {
604 rewind(logfile->fp);
605 fgetpos(logfile->fp, &(logfile->offset));
606 }
607 }
608
609 return 1;
610}
611
612/******************************************************
613 * Default reader for ascii text files
614 */
615sh_string * sh_default_reader (sh_string * s, struct sh_logfile * logfile)
616{
617 int status;
618 char * tmp;
619
620 start_read:
621
622 if (logfile->fp)
623 {
624 /* Result cannot be larger than 8192, thus cast is ok
625 */
626 status = (int) sh_string_read(s, logfile->fp, 8192);
627 if (status <= 0)
628 {
629 fgetpos(logfile->fp, &(logfile->offset));
630 sl_fclose(FIL__, __LINE__, logfile->fp);
631 logfile->fp = NULL;
632 sh_string_destroy(&s);
633 if (status == 0)
634 {
635 return NULL;
636 }
637
638 SH_MUTEX_LOCK(mutex_thread_nolog);
639 tmp = sh_util_safe_name (logfile->filename);
640 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
641 tmp);
642 SH_FREE(tmp);
643 SH_MUTEX_UNLOCK(mutex_thread_nolog);
644
645 return NULL;
646 }
647 return s;
648 }
649
650 if (0 != sh_open_for_reader(logfile))
651 goto start_read;
652
653 return NULL;
654}
655
656/******************************************************
657 * Reader for continued text files
658 */
659sh_string * sh_cont_reader (sh_string * s, struct sh_logfile * logfile, char*cont)
660{
661 int status;
662 char * tmp;
663 sh_string * str;
664 int remain = 8192;
665 int count = 0;
666
667 if (!sh_string_truncate(s, 0))
668 return NULL;
669
670 start_read:
671
672 if (logfile->fp)
673 {
674 str = sh_string_new(0);
675
676 /* Result cannot be larger than 8192, thus cast is ok
677 */
678 status = (int) sh_string_read(str, logfile->fp, 8192);
679
680 if (status > 0)
681 {
682
683 do {
684 s = sh_string_add (s, str);
685 count += status;
686 remain -= status;
687
688 if (remain <= 0)
689 {
690 return s;
691 }
692
693 status = (int) sh_string_read_cont(str, logfile->fp, count, cont);
694
695 if (status == 0)
696 {
697 return s;
698 }
699 }
700 while (status > 0);
701 }
702
703 if (status <= 0)
704 {
705 fgetpos(logfile->fp, &(logfile->offset));
706 sl_fclose(FIL__, __LINE__, logfile->fp);
707 logfile->fp = NULL;
708 sh_string_destroy(&s);
709 if (status == 0)
710 {
711 return NULL;
712 }
713
714 SH_MUTEX_LOCK(mutex_thread_nolog);
715 tmp = sh_util_safe_name (logfile->filename);
716 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
717 tmp);
718 SH_FREE(tmp);
719 SH_MUTEX_UNLOCK(mutex_thread_nolog);
720
721 return NULL;
722 }
723
724 return s;
725 }
726
727 if (0 != sh_open_for_reader(logfile))
728 goto start_read;
729
730 return NULL;
731}
732
733/******************************************************
734 * Reader for binary files
735 */
736sh_string * sh_binary_reader (void * s, size_t size, struct sh_logfile * logfile)
737{
738 size_t status;
739
740 start_read:
741
742 if (logfile->fp)
743 {
744
745 status = fread(s, size, 1, logfile->fp);
746
747 if (status != 1)
748 {
749 if (ferror(logfile->fp))
750 {
751 char * tmp;
752 SH_MUTEX_LOCK(mutex_thread_nolog);
753 tmp = sh_util_safe_name (logfile->filename);
754 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_LOGMON_EREAD,
755 tmp);
756 SH_FREE(tmp);
757 SH_MUTEX_UNLOCK(mutex_thread_nolog);
758 }
759 fgetpos(logfile->fp, &(logfile->offset));
760 sl_fclose(FIL__, __LINE__, logfile->fp);
761 logfile->fp = NULL;
762 memset(s, '\0', size);
763 return NULL;
764 }
765 return s;
766 }
767
768 if (0 != sh_open_for_reader(logfile))
769 goto start_read;
770
771 return NULL;
772}
773
774
775
776/**********************************************************
777 *
778 * Utilities
779 *
780 **********************************************************/
781
782/* Return current year, unless that would result
783 * in a date far in the future. If that happens,
784 * return last year.
785 */
786static int year_guess (struct tm * btime)
787{
788 int year;
789 struct tm ts;
790 time_t now = time(NULL);
791 time_t check;
792
793 memcpy(&ts, localtime(&now), sizeof(struct tm));
794 year = ts.tm_year;
795
796 /* Check result to detect year wrap
797 * (logfile entry from last year).
798 */
799 btime->tm_year = year;
800 check = mktime(btime);
801 if (check > (now + (86400*30)))
802 --year;
803
804 return year;
805}
806
807time_t conv_timestamp (struct tm * btime,
808 struct tm * old_tm, time_t * old_time)
809{
810 time_t timestamp;
811 long offtime;
812
813
814 /* timestamp - mktime is slooow, thus cache result
815 */
816 if (btime->tm_isdst == old_tm->tm_isdst &&
817 btime->tm_year == old_tm->tm_year &&
818 btime->tm_mon == old_tm->tm_mon &&
819 btime->tm_mday == old_tm->tm_mday)
820 {
821 offtime =
822 (btime->tm_hour - old_tm->tm_hour) * 3600 +
823 (btime->tm_min - old_tm->tm_min) * 60 +
824 (btime->tm_sec - old_tm->tm_sec);
825
826 *old_time += offtime;
827 memcpy(old_tm, btime, sizeof(struct tm));
828 timestamp = *old_time;
829 }
830 else
831 {
832 int year_btime = btime->tm_year;
833
834 if (btime->tm_year == 0)
835 btime->tm_year = year_guess(btime);
836 timestamp = mktime(btime);
837 btime->tm_year = year_btime;
838
839 *old_time = timestamp;
840 memcpy(old_tm, btime, sizeof(struct tm));
841 }
842 return timestamp;
843}
844
845/*********************************************************
846 *
847 * MODULE STUFF
848 *
849 *********************************************************/
850#include "sh_modules.h"
851
852SH_MUTEX_STATIC(mutex_logmon_check, PTHREAD_MUTEX_INITIALIZER);
853
854static int ShLogmonActive = S_FALSE;
855#define SH_LOGMON_INTERVAL 10
856static time_t sh_logmon_interval = SH_LOGMON_INTERVAL;
857
858int sh_log_check_init (struct mod_type * arg)
859{
860#if !defined(HAVE_PTHREAD)
861 (void) arg;
862#endif
863
864 if (ShLogmonActive == S_FALSE)
865 return SH_MOD_FAILED;
866#ifdef HAVE_PTHREAD
867 if (arg != NULL && arg->initval < 0 &&
868 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
869 {
870 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
871 return SH_MOD_THREAD;
872 else
873 return SH_MOD_FAILED;
874 }
875#endif
876 if (sh_watched_logs != NULL)
877 return 0;
878
879 return -1;
880}
881
882int sh_log_check_timer(time_t tcurrent)
883{
884 static time_t lastcheck = 0;
885
886 SL_ENTER(_("sh_log_check_timer"));
887 if ((time_t) (tcurrent - lastcheck) >= sh_logmon_interval)
888 {
889 lastcheck = tcurrent;
890 SL_RETURN((-1), _("sh_log_check_timer"));
891 }
892 SL_RETURN(0, _("sh_log_check_timer"));
893}
894
895
896int sh_log_check_check(void)
897{
898 int status = 0;
899
900 SL_ENTER(_("sh_log_check_check"));
901
902 SH_MUTEX_LOCK(mutex_logmon_check);
903
904 status = 0;
905
906 if( ShLogmonActive != S_FALSE )
907 {
908 sh_check_watches();
909 sh_keep_match();
910 sh_log_mark_check();
911 }
912 SH_MUTEX_UNLOCK(mutex_logmon_check);
913
914 SL_RETURN(status, _("sh_log_check_check"));
915}
916
917int sh_log_check_reconf(void)
918{
919 int status = 0;
920
921 SL_ENTER(_("sh_log_check_check"));
922
923 SH_MUTEX_LOCK(mutex_logmon_check);
924
925 ShLogmonActive = S_FALSE;
926 sh_logmon_interval = SH_LOGMON_INTERVAL;
927 sh_dump_watches();
928 sh_eval_cleanup();
929
930 SH_MUTEX_UNLOCK(mutex_logmon_check);
931
932 SL_RETURN(status, _("sh_log_check_check"));
933}
934
935int sh_log_check_cleanup(void)
936{
937 sh_log_mark_destroy();
938 return sh_log_check_reconf();
939}
940
941/********************* OPTIONS **********************/
942
943static int sh_logmon_set_active (const char *str);
944static int sh_logmon_set_interval(const char *str);
945static int sh_logmon_add_watch (const char * str);
946static int sh_logmon_add_group (const char * str);
947static int sh_logmon_end_group (const char * str);
948static int sh_logmon_add_host (const char * str);
949static int sh_logmon_end_host (const char * str);
950static int sh_logmon_add_queue (const char * str);
951static int sh_logmon_add_rule (const char * str);
952extern int sh_set_hidepid(const char *s);
953static int sh_logmon_set_save_dir(const char *s);
954
955sh_rconf sh_log_check_table[] = {
956 {
957 N_("logmonactive"),
958 sh_logmon_set_active,
959 },
960 {
961 N_("logmoninterval"),
962 sh_logmon_set_interval,
963 },
964 {
965 N_("logmonwatch"),
966 sh_logmon_add_watch,
967 },
968 {
969 N_("logmonqueue"),
970 sh_logmon_add_queue,
971 },
972 {
973 N_("logmongroup"),
974 sh_logmon_add_group,
975 },
976 {
977 N_("logmonendgroup"),
978 sh_logmon_end_group,
979 },
980 {
981 N_("logmonhost"),
982 sh_logmon_add_host,
983 },
984 {
985 N_("logmonendhost"),
986 sh_logmon_end_host,
987 },
988 {
989 N_("logmonrule"),
990 sh_logmon_add_rule,
991 },
992 {
993 N_("logmonhidepid"),
994 sh_set_hidepid,
995 },
996 {
997 N_("logmonsavedir"),
998 sh_logmon_set_save_dir,
999 },
1000 {
1001 N_("logmonmarkseverity"),
1002 sh_logmon_set_save_dir,
1003 },
1004 {
1005 N_("logmonburstthreshold"),
1006 sh_repeat_set_trigger,
1007 },
1008 {
1009 N_("logmonburstqueue"),
1010 sh_repeat_set_queue,
1011 },
1012 {
1013 N_("logmonburstcron"),
1014 sh_repeat_set_cron,
1015 },
1016 {
1017 NULL,
1018 NULL
1019 }
1020};
1021
1022/* Decide if we're active.
1023 */
1024static int sh_logmon_set_active(const char *str)
1025{
1026 int value;
1027
1028 SL_ENTER(_("sh_logmon_set_active"));
1029
1030 value = sh_util_flagval(str, &ShLogmonActive);
1031
1032 SL_RETURN((value), _("sh_logmon_set_active"));
1033}
1034
1035static int sh_logmon_set_save_dir(const char *str)
1036{
1037 int retval = -1;
1038
1039 SL_ENTER(_("sh_logmon_set_save_dir"));
1040
1041 if (str && str[0] == '/')
1042 {
1043 if (save_dir)
1044 {
1045 SH_FREE(save_dir);
1046 save_dir = NULL;
1047 }
1048 save_dir = sh_util_strdup(str);
1049 retval = 0;
1050 }
1051
1052 SL_RETURN((retval), _("sh_logmon_set_save_dir"));
1053}
1054
1055static int sh_logmon_set_interval (const char * c)
1056{
1057 int retval = 0;
1058 long val;
1059
1060 SL_ENTER(_("sh_logmon_set_interval"));
1061 val = strtol (c, (char **)NULL, 10);
1062 if (val <= 0)
1063 {
1064 SH_MUTEX_LOCK(mutex_thread_nolog);
1065 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1066 _("log monitoring interval"), c);
1067 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1068 retval = -1;
1069 }
1070
1071 sh_logmon_interval = (time_t) val;
1072 SL_RETURN(0, _("sh_logmon_set_interval"));
1073}
1074
1075/* Add a watch on a logfile.
1076 * Format: TYPE : Filename [: File_Format]
1077 */
1078static int sh_logmon_add_watch (const char * str)
1079{
1080 return sh_add_watch(str);
1081}
1082
1083/* Add a host.
1084 * Format: Name_Regex
1085 */
1086static int sh_logmon_add_host (const char * str)
1087{
1088 return sh_eval_hadd(str);
1089}
1090
1091/* End a host.
1092 * Format: Name
1093 */
1094static int sh_logmon_end_host (const char * str)
1095{
1096 (void) str;
1097 return sh_eval_hend(NULL);
1098}
1099
1100/* Add a group of rules.
1101 * Groups can be under hosts, but not vice versa.
1102 * Format: Name : Prefix_Regex
1103 */
1104static int sh_logmon_add_group (const char * str)
1105{
1106 return sh_eval_gadd(str);
1107}
1108
1109/* End a group of rules.
1110 * Format: Name
1111 */
1112static int sh_logmon_end_group (const char * str)
1113{
1114 (void) str;
1115 return sh_eval_gend(NULL);
1116}
1117
1118/* Define a reporting queue.
1119 * Format: Label : [Interval] : TYPE : Severity
1120 * TYPE must be 'report' or 'sum'
1121 * Interval is ignored for TYPE='report'
1122 */
1123static int sh_logmon_add_queue (const char * str)
1124{
1125 return sh_eval_qadd(str);
1126}
1127
1128/* Define a check rule.
1129 * Format: [KEEP(seconds,label):]Queue_Label : Regex
1130 * KEEP indicates that we keep the label, to perform
1131 * correlation matching
1132 */
1133static int sh_logmon_add_rule (const char * str)
1134{
1135 return sh_eval_radd(str);
1136}
1137
1138
1139#if 0
1140
1141/* >>>>>>>>>>> MAIN <<<<<<<<<<<<<<<<<<< */
1142
1143int main (int argc, char * argv[])
1144{
1145 int status, i;
1146 FILE * fp;
1147 sh_string * s = NULL;
1148 static char template[] = "/tmp/xtest.XXXXXX";
1149
1150 /* pacct */
1151 status = sh_add_watch("PACCT:/var/log/account/pacct");
1152 sh_check_watches();
1153 sh_dump_watches();
1154 exit(0);
1155
1156 /* apache log */
1157 sh_eval_gadd("four_o_four:404");
1158 sh_eval_qadd("test:1:sum:7");
1159 sh_eval_radd("test:^(\\d+.\\d+.\\d+.\\d+).*");
1160 sh_eval_gend(NULL);
1161 sh_eval_radd("trash:.*");
1162 status = sh_add_watch("APACHE:/var/log/apache2/access.log:combined");
1163 sh_check_watches();
1164 sh_dump_watches();
1165 exit(0);
1166
1167 /* logfile */
1168 sh_set_hidepid(1);
1169 sh_eval_hadd("hslxmsrv1");
1170 sh_eval_gadd("postfix:postfix");
1171 sh_eval_qadd("test::report:7");
1172 sh_eval_radd("test:postfix/smtpd: disconnect from localhost.*");
1173 sh_eval_radd("trash:postfix/smtpd: disconnect.*");
1174 sh_eval_hadd("hspc05");
1175 sh_eval_gadd("cron:CRON");
1176 sh_eval_qadd("test:1:sum:7");
1177 sh_eval_radd("test:CRON: PAM adding faulty module: (/lib/security/.*.so)");
1178 sh_eval_radd("trash:.*");
1179 status = sh_add_watch("SYSLOG:/var/log/messages");
1180 sh_check_watches();
1181
1182 sh_dump_watches();
1183 exit(0);
1184
1185 printf("%d types\n",
1186 (int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type)));
1187
1188 /* test sh_add_watch
1189 */
1190 status = sh_add_watch("");
1191 printf("%2d: zero length, expect -1\n", status);
1192 status = sh_add_watch(NULL);
1193 printf("%2d: NULL, expect -2\n", status);
1194 status = sh_add_watch("0123456789012345:/var/log/messages");
1195 printf("%2d: long, expect -2\n", status);
1196 status = sh_add_watch("012345678901234:/var/log/messages");
1197 printf("%2d: exact length, expect -3\n", status);
1198 status = sh_add_watch("01234567890123:56789");
1199 printf("%2d: short length, expect -3\n", status);
1200 status = sh_add_watch("SYSLOG:var/log/messages");
1201 printf("%2d: short badpath, expect -4\n", status);
1202 status = sh_add_watch("SYSLOG:/var/log/messages");
1203 /* status = sh_add_watch("SYSLOG:/var/log/dpkg.log.1"); */
1204 printf("%2d: short path ok, expect 0\n", status);
1205
1206 /* test sh_string_read
1207 */
1208 s = sh_string_new();
1209
1210 status = /*@i@*/mkstemp(template);
1211
1212 if (status < 0) {
1213 fprintf(stderr, "error in mkstemp!\n"); exit(EXIT_FAILURE); }
1214
1215 fp = fdopen(status, "r+");
1216 if (!fp) {
1217 fprintf(stderr, "error in fdopen!\n"); exit(EXIT_FAILURE); }
1218
1219 for (i = 0; i < 80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
1220 for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
1221 for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
1222 for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
1223 for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
1224 for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1225 for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1226 for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1227 for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1228
1229 rewind(fp);
1230
1231 for (i = 0; i < 9; ++i)
1232 {
1233 status = (int) sh_string_read(s, fp, 120);
1234 printf("%d: status = %d, len = %d, size = %d\n",
1235 i, status, (int)s->len, (int)s->siz);
1236 if (status == -2)
1237 (void) sh_string_read(s, fp, 240);
1238 else
1239 printf("%s\n", s->str);
1240 }
1241
1242 rewind(fp);
1243
1244 (void) sh_string_truncate(s, 0);
1245
1246 for (i = 0; i < 9; ++i)
1247 {
1248 status = (int) sh_string_read(s, fp, 240);
1249 printf("%d: status = %d, len = %d, size = %d\n",
1250 i, status, (int)s->len, (int)s->siz);
1251 if (status == -2)
1252 (void) sh_string_read(s, fp, 240);
1253 else
1254 {
1255 for (status = 0; status < (int)s->len; ++status)
1256 {
1257 if (s->str[status] != 'a')
1258 {
1259 break;
1260 }
1261 }
1262 printf("%d %s\n", status, s->str);
1263 }
1264 }
1265
1266 sl_fclose(FIL__, __LINE__, fp); remove(template);
1267
1268
1269
1270 return 0;
1271}
1272#endif
1273
1274/* #ifdef USE_LOGFILE_MONITOR */
1275#endif
1276
Note: See TracBrowser for help on using the repository browser.