source: trunk/src/sh_log_check.c@ 581

Last change on this file since 581 was 581, checked in by katerina, 12 days ago

Fix for ticket #469 (regression in log monitoring code).

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