source: trunk/src/sh_log_evalrule.c@ 397

Last change on this file since 397 was 383, checked in by katerina, 13 years ago

Fix for ticket #281 (warnings from clang static analyzer).

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