source: trunk/src/sh_log_evalrule.c@ 264

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

Fix for ticket #179, and some minor bugfixes.

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