source: trunk/src/sh_log_evalrule.c@ 572

Last change on this file since 572 was 541, checked in by katerina, 6 years ago

Fix for ticket #433 (coding standardisation).

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