source: trunk/src/sh_log_check.c@ 186

Last change on this file since 186 was 186, checked in by katerina, 16 years ago

More fixes for log monitoring, and documentation update.

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