X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?a=blobdiff_plain;ds=sidebyside;f=src%2Fanalysisd%2Faccumulator.c;fp=src%2Fanalysisd%2Faccumulator.c;h=e35d9bbb52d3901071e37c816df1215aec7b74db;hb=3f728675941dc69d4e544d3a880a56240a6e394a;hp=0000000000000000000000000000000000000000;hpb=927951d1c1ad45ba9e7325f07d996154a91c911b;p=ossec-hids.git diff --git a/src/analysisd/accumulator.c b/src/analysisd/accumulator.c new file mode 100644 index 0000000..e35d9bb --- /dev/null +++ b/src/analysisd/accumulator.c @@ -0,0 +1,339 @@ +/* Copyright (C) 2009 Trend Micro Inc. + * All rights reserved. + * + * This program is a free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License (version 2) as published by the FSF - Free Software + * Foundation. + */ + +/* Accumulator Functions which accumulate objects based on an ID */ + +#include + +#include "shared.h" +#include "accumulator.h" +#include "eventinfo.h" + +/* Local variables */ +static OSHash *acm_store = NULL; + +/* Counters for Purging */ +static int acm_lookups = 0; +static time_t acm_purge_ts = 0; + +/* Accumulator Constants */ +#define OS_ACM_EXPIRE_ELM 120 +#define OS_ACM_PURGE_INTERVAL 300 +#define OS_ACM_PURGE_COUNT 200 + +/* Accumulator Max Values */ +#define OS_ACM_MAXKEY 256 +#define OS_ACM_MAXELM 81 + +typedef struct _OS_ACM_Store { + time_t timestamp; + char *dstuser; + char *srcuser; + char *dstip; + char *srcip; + char *dstport; + char *srcport; + char *data; +} OS_ACM_Store; + +/* Internal Functions */ +static int acm_str_replace(char **dst, const char *src); +static OS_ACM_Store *InitACMStore(void); +static void FreeACMStore(OS_ACM_Store *obj); + +/* Start the Accumulator module */ +int Accumulate_Init() +{ + struct timeval tp; + + /* Create store data */ + acm_store = OSHash_Create(); + if (!acm_store) { + merror(LIST_ERROR, ARGV0); + return (0); + } + if (!OSHash_setSize(acm_store, 2048)) { + merror(LIST_ERROR, ARGV0); + return (0); + } + + /* Default Expiry */ + gettimeofday(&tp, NULL); + acm_purge_ts = tp.tv_sec; + + debug1("%s: DEBUG: Accumulator Init completed.", ARGV0); + return (1); +} + +/* Accumulate data from events sharing the same ID */ +Eventinfo *Accumulate(Eventinfo *lf) +{ + int result; + int do_update = 0; + + char _key[OS_ACM_MAXKEY]; + OS_ACM_Store *stored_data = 0; + + time_t current_ts; + struct timeval tp; + + if ( lf == NULL ) { + debug1("accumulator: DEBUG: Received NULL EventInfo"); + return lf; + } + if ( lf->id == NULL ) { + debug2("accumulator: DEBUG: No id available"); + return lf; + } + if ( lf->decoder_info == NULL ) { + debug1("accumulator: DEBUG: No decoder_info available"); + return lf; + } + if ( lf->decoder_info->name == NULL ) { + debug1("accumulator: DEBUG: No decoder name available"); + return lf; + } + + /* Purge the cache as needed */ + Accumulate_CleanUp(); + + gettimeofday(&tp, NULL); + current_ts = tp.tv_sec; + + /* Accumulator Key */ + result = snprintf(_key, OS_FLSIZE, "%s %s %s", + lf->hostname, + lf->decoder_info->name, + lf->id + ); + if ( result < 0 || (unsigned) result >= sizeof(_key) ) { + debug1("accumulator: DEBUG: error setting accumulator key, id:%s,name:%s", lf->id, lf->decoder_info->name); + return lf; + } + + /* Check if acm is already present */ + if ((stored_data = (OS_ACM_Store *)OSHash_Get(acm_store, _key)) != NULL) { + debug2("accumulator: DEBUG: Lookup for '%s' found a stored value!", _key); + + if ( stored_data->timestamp > 0 && stored_data->timestamp < current_ts - OS_ACM_EXPIRE_ELM ) { + if ( OSHash_Delete(acm_store, _key) != NULL ) { + debug1("accumulator: DEBUG: Deleted expired hash entry for '%s'", _key); + /* Clear this memory */ + FreeACMStore(stored_data); + /* Reallocate what we need */ + stored_data = InitACMStore(); + } + } else { + /* Update the event */ + do_update = 1; + if (acm_str_replace(&lf->dstuser, stored_data->dstuser) == 0) { + debug2("accumulator: DEBUG: (%s) updated lf->dstuser to %s", _key, lf->dstuser); + } + + if (acm_str_replace(&lf->srcuser, stored_data->srcuser) == 0) { + debug2("accumulator: DEBUG: (%s) updated lf->srcuser to %s", _key, lf->srcuser); + } + + if (acm_str_replace(&lf->dstip, stored_data->dstip) == 0) { + debug2("accumulator: DEBUG: (%s) updated lf->dstip to %s", _key, lf->dstip); + } + + if (acm_str_replace(&lf->srcip, stored_data->srcip) == 0) { + debug2("accumulator: DEBUG: (%s) updated lf->srcip to %s", _key, lf->srcip); + } + + if (acm_str_replace(&lf->dstport, stored_data->dstport) == 0) { + debug2("accumulator: DEBUG: (%s) updated lf->dstport to %s", _key, lf->dstport); + } + + if (acm_str_replace(&lf->srcport, stored_data->srcport) == 0) { + debug2("accumulator: DEBUG: (%s) updated lf->srcport to %s", _key, lf->srcport); + } + + if (acm_str_replace(&lf->data, stored_data->data) == 0) { + debug2("accumulator: DEBUG: (%s) updated lf->data to %s", _key, lf->data); + } + } + } else { + stored_data = InitACMStore(); + } + + /* Store the object in the cache */ + stored_data->timestamp = current_ts; + if (acm_str_replace(&stored_data->dstuser, lf->dstuser) == 0) { + debug2("accumulator: DEBUG: (%s) updated stored_data->dstuser to %s", _key, stored_data->dstuser); + } + + if (acm_str_replace(&stored_data->srcuser, lf->srcuser) == 0) { + debug2("accumulator: DEBUG: (%s) updated stored_data->srcuser to %s", _key, stored_data->srcuser); + } + + if (acm_str_replace(&stored_data->dstip, lf->dstip) == 0) { + debug2("accumulator: DEBUG: (%s) updated stored_data->dstip to %s", _key, stored_data->dstip); + } + + if (acm_str_replace(&stored_data->srcip, lf->srcip) == 0) { + debug2("accumulator: DEBUG: (%s) updated stored_data->srcip to %s", _key, stored_data->srcip); + } + + if (acm_str_replace(&stored_data->dstport, lf->dstport) == 0) { + debug2("accumulator: DEBUG: (%s) updated stored_data->dstport to %s", _key, stored_data->dstport); + } + + if (acm_str_replace(&stored_data->srcport, lf->srcport) == 0) { + debug2("accumulator: DEBUG: (%s) updated stored_data->srcport to %s", _key, stored_data->srcport); + } + + if (acm_str_replace(&stored_data->data, lf->data) == 0) { + debug2("accumulator: DEBUG: (%s) updated stored_data->data to %s", _key, stored_data->data); + } + + /* Update or Add to the hash */ + if ( do_update == 1 ) { + /* Update the hash entry */ + if ( (result = OSHash_Update(acm_store, _key, stored_data)) != 1) { + verbose("accumulator: ERROR: Update of stored data for %s failed (%d).", _key, result); + } else { + debug1("accumulator: DEBUG: Updated stored data for %s", _key); + } + } else { + if ((result = OSHash_Add(acm_store, _key, stored_data)) != 2 ) { + verbose("accumulator: ERROR: Addition of stored data for %s failed (%d).", _key, result); + } else { + debug1("accumulator: DEBUG: Added stored data for %s", _key); + } + } + + return lf; +} + +void Accumulate_CleanUp() +{ + struct timeval tp; + time_t current_ts = 0; + int expired = 0; + + OSHashNode *curr; + OS_ACM_Store *stored_data; + char *key; + unsigned int ti; + + /* Keep track of how many times we're called */ + acm_lookups++; + + gettimeofday(&tp, NULL); + current_ts = tp.tv_sec; + + /* Do we really need to purge? */ + if ( acm_lookups < OS_ACM_PURGE_COUNT && acm_purge_ts < current_ts + OS_ACM_PURGE_INTERVAL ) { + return; + } + debug1("accumulator: DEBUG: Accumulator_CleanUp() running .. "); + + /* Yes, we do */ + acm_lookups = 0; + acm_purge_ts = current_ts; + + /* Loop through the hash */ + for ( ti = 0; ti < acm_store->rows; ti++ ) { + curr = acm_store->table[ti]; + while ( curr != NULL ) { + /* Get the Key and Data */ + key = (char *) curr->key; + stored_data = (OS_ACM_Store *) curr->data; + /* Increment to the next element */ + curr = curr->next; + + debug2("accumulator: DEBUG: CleanUp() evaluating cached key: %s ", key); + /* Check for a valid element */ + if ( stored_data != NULL ) { + /* Check for expiration */ + debug2("accumulator: DEBUG: CleanUp() elm:%ld, curr:%ld", (long int)stored_data->timestamp, (long int)current_ts); + if ( stored_data->timestamp < current_ts - OS_ACM_EXPIRE_ELM ) { + debug2("accumulator: DEBUG: CleanUp() Expiring '%s'", key); + if ( OSHash_Delete(acm_store, key) != NULL ) { + FreeACMStore(stored_data); + expired++; + } else { + debug1("accumulator: DEBUG: CleanUp() failed to find key '%s'", key); + } + } + } + } + } + debug1("accumulator: DEBUG: Expired %d elements", expired); +} + +/* Initialize a storage object */ +OS_ACM_Store *InitACMStore() +{ + OS_ACM_Store *obj; + os_calloc(1, sizeof(OS_ACM_Store), obj); + + obj->timestamp = 0; + obj->srcuser = NULL; + obj->dstuser = NULL; + obj->srcip = NULL; + obj->dstip = NULL; + obj->srcport = NULL; + obj->dstport = NULL; + obj->data = NULL; + + return obj; +} + +/* Free an accumulation store struct */ +void FreeACMStore(OS_ACM_Store *obj) +{ + if ( obj != NULL ) { + debug2("accumulator: DEBUG: Freeing an accumulator struct."); + free(obj->dstuser); + free(obj->srcuser); + free(obj->dstip); + free(obj->srcip); + free(obj->dstport); + free(obj->srcport); + free(obj->data); + free(obj); + } +} + +int acm_str_replace(char **dst, const char *src) +{ + int result = 0; + + /* Don't overwrite with a null str */ + if ( src == NULL ) { + return -1; + } + + /* Don't overwrite something we already know */ + if (*dst != NULL && **dst != '\0') { + return -1; + } + + /* Make sure we have data to write */ + size_t slen = strlen(src); + if ( slen <= 0 || slen > OS_ACM_MAXELM - 1 ) { + return -1; + } + + /* Free dst, and malloc the memory we need! */ + if ( *dst != NULL ) { + free(*dst); + } + os_malloc(slen + 1, *dst); + + result = strcpy(*dst, src) == NULL ? -1 : 0; + if (result < 0) { + debug1("accumulator: DEBUG: error in acm_str_replace()"); + } + return result; +} +