source: trunk/src/sh_log_check.c@ 263

Last change on this file since 263 was 260, checked in by katerina, 15 years ago

Support event correlation (ticket #178).

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