source: trunk/src/sh_log_evalrule.c@ 279

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

Fix for bugs in log monitoring (tickets #196, #199), and allow shell command monitoring (ticket #197).

File size: 28.7 KB
Line 
1
2#include "config_xor.h"
3
4#include <stdio.h>
5#include <stdarg.h>
6#include <string.h>
7#include <ctype.h>
8#include <time.h>
9#include <limits.h>
10#include <sys/types.h>
11
12#ifdef USE_LOGFILE_MONITOR
13
14#undef FIL__
15#define FIL__ _("sh_log_evalrule.c")
16
17/* Debian/Ubuntu: libpcre3-dev */
18#ifdef HAVE_PCRE_PCRE_H
19#include <pcre/pcre.h>
20#else
21#include <pcre.h>
22#endif
23
24#ifndef PCRE_NO_AUTO_CAPTURE
25#define PCRE_NO_AUTO_CAPTURE 0
26#endif
27
28#include "samhain.h"
29#include "sh_pthread.h"
30#include "sh_utils.h"
31#include "sh_string.h"
32#include "sh_log_check.h"
33#include "sh_log_evalrule.h"
34#include "sh_log_correlate.h"
35#include "sh_log_mark.h"
36#include "sh_log_repeat.h"
37#include "zAVLTree.h"
38
39extern int flag_err_debug;
40
41/* #define DEBUG_EVALRULES */
42
43#ifdef DEBUG_EVALRULES
44static void DEBUG(const char *fmt, ...)
45{
46 va_list ap;
47 va_start(ap, fmt);
48 vfprintf(stderr, fmt, ap); /* flawfinder: ignore *//* we control fmt string */
49 va_end(ap);
50 return;
51}
52#else
53static void DEBUG(const char *fmt, ...)
54{
55 (void) fmt;
56 return;
57}
58#endif
59
60struct sh_ceval /* Counter for summarizing */
61{
62 sh_string * hostname;
63 sh_string * counted_str;
64 sh_string * filename;
65 unsigned long count;
66 time_t start;
67 time_t interval;
68};
69
70void sh_ceval_free(void * item)
71{
72 struct sh_ceval * counter = (struct sh_ceval *) item;
73 if (!counter)
74 return;
75 sh_string_destroy(&(counter->hostname));
76 sh_string_destroy(&(counter->counted_str));
77 sh_string_destroy(&(counter->filename));
78 SH_FREE(counter);
79}
80
81enum {
82 RFL_ISRULE = 1 << 0,
83 RFL_ISGROUP = 1 << 1,
84 RFL_KEEP = 1 << 2,
85 RFL_MARK = 1 << 3
86};
87
88
89/*--------------------------------------------------------------
90 *
91 * Adding rules/groups/hosts
92 *
93 *--------------------------------------------------------------*/
94
95struct sh_geval /* Group of rules (may be a single rule) */
96{
97 sh_string * label; /* label for this group */
98 pcre * rule; /* compiled regex for rule */
99 pcre_extra * rule_extra;
100 int * ovector; /* captured substrings */
101 int ovecnum; /* how many captured */
102 int captures; /* (captures+1)*3 required */
103 int flags; /* bit flags */
104 unsigned long delay; /* delay for keep rules */
105 zAVLTree * counterlist; /* counters if EVAL_SUM */
106 struct sh_qeval * queue; /* queue for this rule */
107 struct sh_geval * nextrule; /* next rule in this group */
108 struct sh_geval * next; /* next group of rules */
109 struct sh_geval * gnext; /* grouplist next */
110};
111
112struct sh_heval /* host-specific rules */
113{
114 pcre * hostname; /* compiled regex for hostname */
115 pcre_extra * hostname_extra;
116 struct sh_geval * rulegroups; /* list of group of rules */
117 struct sh_heval * next;
118};
119
120static struct sh_heval * hostlist = NULL;
121static struct sh_qeval * queuelist = NULL;
122static struct sh_geval * grouplist = NULL;
123
124/* These flags are set if we are within
125 * the define of a host/rule group.
126 */
127static struct sh_heval * host_open = NULL;
128static struct sh_geval * group_open = NULL;
129
130int sh_eval_gend (const char * str)
131{
132 (void) str;
133 if (group_open) {
134 group_open = NULL;
135 return 0;
136 }
137 return -1;
138}
139
140int sh_eval_gadd (const char * str)
141{
142 struct sh_geval * ng;
143 struct sh_geval * tmp;
144 pcre * group;
145 pcre_extra * group_extra;
146 const char * error;
147 int erroffset;
148 unsigned int nfields = 2;
149 size_t lengths[2];
150 char * new = sh_util_strdup(str);
151 char ** splits = split_array(new, &nfields, ':', lengths);
152
153 /* group is label:regex
154 */
155
156 if (group_open)
157 group_open = NULL;
158
159 if (nfields != 2)
160 {
161 SH_FREE(splits);
162 SH_FREE(new);
163 return -1;
164 }
165
166 group = pcre_compile(splits[1], PCRE_NO_AUTO_CAPTURE,
167 &error, &erroffset, NULL);
168 if (!group)
169 {
170 sh_string * msg = sh_string_new(0);
171 sh_string_add_from_char(msg, _("Bad regex: "));
172 sh_string_add_from_char(msg, splits[1]);
173
174 SH_MUTEX_LOCK(mutex_thread_nolog);
175 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
176 sh_string_str(msg),
177 _("sh_eval_gadd"));
178 SH_MUTEX_UNLOCK(mutex_thread_nolog);
179 sh_string_destroy(&msg);
180
181 SH_FREE(splits);
182 SH_FREE(new);
183 return -1;
184 }
185 group_extra = NULL; /* pcre_study(group, 0, &error); */
186
187 ng = SH_ALLOC(sizeof(struct sh_geval));
188 ng->label = sh_string_new_from_lchar(splits[0], lengths[0]);
189 ng->flags = RFL_ISGROUP;
190
191 ng->rule = group;
192 ng->rule_extra = group_extra;
193 ng->ovector = NULL;
194 ng->ovecnum = 0;
195 ng->captures = 0;
196 ng->counterlist = NULL;
197 ng->queue = NULL;
198 ng->nextrule = NULL;
199 ng->next = NULL;
200 ng->gnext = NULL;
201
202 if (!host_open)
203 {
204 if (0 != sh_eval_hadd("^.*"))
205 {
206 pcre_free(group);
207 sh_string_destroy(&(ng->label));
208 SH_FREE(splits);
209 SH_FREE(new);
210 SH_FREE(ng);
211 return -1;
212 }
213 }
214
215 /*
216 * Insert at end, to keep user-defined order
217 */
218
219 if (host_open)
220 {
221 if (grouplist)
222 {
223 tmp = grouplist;
224 while (tmp->gnext != NULL) { tmp = tmp->gnext; }
225 tmp->gnext = ng;
226 } else {
227 grouplist = ng;
228 }
229
230
231 /*
232 * If there is an open host group, add it to its
233 * rulegroups
234 */
235
236 if (host_open->rulegroups)
237 {
238 tmp = host_open->rulegroups;
239 while (tmp->next != NULL) { tmp = tmp->next; }
240 tmp->next = ng;
241 } else {
242 host_open->rulegroups = ng;
243 }
244 }
245
246 group_open = ng;
247 SH_FREE(splits);
248 SH_FREE(new);
249 return 0;
250}
251
252int sh_eval_hend (const char * str)
253{
254 (void) str;
255 if (host_open) {
256 host_open = NULL;
257 return 0;
258 }
259 return -1;
260}
261
262int sh_eval_hadd (const char * str)
263{
264 struct sh_heval * nh;
265 struct sh_heval * tmp;
266 pcre * host;
267 pcre_extra * host_extra;
268 const char * error;
269 int erroffset;
270
271 if (host_open)
272 host_open = NULL;
273
274 host = pcre_compile(str, PCRE_NO_AUTO_CAPTURE,
275 &error, &erroffset, NULL);
276 if (!host)
277 {
278 sh_string * msg = sh_string_new(0);
279 sh_string_add_from_char(msg, _("Bad regex: "));
280 sh_string_add_from_char(msg, str);
281
282 SH_MUTEX_LOCK(mutex_thread_nolog);
283 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
284 sh_string_str(msg),
285 _("sh_eval_hadd"));
286 SH_MUTEX_UNLOCK(mutex_thread_nolog);
287 sh_string_destroy(&msg);
288
289 return -1;
290 }
291 host_extra = NULL; /* pcre_study(host, 0, &error); */
292
293 nh = SH_ALLOC(sizeof(struct sh_heval));
294 nh->hostname = host;
295 nh->hostname_extra = host_extra;
296 nh->rulegroups = NULL;
297
298 /*
299 * Insert at end, to keep user-defined order
300 */
301 nh->next = NULL;
302 if (hostlist) {
303 tmp = hostlist;
304 while (tmp->next != NULL) { tmp = tmp->next; }
305 tmp->next = nh;
306 } else {
307 hostlist = nh;
308 }
309 host_open = nh;
310
311 return 0;
312}
313
314int sh_eval_qadd (const char * str)
315{
316 struct sh_qeval * nq;
317 int severity;
318 unsigned int nfields = 5; /* label:interval:(report|sum):severity[:alias] */
319 size_t lengths[5];
320 char * new = sh_util_strdup(str);
321 char ** splits = split_array(new, &nfields, ':', lengths);
322
323 if (nfields < 4)
324 {
325 SH_FREE(splits);
326 SH_FREE(new);
327 return -1;
328 }
329
330 if (strcmp(splits[2], _("sum")) && strcmp(splits[2], _("report")))
331 {
332 SH_FREE(splits);
333 SH_FREE(new);
334 return -1;
335 }
336
337 if (!strcmp(splits[2], _("sum")) && atoi(splits[1]) < 0)
338 {
339 SH_FREE(splits);
340 SH_FREE(new);
341 return -1;
342 }
343
344 if (!strcmp(splits[1], _("trash"))) /* predefined, reserved */
345 {
346 SH_FREE(splits);
347 SH_FREE(new);
348 return -1;
349 }
350
351 severity = sh_error_convert_level (splits[3]);
352 if (severity < 0)
353 {
354 SH_FREE(splits);
355 SH_FREE(new);
356 return -1;
357 }
358
359 nq = SH_ALLOC(sizeof(struct sh_qeval));
360 nq->label = sh_string_new_from_lchar(splits[0], lengths[0]);
361 nq->alias = NULL;
362
363 DEBUG("debug: splits[2] = %s, policy = %d\n",splits[2],nq->policy);
364 if (0 == strcmp(splits[2], _("report"))) {
365 nq->policy = EVAL_REPORT;
366 nq->interval = 0;
367 }
368 else {
369 nq->policy = EVAL_SUM;
370 nq->interval = (time_t) atoi(splits[1]);
371 }
372
373 nq->severity = severity;
374
375 if (nfields == 5)
376 {
377 nq->alias = sh_string_new_from_lchar(splits[4], lengths[4]);
378 }
379
380 nq->next = queuelist;
381 queuelist = nq;
382
383 SH_FREE(splits);
384 SH_FREE(new);
385 return 0;
386}
387
388struct sh_qeval * sh_log_find_queue(const char * str)
389{
390 struct sh_qeval * retval = queuelist;
391
392 if (!str)
393 return NULL;
394
395 while (retval)
396 {
397 if (0 == strcmp(str, sh_string_str(retval->label)))
398 break;
399 retval = retval->next;
400 }
401 return retval;
402}
403
404int sh_log_lookup_severity(const char * str)
405{
406 struct sh_qeval * queue;
407
408 if (str)
409 {
410 if (0 != strcmp(str, _("trash")))
411 {
412 queue = sh_log_find_queue(str);
413
414 if (queue)
415 return queue->severity;
416 }
417 }
418 return SH_ERR_SEVERE;
419}
420
421sh_string * sh_log_lookup_alias(const char * str)
422{
423 struct sh_qeval * queue;
424
425 if (str)
426 {
427 if (0 != strcmp(str, _("trash")))
428 {
429 queue = sh_log_find_queue(str);
430
431 if (queue)
432 return queue->alias;
433 }
434 }
435 return NULL;
436}
437
438
439static char * get_label_and_time(const char * inprefix, char * str,
440 unsigned long * seconds)
441{
442 char * res = NULL;
443 char * endptr = NULL;
444
445 unsigned int nfields = 2; /* seconds:label */
446 size_t lengths[2];
447 char * prefix = sh_util_strdup(inprefix);
448 char * new = sh_util_strdup(str);
449 char ** splits = split_array_braced(new, prefix, &nfields, lengths);
450
451 if (splits && nfields == 2 && lengths[0] > 0 && lengths[1] > 0)
452 {
453 *seconds = strtoul(splits[0], &endptr, 10);
454 if ((endptr == '\0' || endptr != splits[0]) && (*seconds != ULONG_MAX))
455 {
456 res = sh_util_strdup(splits[1]);
457 }
458 }
459 if (splits)
460 SH_FREE(splits);
461 SH_FREE(new);
462 SH_FREE(prefix);
463 return res;
464}
465
466static struct sh_qeval ** dummy_queue;
467static char ** dummy_dstr;
468
469int sh_eval_radd (const char * str)
470{
471 struct sh_geval * nr;
472 struct sh_geval * tmp;
473 struct sh_qeval * queue = NULL;
474 pcre * rule;
475 pcre_extra * rule_extra;
476 const char * error;
477 int erroffset;
478 int captures = 0;
479 unsigned int nfields = 2; /* queue:regex */
480 size_t lengths[3];
481 char * new = sh_util_strdup(str);
482 char ** splits;
483
484 int qpos = 0;
485 volatile int rpos = 1;
486 unsigned long dsec = 0;
487 char * dstr = NULL;
488 char * s = new;
489 volatile char pflag = '-';
490
491 while ( *s && isspace((int)*s) ) ++s;
492 if (0 == strncmp(s, _("KEEP"), 4) ||
493 0 == strncmp(s, _("CORRELATE"), 9) ||
494 0 == strncmp(s, _("MARK"), 4))
495 {
496 pflag = s[0];
497 nfields = 3;
498 }
499
500 splits = split_array(new, &nfields, ':', lengths);
501
502 dummy_queue = &queue;
503 dummy_dstr = &dstr;
504
505 if (nfields < 2 || nfields > 3)
506 {
507 SH_FREE(splits);
508 SH_FREE(new);
509 return -1;
510 }
511
512 if (nfields == 3)
513 {
514 if (pflag == 'K')
515 {
516 /* KEEP(nsec,label):queue:regex
517 */
518 dstr = get_label_and_time(_("KEEP"), splits[0], &dsec);
519 if (!dstr)
520 {
521 SH_FREE(splits);
522 SH_FREE(new);
523 return -1;
524 }
525 }
526 else if (pflag == 'C')
527 {
528 /* CORRELATE(description):queue:regex
529 */
530 int retval = sh_keep_match_add(splits[0], splits[1], splits[2]);
531 SH_FREE(splits);
532 SH_FREE(new);
533 return retval;
534 }
535 else if (pflag == 'M')
536 {
537 /* MARK(description, interval):queue:regex
538 */
539 int retval = -1;
540
541 dstr = get_label_and_time(_("MARK"), splits[0], &dsec);
542 if (dstr)
543 {
544 retval = sh_log_mark_add(dstr, dsec, splits[1]);
545 }
546 if (retval != 0)
547 {
548 SH_FREE(splits);
549 SH_FREE(new);
550 return retval;
551 }
552 }
553 ++qpos; ++rpos;
554 }
555
556 if (0 != strcmp(splits[qpos], _("trash")))
557 {
558 queue = sh_log_find_queue(splits[qpos]);
559 if (!queue)
560 {
561 SH_FREE(splits);
562 SH_FREE(new);
563 return -1;
564 }
565 }
566
567 rule = pcre_compile(splits[rpos], 0,
568 &error, &erroffset, NULL);
569 if (!rule)
570 {
571 sh_string * msg = sh_string_new(0);
572 sh_string_add_from_char(msg, _("Bad regex: "));
573 sh_string_add_from_char(msg, splits[rpos]);
574
575 SH_MUTEX_LOCK(mutex_thread_nolog);
576 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
577 sh_string_str(msg),
578 _("sh_eval_radd"));
579 SH_MUTEX_UNLOCK(mutex_thread_nolog);
580 sh_string_destroy(&msg);
581
582 SH_FREE(splits);
583 SH_FREE(new);
584 return -1;
585 }
586 rule_extra = NULL; /* pcre_study(rule, 0, &error); */
587 pcre_fullinfo(rule, rule_extra, PCRE_INFO_CAPTURECOUNT, &captures);
588
589 if (flag_err_debug == SL_TRUE)
590 {
591 char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
592 if (dstr)
593 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures, keep(%lu,%s)"),
594 splits[rpos], captures, dsec, dstr);
595 else
596 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures"),
597 splits[rpos], captures);
598 SH_MUTEX_LOCK(mutex_thread_nolog);
599 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
600 emsg, _("sh_eval_radd"));
601 SH_MUTEX_UNLOCK(mutex_thread_nolog);
602 SH_FREE(emsg);
603 }
604
605 DEBUG("adding rule: |%s| with %d captures\n", splits[rpos], captures);
606
607 SH_FREE(splits);
608 SH_FREE(new);
609
610 nr = SH_ALLOC(sizeof(struct sh_geval));
611 nr->label = NULL;
612 nr->flags = RFL_ISRULE;
613 nr->delay = 0;
614
615 nr->rule = rule;
616 nr->rule_extra = rule_extra;
617 nr->captures = captures;
618 nr->ovector = SH_ALLOC(sizeof(int) * (captures+1) * 3);
619 nr->ovecnum = 0;
620 nr->counterlist = NULL;
621 nr->queue = queue;
622 nr->nextrule = NULL;
623 nr->next = NULL;
624 nr->gnext = NULL;
625
626
627 if (pflag == 'K')
628 {
629 nr->label = sh_string_new_from_lchar(dstr, strlen(dstr));
630 nr->flags |= RFL_KEEP;
631 nr->delay = dsec;
632 SH_FREE(dstr);
633 }
634 else if (pflag == 'M')
635 {
636 nr->label = sh_string_new_from_lchar(dstr, strlen(dstr));
637 nr->flags |= RFL_MARK;
638 nr->delay = dsec;
639 SH_FREE(dstr);
640 }
641
642 /*
643 * If there is an open group, add it to its
644 * rules
645 */
646 if (group_open)
647 {
648 if (flag_err_debug == SL_TRUE)
649 {
650 char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
651 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Adding rule to group |%s|"),
652 sh_string_str(group_open->label));
653 SH_MUTEX_LOCK(mutex_thread_nolog);
654 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
655 emsg, _("sh_eval_radd"));
656 SH_MUTEX_UNLOCK(mutex_thread_nolog);
657 SH_FREE(emsg);
658 }
659
660 DEBUG("adding rule to group |%s|\n", sh_string_str(group_open->label));
661
662 if (group_open->nextrule)
663 {
664 tmp = group_open->nextrule;
665 while (tmp->nextrule != NULL) { tmp = tmp->nextrule; } /* next -> nextrule */
666 tmp->nextrule = nr; /* next -> nextrule */
667 } else {
668 group_open->nextrule = nr;
669 }
670 }
671
672 /*
673 * ..else, add it to the currently open host (open the
674 * default host, if there is no open one)
675 */
676 else
677 {
678 if (!host_open)
679 {
680 if (0 != sh_eval_hadd("^.*"))
681 {
682 if (nr->label)
683 sh_string_destroy(&(nr->label));
684 SH_FREE(nr->ovector);
685 SH_FREE(nr);
686 return -1;
687 }
688 }
689
690 if (host_open)
691 {
692 /*
693 * Add rule as member to grouplist, to facilitate cleanup
694 */
695
696 DEBUG("adding solitary rule to grouplist\n");
697
698 if (grouplist)
699 {
700 tmp = grouplist;
701 while (tmp->gnext != NULL) { tmp = tmp->gnext; }
702 tmp->gnext = nr;
703 } else {
704 grouplist = nr;
705 }
706
707
708 /*
709 * Add rule to host rulegroups
710 */
711 DEBUG("adding solitary rule to host rulegroups\n");
712
713 if (host_open->rulegroups)
714 {
715 /* Second, third, ... rule go to host_open->rulegroups->next,
716 * since test_grules() iterates over nextrules
717 */
718 tmp = host_open->rulegroups;
719 while (tmp->next != NULL) { tmp = tmp->next; }
720 tmp->next = nr;
721 }
722 else
723 {
724 /* First rule goes to host_open->rulegroups */
725 host_open->rulegroups = nr;
726 }
727 }
728 else
729 {
730 if (nr->label)
731 sh_string_destroy(&(nr->label));
732 SH_FREE(nr->ovector);
733 SH_FREE(nr);
734 return -1;
735 }
736 }
737
738 return 0;
739}
740
741void sh_eval_cleanup()
742{
743 struct sh_geval * gtmp;
744 struct sh_qeval * qtmp;
745 struct sh_heval * htmp;
746
747 while (grouplist)
748 {
749 gtmp = grouplist;
750 grouplist = gtmp->gnext;
751
752 if (gtmp->label) sh_string_destroy(&(gtmp->label));
753 if (gtmp->rule_extra) (*pcre_free)(gtmp->rule_extra);
754 if (gtmp->rule) (*pcre_free)(gtmp->rule);
755 if (gtmp->counterlist)
756 zAVLFreeTree(gtmp->counterlist, sh_ceval_free);
757 if (gtmp->ovector)
758 SH_FREE(gtmp->ovector);
759#if 0
760 while (gtmp->nextrule)
761 {
762 tmp = gtmp->nextrule;
763 gtmp->nextrule = tmp->nextrule;
764
765 if (tmp->rule_extra) (*pcre_free)(tmp->rule_extra);
766 if (tmp->rule) (*pcre_free)(tmp->rule);
767 if (tmp->counterlist)
768 zAVLFreeTree(tmp->counterlist, sh_ceval_free);
769 if (tmp->ovector)
770 SH_FREE(tmp->ovector);
771 SH_FREE(tmp);
772 }
773#endif
774 SH_FREE(gtmp);
775 }
776
777 qtmp = queuelist;
778 while (qtmp)
779 {
780 if (qtmp->label) sh_string_destroy(&(qtmp->label));
781 queuelist = qtmp->next;
782 SH_FREE(qtmp);
783 qtmp = queuelist;
784 }
785
786 htmp = hostlist;
787 while (htmp)
788 {
789 if (htmp->hostname_extra) (*pcre_free)(htmp->hostname_extra);
790 if (htmp->hostname) (*pcre_free)(htmp->hostname);
791 hostlist = htmp->next;
792 SH_FREE(htmp);
793 htmp = hostlist;
794 }
795
796 sh_keep_destroy();
797 sh_keep_match_del();
798
799 return;
800}
801
802/**********************************************************************
803 *
804 * Actual rule processing
805 *
806 **********************************************************************/
807
808/* Test a list of rules against msg; return matched rule, with ovector
809 * filled in
810 */
811static struct sh_geval ** dummy1;
812
813static struct sh_geval * test_rule (struct sh_geval * rule, sh_string *msg, time_t tstamp)
814{
815 int res;
816 volatile int count;
817 volatile time_t timestamp = tstamp;
818
819 dummy1 = &rule;
820
821 if (!rule)
822 DEBUG("debug: (NULL) rule\n");
823
824 if (rule && sh_string_len(msg) < (size_t)INT_MAX)
825 {
826 count = 1;
827 do {
828
829 if (flag_err_debug == SL_TRUE)
830 {
831 char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
832 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Check rule %d for |%s|"),
833 count, sh_string_str(msg));
834 SH_MUTEX_LOCK(mutex_thread_nolog);
835 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
836 emsg, _("test_rule"));
837 SH_MUTEX_UNLOCK(mutex_thread_nolog);
838 SH_FREE(emsg);
839 }
840
841 DEBUG("debug: check rule %d for <%s>\n", count, msg->str);
842 res = pcre_exec(rule->rule, rule->rule_extra,
843 sh_string_str(msg), (int)sh_string_len(msg), 0,
844 0, rule->ovector, (3*(1+rule->captures)));
845 if (res >= 0)
846 {
847 rule->ovecnum = res;
848
849 if (flag_err_debug == SL_TRUE)
850 {
851 char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
852 if ( rule->flags & RFL_KEEP )
853 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d matches, result = %d (keep)"),
854 count, res);
855 else if ( rule->flags & RFL_MARK )
856 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d matches, result = %d (mark)"),
857 count, res);
858 else
859 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d matches, result = %d"),
860 count, res);
861 SH_MUTEX_LOCK(mutex_thread_nolog);
862 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
863 emsg, _("test_rule"));
864 SH_MUTEX_UNLOCK(mutex_thread_nolog);
865 SH_FREE(emsg);
866 }
867
868 if ( rule->flags & RFL_KEEP )
869 {
870 DEBUG("debug: rule %d matches (keep)\n", count);
871 sh_keep_add(rule->label, rule->delay,
872 timestamp == 0 ? time(NULL) : timestamp);
873 }
874
875 else if ( rule->flags & RFL_MARK )
876 {
877 DEBUG("debug: rule %d matches (mark)\n", count);
878 sh_log_mark_update(rule->label,
879 timestamp == 0 ? time(NULL) : timestamp);
880 }
881
882 break; /* return the matching rule; ovector is filled in */
883 }
884
885 if (flag_err_debug == SL_TRUE)
886 {
887 char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
888 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d did not match"),
889 count);
890 SH_MUTEX_LOCK(mutex_thread_nolog);
891 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
892 emsg, _("test_rule"));
893 SH_MUTEX_UNLOCK(mutex_thread_nolog);
894 SH_FREE(emsg);
895 }
896 DEBUG("debug: rule %d did not match\n", count);
897
898 rule = rule->nextrule; ++count;
899 } while (rule);
900 }
901 if (!rule)
902 DEBUG("debug: no match found\n");
903 /* If there was no match, this is NULL */
904 return rule;
905}
906
907/* Test a (struct sh_geval *), which may be single rule or a group of rules,
908 * against msg
909 */
910static struct sh_geval ** dummy2;
911static struct sh_geval ** dummy3;
912
913static struct sh_geval * test_grules (struct sh_heval * host,
914 sh_string * msg,
915 time_t timestamp)
916{
917 struct sh_geval * result = NULL;
918 struct sh_geval * group = host->rulegroups;
919
920 dummy2 = &result;
921 dummy3 = &group;
922
923 if (group && sh_string_len(msg) < (size_t)INT_MAX)
924 {
925 DEBUG("debug: if group\n");
926 do {
927 if( (group->label != NULL) && (0 != (group->flags & RFL_ISGROUP)))
928 {
929 /* this is a rule group */
930
931 if (flag_err_debug == SL_TRUE)
932 {
933 char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
934 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Checking group |%s| of rules against |%s|"),
935 sh_string_str(group->label), sh_string_str(msg));
936 SH_MUTEX_LOCK(mutex_thread_nolog);
937 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
938 emsg, _("test_rule"));
939 SH_MUTEX_UNLOCK(mutex_thread_nolog);
940 SH_FREE(emsg);
941 }
942
943 DEBUG("debug: if group->label %s\n", sh_string_str(group->label));
944 if (pcre_exec(group->rule, group->rule_extra,
945 sh_string_str(msg), (int) sh_string_len(msg),
946 0, 0, NULL, 0) >= 0)
947 {
948 result = test_rule(group->nextrule, msg, timestamp);
949 if (result)
950 break;
951 }
952 }
953 else
954 {
955 /* If there is no group label, the 'group' is actually a solitary
956 * rule (not within any group).
957 */
958
959 if (flag_err_debug == SL_TRUE)
960 {
961 char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
962 sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Checking solitary rules"));
963 SH_MUTEX_LOCK(mutex_thread_nolog);
964 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
965 emsg, _("test_rule"));
966 SH_MUTEX_UNLOCK(mutex_thread_nolog);
967 SH_FREE(emsg);
968 }
969
970 DEBUG("debug: else (single rule)\n");
971 result = test_rule(group, msg, timestamp);
972 if (result)
973 break;
974 }
975 group = group->next; /* next group of rules */
976 } while (group);
977 }
978 return result;
979}
980
981/* Top-level find_rule() function
982 */
983static struct sh_geval * find_rule (sh_string *host,
984 sh_string *msg,
985 time_t timestamp)
986{
987 struct sh_geval * result = NULL;
988 struct sh_heval * hlist = hostlist;
989
990 if (hlist && sh_string_len(host) < (size_t)INT_MAX)
991 {
992 do {
993 if (pcre_exec(hlist->hostname, hlist->hostname_extra,
994 sh_string_str(host), (int) sh_string_len(host),
995 0, 0, NULL, 0) >= 0)
996 {
997 /* matching host, check rules/groups of rules */
998 result = test_grules(hlist, msg, timestamp);
999 if (result)
1000 break;
1001 }
1002 hlist = hlist->next;
1003 } while (hlist);
1004 }
1005 return result;
1006}
1007
1008/* copy the message and replace captured substrings with '___'
1009 */
1010static sh_string * replace_captures(const sh_string * message,
1011 int * ovector, int ovecnum)
1012{
1013 sh_string * retval = sh_string_new_from_lchar(sh_string_str(message),
1014 sh_string_len(message));
1015
1016 if (ovecnum > 1)
1017 {
1018 retval = sh_string_replace(retval, &(ovector[2]), (ovecnum-1), "___", 3);
1019 }
1020 return retval;
1021}
1022
1023static void msg_report(int severity, const sh_string * alias,
1024 struct sh_geval * rule, struct sh_logrecord * record)
1025{
1026 char * tmp;
1027 char * msg;
1028 sh_string * mmm = NULL;
1029 char * ttt;
1030
1031
1032 SH_MUTEX_LOCK(mutex_thread_nolog);
1033 if (rule) {
1034 mmm = replace_captures(record->message, rule->ovector,
1035 rule->ovecnum);
1036 msg = sh_util_safe_name_keepspace (sh_string_str(mmm));
1037 }
1038 else {
1039 msg = sh_util_safe_name_keepspace (sh_string_str(record->message));
1040 }
1041 tmp = sh_util_safe_name_keepspace (record->filename);
1042 ttt = sh_util_safe_name_keepspace (sh_string_str(record->timestr));
1043 sh_error_handle (severity, FIL__, __LINE__, 0, MSG_LOGMON_REP,
1044 msg,
1045 ttt,
1046 sh_string_str(record->host),
1047 tmp);
1048 if (alias)
1049 {
1050 sh_error_mail (sh_string_str(alias),
1051 severity, FIL__, __LINE__, 0, MSG_LOGMON_REP,
1052 msg,
1053 ttt,
1054 sh_string_str(record->host),
1055 tmp);
1056 }
1057 SH_FREE(ttt);
1058 SH_FREE(msg);
1059 SH_FREE(tmp);
1060 if (mmm)
1061 sh_string_destroy(&mmm);
1062 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1063}
1064
1065static void sum_report(int severity, const sh_string * alias,
1066 sh_string * host, sh_string * message, sh_string * path)
1067{
1068 char * tmp;
1069 char * msg;
1070
1071 SH_MUTEX_LOCK(mutex_thread_nolog);
1072 tmp = sh_util_safe_name_keepspace (sh_string_str(path));
1073 msg = sh_util_safe_name_keepspace (sh_string_str(message));
1074 sh_error_handle (severity, FIL__, __LINE__, 0, MSG_LOGMON_SUM,
1075 msg,
1076 sh_string_str(host),
1077 tmp);
1078 if (alias)
1079 {
1080 sh_error_mail (sh_string_str(alias),
1081 severity, FIL__, __LINE__, 0, MSG_LOGMON_SUM,
1082 msg,
1083 sh_string_str(host),
1084 tmp);
1085 }
1086 SH_FREE(msg);
1087 SH_FREE(tmp);
1088 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1089}
1090
1091static zAVLKey sh_eval_getkey(void const *item)
1092{
1093 return ((struct sh_ceval *)item)->hostname->str;
1094}
1095
1096/* Find the counter, or initialize one if there is none already
1097 */
1098static struct sh_ceval * find_counter(struct sh_geval * rule,
1099 sh_string * host, time_t interval)
1100{
1101 struct sh_ceval * counter;
1102
1103 if (!(rule->counterlist))
1104 {
1105 DEBUG("debug: allocate new counterlist AVL tree\n");
1106 rule->counterlist = zAVLAllocTree(sh_eval_getkey);
1107 }
1108
1109 counter = (struct sh_ceval *) zAVLSearch (rule->counterlist,
1110 sh_string_str(host));
1111
1112 if (!counter)
1113 {
1114 DEBUG("debug: no counter found\n");
1115
1116 counter = SH_ALLOC(sizeof(struct sh_ceval));
1117 counter->hostname = sh_string_new_from_lchar(sh_string_str(host),
1118 sh_string_len(host));
1119 counter->counted_str = NULL;
1120 counter->filename = NULL;
1121 counter->count = 0;
1122 counter->start = time(NULL);
1123 counter->interval = interval;
1124
1125 zAVLInsert(rule->counterlist, counter);
1126 }
1127 return counter;
1128
1129}
1130
1131
1132/* process the counter for a SUM rule
1133 */
1134static int process_counter(struct sh_ceval * counter,
1135 struct sh_geval * rule, struct sh_logrecord * record)
1136{
1137 int retval = -1;
1138 time_t now;
1139
1140 if (!(counter->counted_str))
1141 {
1142 counter->counted_str = replace_captures(record->message, rule->ovector,
1143 rule->ovecnum);
1144 counter->filename = sh_string_new_from_lchar(record->filename,
1145 strlen(record->filename));
1146 DEBUG("debug: counted_str after replace: %s\n",
1147 sh_string_str(counter->counted_str));
1148 }
1149
1150 ++(counter->count);
1151 now = time(NULL); now -= counter->start;
1152 DEBUG("debug: count %lu, interval %lu, time %lu\n",
1153 counter->count, counter->interval, now);
1154 if (now >= counter->interval)
1155 {
1156 DEBUG("debug: report count\n");
1157 sum_report(rule->queue->severity, rule->queue->alias,
1158 counter->hostname, counter->counted_str, counter->filename);
1159 counter->start = time(NULL);
1160 counter->count = 0;
1161 }
1162 return retval;
1163}
1164
1165/* Process a rule
1166 */
1167static int process_rule(struct sh_geval * rule, struct sh_logrecord * record)
1168{
1169 int retval = -1;
1170 struct sh_qeval * queue = rule->queue;
1171
1172 if (queue)
1173 {
1174 DEBUG("debug: queue policy = %d found\n", queue->policy);
1175 if (queue->policy == EVAL_REPORT)
1176 {
1177 DEBUG("debug: EVAL_REPORT host: %s, message: %s\n",
1178 sh_string_str(record->host),
1179 sh_string_str(record->message));
1180 msg_report(queue->severity, queue->alias, rule, record);
1181 retval = 0;
1182 }
1183 else if (queue->policy == EVAL_SUM)
1184 {
1185
1186 struct sh_ceval * counter =
1187 find_counter(rule, record->host, queue->interval);
1188 DEBUG("debug: EVAL_SUM host: %s, message: %s\n",
1189 sh_string_str(record->host),
1190 sh_string_str(record->message));
1191 if (counter)
1192 {
1193 DEBUG("debug: counter found\n");
1194 retval = process_counter(counter, rule, record);
1195 }
1196 }
1197 }
1198 else
1199 {
1200 DEBUG("debug: no queue found -- trash\n");
1201 /* No queue means 'trash' */
1202 retval = 0;
1203 }
1204 return retval;
1205}
1206
1207#define DEFAULT_SEVERITY (-1)
1208
1209int sh_eval_process_msg(struct sh_logrecord * record)
1210{
1211 static unsigned long i = 0;
1212 if (record)
1213 {
1214 struct sh_geval * rule = find_rule (record->host,
1215 record->message,
1216 record->timestamp);
1217
1218 if (rule)
1219 {
1220 DEBUG("debug: (%lu) rule found\n", i); ++i;
1221 return process_rule(rule, record);
1222 }
1223 else
1224 {
1225 DEBUG("debug: (%lu) no rule found\n", i); ++i;
1226 msg_report(DEFAULT_SEVERITY, NULL, NULL, record);
1227 }
1228
1229 sh_repeat_message_check(record->host,
1230 record->message,
1231 record->timestamp);
1232
1233 return 0;
1234 }
1235 return -1;
1236}
1237
1238#endif
Note: See TracBrowser for help on using the repository browser.