source: trunk/src/sh_log_check.c@ 199

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

While we're at it, implement 'else' cor the config file conditionals. Also fix some compile warnings and improve docs.

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