source: trunk/src/sh_log_check.c@ 185

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

Bugfixes for log monitoring, samba logfile parser.

File size: 26.5 KB
Line 
1
2#include "config_xor.h"
3
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9
10#ifdef USE_LOGFILE_MONITOR
11
12#undef FIL__
13#define FIL__ _("sh_log_check.c")
14
15/* Debian/Ubuntu: libpcre3-dev */
16#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->prefix)
385 sh_string_destroy(&(logrecord->prefix));
386 if (logrecord->timestr)
387 sh_string_destroy(&(logrecord->timestr));
388 SH_FREE(logrecord);
389 }
390 }
391 else
392 {
393 record = sh_string_new(0);
394 break;
395 }
396 }
397
398 SH_MUTEX_LOCK(mutex_thread_nolog);
399 tmp = sh_util_safe_name (thisfile->filename);
400 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKE,
401 tmp, (unsigned long)count);
402 SH_FREE(tmp);
403 SH_MUTEX_UNLOCK(mutex_thread_nolog);
404
405 thisfile = thisfile->next;
406 }
407 sh_string_destroy(&record);
408 return;
409}
410
411/********************************************************
412 * Search rotated logfile
413 */
414#include <unistd.h>
415#include <libgen.h>
416#include <dirent.h>
417
418char * sh_rotated_log_search(const char * path, struct stat * buf)
419{
420
421 size_t size;
422 int i;
423 char * searchpath;
424 struct stat sbuf;
425 DIR * dp;
426 char * dname;
427 char * bname;
428
429 dname = sh_util_dirname(path);
430 bname = sh_util_basename(path);
431
432 size = strlen(dname) + strlen(bname) + 4;
433 searchpath = SH_ALLOC(size);
434
435 for (i = 0; i < 2; ++i)
436 {
437 snprintf(searchpath, size, "%s/%s.%1d", dname, bname, i);
438 if (0 == stat(searchpath, &sbuf) && sbuf.st_ino == buf->st_ino)
439 {
440 SH_FREE(dname);
441 SH_FREE(bname);
442 return searchpath;
443 }
444 }
445
446 SH_FREE(searchpath);
447
448 if (NULL != (dp = opendir(dname)))
449 {
450 struct dirent * de;
451
452 while (NULL != (de = readdir(dp)))
453 {
454 if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, ".."))
455 continue;
456
457 size = strlen(dname) + strlen(de->d_name) + 2;
458 searchpath = SH_ALLOC(size);
459 snprintf(searchpath, size, "%s/%s", dname, de->d_name);
460
461 if (0 == stat(searchpath, &sbuf) && sbuf.st_ino == buf->st_ino)
462 {
463 SH_FREE(dname);
464 SH_FREE(bname);
465 closedir(dp);
466 return searchpath;
467 }
468
469 SH_FREE(searchpath);
470 }
471 closedir(dp);
472 }
473
474 SH_FREE(dname);
475 SH_FREE(bname);
476
477 return NULL;
478}
479
480/* Open file, position at stored offset
481 */
482int sh_open_for_reader (struct sh_logfile * logfile)
483{
484 struct stat buf;
485 sh_string * filename;
486
487 /* check whether file exists, get inode to check for
488 * logfile rotation
489 */
490 if (0 != retry_stat(FIL__, __LINE__, logfile->filename, &buf))
491 {
492 char * tmp;
493
494 SH_MUTEX_LOCK(mutex_thread_nolog);
495 tmp = sh_util_safe_name (logfile->filename);
496 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_MISS,
497 tmp);
498 SH_FREE(tmp);
499 SH_MUTEX_UNLOCK(mutex_thread_nolog);
500
501 memset (&(logfile->offset), '\0', sizeof(fpos_t));
502 logfile->flags |= SH_LOGFILE_REWIND;
503 return 0;
504 }
505
506 filename = sh_string_new(0);
507 (void) sh_string_set_from_char (filename, logfile->filename);
508
509 /* detect and handle logfile rotation
510 */
511 if (logfile->inode != buf.st_ino && logfile->inode != 0)
512 {
513 /* Case 1) We have dealt with the moved file already.
514 * Clear the moved flag, set the rewind flag,
515 * fix logfile->inode.
516 */
517 if ((logfile->flags & SH_LOGFILE_MOVED) != 0)
518 {
519 /* done with rotated file, start with current file
520 */
521 memset (&(logfile->offset), '\0', sizeof(fpos_t));
522 logfile->flags |= SH_LOGFILE_REWIND;
523 logfile->flags &= ~SH_LOGFILE_MOVED;
524 logfile->inode = buf.st_ino;
525 logfile->device_id = buf.st_dev;
526 }
527
528 /* Case 2) Searching for rotated file.
529 * If found: set the moved flag, fix path for fopen.
530 * If not found: set the rewind flag, fix logfile->inode.
531 */
532 else
533 {
534 char *oldfile = sh_rotated_log_search(logfile->filename, &buf);
535
536 if (NULL != oldfile)
537 {
538 (void) sh_string_set_from_char (filename, oldfile);
539 SH_FREE(oldfile);
540 logfile->flags |= SH_LOGFILE_MOVED;
541 }
542 else
543 {
544 memset (&(logfile->offset), '\0', sizeof(fpos_t));
545 logfile->flags |= SH_LOGFILE_REWIND;
546 logfile->inode = buf.st_ino;
547 logfile->device_id = buf.st_dev;
548 }
549 }
550 }
551
552 /* open file
553 */
554 logfile->fp = fopen(filename->str, "r");
555 if (!logfile->fp)
556 {
557 char * tmp;
558
559 SH_MUTEX_LOCK(mutex_thread_nolog);
560 tmp = sh_util_safe_name (logfile->filename);
561 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EOPEN,
562 tmp);
563 SH_FREE(tmp);
564 SH_MUTEX_UNLOCK(mutex_thread_nolog);
565
566 sh_string_destroy(&filename);
567 return 0;
568 }
569
570 sh_string_destroy(&filename);
571
572 if ((logfile->flags & SH_LOGFILE_REWIND) != 0)
573 {
574 rewind(logfile->fp);
575 fgetpos(logfile->fp, &(logfile->offset));
576 logfile->flags &= ~SH_LOGFILE_REWIND;
577 }
578 else
579 {
580 /* file too short
581 */
582 if (0 != fsetpos(logfile->fp, &(logfile->offset)))
583 {
584 rewind(logfile->fp);
585 fgetpos(logfile->fp, &(logfile->offset));
586 }
587 }
588
589 return 1;
590}
591
592/******************************************************
593 * Default reader for ascii text files
594 */
595sh_string * sh_default_reader (sh_string * s, struct sh_logfile * logfile)
596{
597 int status;
598 char * tmp;
599
600 start_read:
601
602 if (logfile->fp)
603 {
604 /* Result cannot be larger than 8192, thus cast is ok
605 */
606 status = (int) sh_string_read(s, logfile->fp, 8192);
607 if (status <= 0)
608 {
609 fgetpos(logfile->fp, &(logfile->offset));
610 fclose(logfile->fp);
611 logfile->fp = NULL;
612 sh_string_destroy(&s);
613 if (status == 0)
614 {
615 return NULL;
616 }
617
618 SH_MUTEX_LOCK(mutex_thread_nolog);
619 tmp = sh_util_safe_name (logfile->filename);
620 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
621 tmp);
622 SH_FREE(tmp);
623 SH_MUTEX_UNLOCK(mutex_thread_nolog);
624
625 return NULL;
626 }
627 return s;
628 }
629
630 if (0 != sh_open_for_reader(logfile))
631 goto start_read;
632
633 return NULL;
634}
635
636/******************************************************
637 * Reader for continued text files
638 */
639sh_string * sh_cont_reader (sh_string * s, struct sh_logfile * logfile, char*cont)
640{
641 int status;
642 char * tmp;
643 sh_string * str;
644 int remain = 8192;
645 int count = 0;
646
647 if (!sh_string_truncate(s, 0))
648 return NULL;
649
650 start_read:
651
652 if (logfile->fp)
653 {
654 str = sh_string_new(0);
655
656 /* Result cannot be larger than 8192, thus cast is ok
657 */
658 status = (int) sh_string_read(str, logfile->fp, 8192);
659
660 if (status > 0)
661 {
662
663 do {
664 s = sh_string_add (s, str);
665 count += status;
666 remain -= status;
667
668 if (remain <= 0)
669 {
670 return s;
671 }
672
673 status = (int) sh_string_read_cont(str, logfile->fp, count, cont);
674
675 if (status == 0)
676 {
677 return s;
678 }
679 }
680 while (status > 0);
681 }
682
683 if (status <= 0)
684 {
685 fgetpos(logfile->fp, &(logfile->offset));
686 fclose(logfile->fp);
687 logfile->fp = NULL;
688 sh_string_destroy(&s);
689 if (status == 0)
690 {
691 return NULL;
692 }
693
694 SH_MUTEX_LOCK(mutex_thread_nolog);
695 tmp = sh_util_safe_name (logfile->filename);
696 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
697 tmp);
698 SH_FREE(tmp);
699 SH_MUTEX_UNLOCK(mutex_thread_nolog);
700
701 return NULL;
702 }
703
704 return s;
705 }
706
707 if (0 != sh_open_for_reader(logfile))
708 goto start_read;
709
710 return NULL;
711}
712
713/******************************************************
714 * Reader for binary files
715 */
716sh_string * sh_binary_reader (void * s, size_t size, struct sh_logfile * logfile)
717{
718 size_t status;
719
720 start_read:
721
722 if (logfile->fp)
723 {
724
725 status = fread(s, size, 1, logfile->fp);
726
727 if (status != 1)
728 {
729 if (ferror(logfile->fp))
730 {
731 char * tmp;
732 SH_MUTEX_LOCK(mutex_thread_nolog);
733 tmp = sh_util_safe_name (logfile->filename);
734 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_LOGMON_EREAD,
735 tmp);
736 SH_FREE(tmp);
737 SH_MUTEX_UNLOCK(mutex_thread_nolog);
738 }
739 fgetpos(logfile->fp, &(logfile->offset));
740 fclose(logfile->fp);
741 logfile->fp = NULL;
742 memset(s, '\0', size);
743 return NULL;
744 }
745 return s;
746 }
747
748 if (0 != sh_open_for_reader(logfile))
749 goto start_read;
750
751 return NULL;
752}
753
754
755
756/**********************************************************
757 *
758 * Utilities
759 *
760 **********************************************************/
761
762time_t conv_timestamp (struct tm * btime,
763 struct tm * old_tm, time_t * old_time)
764{
765 time_t timestamp;
766 long offtime;
767
768 /* timestamp - mktime is slooow, thus cache result
769 */
770 if (btime->tm_isdst == old_tm->tm_isdst &&
771 btime->tm_year == old_tm->tm_year &&
772 btime->tm_mon == old_tm->tm_mon &&
773 btime->tm_mday == old_tm->tm_mday)
774 {
775 offtime =
776 (btime->tm_hour - old_tm->tm_hour) * 3600 +
777 (btime->tm_min - old_tm->tm_min) * 60 +
778 (btime->tm_sec - old_tm->tm_sec);
779 *old_time += offtime;
780 memcpy(old_tm, btime, sizeof(struct tm));
781 timestamp = *old_time;
782 }
783 else
784 {
785 timestamp = mktime(btime);
786 *old_time = timestamp;
787 memcpy(old_tm, btime, sizeof(struct tm));
788 }
789 return timestamp;
790}
791
792/*********************************************************
793 *
794 * MODULE STUFF
795 *
796 *********************************************************/
797#include "sh_modules.h"
798
799SH_MUTEX_STATIC(mutex_logmon_check, PTHREAD_MUTEX_INITIALIZER);
800
801static int ShLogmonActive = S_FALSE;
802#define SH_LOGMON_INTERVAL 10
803static time_t sh_logmon_interval = SH_LOGMON_INTERVAL;
804
805int sh_log_check_init (struct mod_type * arg)
806{
807 if (ShLogmonActive == S_FALSE)
808 return SH_MOD_FAILED;
809#ifdef HAVE_PTHREAD
810 if (arg != NULL && arg->initval < 0 &&
811 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
812 {
813 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
814 return SH_MOD_THREAD;
815 else
816 return SH_MOD_FAILED;
817 }
818#endif
819 if (sh_watched_logs != NULL)
820 return 0;
821
822 return -1;
823}
824
825int sh_log_check_timer(time_t tcurrent)
826{
827 static time_t lastcheck = 0;
828
829 SL_ENTER(_("sh_log_check_timer"));
830 if ((time_t) (tcurrent - lastcheck) >= sh_logmon_interval)
831 {
832 lastcheck = tcurrent;
833 SL_RETURN((-1), _("sh_log_check_timer"));
834 }
835 SL_RETURN(0, _("sh_log_check_timer"));
836}
837
838
839int sh_log_check_check(void)
840{
841 int status = 0;
842
843 SL_ENTER(_("sh_log_check_check"));
844
845 SH_MUTEX_LOCK(mutex_logmon_check);
846
847 status = 0;
848
849 if( ShLogmonActive != S_FALSE )
850 {
851 sh_check_watches();
852 }
853 SH_MUTEX_UNLOCK(mutex_logmon_check);
854
855 SL_RETURN(status, _("sh_log_check_check"));
856}
857
858int sh_log_check_reconf(void)
859{
860 int status = 0;
861
862 SL_ENTER(_("sh_log_check_check"));
863
864 SH_MUTEX_LOCK(mutex_logmon_check);
865
866 ShLogmonActive = S_FALSE;
867 sh_logmon_interval = SH_LOGMON_INTERVAL;
868 sh_dump_watches();
869 sh_eval_cleanup();
870
871 SH_MUTEX_UNLOCK(mutex_logmon_check);
872
873 SL_RETURN(status, _("sh_log_check_check"));
874}
875
876int sh_log_check_cleanup(void)
877{
878 return sh_log_check_reconf();
879}
880
881/********************* OPTIONS **********************/
882
883static int sh_logmon_set_active (const char *str);
884static int sh_logmon_set_interval(const char *str);
885static int sh_logmon_add_watch (const char * str);
886static int sh_logmon_add_group (const char * str);
887static int sh_logmon_end_group (const char * str);
888static int sh_logmon_add_host (const char * str);
889static int sh_logmon_end_host (const char * str);
890static int sh_logmon_add_queue (const char * str);
891static int sh_logmon_add_rule (const char * str);
892extern int sh_set_hidepid(const char *s);
893
894sh_rconf sh_log_check_table[] = {
895 {
896 N_("logmonactive"),
897 sh_logmon_set_active,
898 },
899 {
900 N_("logmoninterval"),
901 sh_logmon_set_interval,
902 },
903 {
904 N_("logmonwatch"),
905 sh_logmon_add_watch,
906 },
907 {
908 N_("logmonqueue"),
909 sh_logmon_add_queue,
910 },
911 {
912 N_("logmongroup"),
913 sh_logmon_add_group,
914 },
915 {
916 N_("logmonendgroup"),
917 sh_logmon_end_group,
918 },
919 {
920 N_("logmonhost"),
921 sh_logmon_add_host,
922 },
923 {
924 N_("logmonendhost"),
925 sh_logmon_end_host,
926 },
927 {
928 N_("logmonrule"),
929 sh_logmon_add_rule,
930 },
931 {
932 N_("logmonhidepid"),
933 sh_set_hidepid,
934 },
935 {
936 NULL,
937 NULL
938 }
939};
940
941/* Decide if we're active.
942 */
943static int sh_logmon_set_active(const char *str)
944{
945 int value;
946
947 SL_ENTER(_("sh_logmon_set_active"));
948
949 value = sh_util_flagval(str, &ShLogmonActive);
950
951 SL_RETURN((value), _("sh_logmon_set_active"));
952}
953
954static int sh_logmon_set_interval (const char * c)
955{
956 int retval = 0;
957 long val;
958
959 SL_ENTER(_("sh_logmon_set_interval"));
960 val = strtol (c, (char **)NULL, 10);
961 if (val <= 0)
962 {
963 SH_MUTEX_LOCK(mutex_thread_nolog);
964 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
965 _("log monitoring interval"), c);
966 SH_MUTEX_UNLOCK(mutex_thread_nolog);
967 retval = -1;
968 }
969
970 sh_logmon_interval = (time_t) val;
971 SL_RETURN(0, _("sh_logmon_set_interval"));
972}
973
974/* Add a watch on a logfile.
975 * Format: TYPE : Filename [: File_Format]
976 */
977static int sh_logmon_add_watch (const char * str)
978{
979 return sh_add_watch(str);
980}
981
982/* Add a host.
983 * Format: Name_Regex
984 */
985static int sh_logmon_add_host (const char * str)
986{
987 return sh_eval_hadd(str);
988}
989
990/* End a host.
991 * Format: Name
992 */
993static int sh_logmon_end_host (const char * str)
994{
995 (void) str;
996 return sh_eval_hend(NULL);
997}
998
999/* Add a group of rules.
1000 * Groups can be under hosts, but not vice versa.
1001 * Format: Name : Prefix_Regex
1002 */
1003static int sh_logmon_add_group (const char * str)
1004{
1005 return sh_eval_gadd(str);
1006}
1007
1008/* End a group of rules.
1009 * Format: Name
1010 */
1011static int sh_logmon_end_group (const char * str)
1012{
1013 (void) str;
1014 return sh_eval_gend(NULL);
1015}
1016
1017/* Define a reporting queue.
1018 * Format: Label : [Interval] : TYPE : Severity
1019 * TYPE must be 'report' or 'sum'
1020 * Interval is ignored for TYPE='report'
1021 */
1022static int sh_logmon_add_queue (const char * str)
1023{
1024 return sh_eval_qadd(str);
1025}
1026
1027/* Define a check rule.
1028 * Format: Queue_Label : Regex
1029 * TYPE must be 'report' or 'sum'
1030 */
1031static int sh_logmon_add_rule (const char * str)
1032{
1033 return sh_eval_radd(str);
1034}
1035
1036
1037#if 0
1038
1039/* >>>>>>>>>>> MAIN <<<<<<<<<<<<<<<<<<< */
1040
1041int main (int argc, char * argv[])
1042{
1043 int status, i;
1044 FILE * fp;
1045 sh_string * s = NULL;
1046 static char template[] = "/tmp/xtest.XXXXXX";
1047
1048 /* pacct */
1049 status = sh_add_watch("PACCT:/var/log/account/pacct");
1050 sh_check_watches();
1051 sh_dump_watches();
1052 exit(0);
1053
1054 /* apache log */
1055 sh_eval_gadd("four_o_four:404");
1056 sh_eval_qadd("test:1:sum:7");
1057 sh_eval_radd("test:^(\\d+.\\d+.\\d+.\\d+).*");
1058 sh_eval_gend(NULL);
1059 sh_eval_radd("trash:.*");
1060 status = sh_add_watch("APACHE:/var/log/apache2/access.log:combined");
1061 sh_check_watches();
1062 sh_dump_watches();
1063 exit(0);
1064
1065 /* logfile */
1066 sh_set_hidepid(1);
1067 sh_eval_hadd("hslxmsrv1");
1068 sh_eval_gadd("postfix:postfix");
1069 sh_eval_qadd("test::report:7");
1070 sh_eval_radd("test:postfix/smtpd: disconnect from localhost.*");
1071 sh_eval_radd("trash:postfix/smtpd: disconnect.*");
1072 sh_eval_hadd("hspc05");
1073 sh_eval_gadd("cron:CRON");
1074 sh_eval_qadd("test:1:sum:7");
1075 sh_eval_radd("test:CRON: PAM adding faulty module: (/lib/security/.*.so)");
1076 sh_eval_radd("trash:.*");
1077 status = sh_add_watch("SYSLOG:/var/log/messages");
1078 sh_check_watches();
1079
1080 sh_dump_watches();
1081 exit(0);
1082
1083 printf("%d types\n",
1084 (int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type)));
1085
1086 /* test sh_add_watch
1087 */
1088 status = sh_add_watch("");
1089 printf("%2d: zero length, expect -1\n", status);
1090 status = sh_add_watch(NULL);
1091 printf("%2d: NULL, expect -2\n", status);
1092 status = sh_add_watch("0123456789012345:/var/log/messages");
1093 printf("%2d: long, expect -2\n", status);
1094 status = sh_add_watch("012345678901234:/var/log/messages");
1095 printf("%2d: exact length, expect -3\n", status);
1096 status = sh_add_watch("01234567890123:56789");
1097 printf("%2d: short length, expect -3\n", status);
1098 status = sh_add_watch("SYSLOG:var/log/messages");
1099 printf("%2d: short badpath, expect -4\n", status);
1100 status = sh_add_watch("SYSLOG:/var/log/messages");
1101 // status = sh_add_watch("SYSLOG:/var/log/dpkg.log.1");
1102 printf("%2d: short path ok, expect 0\n", status);
1103
1104 /* test sh_string_read
1105 */
1106 s = sh_string_new();
1107
1108 status = /*@i@*/mkstemp(template);
1109
1110 if (status < 0) {
1111 fprintf(stderr, "error in mkstemp!\n"); exit(EXIT_FAILURE); }
1112
1113 fp = fdopen(status, "r+");
1114 if (!fp) {
1115 fprintf(stderr, "error in fdopen!\n"); exit(EXIT_FAILURE); }
1116
1117 for (i = 0; i < 80; ++i) { fputc ('a', fp); } fputc ('\n', fp); // 0
1118 for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); // 1
1119 for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); // 2
1120 for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); // 3
1121 for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); // 4
1122 for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1123 for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1124 for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1125 for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1126
1127 rewind(fp);
1128
1129 for (i = 0; i < 9; ++i)
1130 {
1131 status = (int) sh_string_read(s, fp, 120);
1132 printf("%d: status = %d, len = %d, size = %d\n",
1133 i, status, (int)s->len, (int)s->siz);
1134 if (status == -2)
1135 (void) sh_string_read(s, fp, 240);
1136 else
1137 printf("%s\n", s->str);
1138 }
1139
1140 rewind(fp);
1141
1142 (void) sh_string_truncate(s, 0);
1143
1144 for (i = 0; i < 9; ++i)
1145 {
1146 status = (int) sh_string_read(s, fp, 240);
1147 printf("%d: status = %d, len = %d, size = %d\n",
1148 i, status, (int)s->len, (int)s->siz);
1149 if (status == -2)
1150 (void) sh_string_read(s, fp, 240);
1151 else
1152 {
1153 for (status = 0; status < (int)s->len; ++status)
1154 {
1155 if (s->str[status] != 'a')
1156 {
1157 break;
1158 }
1159 }
1160 printf("%d %s\n", status, s->str);
1161 }
1162 }
1163
1164 fclose(fp); remove(template);
1165
1166
1167
1168 return 0;
1169}
1170#endif
1171
1172/* #ifdef USE_LOGFILE_MONITOR */
1173#endif
1174
Note: See TracBrowser for help on using the repository browser.