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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
105 | int sh_keep_comp(const void * a, const void * b)
|
---|
106 | {
|
---|
107 | return ( (int)(((struct sh_keep *)a)->last) -
|
---|
108 | (int)(((struct sh_keep *)b)->last) );
|
---|
109 | }
|
---|
110 |
|
---|
111 | /* -- Sort the kept labels and build a string ----------------- */
|
---|
112 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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
|
---|