source: trunk/src/sh_log_check.c@ 254

Last change on this file since 254 was 252, checked in by katerina, 15 years ago

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

File size: 26.7 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) sl_fclose(FIL__, __LINE__, fd);
111 (void) remove(path);
112 }
113 else
114 {
115 (void) sl_fclose(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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 sl_fclose(FIL__, __LINE__, 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 sl_fclose(FIL__, __LINE__, 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 sl_fclose(FIL__, __LINE__, 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 sl_fclose(FIL__, __LINE__, 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 sl_fclose(FIL__, __LINE__, 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.