source: trunk/src/sh_log_evalrule.c@ 214

Last change on this file since 214 was 203, checked in by katerina, 16 years ago

Fix compile failures on RHEL3 (ticket #130) and FreeBSD7 amd64 (ticket #131).

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