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