source: trunk/src/sh_log_check.c@ 225

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

Fix compile failures on RHEL3 (ticket #130) and FreeBSD7 amd64 (ticket #131).

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