source: trunk/src/sh_log_check.c@ 275

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

Fix for ticket #195 (broken immediate mailing of highest priority messages).

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