]> jfr.im git - irc/rqf/shadowircd.git/blobdiff - src/privilege.c
Make rehashing privset{} change online oper privileges.
[irc/rqf/shadowircd.git] / src / privilege.c
index 060cf4895fd5fe488d585485db30e9d174a1f7f2..239b7796d75cd4ba3c207b1968ddf92b8f70379a 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <stdinc.h>
+#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);
+       }
+}