From e7c4ecd5b19d821d7815c2977f294e674ea45968 Mon Sep 17 00:00:00 2001 From: Elizabeth Myers Date: Sat, 30 Apr 2016 01:11:08 -0500 Subject: [PATCH] authproc: don't delete during iteration, this is not safe. --- ircd/authproc.c | 98 ++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/ircd/authproc.c b/ircd/authproc.c index 7aa93dd7c..ff1791604 100644 --- a/ircd/authproc.c +++ b/ircd/authproc.c @@ -119,9 +119,6 @@ start_authd(void) if(cid_clients == NULL) cid_clients = rb_dictionary_create("authd cid to uid mapping", rb_uint32cmp); - if(bl_stats == NULL) - bl_stats = rb_dictionary_create("blacklist statistics", rb_strcasecmp); - if(timeout_ev == NULL) timeout_ev = rb_event_addish("timeout_dead_authd_clients", timeout_dead_authd_clients, NULL, 1); @@ -133,6 +130,7 @@ start_authd(void) sendto_realops_snomask(SNO_GENERAL, L_ALL, "Unable to start authd helper: %s", strerror(errno)); return 1; } + ilog(L_MAIN, "authd helper started"); sendto_realops_snomask(SNO_GENERAL, L_ALL, "authd helper started"); rb_helper_run(authd_helper); @@ -356,6 +354,36 @@ configure_authd(void) opm_check_enable(false); } +static void +authd_free_client(struct Client *client_p) +{ + if(client_p == NULL || client_p->preClient == NULL) + return; + + if(client_p->preClient->auth.cid == 0) + return; + + if(authd_helper != NULL) + rb_helper_write(authd_helper, "E %x", client_p->preClient->auth.cid); + + client_p->preClient->auth.accepted = true; + client_p->preClient->auth.cid = 0; +} + +static void +authd_free_client_cb(rb_dictionary_element *delem, void *unused) +{ + struct Client *client_p = delem->data; + authd_free_client(client_p); +} + +void +authd_abort_client(struct Client *client_p) +{ + rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid)); + authd_free_client(client_p); +} + static void restart_authd_cb(rb_helper * helper) { @@ -371,11 +399,8 @@ restart_authd_cb(rb_helper * helper) authd_helper = NULL; } - RB_DICTIONARY_FOREACH(client_p, &iter, cid_clients) - { - /* Abort any existing clients */ - authd_abort_client(client_p); - } + rb_dictionary_destroy(cid_clients, authd_free_client_cb, NULL); + cid_clients = NULL; start_authd(); configure_authd(); @@ -531,34 +556,28 @@ authd_reject_client(struct Client *client_p, const char *ident, const char *host authd_decide_client(client_p, ident, host, false, cause, data, reason); } -void -authd_abort_client(struct Client *client_p) -{ - if(client_p == NULL || client_p->preClient == NULL) - return; - - if(client_p->preClient->auth.cid == 0) - return; - - rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid)); - - if(authd_helper != NULL) - rb_helper_write(authd_helper, "E %x", client_p->preClient->auth.cid); - - client_p->preClient->auth.accepted = true; - client_p->preClient->auth.cid = 0; -} - static void timeout_dead_authd_clients(void *notused __unused) { rb_dictionary_iter iter; struct Client *client_p; + rb_dlink_list freelist = { NULL, NULL, 0 }; + rb_dlink_node *ptr, *nptr; RB_DICTIONARY_FOREACH(client_p, &iter, cid_clients) { if(client_p->preClient->auth.timeout < rb_current_time()) - authd_abort_client(client_p); + { + authd_free_client(client_p); + rb_dlinkAddAlloc(client_p, &freelist); + } + } + + /* RB_DICTIONARY_FOREACH is not safe for deletion, so we do this crap */ + RB_DLINK_FOREACH_SAFE(ptr, nptr, freelist.head) + { + client_p = ptr->data; + rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid)); } } @@ -571,6 +590,9 @@ add_blacklist(const char *host, const char *reason, uint8_t iptype, rb_dlink_lis char filterbuf[BUFSIZE] = "*"; size_t s = 0; + if(bl_stats == NULL) + bl_stats = rb_dictionary_create("blacklist statistics", rb_strcasecmp); + /* Build a list of comma-separated values for authd. * We don't check for validity - do it elsewhere. */ @@ -605,27 +627,29 @@ del_blacklist(const char *host) struct BlacklistStats *stats = rb_dictionary_retrieve(bl_stats, host); if(stats != NULL) { - rb_dictionary_delete(bl_stats, host); rb_free(stats->host); rb_free(stats); + rb_dictionary_delete(bl_stats, host); } rb_helper_write(authd_helper, "O rbl_del %s", host); } +static void +blacklist_delete(rb_dictionary_element *delem, void *unused) +{ + struct BlacklistStats *stats = delem->data; + + rb_free(stats->host); + rb_free(stats); +} + /* Delete all the blacklists */ void del_blacklist_all(void) { - struct BlacklistStats *stats; - rb_dictionary_iter iter; - - RB_DICTIONARY_FOREACH(stats, &iter, bl_stats) - { - rb_dictionary_delete(bl_stats, stats->host); - rb_free(stats->host); - rb_free(stats); - } + rb_dictionary_destroy(bl_stats, blacklist_delete, NULL); + bl_stats = NULL; rb_helper_write(authd_helper, "O rbl_del_all"); }