source: trunk/src/sh_log_check.c@ 258

Last change on this file since 258 was 257, checked in by katerina, 15 years ago

Fix for issues with debug code and testsuite (tickets #174, #175).

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 !defined(HAVE_PTHREAD)
814 (void) arg;
815#endif
816
817 if (ShLogmonActive == S_FALSE)
818 return SH_MOD_FAILED;
819#ifdef HAVE_PTHREAD
820 if (arg != NULL && arg->initval < 0 &&
821 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
822 {
823 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
824 return SH_MOD_THREAD;
825 else
826 return SH_MOD_FAILED;
827 }
828#endif
829 if (sh_watched_logs != NULL)
830 return 0;
831
832 return -1;
833}
834
835int sh_log_check_timer(time_t tcurrent)
836{
837 static time_t lastcheck = 0;
838
839 SL_ENTER(_("sh_log_check_timer"));
840 if ((time_t) (tcurrent - lastcheck) >= sh_logmon_interval)
841 {
842 lastcheck = tcurrent;
843 SL_RETURN((-1), _("sh_log_check_timer"));
844 }
845 SL_RETURN(0, _("sh_log_check_timer"));
846}
847
848
849int sh_log_check_check(void)
850{
851 int status = 0;
852
853 SL_ENTER(_("sh_log_check_check"));
854
855 SH_MUTEX_LOCK(mutex_logmon_check);
856
857 status = 0;
858
859 if( ShLogmonActive != S_FALSE )
860 {
861 sh_check_watches();
862 }
863 SH_MUTEX_UNLOCK(mutex_logmon_check);
864
865 SL_RETURN(status, _("sh_log_check_check"));
866}
867
868int sh_log_check_reconf(void)
869{
870 int status = 0;
871
872 SL_ENTER(_("sh_log_check_check"));
873
874 SH_MUTEX_LOCK(mutex_logmon_check);
875
876 ShLogmonActive = S_FALSE;
877 sh_logmon_interval = SH_LOGMON_INTERVAL;
878 sh_dump_watches();
879 sh_eval_cleanup();
880
881 SH_MUTEX_UNLOCK(mutex_logmon_check);
882
883 SL_RETURN(status, _("sh_log_check_check"));
884}
885
886int sh_log_check_cleanup(void)
887{
888 return sh_log_check_reconf();
889}
890
891/********************* OPTIONS **********************/
892
893static int sh_logmon_set_active (const char *str);
894static int sh_logmon_set_interval(const char *str);
895static int sh_logmon_add_watch (const char * str);
896static int sh_logmon_add_group (const char * str);
897static int sh_logmon_end_group (const char * str);
898static int sh_logmon_add_host (const char * str);
899static int sh_logmon_end_host (const char * str);
900static int sh_logmon_add_queue (const char * str);
901static int sh_logmon_add_rule (const char * str);
902extern int sh_set_hidepid(const char *s);
903
904sh_rconf sh_log_check_table[] = {
905 {
906 N_("logmonactive"),
907 sh_logmon_set_active,
908 },
909 {
910 N_("logmoninterval"),
911 sh_logmon_set_interval,
912 },
913 {
914 N_("logmonwatch"),
915 sh_logmon_add_watch,
916 },
917 {
918 N_("logmonqueue"),
919 sh_logmon_add_queue,
920 },
921 {
922 N_("logmongroup"),
923 sh_logmon_add_group,
924 },
925 {
926 N_("logmonendgroup"),
927 sh_logmon_end_group,
928 },
929 {
930 N_("logmonhost"),
931 sh_logmon_add_host,
932 },
933 {
934 N_("logmonendhost"),
935 sh_logmon_end_host,
936 },
937 {
938 N_("logmonrule"),
939 sh_logmon_add_rule,
940 },
941 {
942 N_("logmonhidepid"),
943 sh_set_hidepid,
944 },
945 {
946 NULL,
947 NULL
948 }
949};
950
951/* Decide if we're active.
952 */
953static int sh_logmon_set_active(const char *str)
954{
955 int value;
956
957 SL_ENTER(_("sh_logmon_set_active"));
958
959 value = sh_util_flagval(str, &ShLogmonActive);
960
961 SL_RETURN((value), _("sh_logmon_set_active"));
962}
963
964static int sh_logmon_set_interval (const char * c)
965{
966 int retval = 0;
967 long val;
968
969 SL_ENTER(_("sh_logmon_set_interval"));
970 val = strtol (c, (char **)NULL, 10);
971 if (val <= 0)
972 {
973 SH_MUTEX_LOCK(mutex_thread_nolog);
974 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
975 _("log monitoring interval"), c);
976 SH_MUTEX_UNLOCK(mutex_thread_nolog);
977 retval = -1;
978 }
979
980 sh_logmon_interval = (time_t) val;
981 SL_RETURN(0, _("sh_logmon_set_interval"));
982}
983
984/* Add a watch on a logfile.
985 * Format: TYPE : Filename [: File_Format]
986 */
987static int sh_logmon_add_watch (const char * str)
988{
989 return sh_add_watch(str);
990}
991
992/* Add a host.
993 * Format: Name_Regex
994 */
995static int sh_logmon_add_host (const char * str)
996{
997 return sh_eval_hadd(str);
998}
999
1000/* End a host.
1001 * Format: Name
1002 */
1003static int sh_logmon_end_host (const char * str)
1004{
1005 (void) str;
1006 return sh_eval_hend(NULL);
1007}
1008
1009/* Add a group of rules.
1010 * Groups can be under hosts, but not vice versa.
1011 * Format: Name : Prefix_Regex
1012 */
1013static int sh_logmon_add_group (const char * str)
1014{
1015 return sh_eval_gadd(str);
1016}
1017
1018/* End a group of rules.
1019 * Format: Name
1020 */
1021static int sh_logmon_end_group (const char * str)
1022{
1023 (void) str;
1024 return sh_eval_gend(NULL);
1025}
1026
1027/* Define a reporting queue.
1028 * Format: Label : [Interval] : TYPE : Severity
1029 * TYPE must be 'report' or 'sum'
1030 * Interval is ignored for TYPE='report'
1031 */
1032static int sh_logmon_add_queue (const char * str)
1033{
1034 return sh_eval_qadd(str);
1035}
1036
1037/* Define a check rule.
1038 * Format: Queue_Label : Regex
1039 * TYPE must be 'report' or 'sum'
1040 */
1041static int sh_logmon_add_rule (const char * str)
1042{
1043 return sh_eval_radd(str);
1044}
1045
1046
1047#if 0
1048
1049/* >>>>>>>>>>> MAIN <<<<<<<<<<<<<<<<<<< */
1050
1051int main (int argc, char * argv[])
1052{
1053 int status, i;
1054 FILE * fp;
1055 sh_string * s = NULL;
1056 static char template[] = "/tmp/xtest.XXXXXX";
1057
1058 /* pacct */
1059 status = sh_add_watch("PACCT:/var/log/account/pacct");
1060 sh_check_watches();
1061 sh_dump_watches();
1062 exit(0);
1063
1064 /* apache log */
1065 sh_eval_gadd("four_o_four:404");
1066 sh_eval_qadd("test:1:sum:7");
1067 sh_eval_radd("test:^(\\d+.\\d+.\\d+.\\d+).*");
1068 sh_eval_gend(NULL);
1069 sh_eval_radd("trash:.*");
1070 status = sh_add_watch("APACHE:/var/log/apache2/access.log:combined");
1071 sh_check_watches();
1072 sh_dump_watches();
1073 exit(0);
1074
1075 /* logfile */
1076 sh_set_hidepid(1);
1077 sh_eval_hadd("hslxmsrv1");
1078 sh_eval_gadd("postfix:postfix");
1079 sh_eval_qadd("test::report:7");
1080 sh_eval_radd("test:postfix/smtpd: disconnect from localhost.*");
1081 sh_eval_radd("trash:postfix/smtpd: disconnect.*");
1082 sh_eval_hadd("hspc05");
1083 sh_eval_gadd("cron:CRON");
1084 sh_eval_qadd("test:1:sum:7");
1085 sh_eval_radd("test:CRON: PAM adding faulty module: (/lib/security/.*.so)");
1086 sh_eval_radd("trash:.*");
1087 status = sh_add_watch("SYSLOG:/var/log/messages");
1088 sh_check_watches();
1089
1090 sh_dump_watches();
1091 exit(0);
1092
1093 printf("%d types\n",
1094 (int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type)));
1095
1096 /* test sh_add_watch
1097 */
1098 status = sh_add_watch("");
1099 printf("%2d: zero length, expect -1\n", status);
1100 status = sh_add_watch(NULL);
1101 printf("%2d: NULL, expect -2\n", status);
1102 status = sh_add_watch("0123456789012345:/var/log/messages");
1103 printf("%2d: long, expect -2\n", status);
1104 status = sh_add_watch("012345678901234:/var/log/messages");
1105 printf("%2d: exact length, expect -3\n", status);
1106 status = sh_add_watch("01234567890123:56789");
1107 printf("%2d: short length, expect -3\n", status);
1108 status = sh_add_watch("SYSLOG:var/log/messages");
1109 printf("%2d: short badpath, expect -4\n", status);
1110 status = sh_add_watch("SYSLOG:/var/log/messages");
1111 /* status = sh_add_watch("SYSLOG:/var/log/dpkg.log.1"); */
1112 printf("%2d: short path ok, expect 0\n", status);
1113
1114 /* test sh_string_read
1115 */
1116 s = sh_string_new();
1117
1118 status = /*@i@*/mkstemp(template);
1119
1120 if (status < 0) {
1121 fprintf(stderr, "error in mkstemp!\n"); exit(EXIT_FAILURE); }
1122
1123 fp = fdopen(status, "r+");
1124 if (!fp) {
1125 fprintf(stderr, "error in fdopen!\n"); exit(EXIT_FAILURE); }
1126
1127 for (i = 0; i < 80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
1128 for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
1129 for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
1130 for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
1131 for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
1132 for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1133 for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1134 for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1135 for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1136
1137 rewind(fp);
1138
1139 for (i = 0; i < 9; ++i)
1140 {
1141 status = (int) sh_string_read(s, fp, 120);
1142 printf("%d: status = %d, len = %d, size = %d\n",
1143 i, status, (int)s->len, (int)s->siz);
1144 if (status == -2)
1145 (void) sh_string_read(s, fp, 240);
1146 else
1147 printf("%s\n", s->str);
1148 }
1149
1150 rewind(fp);
1151
1152 (void) sh_string_truncate(s, 0);
1153
1154 for (i = 0; i < 9; ++i)
1155 {
1156 status = (int) sh_string_read(s, fp, 240);
1157 printf("%d: status = %d, len = %d, size = %d\n",
1158 i, status, (int)s->len, (int)s->siz);
1159 if (status == -2)
1160 (void) sh_string_read(s, fp, 240);
1161 else
1162 {
1163 for (status = 0; status < (int)s->len; ++status)
1164 {
1165 if (s->str[status] != 'a')
1166 {
1167 break;
1168 }
1169 }
1170 printf("%d %s\n", status, s->str);
1171 }
1172 }
1173
1174 sl_fclose(FIL__, __LINE__, fp); remove(template);
1175
1176
1177
1178 return 0;
1179}
1180#endif
1181
1182/* #ifdef USE_LOGFILE_MONITOR */
1183#endif
1184
Note: See TracBrowser for help on using the repository browser.