#include "config_xor.h" #ifdef USE_LOGFILE_MONITOR #include #include #undef FIL__ #define FIL__ _("sh_log_mark.c") #include "samhain.h" #include "sh_pthread.h" #include "sh_mem.h" #include "sh_string.h" #include "sh_error_min.h" #include "sh_log_check.h" #include "sh_log_evalrule.h" #include "zAVLTree.h" /* #define DEBUG_MARK */ #ifdef DEBUG_MARK static void DEBUG(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); /* flawfinder: ignore *//* we control fmt string */ va_end(ap); return; } #else static void DEBUG(const char *fmt, ...) { (void) fmt; return; } #endif static zAVLTree * marklist = NULL; struct sh_mark_event { sh_string * label; sh_string * queue_id; time_t last_seen; time_t interval; time_t delay; time_t last_reported; }; static void sh_marklist_free(void * item) { struct sh_mark_event * event = (struct sh_mark_event *) item; if (!event) return; sh_string_destroy(&(event->label)); sh_string_destroy(&(event->queue_id)); SH_FREE(event); return; } void sh_log_mark_destroy() { zAVLFreeTree(marklist, sh_marklist_free); } static zAVLKey sh_log_mark_getkey(void const *item) { return ((struct sh_mark_event *)item)->label->str; } int sh_log_mark_add (const char * label, time_t interval, const char * qlabel) { struct sh_mark_event * event; if (!(marklist)) { marklist = zAVLAllocTree(sh_log_mark_getkey, zAVL_KEY_STRING); } event = (struct sh_mark_event *) zAVLSearch(marklist, label); if (event) { event->interval = interval; sh_string_destroy(&(event->queue_id)); event->queue_id = sh_string_new_from_lchar(qlabel, strlen(qlabel)); return 0; } event = SH_ALLOC(sizeof(struct sh_mark_event)); event->last_seen = time(NULL); event->interval = interval; event->delay = 0; event->last_reported = 0; event->label = sh_string_new_from_lchar(label, strlen(label)); event->queue_id = sh_string_new_from_lchar(qlabel, strlen(qlabel)); if (0 != zAVLInsert(marklist, event)) { sh_marklist_free(event); return -1; } return 0; } void sh_log_mark_update (sh_string * label, time_t timestamp) { struct sh_mark_event * event = (struct sh_mark_event *) zAVLSearch (marklist, sh_string_str(label)); DEBUG("debug: running mark update for %s\n", sh_string_str(label)); if (event) { DEBUG("debug: updating, timestamp %lu, last_seen %lu, interval %d\n", (unsigned long)timestamp, (unsigned long) event->last_seen, (int)event->interval); if ((timestamp > event->last_seen) && (event->interval < (timestamp - event->last_seen)) && (timestamp > event->last_reported) && (event->interval < (timestamp - event->last_reported))) { event->delay = timestamp - event->last_seen; DEBUG("debug: updating delay to %d\n", (int) event->delay); } event->last_seen = timestamp; } return; } /* This should allow to get all overdue labels with a for loop like: * for (label = sh_log_mark_first(); label; label = sh_log_mark_next()) {} */ static zAVLCursor mark_cursor; static struct sh_mark_event * sh_log_mark_cursor(time_t * delay, time_t now, struct sh_mark_event * event) { while (event) { DEBUG("debug: echeck, delay %d, now %lu, last_seen %lu, reported %lu\n", (int) event->delay, (unsigned long)now, (unsigned long) event->last_seen, (unsigned long)event->last_reported); if (event->delay > 0) { DEBUG("debug: event delay > 0, value %d\n", (int) event->delay); *delay = event->delay; event->delay = 0; event->last_reported = time(NULL); return event; } else if ((now > event->last_seen) && (now > event->last_reported) && (event->interval < (now - event->last_seen)) && (event->interval < (now - event->last_reported)) ) { DEBUG("debug: event delay 0, now %lu, last_seen %lu, reported %lu\n", (unsigned long)now, (unsigned long) event->last_seen, (unsigned long)event->last_reported); *delay = now - event->last_seen; event->delay = 0; /* Subtract 1 sec to prevent accumulation of the * one second offset. */ event->last_reported = time(NULL) - 1; return event; } event = (struct sh_mark_event *) zAVLNext(&mark_cursor); } return NULL; } struct sh_mark_event * sh_log_mark_first(time_t * delay, time_t now) { struct sh_mark_event * event = (struct sh_mark_event *) zAVLFirst(&mark_cursor, marklist); return sh_log_mark_cursor (delay, now, event); } struct sh_mark_event * sh_log_mark_next(time_t * delay, time_t now) { struct sh_mark_event * event = (struct sh_mark_event *) zAVLNext(&mark_cursor); return sh_log_mark_cursor (delay, now, event); } static int sh_mark_default_severity = SH_ERR_SEVERE; int sh_log_set_mark_severity (const char * str) { int val = sh_error_convert_level(str); if (val < 0) return -1; sh_mark_default_severity = val; return 0; } static struct sh_mark_event ** dummy_event; void sh_log_mark_check() { struct sh_mark_event * event; time_t now = time(NULL); time_t delay; /* variable 'event' might be clobbered by 'longjmp' or 'vfork' */ dummy_event = &event; DEBUG("debug: running mark check\n"); for (event = sh_log_mark_first(&delay, now); event; event = sh_log_mark_next (&delay, now)) { int severity; sh_string * alias; SH_MUTEX_LOCK(mutex_thread_nolog); severity = sh_log_lookup_severity(sh_string_str(event->queue_id)); if (severity < 0) severity = sh_mark_default_severity; DEBUG("debug: mark check: queue %s, severity %d\n", sh_string_str(event->queue_id), severity); sh_error_handle (severity, FIL__, __LINE__, 0, MSG_LOGMON_MARK, sh_string_str(event->label), (unsigned long) delay); alias = sh_log_lookup_alias(sh_string_str(event->queue_id)); if (alias) { sh_error_mail (sh_string_str(alias), severity, FIL__, __LINE__, 0, MSG_LOGMON_MARK, sh_string_str(event->label), (unsigned long) delay); } SH_MUTEX_UNLOCK(mutex_thread_nolog); } return; } #endif