Skip to content

Instantly share code, notes, and snippets.

Embed
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
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.