From 543b8c392c9ce80e4f2bef9124455bda984e9947 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Sun, 14 Dec 2008 18:25:15 +0100 Subject: [PATCH] Make rehashing privset{} change online oper privileges. This also fixes memory leak due to multiple privsets with the same name (added after each rehash). --- include/privilege.h | 3 + src/privilege.c | 156 +++++++++++++++++++++++++++++++------------- src/s_conf.c | 4 ++ 3 files changed, 118 insertions(+), 45 deletions(-) diff --git a/include/privilege.h b/include/privilege.h index c454efc..2af53f3 100644 --- a/include/privilege.h +++ b/include/privilege.h @@ -31,6 +31,7 @@ typedef enum { } PrivilegeFlags; struct PrivilegeSet { + unsigned int status; /* If CONF_ILLEGAL, delete when no refs */ int refs; char *name; char *privs; @@ -44,5 +45,7 @@ struct PrivilegeSet *privilegeset_extend(struct PrivilegeSet *parent, const char struct PrivilegeSet *privilegeset_get(const char *name); struct PrivilegeSet *privilegeset_ref(struct PrivilegeSet *set); void privilegeset_unref(struct PrivilegeSet *set); +void privilegeset_mark_all_illegal(void); +void privilegeset_delete_all_illegal(void); #endif diff --git a/src/privilege.c b/src/privilege.c index 060cf48..239b779 100644 --- a/src/privilege.c +++ b/src/privilege.c @@ -22,6 +22,7 @@ */ #include +#include "s_conf.h" #include "privilege.h" static rb_dlink_list privilegeset_list = {}; @@ -35,50 +36,8 @@ privilegeset_in_set(struct PrivilegeSet *set, const char *priv) return strstr(set->privs, priv) != NULL; } -struct PrivilegeSet * -privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags) -{ - struct PrivilegeSet *set; - - s_assert(privilegeset_get(name) == NULL); - - set = rb_malloc(sizeof(struct PrivilegeSet)); - set->refs = 1; - set->name = rb_strdup(name); - set->privs = rb_strdup(privs); - set->flags = flags; - - rb_dlinkAdd(set, &set->node, &privilegeset_list); - - return set; -} - -struct PrivilegeSet * -privilegeset_extend(struct PrivilegeSet *parent, const char *name, const char *privs, PrivilegeFlags flags) -{ - struct PrivilegeSet *set; - - s_assert(parent != NULL); - s_assert(name != NULL); - s_assert(privs != NULL); - s_assert(privilegeset_get(name) == NULL); - - set = rb_malloc(sizeof(struct PrivilegeSet)); - set->refs = 1; - set->name = rb_strdup(name); - set->flags = flags; - set->privs = rb_malloc(strlen(parent->privs) + 1 + strlen(privs) + 1); - strcpy(set->privs, parent->privs); - strcat(set->privs, " "); - strcat(set->privs, privs); - - rb_dlinkAdd(set, &set->node, &privilegeset_list); - - return set; -} - -struct PrivilegeSet * -privilegeset_get(const char *name) +static struct PrivilegeSet * +privilegeset_get_any(const char *name) { rb_dlink_node *iter; @@ -95,6 +54,80 @@ privilegeset_get(const char *name) return NULL; } +struct PrivilegeSet * +privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags) +{ + struct PrivilegeSet *set; + + set = privilegeset_get_any(name); + if (set != NULL) + { + if (!(set->status & CONF_ILLEGAL)) + ilog(L_MAIN, "Duplicate privset %s", name); + set->status &= ~CONF_ILLEGAL; + rb_free(set->privs); + } + else + { + set = rb_malloc(sizeof(struct PrivilegeSet)); + set->status = 0; + set->refs = 0; + set->name = rb_strdup(name); + + rb_dlinkAdd(set, &set->node, &privilegeset_list); + } + set->privs = rb_strdup(privs); + set->flags = flags; + + return set; +} + +struct PrivilegeSet * +privilegeset_extend(struct PrivilegeSet *parent, const char *name, const char *privs, PrivilegeFlags flags) +{ + struct PrivilegeSet *set; + + s_assert(parent != NULL); + s_assert(name != NULL); + s_assert(privs != NULL); + + set = privilegeset_get_any(name); + if (set != NULL) + { + if (!(set->status & CONF_ILLEGAL)) + ilog(L_MAIN, "Duplicate privset %s", name); + set->status &= ~CONF_ILLEGAL; + rb_free(set->privs); + } + else + { + set = rb_malloc(sizeof(struct PrivilegeSet)); + set->status = 0; + set->refs = 0; + set->name = rb_strdup(name); + + rb_dlinkAdd(set, &set->node, &privilegeset_list); + } + set->flags = flags; + set->privs = rb_malloc(strlen(parent->privs) + 1 + strlen(privs) + 1); + strcpy(set->privs, parent->privs); + strcat(set->privs, " "); + strcat(set->privs, privs); + + return set; +} + +struct PrivilegeSet * +privilegeset_get(const char *name) +{ + struct PrivilegeSet *set; + + set = privilegeset_get_any(name); + if (set != NULL && set->status & CONF_ILLEGAL) + set = NULL; + return set; +} + struct PrivilegeSet * privilegeset_ref(struct PrivilegeSet *set) { @@ -110,7 +143,12 @@ privilegeset_unref(struct PrivilegeSet *set) { s_assert(set != NULL); - if (--set->refs == 0) + if (set->refs > 0) + set->refs--; + else + ilog(L_MAIN, "refs on privset %s is already 0", + set->name); + if (set->refs == 0 && set->status & CONF_ILLEGAL) { rb_dlinkDelete(&set->node, &privilegeset_list); @@ -119,3 +157,31 @@ privilegeset_unref(struct PrivilegeSet *set) rb_free(set); } } + +void +privilegeset_mark_all_illegal(void) +{ + rb_dlink_node *iter; + + RB_DLINK_FOREACH(iter, privilegeset_list.head) + { + struct PrivilegeSet *set = (struct PrivilegeSet *) iter->data; + + set->status |= CONF_ILLEGAL; + /* but do not free it yet */ + } +} + +void +privilegeset_delete_all_illegal(void) +{ + rb_dlink_node *iter, *next; + + RB_DLINK_FOREACH_SAFE(iter, next, privilegeset_list.head) + { + struct PrivilegeSet *set = (struct PrivilegeSet *) iter->data; + + privilegeset_ref(set); + privilegeset_unref(set); + } +} diff --git a/src/s_conf.c b/src/s_conf.c index b78fa51..430ef20 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -46,6 +46,7 @@ #include "reject.h" #include "cache.h" #include "blacklist.h" +#include "privilege.h" #include "sslproc.h" struct config_server_hide ConfigServerHide; @@ -853,6 +854,7 @@ read_conf(FILE * file) validate_conf(); /* Check to make sure some values are still okay. */ /* Some global values are also loaded here. */ check_class(); /* Make sure classes are valid */ + privilegeset_delete_all_illegal(); } static void @@ -1253,6 +1255,8 @@ clear_out_old_conf(void) destroy_blacklists(); + privilegeset_mark_all_illegal(); + /* OK, that should be everything... */ }