source: trunk/src/sh_log_check.c@ 183

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

Support for logfile monitoring (ticket #122). Also improved some configure error messages.

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