Track and inform modules of privset changes
This commit is contained in:
parent
2e8a889fc9
commit
8aadf0ce46
9 changed files with 395 additions and 88 deletions
|
@ -45,6 +45,7 @@ extern int h_conf_read_start;
|
||||||
extern int h_conf_read_end;
|
extern int h_conf_read_end;
|
||||||
extern int h_outbound_msgbuf;
|
extern int h_outbound_msgbuf;
|
||||||
extern int h_rehash;
|
extern int h_rehash;
|
||||||
|
extern int h_priv_change;
|
||||||
extern int h_cap_change;
|
extern int h_cap_change;
|
||||||
|
|
||||||
void init_hook(void);
|
void init_hook(void);
|
||||||
|
@ -180,6 +181,16 @@ typedef struct
|
||||||
int approved;
|
int approved;
|
||||||
} hook_data_privmsg_user;
|
} hook_data_privmsg_user;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct Client *client;
|
||||||
|
struct PrivilegeSet *old;
|
||||||
|
struct PrivilegeSet *new;
|
||||||
|
const struct PrivilegeSet *added;
|
||||||
|
const struct PrivilegeSet *removed;
|
||||||
|
const struct PrivilegeSet *unchanged;
|
||||||
|
} hook_data_priv_change;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool signal;
|
bool signal;
|
||||||
|
|
|
@ -2,6 +2,23 @@
|
||||||
* Solanum: a slightly advanced ircd
|
* Solanum: a slightly advanced ircd
|
||||||
* privilege.h: Dynamic privileges API.
|
* privilege.h: Dynamic privileges API.
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2021 Ed Kellett <e@kellett.im>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*
|
||||||
* Copyright (c) 2008 William Pitcock <nenolod@dereferenced.org>
|
* Copyright (c) 2008 William Pitcock <nenolod@dereferenced.org>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
@ -32,22 +49,28 @@ enum {
|
||||||
typedef unsigned int PrivilegeFlags;
|
typedef unsigned int PrivilegeFlags;
|
||||||
|
|
||||||
struct PrivilegeSet {
|
struct PrivilegeSet {
|
||||||
|
rb_dlink_node node;
|
||||||
|
size_t size;
|
||||||
|
const char **privs;
|
||||||
|
size_t stored_size, allocated_size;
|
||||||
|
char *priv_storage;
|
||||||
|
char *name;
|
||||||
|
struct PrivilegeSet *shadow;
|
||||||
|
PrivilegeFlags flags;
|
||||||
unsigned int status; /* If CONF_ILLEGAL, delete when no refs */
|
unsigned int status; /* If CONF_ILLEGAL, delete when no refs */
|
||||||
int refs;
|
int refs;
|
||||||
char *name;
|
|
||||||
char *privs;
|
|
||||||
PrivilegeFlags flags;
|
|
||||||
rb_dlink_node node;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int privilegeset_in_set(struct PrivilegeSet *set, const char *priv);
|
bool privilegeset_in_set(const struct PrivilegeSet *set, const char *priv);
|
||||||
struct PrivilegeSet *privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags);
|
struct PrivilegeSet *privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags);
|
||||||
struct PrivilegeSet *privilegeset_extend(struct PrivilegeSet *parent, const char *name, const char *privs, PrivilegeFlags flags);
|
struct PrivilegeSet *privilegeset_extend(const struct PrivilegeSet *parent, const char *name, const char *privs, PrivilegeFlags flags);
|
||||||
struct PrivilegeSet *privilegeset_get(const char *name);
|
struct PrivilegeSet *privilegeset_get(const char *name);
|
||||||
struct PrivilegeSet *privilegeset_ref(struct PrivilegeSet *set);
|
struct PrivilegeSet *privilegeset_ref(struct PrivilegeSet *set);
|
||||||
void privilegeset_unref(struct PrivilegeSet *set);
|
void privilegeset_unref(struct PrivilegeSet *set);
|
||||||
void privilegeset_mark_all_illegal(void);
|
void privilegeset_prepare_rehash(void);
|
||||||
void privilegeset_delete_all_illegal(void);
|
void privilegeset_cleanup_rehash(void);
|
||||||
void privilegeset_report(struct Client *source_p);
|
void privilegeset_report(struct Client *source_p);
|
||||||
|
|
||||||
|
const struct PrivilegeSet **privilegeset_diff(const struct PrivilegeSet *, const struct PrivilegeSet *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -51,6 +51,8 @@ extern int user_modes[256];
|
||||||
extern unsigned int find_umode_slot(void);
|
extern unsigned int find_umode_slot(void);
|
||||||
extern void construct_umodebuf(void);
|
extern void construct_umodebuf(void);
|
||||||
|
|
||||||
|
struct PrivilegeSet;
|
||||||
|
extern void report_priv_change(struct Client *, struct PrivilegeSet *, struct PrivilegeSet *);
|
||||||
extern void oper_up(struct Client *, struct oper_conf *);
|
extern void oper_up(struct Client *, struct oper_conf *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -71,6 +71,7 @@ int h_conf_read_start;
|
||||||
int h_conf_read_end;
|
int h_conf_read_end;
|
||||||
int h_outbound_msgbuf;
|
int h_outbound_msgbuf;
|
||||||
int h_rehash;
|
int h_rehash;
|
||||||
|
int h_priv_change;
|
||||||
int h_cap_change;
|
int h_cap_change;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -96,6 +97,7 @@ init_hook(void)
|
||||||
h_conf_read_end = register_hook("conf_read_end");
|
h_conf_read_end = register_hook("conf_read_end");
|
||||||
h_outbound_msgbuf = register_hook("outbound_msgbuf");
|
h_outbound_msgbuf = register_hook("outbound_msgbuf");
|
||||||
h_rehash = register_hook("rehash");
|
h_rehash = register_hook("rehash");
|
||||||
|
h_priv_change = register_hook("priv_change");
|
||||||
h_cap_change = register_hook("cap_change");
|
h_cap_change = register_hook("cap_change");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
333
ircd/privilege.c
333
ircd/privilege.c
|
@ -2,6 +2,23 @@
|
||||||
* Solanum: a slightly advanced ircd
|
* Solanum: a slightly advanced ircd
|
||||||
* privilege.c: Dynamic privileges API.
|
* privilege.c: Dynamic privileges API.
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2021 Ed Kellett <e@kellett.im>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*
|
||||||
* Copyright (c) 2008 William Pitcock <nenolod@dereferenced.org>
|
* Copyright (c) 2008 William Pitcock <nenolod@dereferenced.org>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
@ -31,13 +48,19 @@
|
||||||
|
|
||||||
static rb_dlink_list privilegeset_list = {NULL, NULL, 0};
|
static rb_dlink_list privilegeset_list = {NULL, NULL, 0};
|
||||||
|
|
||||||
int
|
bool
|
||||||
privilegeset_in_set(struct PrivilegeSet *set, const char *priv)
|
privilegeset_in_set(const struct PrivilegeSet *set, const char *priv)
|
||||||
{
|
{
|
||||||
s_assert(set != NULL);
|
s_assert(set != NULL);
|
||||||
s_assert(priv != NULL);
|
s_assert(priv != NULL);
|
||||||
|
|
||||||
return strstr(set->privs, priv) != NULL;
|
if (set->privs == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const char **s = set->privs; *s != NULL; s++)
|
||||||
|
if (strcmp(*s, priv) == 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct PrivilegeSet *
|
static struct PrivilegeSet *
|
||||||
|
@ -58,6 +81,163 @@ privilegeset_get_any(const char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
privilegeset_cmp_priv(const void *a_, const void *b_)
|
||||||
|
{
|
||||||
|
const char *const *a = a_, *const *b = b_;
|
||||||
|
return strcmp(*a, *b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
privilegeset_index(struct PrivilegeSet *set)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
const char *s;
|
||||||
|
const char **p;
|
||||||
|
|
||||||
|
rb_free(set->privs);
|
||||||
|
|
||||||
|
set->privs = rb_malloc(sizeof *set->privs * (set->size + 1));
|
||||||
|
p = set->privs;
|
||||||
|
|
||||||
|
for (n = 0, s = set->priv_storage; n < set->size; n++, s += strlen(s) + 1)
|
||||||
|
*p++ = s;
|
||||||
|
qsort(set->privs, set->size, sizeof *set->privs, privilegeset_cmp_priv);
|
||||||
|
set->privs[set->size] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
privilegeset_add_privs(struct PrivilegeSet *dst, const char *privs)
|
||||||
|
{
|
||||||
|
size_t alloc_size;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (dst->priv_storage == NULL)
|
||||||
|
{
|
||||||
|
dst->stored_size = dst->allocated_size = 0;
|
||||||
|
alloc_size = 256;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alloc_size = dst->allocated_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst->stored_size += strlen(privs) + 1;
|
||||||
|
|
||||||
|
while (alloc_size < dst->stored_size)
|
||||||
|
alloc_size *= 2;
|
||||||
|
|
||||||
|
if (alloc_size > dst->allocated_size)
|
||||||
|
dst->priv_storage = rb_realloc(dst->priv_storage, alloc_size);
|
||||||
|
|
||||||
|
dst->allocated_size = alloc_size;
|
||||||
|
|
||||||
|
const char *s;
|
||||||
|
char *d;
|
||||||
|
for (s = privs, d = dst->priv_storage; s < privs + strlen(privs); s += n , d += n)
|
||||||
|
{
|
||||||
|
const char *e = strchr(s, ' ');
|
||||||
|
/* up to space if there is one, else up to end of string */
|
||||||
|
n = 1 + (e != NULL ? e - s : strlen(s));
|
||||||
|
rb_strlcpy(d, s, n);
|
||||||
|
|
||||||
|
dst->size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
privilegeset_index(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
privilegeset_add_privilegeset(struct PrivilegeSet *dst, const struct PrivilegeSet *src)
|
||||||
|
{
|
||||||
|
size_t cur_size, alloc_size;
|
||||||
|
|
||||||
|
if (dst->priv_storage == NULL)
|
||||||
|
{
|
||||||
|
dst->stored_size = dst->allocated_size = 0;
|
||||||
|
cur_size = 0;
|
||||||
|
alloc_size = 256;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cur_size = dst->stored_size;
|
||||||
|
alloc_size = dst->allocated_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst->stored_size = cur_size + src->stored_size;
|
||||||
|
|
||||||
|
while (alloc_size < dst->stored_size)
|
||||||
|
alloc_size *= 2;
|
||||||
|
|
||||||
|
if (alloc_size > dst->allocated_size)
|
||||||
|
dst->priv_storage = rb_realloc(dst->priv_storage, alloc_size);
|
||||||
|
|
||||||
|
dst->allocated_size = alloc_size;
|
||||||
|
|
||||||
|
memcpy(dst->priv_storage + cur_size, src->priv_storage, src->stored_size);
|
||||||
|
dst->size += src->size;
|
||||||
|
|
||||||
|
privilegeset_index(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct PrivilegeSet *
|
||||||
|
privilegeset_new_orphan(const char *name)
|
||||||
|
{
|
||||||
|
struct PrivilegeSet *set;
|
||||||
|
set = rb_malloc(sizeof *set);
|
||||||
|
*set = (struct PrivilegeSet) {
|
||||||
|
.size = 0,
|
||||||
|
.privs = NULL,
|
||||||
|
.priv_storage = NULL,
|
||||||
|
.shadow = NULL,
|
||||||
|
.status = 0,
|
||||||
|
.refs = 0,
|
||||||
|
.name = rb_strdup(name),
|
||||||
|
};
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
privilegeset_free(struct PrivilegeSet *set)
|
||||||
|
{
|
||||||
|
if (set == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
privilegeset_free(set->shadow);
|
||||||
|
rb_free(set->name);
|
||||||
|
rb_free(set->privs);
|
||||||
|
rb_free(set->priv_storage);
|
||||||
|
rb_free(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
privilegeset_shade(struct PrivilegeSet *set)
|
||||||
|
{
|
||||||
|
privilegeset_free(set->shadow);
|
||||||
|
|
||||||
|
set->shadow = privilegeset_new_orphan(set->name);
|
||||||
|
set->shadow->privs = set->privs;
|
||||||
|
set->shadow->size = set->size;
|
||||||
|
set->shadow->priv_storage = set->priv_storage;
|
||||||
|
set->shadow->stored_size = set->stored_size;
|
||||||
|
set->shadow->allocated_size = set->allocated_size;
|
||||||
|
|
||||||
|
set->privs = NULL;
|
||||||
|
set->size = 0;
|
||||||
|
set->priv_storage = NULL;
|
||||||
|
set->stored_size = 0;
|
||||||
|
set->allocated_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
privilegeset_clear(struct PrivilegeSet *set)
|
||||||
|
{
|
||||||
|
rb_free(set->privs);
|
||||||
|
set->privs = NULL;
|
||||||
|
set->size = 0;
|
||||||
|
set->stored_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct PrivilegeSet *
|
struct PrivilegeSet *
|
||||||
privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags)
|
privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags)
|
||||||
{
|
{
|
||||||
|
@ -69,25 +249,21 @@ privilegeset_set_new(const char *name, const char *privs, PrivilegeFlags flags)
|
||||||
if (!(set->status & CONF_ILLEGAL))
|
if (!(set->status & CONF_ILLEGAL))
|
||||||
ilog(L_MAIN, "Duplicate privset %s", name);
|
ilog(L_MAIN, "Duplicate privset %s", name);
|
||||||
set->status &= ~CONF_ILLEGAL;
|
set->status &= ~CONF_ILLEGAL;
|
||||||
rb_free(set->privs);
|
privilegeset_clear(set);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
set = rb_malloc(sizeof(struct PrivilegeSet));
|
set = privilegeset_new_orphan(name);
|
||||||
set->status = 0;
|
|
||||||
set->refs = 0;
|
|
||||||
set->name = rb_strdup(name);
|
|
||||||
|
|
||||||
rb_dlinkAdd(set, &set->node, &privilegeset_list);
|
rb_dlinkAdd(set, &set->node, &privilegeset_list);
|
||||||
}
|
}
|
||||||
set->privs = rb_strdup(privs);
|
privilegeset_add_privs(set, privs);
|
||||||
set->flags = flags;
|
set->flags = flags;
|
||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PrivilegeSet *
|
struct PrivilegeSet *
|
||||||
privilegeset_extend(struct PrivilegeSet *parent, const char *name, const char *privs, PrivilegeFlags flags)
|
privilegeset_extend(const struct PrivilegeSet *parent, const char *name, const char *privs, PrivilegeFlags flags)
|
||||||
{
|
{
|
||||||
struct PrivilegeSet *set;
|
struct PrivilegeSet *set;
|
||||||
|
|
||||||
|
@ -95,28 +271,9 @@ privilegeset_extend(struct PrivilegeSet *parent, const char *name, const char *p
|
||||||
s_assert(name != NULL);
|
s_assert(name != NULL);
|
||||||
s_assert(privs != NULL);
|
s_assert(privs != NULL);
|
||||||
|
|
||||||
set = privilegeset_get_any(name);
|
set = privilegeset_set_new(name, privs, flags);
|
||||||
if (set != NULL)
|
privilegeset_add_privilegeset(set, parent);
|
||||||
{
|
|
||||||
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->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;
|
return set;
|
||||||
}
|
}
|
||||||
|
@ -156,40 +313,118 @@ privilegeset_unref(struct PrivilegeSet *set)
|
||||||
{
|
{
|
||||||
rb_dlinkDelete(&set->node, &privilegeset_list);
|
rb_dlinkDelete(&set->node, &privilegeset_list);
|
||||||
|
|
||||||
rb_free(set->name);
|
privilegeset_free(set);
|
||||||
rb_free(set->privs);
|
|
||||||
rb_free(set);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct PrivilegeSet **
|
||||||
|
privilegeset_diff(const struct PrivilegeSet *old, const struct PrivilegeSet *new)
|
||||||
|
{
|
||||||
|
static const char *no_privs[] = { NULL };
|
||||||
|
static const struct PrivilegeSet empty = { .size = 0, .privs = no_privs };
|
||||||
|
static struct PrivilegeSet *set_unchanged = NULL,
|
||||||
|
*set_added = NULL,
|
||||||
|
*set_removed = NULL;
|
||||||
|
static const struct PrivilegeSet *result_sets[3];
|
||||||
|
static size_t n_privs = 0;
|
||||||
|
size_t new_size = n_privs ? n_privs : 32;
|
||||||
|
size_t i = 0, j = 0;
|
||||||
|
|
||||||
|
if (result_sets[0] == NULL)
|
||||||
|
{
|
||||||
|
result_sets[0] = set_unchanged = privilegeset_new_orphan("<unchanged>");
|
||||||
|
result_sets[1] = set_added = privilegeset_new_orphan("<added>");
|
||||||
|
result_sets[2] = set_removed = privilegeset_new_orphan("<removed>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old == NULL)
|
||||||
|
old = ∅
|
||||||
|
if (new == NULL)
|
||||||
|
new = ∅
|
||||||
|
|
||||||
|
while (new_size < MAX(old->size, new->size) + 1)
|
||||||
|
new_size *= 2;
|
||||||
|
|
||||||
|
if (new_size > n_privs)
|
||||||
|
{
|
||||||
|
set_unchanged->privs = rb_realloc(set_unchanged->privs, sizeof *set_unchanged->privs * new_size);
|
||||||
|
set_added->privs = rb_realloc(set_added->privs, sizeof *set_added->privs * new_size);
|
||||||
|
set_removed->privs = rb_realloc(set_removed->privs, sizeof *set_removed->privs * new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char **res_unchanged = set_unchanged->privs;
|
||||||
|
const char **res_added = set_added->privs;
|
||||||
|
const char **res_removed = set_removed->privs;
|
||||||
|
|
||||||
|
while (i < old->size || j < new->size)
|
||||||
|
{
|
||||||
|
const char *oldpriv = NULL, *newpriv = NULL;
|
||||||
|
int ord = 0;
|
||||||
|
if (i < old->size)
|
||||||
|
oldpriv = old->privs[i];
|
||||||
|
if (j < new->size)
|
||||||
|
newpriv = new->privs[j];
|
||||||
|
|
||||||
|
if (oldpriv && newpriv)
|
||||||
|
ord = strcmp(oldpriv, newpriv);
|
||||||
|
|
||||||
|
if (newpriv == NULL || ord < 0)
|
||||||
|
{
|
||||||
|
*res_removed++ = oldpriv;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if (oldpriv == NULL || ord > 0)
|
||||||
|
{
|
||||||
|
*res_added++ = newpriv;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*res_unchanged++ = oldpriv;
|
||||||
|
i++; j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*res_removed = *res_added = *res_unchanged = NULL;
|
||||||
|
set_unchanged->size = res_unchanged - set_unchanged->privs;
|
||||||
|
set_added->size = res_added - set_added->privs;
|
||||||
|
set_removed->size = res_removed - set_removed->privs;
|
||||||
|
|
||||||
|
return result_sets;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
privilegeset_mark_all_illegal(void)
|
privilegeset_prepare_rehash()
|
||||||
{
|
{
|
||||||
rb_dlink_node *iter;
|
rb_dlink_node *iter;
|
||||||
|
|
||||||
RB_DLINK_FOREACH(iter, privilegeset_list.head)
|
RB_DLINK_FOREACH(iter, privilegeset_list.head)
|
||||||
{
|
{
|
||||||
struct PrivilegeSet *set = (struct PrivilegeSet *) iter->data;
|
struct PrivilegeSet *set = iter->data;
|
||||||
|
|
||||||
/* the "default" privset is special and must remain available */
|
/* the "default" privset is special and must remain available */
|
||||||
if (!strcmp(set->name, "default"))
|
if (!strcmp(set->name, "default"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
set->status |= CONF_ILLEGAL;
|
set->status |= CONF_ILLEGAL;
|
||||||
rb_free(set->privs);
|
privilegeset_shade(set);
|
||||||
set->privs = rb_strdup("");
|
|
||||||
/* but do not free it yet */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
privilegeset_delete_all_illegal(void)
|
privilegeset_cleanup_rehash()
|
||||||
{
|
{
|
||||||
rb_dlink_node *iter, *next;
|
rb_dlink_node *iter, *next;
|
||||||
|
|
||||||
RB_DLINK_FOREACH_SAFE(iter, next, privilegeset_list.head)
|
RB_DLINK_FOREACH_SAFE(iter, next, privilegeset_list.head)
|
||||||
{
|
{
|
||||||
struct PrivilegeSet *set = (struct PrivilegeSet *) iter->data;
|
struct PrivilegeSet *set = iter->data;
|
||||||
|
|
||||||
|
if (set->shadow)
|
||||||
|
{
|
||||||
|
privilegeset_free(set->shadow);
|
||||||
|
set->shadow = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
privilegeset_ref(set);
|
privilegeset_ref(set);
|
||||||
privilegeset_unref(set);
|
privilegeset_unref(set);
|
||||||
|
@ -206,9 +441,15 @@ privilegeset_report(struct Client *source_p)
|
||||||
struct PrivilegeSet *set = ptr->data;
|
struct PrivilegeSet *set = ptr->data;
|
||||||
|
|
||||||
/* use RPL_STATSDEBUG for now -- jilles */
|
/* use RPL_STATSDEBUG for now -- jilles */
|
||||||
sendto_one_numeric(source_p, RPL_STATSDEBUG,
|
send_multiline_init(source_p, " ", ":%s %03d %s O :%s ",
|
||||||
"O :%s %s",
|
get_id(&me, source_p),
|
||||||
set->name,
|
RPL_STATSDEBUG,
|
||||||
set->privs);
|
get_id(source_p, source_p),
|
||||||
|
set->name);
|
||||||
|
send_multiline_remote_pad(source_p, &me);
|
||||||
|
send_multiline_remote_pad(source_p, source_p);
|
||||||
|
for (const char **s = set->privs; s && *s; s++)
|
||||||
|
send_multiline_item(source_p, "%s", *s);
|
||||||
|
send_multiline_fini(source_p, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -654,6 +654,8 @@ rehash(bool sig)
|
||||||
|
|
||||||
rehash_authd();
|
rehash_authd();
|
||||||
|
|
||||||
|
privilegeset_prepare_rehash();
|
||||||
|
|
||||||
/* don't close listeners until we know we can go ahead with the rehash */
|
/* don't close listeners until we know we can go ahead with the rehash */
|
||||||
read_conf_files(false);
|
read_conf_files(false);
|
||||||
|
|
||||||
|
@ -667,13 +669,12 @@ rehash(bool sig)
|
||||||
RB_DLINK_FOREACH(n, local_oper_list.head)
|
RB_DLINK_FOREACH(n, local_oper_list.head)
|
||||||
{
|
{
|
||||||
struct Client *oper = n->data;
|
struct Client *oper = n->data;
|
||||||
const char *modeparv[4];
|
struct PrivilegeSet *privset = oper->user->privset;
|
||||||
modeparv[0] = modeparv[1] = oper->name;
|
report_priv_change(oper, privset ? privset->shadow : NULL, privset);
|
||||||
modeparv[2] = "+";
|
|
||||||
modeparv[3] = NULL;
|
|
||||||
user_mode(oper, oper, 3, modeparv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
privilegeset_cleanup_rehash();
|
||||||
|
|
||||||
call_hook(h_rehash, &hdata);
|
call_hook(h_rehash, &hdata);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -862,7 +863,6 @@ read_conf(void)
|
||||||
validate_conf(); /* Check to make sure some values are still okay. */
|
validate_conf(); /* Check to make sure some values are still okay. */
|
||||||
/* Some global values are also loaded here. */
|
/* Some global values are also loaded here. */
|
||||||
check_class(); /* Make sure classes are valid */
|
check_class(); /* Make sure classes are valid */
|
||||||
privilegeset_delete_all_illegal();
|
|
||||||
construct_cflags_strings();
|
construct_cflags_strings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1577,8 +1577,6 @@ clear_out_old_conf(void)
|
||||||
|
|
||||||
del_dnsbl_entry_all();
|
del_dnsbl_entry_all();
|
||||||
|
|
||||||
privilegeset_mark_all_illegal();
|
|
||||||
|
|
||||||
/* OK, that should be everything... */
|
/* OK, that should be everything... */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -972,6 +972,26 @@ report_and_set_user_flags(struct Client *source_p, struct ConfItem *aconf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
report_priv_change(struct Client *client, struct PrivilegeSet *old, struct PrivilegeSet *new)
|
||||||
|
{
|
||||||
|
const struct PrivilegeSet *added, *removed, *unchanged;
|
||||||
|
const struct PrivilegeSet **result = privilegeset_diff(old, new);
|
||||||
|
unchanged = result[0];
|
||||||
|
added = result[1];
|
||||||
|
removed = result[2];
|
||||||
|
|
||||||
|
hook_data_priv_change hdata = {
|
||||||
|
.client = client,
|
||||||
|
.new = new,
|
||||||
|
.old = old,
|
||||||
|
.unchanged = unchanged,
|
||||||
|
.added = added,
|
||||||
|
.removed = removed,
|
||||||
|
};
|
||||||
|
call_hook(h_priv_change, &hdata);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
show_other_user_mode(struct Client *source_p, struct Client *target_p)
|
show_other_user_mode(struct Client *source_p, struct Client *target_p)
|
||||||
{
|
{
|
||||||
|
@ -1129,6 +1149,8 @@ user_mode(struct Client *client_p, struct Client *source_p, int parc, const char
|
||||||
|
|
||||||
if(source_p->user->privset != NULL)
|
if(source_p->user->privset != NULL)
|
||||||
{
|
{
|
||||||
|
report_priv_change(source_p, source_p->user->privset, NULL);
|
||||||
|
|
||||||
privilegeset_unref(source_p->user->privset);
|
privilegeset_unref(source_p->user->privset);
|
||||||
source_p->user->privset = NULL;
|
source_p->user->privset = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1435,6 +1457,8 @@ oper_up(struct Client *source_p, struct oper_conf *oper_p)
|
||||||
source_p->user->opername = rb_strdup(oper_p->name);
|
source_p->user->opername = rb_strdup(oper_p->name);
|
||||||
source_p->user->privset = privilegeset_ref(oper_p->privset);
|
source_p->user->privset = privilegeset_ref(oper_p->privset);
|
||||||
|
|
||||||
|
report_priv_change(source_p, NULL, source_p->user->privset);
|
||||||
|
|
||||||
rb_dlinkAddAlloc(source_p, &local_oper_list);
|
rb_dlinkAddAlloc(source_p, &local_oper_list);
|
||||||
rb_dlinkAddAlloc(source_p, &oper_list);
|
rb_dlinkAddAlloc(source_p, &oper_list);
|
||||||
|
|
||||||
|
@ -1471,7 +1495,10 @@ oper_up(struct Client *source_p, struct oper_conf *oper_p)
|
||||||
construct_snobuf(source_p->snomask));
|
construct_snobuf(source_p->snomask));
|
||||||
sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
|
sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
|
||||||
sendto_one_notice(source_p, ":*** Oper privilege set is %s", oper_p->privset->name);
|
sendto_one_notice(source_p, ":*** Oper privilege set is %s", oper_p->privset->name);
|
||||||
sendto_one_notice(source_p, ":*** Oper privs are %s", oper_p->privset->privs);
|
send_multiline_init(source_p, " ", ":%s NOTICE %s :*** Oper privs are ", me.name, source_p->name);
|
||||||
|
for (const char **s = oper_p->privset->privs; s && *s; s++)
|
||||||
|
send_multiline_item(source_p, "%s", *s);
|
||||||
|
send_multiline_fini(source_p, NULL);
|
||||||
send_oper_motd(source_p);
|
send_oper_motd(source_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ me_grant(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
|
||||||
static int do_grant(struct Client *source_p, struct Client *target_p, const char *new_privset)
|
static int do_grant(struct Client *source_p, struct Client *target_p, const char *new_privset)
|
||||||
{
|
{
|
||||||
int dooper = 0, dodeoper = 0;
|
int dooper = 0, dodeoper = 0;
|
||||||
struct PrivilegeSet *privset = 0;
|
struct PrivilegeSet *privset = NULL, *old_privset = NULL;
|
||||||
|
|
||||||
if (!strcasecmp(new_privset, "deoper"))
|
if (!strcasecmp(new_privset, "deoper"))
|
||||||
{
|
{
|
||||||
|
@ -144,6 +144,8 @@ static int do_grant(struct Client *source_p, struct Client *target_p, const char
|
||||||
modeparv[2] = "-o";
|
modeparv[2] = "-o";
|
||||||
modeparv[3] = NULL;
|
modeparv[3] = NULL;
|
||||||
user_mode(target_p, target_p, 3, modeparv);
|
user_mode(target_p, target_p, 3, modeparv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dooper)
|
if (dooper)
|
||||||
|
@ -154,13 +156,13 @@ static int do_grant(struct Client *source_p, struct Client *target_p, const char
|
||||||
|
|
||||||
oper_up(target_p, &oper);
|
oper_up(target_p, &oper);
|
||||||
}
|
}
|
||||||
else if (privset != NULL)
|
else
|
||||||
{
|
{
|
||||||
|
if (privset != NULL)
|
||||||
privilegeset_ref(privset);
|
privilegeset_ref(privset);
|
||||||
}
|
|
||||||
|
|
||||||
if (target_p->user->privset != NULL)
|
if (target_p->user->privset != NULL)
|
||||||
privilegeset_unref(target_p->user->privset);
|
old_privset = target_p->user->privset;
|
||||||
|
|
||||||
target_p->user->privset = privset;
|
target_p->user->privset = privset;
|
||||||
|
|
||||||
|
@ -168,11 +170,17 @@ static int do_grant(struct Client *source_p, struct Client *target_p, const char
|
||||||
sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s OPER %s %s",
|
sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s OPER %s %s",
|
||||||
use_id(target_p), target_p->user->opername, privset->name);
|
use_id(target_p), target_p->user->opername, privset->name);
|
||||||
|
|
||||||
|
report_priv_change(target_p, old_privset, privset);
|
||||||
|
|
||||||
|
if (old_privset != NULL)
|
||||||
|
privilegeset_unref(old_privset);
|
||||||
|
|
||||||
const char *modeparv[4];
|
const char *modeparv[4];
|
||||||
modeparv[0] = modeparv[1] = target_p->name;
|
modeparv[0] = modeparv[1] = target_p->name;
|
||||||
modeparv[2] = "+";
|
modeparv[2] = "+";
|
||||||
modeparv[3] = NULL;
|
modeparv[3] = NULL;
|
||||||
user_mode(target_p, target_p, 3, modeparv);
|
user_mode(target_p, target_p, 3, modeparv);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,13 +95,8 @@ static void show_privs(struct Client *source_p, struct Client *target_p)
|
||||||
send_multiline_remote_pad(source_p, source_p);
|
send_multiline_remote_pad(source_p, source_p);
|
||||||
|
|
||||||
if (target_p->user->privset)
|
if (target_p->user->privset)
|
||||||
for (char *s = target_p->user->privset->privs; s != NULL; (s = strchr(s, ' ')) && s++)
|
for (const char **s = target_p->user->privset->privs; *s != NULL; s++)
|
||||||
{
|
send_multiline_item(source_p, "%s", *s);
|
||||||
char *c = strchr(s, ' ');
|
|
||||||
if (c) *c = '\0';
|
|
||||||
send_multiline_item(source_p, "%s", s);
|
|
||||||
if (c) *c = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsOper(target_p))
|
if (IsOper(target_p))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue