source: trunk/src/sh_log_evalrule.c @ 481

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

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

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