source: trunk/src/sh_log_check.c@ 592

Last change on this file since 592 was 592, checked in by katerina, 39 hours ago

Fixes for compiler warnings.

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