source: trunk/src/sh_log_correlate.c

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

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

File size: 7.7 KB
Line 
1#include "config_xor.h"
2
3#ifdef USE_LOGFILE_MONITOR
4
5#undef  FIL__
6#define FIL__  _("sh_log_correlate.c")
7
8#include <string.h>
9#include <time.h>
10
11/* Debian/Ubuntu: libpcre3-dev */
12#ifdef HAVE_PCRE_PCRE_H
13#include <pcre/pcre.h>
14#else
15#include <pcre.h>
16#endif
17
18#ifndef PCRE_NO_AUTO_CAPTURE
19#define PCRE_NO_AUTO_CAPTURE 0
20#endif
21
22#include "samhain.h"
23#include "sh_pthread.h"
24#include "sh_utils.h"
25#include "sh_string.h"
26#include "sh_log_check.h"
27#include "sh_log_evalrule.h"
28
29extern int flag_err_debug;
30
31/*--------------------------------------------------------------
32 *
33 *   Event correlation
34 *
35 *--------------------------------------------------------------*/
36
37/* For each even to be correlated, we keep a label in a list. We
38 * then build a string from the (time-sorted) list of labels, and
39 * match this string against a regular expression.
40 */
41
42/* -- The list of labels kept in memory ----------------------- */
43
44struct sh_keep
45{
46  sh_string       * label;           /* label of keep rule      */
47  unsigned long     delay;           /* valid delay             */
48  time_t            last;            /* seen at                 */
49  struct sh_keep *  next; 
50};
51
52static struct sh_keep * keeplist  = NULL;
53static struct sh_keep * keeplast  = NULL;
54static unsigned long    keepcount = 0;
55
56static void sh_keep_free(void * item)
57{
58  struct sh_keep * keep = (struct sh_keep *) item;
59
60  if (!keep)
61    return;
62  sh_string_destroy(&(keep->label));
63  SH_FREE(keep);
64}
65
66void sh_keep_destroy()
67{
68  struct sh_keep * keep;
69
70  while (keeplist)
71    {
72      keep = keeplist;
73      keeplist = keep->next;
74      sh_keep_free(keep);
75      --keepcount;
76    }
77  keeplist  = NULL;
78  keeplast  = NULL;
79  keepcount = 0;
80}
81
82int sh_keep_add(sh_string * label, unsigned long delay, time_t last)
83{
84  struct sh_keep * keep = SH_ALLOC(sizeof(struct sh_keep));
85
86  keep->label = sh_string_copy(label);
87  keep->delay = delay;
88  keep->last  = last;
89  keep->next  = NULL;
90
91  if (keeplast && keeplist)
92    {
93      keeplast->next = keep;
94      keeplast       = keep;
95    }
96  else
97    {
98      keeplist = keep;
99      keeplast = keeplist;
100    }
101  ++keepcount;
102  return 0;
103}
104
105int sh_keep_comp(const void * a, const void * b)
106{
107  return ( (int)(((const struct sh_keep *)a)->last) - 
108           (int)(((const struct sh_keep *)b)->last) );
109}
110
111/* -- Sort the kept labels and build a string ----------------- */
112
113static sh_string * sh_keep_eval()
114{
115  unsigned long count   = 0;
116  sh_string * res       = NULL;
117  time_t now            = time(NULL);
118  struct sh_keep * keep = keeplist;
119  struct sh_keep * prev = keeplist;
120  struct sh_keep * arr;
121
122  if (keepcount > 0)
123    {
124      arr = SH_ALLOC (keepcount * sizeof(struct sh_keep));
125
126      while (count < keepcount && keep)
127        {
128          if ((now >= keep->last) && 
129              ((unsigned long)(now - keep->last) <= keep->delay))
130            {
131              memcpy(&(arr[count]), keep, sizeof(struct sh_keep));
132              ++count;
133              prev = keep;
134              keep = keep->next;
135            }
136          else /* Too old or in future, delete it */
137            {
138              if (keep != keeplist)
139                {
140                  prev->next = keep->next;
141                  sh_keep_free(keep);
142                  keep = prev->next;
143                  --keepcount;
144                }
145              else /* list head */
146                {
147                  keeplist = keep->next;
148                  prev     = keeplist;
149                  sh_keep_free(keep);
150                  keep     = keeplist;
151                  --keepcount;
152                }
153            }
154        }
155
156      if (count > 0)
157        {
158          unsigned long i;
159          qsort(arr, count, sizeof(struct sh_keep), sh_keep_comp);
160          res = sh_string_copy(arr[0].label);
161          for (i = 1; i < count; ++i)
162            res = sh_string_add(res, arr[i].label);
163        }
164      SH_FREE(arr);
165    }
166
167  return res;
168}
169
170/* -- Match the string against correlation rules -------------- */
171
172struct sh_mkeep
173{
174  sh_string       * label;           /* label of match rule     */
175  pcre            * rule;            /* compiled regex for rule */
176  time_t            reported;        /* last reported           */
177  struct sh_qeval * queue;           /* assigned queue          */
178  struct sh_mkeep * next; 
179};
180
181struct sh_mkeep * mkeep_list = NULL;
182unsigned long     mkeep_deadtime = 60;
183
184int sh_keep_deadtime (const char * str)
185{
186  unsigned long  value;
187  char * foo;
188
189  value = (size_t) strtoul(str, &foo, 0);
190
191  if (*foo == '\0') {
192    mkeep_deadtime = value;
193    return 0;
194  }
195  return -1;
196}
197
198int sh_keep_match_add(const char * str, const char * queue, 
199                      const char * pattern)
200{
201  unsigned int nfields = 1; /* seconds:label */
202  size_t       lengths[1];
203  char *       new    = sh_util_strdup(str);
204  char **      splits = split_array_braced(new, _("CORRELATE"), 
205                                           &nfields, lengths);
206
207  if (nfields == 1 && lengths[0] > 0)
208    {
209      struct sh_mkeep * mkeep = SH_ALLOC(sizeof(struct sh_mkeep));
210      const char * error;
211      int          erroffset;
212      struct sh_qeval * rqueue = NULL;
213
214      mkeep->rule = pcre_compile(pattern, PCRE_NO_AUTO_CAPTURE, 
215                             &error, &erroffset, NULL);
216      if (!(mkeep->rule))
217        {
218          sh_string * msg =  sh_string_new(0);
219          sh_string_add_from_char(msg, _("Bad regex: "));
220          sh_string_add_from_char(msg, pattern);
221         
222          SH_MUTEX_LOCK(mutex_thread_nolog);
223          sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
224                          sh_string_str(msg),
225                          _("sh_keep_match_add"));
226          SH_MUTEX_UNLOCK(mutex_thread_nolog);
227          sh_string_destroy(&msg);
228         
229          SH_FREE(splits);
230          SH_FREE(mkeep);
231          SH_FREE(new);
232          return -1;
233        }
234
235      if (0 != strcmp(queue, _("trash")))
236        {
237
238          rqueue = sh_log_find_queue(queue);
239          if (!rqueue)
240            {
241              pcre_free(mkeep->rule);
242              SH_FREE(splits);
243              SH_FREE(mkeep);
244              SH_FREE(new);
245              return -1;
246            }
247        }
248
249      mkeep->queue = rqueue;
250      mkeep->label = sh_string_new_from_lchar(splits[0], strlen(splits[0]));
251      mkeep->reported = 0;
252      mkeep->next  = mkeep_list;
253      mkeep_list   = mkeep;
254    }
255  SH_FREE(new);
256  return 0;
257}
258
259void sh_keep_match_del()
260{
261  struct sh_mkeep * mkeep = mkeep_list;
262  while (mkeep)
263    {
264      mkeep_list = mkeep->next;
265      sh_string_destroy(&(mkeep->label));
266      pcre_free(mkeep->rule);
267      mkeep = mkeep_list;
268    }
269  mkeep_list = NULL;
270}
271
272static struct sh_mkeep ** dummy_mkeep;
273
274void sh_keep_match()
275{
276  if (mkeep_list)
277    {
278      sh_string       * res = sh_keep_eval();
279
280      if (res)
281        {
282          struct sh_mkeep * mkeep = mkeep_list;
283
284          dummy_mkeep = &mkeep;
285
286          while (mkeep)
287            {
288              /* Use pcre_dfa_exec() to obtain number of matches. Needs ovector
289               * array, otherwise number of matches is not returned.
290               */
291#if defined(HAVE_PCRE_DFA_EXEC)
292              int ovector[SH_MINIBUF];
293              int wspace[SH_MINIBUF];
294#endif
295
296#if defined(HAVE_PCRE_DFA_EXEC)
297              int val = pcre_dfa_exec(mkeep->rule, NULL, 
298                                      sh_string_str(res), 
299                                      (int)sh_string_len(res), 
300                                      0, /* start at offset 0 in the subject */
301                                      0, 
302                                      ovector, SH_MINIBUF,
303                                      wspace, SH_MINIBUF);
304#else
305              int val = pcre_exec(mkeep->rule, NULL, 
306                                  sh_string_str(res), 
307                                  (int)sh_string_len(res), 
308                                  0, /* start at offset 0 in the subject */
309                                  0, 
310                                  NULL, 0);
311              val = (val >= 0) ? 1 : val;                             
312#endif
313
314              if (val >= 0)
315                {
316                  sh_string * alias;
317                  time_t      now = time(NULL);
318
319                  if ((mkeep->reported < now) &&
320                      (mkeep_deadtime < (unsigned int)(now - mkeep->reported)))
321                    {
322                      mkeep->reported = now;
323
324                      SH_MUTEX_LOCK(mutex_thread_nolog);
325                      sh_error_handle (mkeep->queue->severity, FIL__, __LINE__, 0, 
326                                       MSG_LOGMON_COR, sh_string_str(mkeep->label),
327                                       val);
328
329                      alias = mkeep->queue->alias;
330                      if (alias)
331                        {
332                          sh_error_mail (sh_string_str(alias), 
333                                         mkeep->queue->severity, FIL__, __LINE__, 0, 
334                                         MSG_LOGMON_COR, sh_string_str(mkeep->label),
335                                         val);
336                        }
337                     
338                      SH_MUTEX_UNLOCK(mutex_thread_nolog);
339                    }
340                }
341              mkeep = mkeep->next;
342            }
343          sh_string_destroy(&res);
344        }
345    }
346  return;
347}
348
349#endif
Note: See TracBrowser for help on using the repository browser.