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 | if (!keep)
|
---|
60 | return;
|
---|
61 | sh_string_destroy(&(keep->label));
|
---|
62 | SH_FREE(keep);
|
---|
63 | }
|
---|
64 |
|
---|
65 | void sh_keep_destroy()
|
---|
66 | {
|
---|
67 | struct sh_keep * keep;
|
---|
68 |
|
---|
69 | while (keeplist)
|
---|
70 | {
|
---|
71 | keep = keeplist;
|
---|
72 | keeplist = keep->next;
|
---|
73 | sh_keep_free(keep);
|
---|
74 | --keepcount;
|
---|
75 | }
|
---|
76 | keeplist = NULL;
|
---|
77 | keeplast = NULL;
|
---|
78 | keepcount = 0;
|
---|
79 | }
|
---|
80 |
|
---|
81 | int sh_keep_add(sh_string * label, unsigned long delay, time_t last)
|
---|
82 | {
|
---|
83 | struct sh_keep * keep = SH_ALLOC(sizeof(struct sh_keep));
|
---|
84 |
|
---|
85 | keep->label = sh_string_copy(label);
|
---|
86 | keep->delay = delay;
|
---|
87 | keep->last = last;
|
---|
88 | keep->next = NULL;
|
---|
89 |
|
---|
90 | if (keeplast && keeplist)
|
---|
91 | {
|
---|
92 | keeplast->next = keep;
|
---|
93 | keeplast = keep;
|
---|
94 | }
|
---|
95 | else
|
---|
96 | {
|
---|
97 | keeplist = keep;
|
---|
98 | keeplast = keeplist;
|
---|
99 | }
|
---|
100 | ++keepcount;
|
---|
101 | return 0;
|
---|
102 | }
|
---|
103 |
|
---|
104 | int sh_keep_comp(const void * a, const void * b)
|
---|
105 | {
|
---|
106 | return ( (int)(((struct sh_keep *)a)->last) -
|
---|
107 | (int)(((struct sh_keep *)b)->last) );
|
---|
108 | }
|
---|
109 |
|
---|
110 | /* -- Sort the kept labels and build a string ----------------- */
|
---|
111 |
|
---|
112 | static sh_string * sh_keep_eval()
|
---|
113 | {
|
---|
114 | unsigned long count = 0;
|
---|
115 | sh_string * res = NULL;
|
---|
116 | time_t now = time(NULL);
|
---|
117 | struct sh_keep * keep = keeplist;
|
---|
118 | struct sh_keep * prev = keeplist;
|
---|
119 | struct sh_keep * arr;
|
---|
120 |
|
---|
121 | if (keepcount > 0)
|
---|
122 | {
|
---|
123 | arr = SH_ALLOC (keepcount * sizeof(struct sh_keep));
|
---|
124 |
|
---|
125 | while (count < keepcount && keep)
|
---|
126 | {
|
---|
127 | if ((now > keep->last) &&
|
---|
128 | ((unsigned long)(now - keep->last) <= keep->delay))
|
---|
129 | {
|
---|
130 | memcpy(&(arr[count]), keep, sizeof(struct sh_keep));
|
---|
131 | ++count;
|
---|
132 | prev = keep;
|
---|
133 | keep = keep->next;
|
---|
134 | }
|
---|
135 | else /* Too old or in future, delete it */
|
---|
136 | {
|
---|
137 | if (keep != keeplist)
|
---|
138 | {
|
---|
139 | prev->next = keep->next;
|
---|
140 | sh_keep_free(keep);
|
---|
141 | keep = prev->next;
|
---|
142 | --keepcount;
|
---|
143 | }
|
---|
144 | else /* list head */
|
---|
145 | {
|
---|
146 | keeplist = keep->next;
|
---|
147 | prev = keeplist;
|
---|
148 | sh_keep_free(keep);
|
---|
149 | keep = keeplist;
|
---|
150 | --keepcount;
|
---|
151 | }
|
---|
152 | }
|
---|
153 | }
|
---|
154 |
|
---|
155 | if (count > 0)
|
---|
156 | {
|
---|
157 | unsigned long i;
|
---|
158 | qsort(arr, count, sizeof(struct sh_keep), sh_keep_comp);
|
---|
159 | res = sh_string_copy(arr[0].label);
|
---|
160 | for (i = 1; i < count; ++i)
|
---|
161 | res = sh_string_add(res, arr[i].label);
|
---|
162 | }
|
---|
163 | SH_FREE(arr);
|
---|
164 | }
|
---|
165 | return res;
|
---|
166 | }
|
---|
167 |
|
---|
168 | /* -- Match the string against correlation rules -------------- */
|
---|
169 |
|
---|
170 | struct sh_mkeep
|
---|
171 | {
|
---|
172 | sh_string * label; /* label of match rule */
|
---|
173 | pcre * rule; /* compiled regex for rule */
|
---|
174 | struct sh_qeval * queue; /* assigned queue */
|
---|
175 | struct sh_mkeep * next;
|
---|
176 | };
|
---|
177 |
|
---|
178 | struct sh_mkeep * mkeep_list = NULL;
|
---|
179 |
|
---|
180 |
|
---|
181 | int sh_keep_match_add(const char * str, const char * queue,
|
---|
182 | const char * pattern)
|
---|
183 | {
|
---|
184 | unsigned int nfields = 1; /* seconds:label */
|
---|
185 | size_t lengths[1];
|
---|
186 | char * new = sh_util_strdup(str);
|
---|
187 | char ** splits = split_array_braced(new, _("CORRELATE"),
|
---|
188 | &nfields, lengths);
|
---|
189 |
|
---|
190 | if (nfields == 1 && lengths[0] > 0)
|
---|
191 | {
|
---|
192 | struct sh_mkeep * mkeep = SH_ALLOC(sizeof(struct sh_mkeep));
|
---|
193 | const char * error;
|
---|
194 | int erroffset;
|
---|
195 | struct sh_qeval * rqueue = NULL;
|
---|
196 |
|
---|
197 | mkeep->rule = pcre_compile(pattern, PCRE_NO_AUTO_CAPTURE,
|
---|
198 | &error, &erroffset, NULL);
|
---|
199 | if (!(mkeep->rule))
|
---|
200 | {
|
---|
201 | sh_string * msg = sh_string_new(0);
|
---|
202 | sh_string_add_from_char(msg, _("Bad regex: "));
|
---|
203 | sh_string_add_from_char(msg, pattern);
|
---|
204 |
|
---|
205 | SH_MUTEX_LOCK(mutex_thread_nolog);
|
---|
206 | sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
|
---|
207 | sh_string_str(msg),
|
---|
208 | _("sh_keep_match_add"));
|
---|
209 | SH_MUTEX_UNLOCK(mutex_thread_nolog);
|
---|
210 | sh_string_destroy(&msg);
|
---|
211 |
|
---|
212 | SH_FREE(splits);
|
---|
213 | SH_FREE(mkeep);
|
---|
214 | SH_FREE(new);
|
---|
215 | return -1;
|
---|
216 | }
|
---|
217 |
|
---|
218 | if (0 != strcmp(queue, _("trash")))
|
---|
219 | {
|
---|
220 |
|
---|
221 | rqueue = sh_log_find_queue(queue);
|
---|
222 | if (!rqueue)
|
---|
223 | {
|
---|
224 | pcre_free(mkeep->rule);
|
---|
225 | SH_FREE(splits);
|
---|
226 | SH_FREE(mkeep);
|
---|
227 | SH_FREE(new);
|
---|
228 | return -1;
|
---|
229 | }
|
---|
230 | }
|
---|
231 |
|
---|
232 | mkeep->queue = rqueue;
|
---|
233 | mkeep->label = sh_string_new_from_lchar(splits[0], strlen(splits[0]));
|
---|
234 | mkeep->next = mkeep_list;
|
---|
235 | mkeep_list = mkeep;
|
---|
236 | }
|
---|
237 | SH_FREE(new);
|
---|
238 | return 0;
|
---|
239 | }
|
---|
240 |
|
---|
241 | void sh_keep_match_del()
|
---|
242 | {
|
---|
243 | struct sh_mkeep * mkeep = mkeep_list;
|
---|
244 | while (mkeep)
|
---|
245 | {
|
---|
246 | mkeep_list = mkeep->next;
|
---|
247 | sh_string_destroy(&(mkeep->label));
|
---|
248 | pcre_free(mkeep->rule);
|
---|
249 | mkeep = mkeep_list;
|
---|
250 | }
|
---|
251 | mkeep_list = NULL;
|
---|
252 | }
|
---|
253 |
|
---|
254 | static struct sh_mkeep ** dummy_mkeep;
|
---|
255 |
|
---|
256 | void sh_keep_match()
|
---|
257 | {
|
---|
258 | if (mkeep_list)
|
---|
259 | {
|
---|
260 | sh_string * res = sh_keep_eval();
|
---|
261 |
|
---|
262 | if (res)
|
---|
263 | {
|
---|
264 | struct sh_mkeep * mkeep = mkeep_list;
|
---|
265 |
|
---|
266 | dummy_mkeep = &mkeep;
|
---|
267 |
|
---|
268 | while (mkeep)
|
---|
269 | {
|
---|
270 | /* Use pcre_dfa_exec() to obtain number of matches. Needs ovector
|
---|
271 | * array, otherwise number of matches is not returned.
|
---|
272 | */
|
---|
273 | #if defined(HAVE_PCRE_DFA_EXEC)
|
---|
274 | int ovector[SH_MINIBUF];
|
---|
275 | int wspace[SH_MINIBUF];
|
---|
276 | #endif
|
---|
277 |
|
---|
278 | #if defined(HAVE_PCRE_DFA_EXEC)
|
---|
279 | int val = pcre_dfa_exec(mkeep->rule, NULL,
|
---|
280 | sh_string_str(res),
|
---|
281 | (int)sh_string_len(res),
|
---|
282 | 0, /* start at offset 0 in the subject */
|
---|
283 | 0,
|
---|
284 | ovector, SH_MINIBUF,
|
---|
285 | wspace, SH_MINIBUF);
|
---|
286 | #else
|
---|
287 | int val = pcre_exec(mkeep->rule, NULL,
|
---|
288 | sh_string_str(res),
|
---|
289 | (int)sh_string_len(res),
|
---|
290 | 0, /* start at offset 0 in the subject */
|
---|
291 | 0,
|
---|
292 | NULL, 0);
|
---|
293 | val = (val >= 0) ? 1 : val;
|
---|
294 | #endif
|
---|
295 |
|
---|
296 | if (val >= 0)
|
---|
297 | {
|
---|
298 | sh_string * alias;
|
---|
299 | SH_MUTEX_LOCK(mutex_thread_nolog);
|
---|
300 | sh_error_handle (mkeep->queue->severity, FIL__, __LINE__, 0,
|
---|
301 | MSG_LOGMON_COR, sh_string_str(mkeep->label),
|
---|
302 | val);
|
---|
303 |
|
---|
304 | alias = mkeep->queue->alias;
|
---|
305 | if (alias)
|
---|
306 | {
|
---|
307 | sh_error_mail (sh_string_str(alias),
|
---|
308 | mkeep->queue->severity, FIL__, __LINE__, 0,
|
---|
309 | MSG_LOGMON_COR, sh_string_str(mkeep->label),
|
---|
310 | val);
|
---|
311 | }
|
---|
312 |
|
---|
313 | SH_MUTEX_UNLOCK(mutex_thread_nolog);
|
---|
314 | }
|
---|
315 | mkeep = mkeep->next;
|
---|
316 | }
|
---|
317 | sh_string_destroy(&res);
|
---|
318 | }
|
---|
319 | }
|
---|
320 | return;
|
---|
321 | }
|
---|
322 |
|
---|
323 | #endif
|
---|