source: trunk/src/sh_log_evalrule.c@ 201

Last change on this file since 201 was 186, checked in by katerina, 16 years ago

More fixes for log monitoring, and documentation update.

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