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 
29 extern 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 
44 struct 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 
52 static struct sh_keep * keeplist  = NULL;
53 static struct sh_keep * keeplast  = NULL;
54 static unsigned long    keepcount = 0;
55 
sh_keep_free(void * item)56 static 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 
sh_keep_destroy()66 void 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 
sh_keep_add(sh_string * label,unsigned long delay,time_t last)82 int 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 
sh_keep_comp(const void * a,const void * b)105 int 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 
sh_keep_eval()113 static 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 
172 struct 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 
181 struct sh_mkeep * mkeep_list = NULL;
182 unsigned long     mkeep_deadtime = 60;
183 
sh_keep_deadtime(const char * str)184 int 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 
sh_keep_match_add(const char * str,const char * queue,const char * pattern)198 int 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 
sh_keep_match_del()259 void 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 
272 static struct sh_mkeep ** dummy_mkeep;
273 
sh_keep_match()274 void 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
350