source: trunk/src/sh_log_check.c@ 274

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

Fixes tickets #190, #191, #192, #193, and #194.

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