source: trunk/src/sh_log_check.c@ 589

Last change on this file since 589 was 588, checked in by katerina, 30 hours ago

Fix for ticket #476 (move logfile monitoring module from PCRE to PCRE2).

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 || S_ISLNK(buf.st_mode)
426#endif
427 )
428 {
429 thisfile->inode = buf.st_ino;
430 thisfile->device_id = buf.st_dev;
431
432 if (0 != read_pos(thisfile))
433 {
434 thisfile->flags &= ~SH_LOGFILE_REWIND;
435 }
436 }
437 else if (S_ISFIFO(buf.st_mode))
438 {
439 thisfile->inode = buf.st_ino;
440 thisfile->device_id = buf.st_dev;
441 thisfile->flags |= SH_LOGFILE_PIPE;
442 }
443 }
444 else
445 {
446 sh_string * msg = sh_string_new(0);
447 sh_string_add_from_char(msg, _("Logfile is not a regular file, link, or named pipe: "));
448 sh_string_add_from_char(msg, splits[1]);
449
450 SH_MUTEX_LOCK(mutex_thread_nolog);
451 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
452 sh_string_str(msg),
453 _("sh_add_watch"));
454 SH_MUTEX_UNLOCK(mutex_thread_nolog);
455 sh_string_destroy(&msg);
456
457 SH_FREE(filename);
458 SH_FREE(thisfile);
459 SH_FREE(new);
460 return -1;
461 }
462 }
463
464 sh_watched_logs = thisfile;
465
466 SH_FREE(new);
467 return 0;
468}
469
470void sh_dump_watches()
471{
472 struct sh_logfile * thisfile;
473
474 while (sh_watched_logs)
475 {
476 thisfile = sh_watched_logs;
477 sh_watched_logs = thisfile->next;
478
479 if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0 &&
480 (thisfile->flags & SH_LOGFILE_PIPE) == 0)
481 {
482 save_pos(thisfile);
483 }
484
485 if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0)
486 {
487 if (thisfile->fp)
488 sl_fclose(FIL__, __LINE__, thisfile->fp);
489 }
490
491 if (thisfile->filename)
492 SH_FREE(thisfile->filename);
493 SH_FREE(thisfile);
494 }
495 return;
496}
497
498/* This variable is not used anywhere. It only exist
499 * to assign &new to them, which keeps gcc from
500 * putting it into a register, and avoids the 'clobbered
501 * by longjmp' warning. And no, 'volatile' proved insufficient.
502 */
503void * sh_dummy_502_thisfile = NULL;
504
505void sh_check_watches()
506{
507 struct sh_logrecord * logrecord;
508 struct sh_logfile * thisfile = sh_watched_logs;
509 sh_string * record = sh_string_new(0);
510 char * tmp;
511
512 /* Take the address to keep gcc from putting them into registers.
513 * Avoids the 'clobbered by longjmp' warning.
514 */
515 sh_dummy_502_thisfile = (void*) &thisfile;
516
517 while (thisfile)
518 {
519 volatile size_t count = 0;
520
521 SH_MUTEX_LOCK(mutex_thread_nolog);
522 tmp = sh_util_safe_name (thisfile->filename);
523 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKS,
524 tmp);
525 SH_FREE(tmp);
526 SH_MUTEX_UNLOCK(mutex_thread_nolog);
527
528 for (;;) {
529
530 record = thisfile->get_record(record, thisfile);
531
532 if (record)
533 {
534 logrecord = thisfile->parse_record(record, thisfile->fileinfo);
535 ++count;
536
537 if (logrecord)
538 {
539 logrecord->filename = thisfile->filename;
540
541 /* Don't report if 'init', just set file pointer
542 */
543 if (sh.flag.checkSum != SH_CHECK_INIT)
544 {
545 sh_eval_process_msg(logrecord);
546 }
547
548 if (logrecord->message)
549 sh_string_destroy(&(logrecord->message));
550 if (logrecord->host)
551 sh_string_destroy(&(logrecord->host));
552 if (logrecord->timestr)
553 sh_string_destroy(&(logrecord->timestr));
554 SH_FREE(logrecord);
555 }
556 }
557 else
558 {
559 record = sh_string_new(0);
560 break;
561 }
562 }
563
564 SH_MUTEX_LOCK(mutex_thread_nolog);
565 tmp = sh_util_safe_name (thisfile->filename);
566 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKE,
567 tmp, (unsigned long)count);
568 SH_FREE(tmp);
569 SH_MUTEX_UNLOCK(mutex_thread_nolog);
570
571 thisfile = thisfile->next;
572 }
573 sh_string_destroy(&record);
574 return;
575}
576
577/********************************************************
578 * Search rotated logfile
579 */
580extern char * sh_rotated_log_search(const char * path, struct stat * buf);
581
582
583/* Open file, position at stored offset
584 */
585int sh_open_for_reader (struct sh_logfile * logfile)
586{
587 struct stat buf;
588 sh_string * filename;
589
590 /* check whether file exists, get inode to check for
591 * logfile rotation
592 */
593 if (0 != retry_stat(FIL__, __LINE__, logfile->filename, &buf))
594 {
595 char * tmp;
596
597 SH_MUTEX_LOCK(mutex_thread_nolog);
598 tmp = sh_util_safe_name (logfile->filename);
599 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_MISS,
600 tmp);
601 SH_FREE(tmp);
602 SH_MUTEX_UNLOCK(mutex_thread_nolog);
603
604 memset (&(logfile->offset), 0, sizeof(fpos_t));
605 logfile->flags |= SH_LOGFILE_REWIND;
606 return 0;
607 }
608
609 filename = sh_string_new(0);
610 (void) sh_string_set_from_char (filename, logfile->filename);
611
612 /* detect and handle logfile rotation
613 */
614 if (logfile->inode != buf.st_ino &&
615 logfile->inode != 0 &&
616 !S_ISFIFO(buf.st_mode))
617 {
618 /* Case 1) We have dealt with the moved file already.
619 * Clear the moved flag, set the rewind flag,
620 * fix logfile->inode.
621 */
622 if ((logfile->flags & SH_LOGFILE_MOVED) != 0)
623 {
624 /* done with rotated file, start with current file
625 */
626 memset (&(logfile->offset), 0, sizeof(fpos_t));
627 logfile->flags |= SH_LOGFILE_REWIND;
628 logfile->flags &= ~SH_LOGFILE_MOVED;
629 logfile->inode = buf.st_ino;
630 logfile->device_id = buf.st_dev;
631 }
632
633 /* Case 2) Searching for rotated file.
634 * If found: set the moved flag, fix path for fopen.
635 * If not found: set the rewind flag, fix logfile->inode.
636 */
637 else
638 {
639 char *oldfile = sh_rotated_log_search(logfile->filename, &buf);
640
641 if (NULL != oldfile)
642 {
643 (void) sh_string_set_from_char (filename, oldfile);
644 SH_FREE(oldfile);
645 logfile->flags |= SH_LOGFILE_MOVED;
646 }
647 else
648 {
649 memset (&(logfile->offset), 0, sizeof(fpos_t));
650 logfile->flags |= SH_LOGFILE_REWIND;
651 logfile->inode = buf.st_ino;
652 logfile->device_id = buf.st_dev;
653 }
654 }
655 }
656
657 /* open file
658 */
659 if (!S_ISFIFO(buf.st_mode))
660 {
661 logfile->fp = fopen(filename->str, "r");
662 }
663 else
664 {
665 int fd_temp = open (filename->str, O_RDONLY|O_NONBLOCK);
666
667 if (fd_temp >= 0)
668 {
669 logfile->fp = fdopen(fd_temp, "r");
670 }
671 }
672
673 if (!logfile->fp)
674 {
675 char * tmp;
676
677 SH_MUTEX_LOCK(mutex_thread_nolog);
678 tmp = sh_util_safe_name (logfile->filename);
679 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EOPEN,
680 tmp);
681 SH_FREE(tmp);
682 SH_MUTEX_UNLOCK(mutex_thread_nolog);
683
684 sh_string_destroy(&filename);
685 return 0;
686 }
687
688 sh_string_destroy(&filename);
689
690 if ((logfile->flags & SH_LOGFILE_PIPE) == 0)
691 {
692 if ((logfile->flags & SH_LOGFILE_REWIND) != 0)
693 {
694 rewind(logfile->fp);
695 fgetpos(logfile->fp, &(logfile->offset));
696 logfile->flags &= ~SH_LOGFILE_REWIND;
697 }
698 else
699 {
700 /* file too short
701 */
702 if (0 != fsetpos(logfile->fp, &(logfile->offset)))
703 {
704 rewind(logfile->fp);
705 fgetpos(logfile->fp, &(logfile->offset));
706 }
707 }
708 }
709
710 return 1;
711}
712
713/******************************************************
714 * Default reader for ascii text files
715 */
716sh_string * sh_default_reader (sh_string * s, struct sh_logfile * logfile)
717{
718 volatile int status;
719 char * tmp;
720
721 start_read:
722
723 if (logfile->fp)
724 {
725 /* Result cannot be larger than 8192, thus cast is ok
726 */
727 status = (int) sh_string_read(s, logfile->fp, 8192);
728 if (status <= 0)
729 {
730 fgetpos(logfile->fp, &(logfile->offset));
731 sl_fclose(FIL__, __LINE__, logfile->fp);
732 logfile->fp = NULL;
733 sh_string_destroy(&s);
734 if (status == 0 || (logfile->flags & SH_LOGFILE_PIPE) != 0)
735 {
736 return NULL;
737 }
738
739 SH_MUTEX_LOCK(mutex_thread_nolog);
740 tmp = sh_util_safe_name (logfile->filename);
741 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
742 tmp);
743 SH_FREE(tmp);
744 SH_MUTEX_UNLOCK(mutex_thread_nolog);
745
746 return NULL;
747 }
748 return s;
749 }
750
751 if (0 != sh_open_for_reader(logfile))
752 goto start_read;
753
754 return NULL;
755}
756
757struct task_entry
758{
759 sh_tas_t task;
760 struct task_entry * next;
761};
762
763static struct task_entry * tasklist = NULL;
764
765static struct task_entry * task_find(FILE * fp)
766{
767 struct task_entry * entry = tasklist;
768 while (entry)
769 {
770 if (entry->task.pipe == fp)
771 return (entry);
772 entry = entry->next;
773 }
774 return NULL;
775}
776
777static void task_remove(struct task_entry * task)
778{
779 struct task_entry * entry = tasklist;
780 struct task_entry * prev = tasklist;
781
782 while (entry)
783 {
784 if (entry == task)
785 {
786 if (entry == tasklist)
787 {
788 tasklist = entry->next;
789 SH_FREE(entry);
790 return;
791 }
792 else
793 {
794 prev->next = entry->next;
795 SH_FREE(entry);
796 return;
797 }
798 }
799 prev = entry;
800 entry = entry->next;
801 }
802 return;
803}
804
805static void task_add(struct task_entry * entry)
806{
807 entry->next = tasklist;
808 tasklist = entry;
809 return;
810}
811
812sh_string * sh_command_reader (sh_string * s, struct sh_logfile * logfile)
813{
814 struct task_entry * entry;
815
816 volatile int status;
817 char * tmp;
818
819 start_read:
820
821 if (logfile->fp)
822 {
823 /* Result cannot be larger than 8192, thus cast is ok
824 */
825 status = (int) sh_string_read(s, logfile->fp, 8192);
826
827 if (status <= 0)
828 {
829 entry = task_find(logfile->fp);
830 sh_ext_pclose (&(entry->task));
831 task_remove(entry);
832
833 logfile->fp = NULL;
834 sh_string_destroy(&s);
835
836 if (status == 0)
837 {
838 return NULL;
839 }
840
841 SH_MUTEX_LOCK(mutex_thread_nolog);
842 tmp = sh_util_safe_name (logfile->filename);
843 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
844 tmp);
845 SH_FREE(tmp);
846 SH_MUTEX_UNLOCK(mutex_thread_nolog);
847
848 return NULL;
849 }
850 return s;
851 }
852
853 entry = SH_ALLOC(sizeof(struct task_entry));
854
855 status = sh_ext_popen_init (&(entry->task), logfile->filename, NULL, NULL);
856 if (0 == status)
857 {
858 task_add(entry);
859 logfile->fp = entry->task.pipe;
860 goto start_read;
861 }
862 else
863 {
864 SH_FREE(entry);
865 SH_MUTEX_LOCK(mutex_thread_nolog);
866 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
867 _("Could not open pipe"), _("sh_command reader"));
868 SH_MUTEX_UNLOCK(mutex_thread_nolog);
869 }
870
871 return NULL;
872}
873
874/******************************************************
875 * Reader for continued text files
876 */
877sh_string * sh_cont_reader (sh_string * s, struct sh_logfile * logfile, char*cont)
878{
879 int status;
880 char * tmp;
881 sh_string * str;
882 int remain = 8192;
883 int count = 0;
884
885 if (!sh_string_truncate(s, 0))
886 return NULL;
887
888 start_read:
889
890 if (logfile->fp)
891 {
892 str = sh_string_new(0);
893
894 /* Result cannot be larger than 8192, thus cast is ok
895 */
896 status = (int) sh_string_read(str, logfile->fp, 8192);
897
898 if (status > 0)
899 {
900
901 do {
902 s = sh_string_add (s, str);
903 count += status;
904 remain -= status;
905
906 if (remain <= 0)
907 {
908 return s;
909 }
910
911 status = (int) sh_string_read_cont(str, logfile->fp, count, cont);
912
913 if (status == 0)
914 {
915 return s;
916 }
917 }
918 while (status > 0);
919 }
920
921 if (status <= 0)
922 {
923 fgetpos(logfile->fp, &(logfile->offset));
924 sl_fclose(FIL__, __LINE__, logfile->fp);
925 logfile->fp = NULL;
926 sh_string_destroy(&s);
927 if (status == 0 || (logfile->flags & SH_LOGFILE_PIPE) != 0)
928 {
929 return NULL;
930 }
931
932 SH_MUTEX_LOCK(mutex_thread_nolog);
933 tmp = sh_util_safe_name (logfile->filename);
934 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
935 tmp);
936 SH_FREE(tmp);
937 SH_MUTEX_UNLOCK(mutex_thread_nolog);
938
939 return NULL;
940 }
941
942 return s;
943 }
944
945 if (0 != sh_open_for_reader(logfile))
946 goto start_read;
947
948 return NULL;
949}
950
951/******************************************************
952 * Reader for binary files
953 */
954sh_string * sh_binary_reader (void * s, size_t size,
955 struct sh_logfile * logfile)
956{
957 size_t status;
958
959 start_read:
960
961 if (logfile->fp)
962 {
963
964 status = fread(s, size, 1, logfile->fp);
965
966 if (status != 1)
967 {
968 memset(s, 0, size);
969 if (ferror(logfile->fp) && (logfile->flags & SH_LOGFILE_PIPE) == 0)
970 {
971 char * tmp;
972 SH_MUTEX_LOCK(mutex_thread_nolog);
973 tmp = sh_util_safe_name (logfile->filename);
974 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_LOGMON_EREAD,
975 tmp);
976 SH_FREE(tmp);
977 SH_MUTEX_UNLOCK(mutex_thread_nolog);
978 }
979 fgetpos(logfile->fp, &(logfile->offset));
980 sl_fclose(FIL__, __LINE__, logfile->fp);
981 logfile->fp = NULL;
982 return NULL;
983 }
984 return s;
985 }
986
987 if (0 != sh_open_for_reader(logfile))
988 goto start_read;
989
990 return NULL;
991}
992
993
994
995/**********************************************************
996 *
997 * Utilities
998 *
999 **********************************************************/
1000
1001/* Return current year, unless that would result
1002 * in a date far in the future. If that happens,
1003 * return last year.
1004 */
1005static int year_guess (struct tm * btime)
1006{
1007 int year;
1008 struct tm ts;
1009 time_t now = time(NULL);
1010 time_t check;
1011
1012 memcpy(&ts, localtime(&now), sizeof(struct tm));
1013 year = ts.tm_year;
1014
1015 /* Check result to detect year wrap
1016 * (logfile entry from last year).
1017 */
1018 btime->tm_year = year;
1019 check = mktime(btime);
1020 if (check > (now + (86400*30)))
1021 --year;
1022
1023 return year;
1024}
1025
1026time_t conv_timestamp (struct tm * btime,
1027 struct tm * old_tm, time_t * old_time)
1028{
1029 time_t timestamp;
1030 long offtime;
1031
1032 /* timestamp - mktime is slooow, thus cache result
1033 */
1034 if (btime->tm_isdst == old_tm->tm_isdst &&
1035 btime->tm_year == old_tm->tm_year &&
1036 btime->tm_mon == old_tm->tm_mon &&
1037 btime->tm_mday == old_tm->tm_mday)
1038 {
1039 offtime =
1040 (btime->tm_hour - old_tm->tm_hour) * 3600 +
1041 (btime->tm_min - old_tm->tm_min) * 60 +
1042 (btime->tm_sec - old_tm->tm_sec);
1043
1044 *old_time += offtime;
1045 memcpy(old_tm, btime, sizeof(struct tm));
1046 timestamp = *old_time;
1047 }
1048 else
1049 {
1050 int year_btime = btime->tm_year;
1051
1052 if (btime->tm_year == 0)
1053 btime->tm_year = year_guess(btime);
1054 timestamp = mktime(btime);
1055 btime->tm_year = year_btime;
1056 *old_time = timestamp;
1057 memcpy(old_tm, btime, sizeof(struct tm));
1058 }
1059 return timestamp;
1060}
1061
1062/*********************************************************
1063 *
1064 * MODULE STUFF
1065 *
1066 *********************************************************/
1067#include "sh_modules.h"
1068
1069SH_MUTEX_STATIC(mutex_logmon_check, PTHREAD_MUTEX_INITIALIZER);
1070
1071static int ShLogmonActive = S_FALSE;
1072#define SH_LOGMON_INTERVAL 10
1073static time_t sh_logmon_interval = SH_LOGMON_INTERVAL;
1074
1075int sh_log_check_init (struct mod_type * arg)
1076{
1077#if !defined(HAVE_PTHREAD)
1078 (void) arg;
1079#endif
1080
1081 if (ShLogmonActive == S_FALSE)
1082 return SH_MOD_FAILED;
1083#ifdef HAVE_PTHREAD
1084 if (arg != NULL && arg->initval < 0 &&
1085 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
1086 {
1087 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
1088 return SH_MOD_THREAD;
1089 else
1090 return SH_MOD_FAILED;
1091 }
1092 else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
1093 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
1094 {
1095 return SH_MOD_THREAD;
1096 }
1097#endif
1098 if (sh_watched_logs != NULL)
1099 return 0;
1100
1101 return -1;
1102}
1103
1104int sh_log_check_timer(time_t tcurrent)
1105{
1106 static time_t lastcheck = 0;
1107
1108 SL_ENTER(_("sh_log_check_timer"));
1109 if ((time_t) (tcurrent - lastcheck) >= sh_logmon_interval)
1110 {
1111 lastcheck = tcurrent;
1112 SL_RETURN((-1), _("sh_log_check_timer"));
1113 }
1114 SL_RETURN(0, _("sh_log_check_timer"));
1115}
1116
1117
1118int sh_log_check_check(void)
1119{
1120 int status = 0;
1121
1122 SL_ENTER(_("sh_log_check_check"));
1123
1124 SH_MUTEX_LOCK(mutex_logmon_check);
1125
1126 status = 0;
1127
1128 if( ShLogmonActive != S_FALSE )
1129 {
1130 sh_check_watches();
1131 sh_keep_match();
1132 sh_log_mark_check();
1133 clean_dir();
1134 }
1135 SH_MUTEX_UNLOCK(mutex_logmon_check);
1136
1137 SL_RETURN(status, _("sh_log_check_check"));
1138}
1139
1140int sh_log_check_reconf(void)
1141{
1142 int status = 0;
1143
1144 SL_ENTER(_("sh_log_check_check"));
1145
1146 SH_MUTEX_LOCK(mutex_logmon_check);
1147
1148 ShLogmonActive = S_FALSE;
1149 sh_logmon_interval = SH_LOGMON_INTERVAL;
1150 sh_dump_watches();
1151 sh_eval_cleanup();
1152
1153 SH_MUTEX_UNLOCK(mutex_logmon_check);
1154
1155 SL_RETURN(status, _("sh_log_check_check"));
1156}
1157
1158int sh_log_check_cleanup(void)
1159{
1160 sh_log_mark_destroy();
1161 return sh_log_check_reconf();
1162}
1163
1164/********************* OPTIONS **********************/
1165
1166static int sh_logmon_set_active (const char *str);
1167static int sh_logmon_set_clean (const char *str);
1168static int sh_logmon_set_interval(const char *str);
1169static int sh_logmon_add_watch (const char * str);
1170static int sh_logmon_add_group (const char * str);
1171static int sh_logmon_end_group (const char * str);
1172static int sh_logmon_add_host (const char * str);
1173static int sh_logmon_end_host (const char * str);
1174static int sh_logmon_add_queue (const char * str);
1175static int sh_logmon_add_rule (const char * str);
1176extern int sh_set_hidepid(const char *s);
1177static int sh_logmon_set_save_dir(const char *s);
1178
1179sh_rconf sh_log_check_table[] = {
1180 {
1181 N_("logmonactive"),
1182 sh_logmon_set_active,
1183 },
1184 {
1185 N_("logmoninterval"),
1186 sh_logmon_set_interval,
1187 },
1188 {
1189 N_("logmonclean"),
1190 sh_logmon_set_clean,
1191 },
1192 {
1193 N_("logmonwatch"),
1194 sh_logmon_add_watch,
1195 },
1196 {
1197 N_("logmonqueue"),
1198 sh_logmon_add_queue,
1199 },
1200 {
1201 N_("logmongroup"),
1202 sh_logmon_add_group,
1203 },
1204 {
1205 N_("logmonendgroup"),
1206 sh_logmon_end_group,
1207 },
1208 {
1209 N_("logmonhost"),
1210 sh_logmon_add_host,
1211 },
1212 {
1213 N_("logmonendhost"),
1214 sh_logmon_end_host,
1215 },
1216 {
1217 N_("logmonrule"),
1218 sh_logmon_add_rule,
1219 },
1220 {
1221 N_("logmonhidepid"),
1222 sh_set_hidepid,
1223 },
1224 {
1225 N_("logmonsavedir"),
1226 sh_logmon_set_save_dir,
1227 },
1228 {
1229 N_("logmonmarkseverity"),
1230 sh_log_set_mark_severity,
1231 },
1232 {
1233 N_("logmonburstthreshold"),
1234 sh_repeat_set_trigger,
1235 },
1236 {
1237 N_("logmonburstqueue"),
1238 sh_repeat_set_queue,
1239 },
1240 {
1241 N_("logmonburstcron"),
1242 sh_repeat_set_cron,
1243 },
1244 {
1245 N_("logmondeadtime"),
1246 sh_keep_deadtime,
1247 },
1248 {
1249 NULL,
1250 NULL
1251 }
1252};
1253
1254/* Decide if we're active.
1255 */
1256static int sh_logmon_set_active(const char *str)
1257{
1258 int value;
1259
1260 SL_ENTER(_("sh_logmon_set_active"));
1261
1262 value = sh_util_flagval(str, &ShLogmonActive);
1263
1264 SL_RETURN((value), _("sh_logmon_set_active"));
1265}
1266
1267/* Decide if we're active.
1268 */
1269static int sh_logmon_set_clean(const char *str)
1270{
1271 int value;
1272
1273 SL_ENTER(_("sh_logmon_set_active"));
1274
1275 value = sh_util_flagval(str, &do_checkpoint_cleanup);
1276
1277 SL_RETURN((value), _("sh_logmon_set_active"));
1278}
1279
1280static int sh_logmon_set_save_dir(const char *str)
1281{
1282 int retval = -1;
1283
1284 SL_ENTER(_("sh_logmon_set_save_dir"));
1285
1286 if (str && str[0] == '/')
1287 {
1288 if (save_dir)
1289 {
1290 SH_FREE(save_dir);
1291 save_dir = NULL;
1292 }
1293 save_dir = sh_util_strdup(str);
1294 retval = 0;
1295 }
1296
1297 SL_RETURN((retval), _("sh_logmon_set_save_dir"));
1298}
1299
1300static int sh_logmon_set_interval (const char * c)
1301{
1302 int retval = 0;
1303 long val;
1304
1305 SL_ENTER(_("sh_logmon_set_interval"));
1306 val = strtol (c, (char **)NULL, 10);
1307 if (val <= 0)
1308 {
1309 SH_MUTEX_LOCK(mutex_thread_nolog);
1310 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1311 _("log monitoring interval"), c);
1312 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1313 retval = -1;
1314 }
1315 else
1316 {
1317 sh_logmon_interval = (time_t) val;
1318 }
1319 SL_RETURN(retval, _("sh_logmon_set_interval"));
1320}
1321
1322/* Add a watch on a logfile.
1323 * Format: TYPE : Filename [: File_Format]
1324 */
1325static int sh_logmon_add_watch (const char * str)
1326{
1327 return sh_add_watch(str);
1328}
1329
1330/* Add a host.
1331 * Format: Name_Regex
1332 */
1333static int sh_logmon_add_host (const char * str)
1334{
1335 return sh_eval_hadd(str);
1336}
1337
1338/* End a host.
1339 * Format: Name
1340 */
1341static int sh_logmon_end_host (const char * str)
1342{
1343 (void) str;
1344 return sh_eval_hend(NULL);
1345}
1346
1347/* Add a group of rules.
1348 * Groups can be under hosts, but not vice versa.
1349 * Format: Name : Prefix_Regex
1350 */
1351static int sh_logmon_add_group (const char * str)
1352{
1353 return sh_eval_gadd(str);
1354}
1355
1356/* End a group of rules.
1357 * Format: Name
1358 */
1359static int sh_logmon_end_group (const char * str)
1360{
1361 (void) str;
1362 return sh_eval_gend(NULL);
1363}
1364
1365/* Define a reporting queue.
1366 * Format: Label : [Interval] : TYPE : Severity[:alias]
1367 * TYPE must be 'report' or 'sum'
1368 * Interval is ignored for TYPE='report'
1369 */
1370static int sh_logmon_add_queue (const char * str)
1371{
1372 return sh_eval_qadd(str);
1373}
1374
1375/* Define a check rule.
1376 * Format: [KEEP(seconds,label):]Queue_Label : Regex
1377 * KEEP indicates that we keep the label, to perform
1378 * correlation matching
1379 */
1380static int sh_logmon_add_rule (const char * str)
1381{
1382 return sh_eval_radd(str);
1383}
1384
1385
1386#if 0
1387
1388/* >>>>>>>>>>> MAIN <<<<<<<<<<<<<<<<<<< */
1389
1390int main (int argc, char * argv[])
1391{
1392 int status, i;
1393 FILE * fp;
1394 sh_string * s = NULL;
1395 static char template[] = "/tmp/xtest.XXXXXX";
1396
1397 /* pacct */
1398 status = sh_add_watch("PACCT:/var/log/account/pacct");
1399 sh_check_watches();
1400 sh_dump_watches();
1401 exit(0);
1402
1403 /* apache log */
1404 sh_eval_gadd("four_o_four:404");
1405 sh_eval_qadd("test:1:sum:7");
1406 sh_eval_radd("test:^(\\d+.\\d+.\\d+.\\d+).*");
1407 sh_eval_gend(NULL);
1408 sh_eval_radd("trash:.*");
1409 status = sh_add_watch("APACHE:/var/log/apache2/access.log:combined");
1410 sh_check_watches();
1411 sh_dump_watches();
1412 exit(0);
1413
1414 /* logfile */
1415 sh_set_hidepid(1);
1416 sh_eval_hadd("hslxmsrv1");
1417 sh_eval_gadd("postfix:postfix");
1418 sh_eval_qadd("test::report:7");
1419 sh_eval_radd("test:postfix/smtpd: disconnect from localhost.*");
1420 sh_eval_radd("trash:postfix/smtpd: disconnect.*");
1421 sh_eval_hadd("hspc05");
1422 sh_eval_gadd("cron:CRON");
1423 sh_eval_qadd("test:1:sum:7");
1424 sh_eval_radd("test:CRON: PAM adding faulty module: (/lib/security/.*.so)");
1425 sh_eval_radd("trash:.*");
1426 status = sh_add_watch("SYSLOG:/var/log/messages");
1427 sh_check_watches();
1428
1429 sh_dump_watches();
1430 exit(0);
1431
1432 printf("%d types\n",
1433 (int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type)));
1434
1435 /* test sh_add_watch
1436 */
1437 status = sh_add_watch("");
1438 printf("%2d: zero length, expect -1\n", status);
1439 status = sh_add_watch(NULL);
1440 printf("%2d: NULL, expect -2\n", status);
1441 status = sh_add_watch("0123456789012345:/var/log/messages");
1442 printf("%2d: long, expect -2\n", status);
1443 status = sh_add_watch("012345678901234:/var/log/messages");
1444 printf("%2d: exact length, expect -3\n", status);
1445 status = sh_add_watch("01234567890123:56789");
1446 printf("%2d: short length, expect -3\n", status);
1447 status = sh_add_watch("SYSLOG:var/log/messages");
1448 printf("%2d: short badpath, expect -4\n", status);
1449 status = sh_add_watch("SYSLOG:/var/log/messages");
1450 /* status = sh_add_watch("SYSLOG:/var/log/dpkg.log.1"); */
1451 printf("%2d: short path ok, expect 0\n", status);
1452
1453 /* test sh_string_read
1454 */
1455 s = sh_string_new();
1456
1457 status = /*@i@*/mkstemp(template);
1458
1459 if (status < 0) {
1460 fprintf(stderr, "error in mkstemp!\n"); exit(EXIT_FAILURE); }
1461
1462 fp = fdopen(status, "r+");
1463 if (!fp) {
1464 fprintf(stderr, "error in fdopen!\n"); exit(EXIT_FAILURE); }
1465
1466 for (i = 0; i < 80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
1467 for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
1468 for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
1469 for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
1470 for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
1471 for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1472 for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1473 for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1474 for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1475
1476 rewind(fp);
1477
1478 for (i = 0; i < 9; ++i)
1479 {
1480 status = (int) sh_string_read(s, fp, 120);
1481 printf("%d: status = %d, len = %d, size = %d\n",
1482 i, status, (int)s->len, (int)s->siz);
1483 if (status == -2)
1484 (void) sh_string_read(s, fp, 240);
1485 else
1486 printf("%s\n", s->str);
1487 }
1488
1489 rewind(fp);
1490
1491 (void) sh_string_truncate(s, 0);
1492
1493 for (i = 0; i < 9; ++i)
1494 {
1495 status = (int) sh_string_read(s, fp, 240);
1496 printf("%d: status = %d, len = %d, size = %d\n",
1497 i, status, (int)s->len, (int)s->siz);
1498 if (status == -2)
1499 (void) sh_string_read(s, fp, 240);
1500 else
1501 {
1502 for (status = 0; status < (int)s->len; ++status)
1503 {
1504 if (s->str[status] != 'a')
1505 {
1506 break;
1507 }
1508 }
1509 printf("%d %s\n", status, s->str);
1510 }
1511 }
1512
1513 sl_fclose(FIL__, __LINE__, fp); remove(template);
1514
1515
1516
1517 return 0;
1518}
1519#endif
1520
1521/* #ifdef USE_LOGFILE_MONITOR */
1522#endif
1523
Note: See TracBrowser for help on using the repository browser.