source: trunk/src/sh_log_evalrule.c@ 588

Last change on this file since 588 was 588, checked in by katerina, 26 hours ago

Fix for ticket #476 (move logfile monitoring module from PCRE to PCRE2).

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