From: Jilles Tjoelker Date: Sun, 14 Dec 2008 17:25:15 +0000 (+0100) Subject: Make rehashing privset{} change online oper privileges. X-Git-Url: https://jfr.im/git/solanum.git/commitdiff_plain/422bb0b553b4dd1d65765d69162f16ab0035e60a?ds=sidebyside Make rehashing privset{} change online oper privileges. This also fixes memory leak due to multiple privsets with the same name (added after each rehash). --- diff --git a/include/privilege.h b/include/privilege.h index c454efca..2af53f3e 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 060cf489..239b7796 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,21 +36,49 @@ privilegeset_in_set(struct PrivilegeSet *set, const char *priv) return strstr(set->privs, priv) != NULL; } +static struct PrivilegeSet * +privilegeset_get_any(const char *name) +{ + rb_dlink_node *iter; + + s_assert(name != NULL); + + RB_DLINK_FOREACH(iter, privilegeset_list.head) + { + struct PrivilegeSet *set = (struct PrivilegeSet *) iter->data; + + if (!strcasecmp(set->name, name)) + return set; + } + + return NULL; +} + struct PrivilegeSet * privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags) { struct PrivilegeSet *set; - s_assert(privilegeset_get(name) == 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); - set = rb_malloc(sizeof(struct PrivilegeSet)); - set->refs = 1; - set->name = rb_strdup(name); + rb_dlinkAdd(set, &set->node, &privilegeset_list); + } set->privs = rb_strdup(privs); set->flags = flags; - rb_dlinkAdd(set, &set->node, &privilegeset_list); - return set; } @@ -61,38 +90,42 @@ privilegeset_extend(struct PrivilegeSet *parent, const char *name, const char *p 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 = 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); - rb_dlinkAdd(set, &set->node, &privilegeset_list); - return set; } struct PrivilegeSet * privilegeset_get(const char *name) { - rb_dlink_node *iter; - - s_assert(name != NULL); - - RB_DLINK_FOREACH(iter, privilegeset_list.head) - { - struct PrivilegeSet *set = (struct PrivilegeSet *) iter->data; - - if (!strcasecmp(set->name, name)) - return set; - } + struct PrivilegeSet *set; - return NULL; + set = privilegeset_get_any(name); + if (set != NULL && set->status & CONF_ILLEGAL) + set = NULL; + return set; } struct PrivilegeSet * @@ -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 b78fa518..430ef201 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... */ }