Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
OSSEC Accumulator Patch against 2.7.0
diff --git a/etc/decoder.xml b/etc/decoder.xml
index a7846ad..1087918 100755
--- a/etc/decoder.xml
+++ b/etc/decoder.xml
@@ -1841,6 +1841,7 @@
</decoder>
<!-- decoder for active responses as logged by an OSSEC agent or server
+
- Examples
Sat May 7 03:17:27 CDT 2011 /var/ossec/active-response/bin/host-deny.sh add - 172.16.0.1 1304756247.60385 31151
Sat May 7 03:17:27 CDT 2011 /var/ossec/active-response/bin/firewall-drop.sh add - 172.16.0.1 1304756247.60385 31151
@@ -2294,15 +2295,47 @@ in HTTP request too long; attack: Malformed HTTP; src: 10.10.10.4; dst:
<!-- OpenLDAP decoder.
- - Jan 11 09:26:57 hostname slapd2.4[20872]: conn=999999 fd=64 ACCEPT from IP=10.10.248.27:33957 (IP=10.10.241.77:389)
+ - Jan 11 09:26:57 hostname slapd[20872]: conn=999999 fd=64 ACCEPT from IP=10.10.248.27:33957 (IP=10.10.241.77:389)
+ - Jan 11 09:26:57 hostname slapd[20872]: conn=999999 op=0 BIND dn="uid=example,ou=People,dc=example,dc=com" method=128
+ - Jan 11 09:26:57 hostname slapd[20872]: conn=999999 op=0 RESULT tag=97 err=49 text=
+ ^- Login Failed
+ - Jan 11 09:26:57 hostname slapd[20872]: conn=999999 op=1 BIND dn="uid=example,ou=People,dc=example,dc=com" method=128
+ ^- Login Retried
+ - Jan 11 09:26:57 hostname slapd[20872]: conn=999999 op=1 RESULT tag=97 err=0 text=
+ ^- Login Successful
+ - Jan 11 09:26:57 hostname slapd[20872]: conn=999999 op=2 UNBIND
+ - Jan 11 09:26:57 hostname slapd[20872]: conn=999999 fd=64
+ ^- Connection closed
+
-->
<decoder name="openldap">
<program_name>^slapd</program_name>
- <regex>^conn=(\d+) </regex>
- <order>id</order>
+ <accumulate/>
</decoder>
+<decoder name="openldap-connect">
+ <parent>openldap</parent>
+ <prematch>ACCEPT</prematch>
+ <regex>^conn=(\d+) fd=\d+ ACCEPT from IP=(\S+):</regex>
+ <order>id, srcip</order>
+ <accumulate/>
+</decoder>
+<decoder name="openldap-bind">
+ <parent>openldap</parent>
+ <prematch>BIND </prematch>
+ <regex>^conn=(\d+) op=\d+ BIND dn="\w+=(\w+),</regex>
+ <order>id, dstuser</order>
+ <accumulate/>
+</decoder>
+
+<decoder name="openldap-result">
+ <accumulate/>
+ <parent>openldap</parent>
+ <prematch> RESULT </prematch>
+ <regex>^conn=(\d+) op=\d+ RESULT </regex>
+ <order>id</order>
+</decoder>
<!-- NTP decoder
- gorilla ntpd[27379]: bad sensor nmea0
diff --git a/src/analysisd/Makefile b/src/analysisd/Makefile
index b57bb1f..3cabd55 100755
--- a/src/analysisd/Makefile
+++ b/src/analysisd/Makefile
@@ -7,7 +7,7 @@ NAME=ossec-analysisd
include ../Config.Make
-OTHER = stats.c lists.c lists_list.c rules.c rules_list.c config.c fts.c dodiff.c eventinfo.c eventinfo_list.c cleanevent.c active-response.c picviz.c prelude.c compiled_rules/*.o ${OS_CONFIG}
+OTHER = stats.c lists.c lists_list.c rules.c rules_list.c config.c fts.c accumulator.c dodiff.c eventinfo.c eventinfo_list.c cleanevent.c active-response.c picviz.c prelude.c compiled_rules/*.o ${OS_CONFIG}
LOCAL = analysisd.c ${OTHER}
PLUGINS = decoders/decoders.a
ALERTS = alerts/alerts.a
diff --git a/src/analysisd/accumulator.c b/src/analysisd/accumulator.c
new file mode 100755
index 0000000..f817a8f
--- /dev/null
+++ b/src/analysisd/accumulator.c
@@ -0,0 +1,320 @@
+/* @(#) $Id$ */
+
+/* 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.
+ *
+ * License details at the LICENSE file included with OSSEC or
+ * online at: http://www.ossec.net/en/licensing.html
+ */
+
+
+/* Accumulator Functions which accumulate objects based on an id
+*/
+
+#include <sys/time.h>
+#include "shared.h"
+#include "accumulator.h"
+#include "eventinfo.h"
+
+OSHash *acm_store = NULL;
+
+// Counters for Purging
+int acm_lookups = 0;
+int acm_purge_ts = 0;
+
+/** int Accumulator_Init()
+ * Starts the Accumulator module.
+ */
+int Accumulate_Init()
+{
+ struct timeval tp;
+
+ /* Creating 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 v0.1
+ * Accumulate data from events sharing the same id
+ */
+Eventinfo* Accumulate(Eventinfo *lf)
+{
+ // Declare our variables
+ int result;
+ int do_update = 0;
+
+ char _key[OS_ACM_MAXKEY];
+ OS_ACM_Store *stored_data = 0;
+
+ // Timing Variables
+ int current_ts;
+ struct timeval tp;
+
+
+ // Check to make sure lf is valid
+ if ( lf == NULL ) {
+ debug1("accumulator: DEBUG: Received NULL EventInfo");
+ return lf;
+ }
+ // We need an ID to use the accumulator
+ 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();
+
+ // Initialize variables
+
+ // Timing data
+ 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 || result >= sizeof(_key) ) {
+ debug1("accumulator: DEBUG: error setting accumulator key, id:%s,name:%s", lf->id, lf->decoder_info->name);
+ return lf;
+ }
+
+ /** Checking 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;
+ int current_ts = 0;
+ int expired = 0;
+
+ OSHashNode *curr;
+ OS_ACM_Store *stored_data;
+ char *key;
+ int ti;
+
+ // Keep track of how many times we're called
+ acm_lookups++;
+
+ // Initialize Variables
+ 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:%d, curr:%d", stored_data->timestamp, 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 an 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 != NULL && **dst != '\0') {
+ return -1;
+ }
+
+ // Make sure we have data to write
+ int slen = strlen(src);
+ if ( slen <= 0 || slen > OS_ACM_MAXELM - 1 ) {
+ return -1;
+ }
+
+ // Free dst, and malloc the memory we need!
+ 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;
+}
+
+/* EOF */
diff --git a/src/analysisd/accumulator.h b/src/analysisd/accumulator.h
new file mode 100755
index 0000000..d46c6d5
--- /dev/null
+++ b/src/analysisd/accumulator.h
@@ -0,0 +1,57 @@
+/* @(#) $Id$ */
+
+/* Copyright (C) 2009 Trend Micro Inc.
+ * All right 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
+ */
+
+
+#ifndef __ACCUMULATOR_H
+
+#define __ACCUMULATOR_H
+
+/* Accumulator queues */
+#ifdef TESTRULE
+ #define ACM_CACHE "var/accumulator-cache"
+#else
+ #define ACM_CACHE "/var/accumulator-queue"
+#endif
+
+#include "eventinfo.h"
+
+/* Accumulator Max Values */
+#define OS_ACM_MAXKEY 256
+#define OS_ACM_MAXELM 81
+#define OS_ACM_MAXDATA 2048
+
+typedef struct _OS_ACM_Store {
+ int timestamp;
+ char *dstuser;
+ char *srcuser;
+ char *dstip;
+ char *srcip;
+ char *dstport;
+ char *srcport;
+ char *data;
+} OS_ACM_Store;
+
+/* Accumulator Constants */
+#define OS_ACM_EXPIRE_ELM 120
+#define OS_ACM_PURGE_INTERVAL 300
+#define OS_ACM_PURGE_COUNT 200
+
+/* Accumulator Functions */
+int Accumulate_Init();
+Eventinfo* Accumulate(Eventinfo *lf);
+void Accumulate_CleanUp();
+
+/* Internal Functions */
+int acm_str_replace(char **dst, const char* src);
+OS_ACM_Store *InitACMStore();
+void FreeACMStore(OS_ACM_Store *obj);
+
+#endif
diff --git a/src/analysisd/analysisd.c b/src/analysisd/analysisd.c
index 579f492..e00cf63 100755
--- a/src/analysisd/analysisd.c
+++ b/src/analysisd/analysisd.c
@@ -44,6 +44,7 @@
#include "stats.h"
#include "eventinfo.h"
+#include "accumulator.h"
#include "analysisd.h"
#include "picviz.h"
@@ -52,7 +53,6 @@
#include "prelude.h"
#endif
-
/** Global data **/
/* execd queue */
@@ -585,6 +585,11 @@ void OS_ReadMSG_analysisd(int m_queue)
ErrorExit(FTS_LIST_ERROR, ARGV0);
}
+ /* Initialize the Accumulator */
+ if(!Accumulate_Init()) {
+ merror("accumulator: ERROR: Initialization failed");
+ exit(1);
+ }
/* Starting the active response queues */
if(Config.ar)
@@ -849,6 +854,10 @@ void OS_ReadMSG_analysisd(int m_queue)
DecodeEvent(lf);
}
+ /* Run accumulator */
+ if( lf->decoder_info->accumulate == 1 ) {
+ lf = Accumulate(lf);
+ }
/* Firewall event */
if(lf->decoder_info->type == FIREWALL)
@@ -1220,8 +1229,6 @@ RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node)
return(NULL);
}
-
-
/* Checking if exist any regex for this rule */
if(currently_rule->regex)
{
diff --git a/src/analysisd/decoders/decode-xml.c b/src/analysisd/decoders/decode-xml.c
index f3c182d..93a24d9 100755
--- a/src/analysisd/decoders/decode-xml.c
+++ b/src/analysisd/decoders/decode-xml.c
@@ -214,6 +214,7 @@ int ReadDecodeXML(char *file)
char *xml_type = "type";
char *xml_fts = "fts";
char *xml_ftscomment = "ftscomment";
+ char *xml_accumulate = "accumulate";
int i = 0;
OSDecoderInfo *NULL_Decoder_tmp = NULL;
@@ -335,6 +336,7 @@ int ReadDecodeXML(char *file)
pi->order = NULL;
pi->plugindecoder = NULL;
pi->fts = 0;
+ pi->accumulate = 0;
pi->type = SYSLOG;
pi->prematch = NULL;
pi->program_name = NULL;
@@ -619,6 +621,12 @@ int ReadDecodeXML(char *file)
free(s_norder);
}
+ else if(strcasecmp(elements[j]->element,xml_accumulate)==0)
+ {
+ /* Enable Accumulator */
+ pi->accumulate = 1;
+ }
+
/* Getting the fts order */
else if(strcasecmp(elements[j]->element,xml_fts)==0)
{
diff --git a/src/analysisd/decoders/decoder.h b/src/analysisd/decoders/decoder.h
index 84e9e86..2fc169a 100755
--- a/src/analysisd/decoders/decoder.h
+++ b/src/analysisd/decoders/decoder.h
@@ -42,6 +42,7 @@ typedef struct
u_int16_t prematch_offset;
int fts;
+ int accumulate;
char *parent;
char *name;
char *ftscomment;
diff --git a/src/analysisd/testrule.c b/src/analysisd/testrule.c
index d2f5b25..91dcf84 100755
--- a/src/analysisd/testrule.c
+++ b/src/analysisd/testrule.c
@@ -47,6 +47,7 @@
#include "stats.h"
#include "eventinfo.h"
+#include "accumulator.h"
#include "analysisd.h"
@@ -432,6 +433,11 @@ void OS_ReadMSG(int m_queue, char *ut_str)
ErrorExit(FTS_LIST_ERROR, ARGV0);
}
+ /* Initialize the Accumulator */
+ if(!Accumulate_Init()) {
+ merror("accumulator: ERROR: Initialization failed");
+ exit(1);
+ }
__crt_ftell = 1;
@@ -517,6 +523,11 @@ void OS_ReadMSG(int m_queue, char *ut_str)
/* Decoding event. */
DecodeEvent(lf);
+ /* Run accumulator */
+ if( lf->decoder_info->accumulate == 1 ) {
+ print_out("\n**ACCUMULATOR: LEVEL UP!!**\n");
+ lf = Accumulate(lf);
+ }
/* Looping all the rules */
rulenode_pt = OS_GetFirstRule();
diff --git a/src/headers/hash_op.h b/src/headers/hash_op.h
index 9b0777a..074dc57 100755
--- a/src/headers/hash_op.h
+++ b/src/headers/hash_op.h
@@ -66,6 +66,7 @@ void *OSHash_Free(OSHash *self);
*/
int OSHash_Add(OSHash *hash, char *key, void *data);
int OSHash_Update(OSHash *hash, char *key, void *data);
+void* OSHash_Delete(OSHash *self, char *key);
/** void *OSHash_Get(OSHash *self, char *key)
diff --git a/src/os_execd/execd.c b/src/os_execd/execd.c
index 09b5107..763bb02 100755
--- a/src/os_execd/execd.c
+++ b/src/os_execd/execd.c
@@ -522,6 +522,7 @@ void ExecdStart(int q)
}
else
{
+ free(ntimes); // In hash_op.c, data belongs to caller
os_calloc(10, sizeof(char), ntimes);
new_timeout = repeated_offenders_timeout[ntimes_int]*60;
ntimes_int++;
diff --git a/src/shared/hash_op.c b/src/shared/hash_op.c
index 20b7392..3a8db63 100755
--- a/src/shared/hash_op.c
+++ b/src/shared/hash_op.c
@@ -92,6 +92,7 @@ void *OSHash_Free(OSHash *self)
while(next_node)
{
next_node = next_node->next;
+ free(curr_node->key);
free(curr_node);
curr_node = next_node;
}
@@ -204,7 +205,6 @@ int OSHash_Update(OSHash *self, char *key, void *data)
/* Checking for duplicated key -- not adding */
if(strcmp(curr_node->key, key) == 0)
{
- free(curr_node->data);
curr_node->data = data;
return(1);
}
@@ -260,7 +260,12 @@ int OSHash_Add(OSHash *self, char *key, void *data)
}
new_node->next = NULL;
new_node->data = data;
- new_node->key = key;
+ new_node->key = strdup(key);
+ if( new_node->key == NULL ) {
+ free(new_node);
+ debug1("hash_op: DEBUG: strdup() failed!");
+ return(0);
+ }
/* Adding to table */
@@ -303,8 +308,12 @@ void *OSHash_Get(OSHash *self, char *key)
/* Getting entry */
curr_node = self->table[index];
- while(curr_node)
+ while(curr_node != NULL)
{
+ /* Skip null pointers */
+ if( curr_node->key == NULL )
+ continue;
+
/* We may have colisions, so double check with strcmp */
if(strcmp(curr_node->key, key) == 0)
{
@@ -317,6 +326,40 @@ void *OSHash_Get(OSHash *self, char *key)
return(NULL);
}
+/* Returns a pointer to a hash node if found, that hash node is removed from the table */
+void* OSHash_Delete(OSHash *self, char *key)
+{
+ OSHashNode *curr_node;
+ OSHashNode *prev_node = 0;
+ unsigned int hash_key;
+ unsigned int index;
+ void *data;
+
+ /* Generating hash of the message */
+ hash_key = _os_genhash(self, key);
+ /* Getting array index */
+ index = hash_key % self->rows;
+
+ curr_node = self->table[index];
+ while( curr_node != NULL ) {
+ if(strcmp(curr_node->key, key) == 0) {
+ if( prev_node == NULL ) {
+ self->table[index] = curr_node->next;
+ }
+ else {
+ prev_node->next = curr_node->next;
+ }
+ free(curr_node->key);
+ data = curr_node->data;
+ free(curr_node);
+ return data;
+ }
+ prev_node = curr_node;
+ curr_node = curr_node->next;
+ }
+
+ return NULL;
+}
/* EOF */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment