Implement chanroles, as discussed with nenolod.
The theory behind this is that services sends an ENCAP * GRANT #channel UID :+flagspec message specifying the chanroles the user has. They are mapped into flag bits and applied to the membership of the user. They then are restricted or permitted to what they can do based on the permissions mask regardless of rank. For backwards compatibility, the default permission bit (without a GRANT statement) allows a user to to anything an existing op can do ONLY if they are an op. Todo: make CHANROLE_STATUS work (the ability to apply +ov to people), which is at the moment controlled by CHANROLE_MODE.
This commit is contained in:
parent
0351022738
commit
8aabb973c0
8 changed files with 148 additions and 9 deletions
|
@ -60,7 +60,7 @@ struct Channel
|
|||
rb_dlink_list members; /* channel members */
|
||||
rb_dlink_list locmembers; /* local channel members */
|
||||
|
||||
rb_dlink_list invites;
|
||||
rb_dlink_list invites;
|
||||
rb_dlink_list banlist;
|
||||
rb_dlink_list exceptlist;
|
||||
rb_dlink_list invexlist;
|
||||
|
@ -87,6 +87,7 @@ struct membership
|
|||
struct Channel *chptr;
|
||||
struct Client *client_p;
|
||||
unsigned int flags;
|
||||
unsigned int roles;
|
||||
|
||||
unsigned long bants;
|
||||
};
|
||||
|
@ -187,11 +188,26 @@ typedef int (*ExtbanFunc)(const char *data, struct Client *client_p,
|
|||
#define MODE_ADD 1
|
||||
#define MODE_DEL -1
|
||||
|
||||
/* Channel roles */
|
||||
#define CHANROLE_NONE 0x000
|
||||
#define CHANROLE_UNSET 0x001 /* Special value */
|
||||
#define CHANROLE_KICK 0x002 /* Can kick */
|
||||
#define CHANROLE_STATUS 0x004 /* Can change status modes */
|
||||
#define CHANROLE_GRANT 0x008 /* Can grant (unused atm) */
|
||||
#define CHANROLE_MODE 0x010 /* Can change modes */
|
||||
#define CHANROLE_TOPIC 0x020 /* Can change topic */
|
||||
|
||||
#define SecretChannel(x) ((x) && ((x)->mode.mode & MODE_SECRET))
|
||||
#define HiddenChannel(x) ((x) && ((x)->mode.mode & MODE_PRIVATE))
|
||||
#define PubChannel(x) ((!x) || ((x)->mode.mode &\
|
||||
(MODE_PRIVATE | MODE_SECRET)) == 0)
|
||||
|
||||
#define HasChanRole(m, r) (((m)->roles & r) != 0)
|
||||
#define SetChanRole(m, r) ((m)->roles |= r)
|
||||
#define RemoveChanRole(m, r) ((m)->roles &= ~r)
|
||||
|
||||
#define IsChanRoleSet(m, r)
|
||||
|
||||
/* channel visible */
|
||||
#define ShowChannel(v,c) (PubChannel(c) || IsMember((v),(c)))
|
||||
|
||||
|
@ -279,7 +295,7 @@ extern int match_extban(const char *banstr, struct Client *client_p, struct Chan
|
|||
extern int valid_extban(const char *banstr, struct Client *client_p, struct Channel *chptr, long mode_type);
|
||||
const char * get_extban_string(void);
|
||||
|
||||
extern int get_channel_access(struct Client *source_p, struct membership *msptr);
|
||||
extern int get_channel_access(struct Client *source_p, struct membership *msptr, int role);
|
||||
|
||||
extern void send_channel_join(struct Channel *chptr, struct Client *client_p);
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ TSRCS = \
|
|||
m_dline.c \
|
||||
m_encap.c \
|
||||
m_etrace.c \
|
||||
m_grant.c \
|
||||
m_help.c \
|
||||
m_info.c \
|
||||
m_invite.c \
|
||||
|
|
|
@ -97,7 +97,7 @@ m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *p
|
|||
return 0;
|
||||
}
|
||||
|
||||
if(get_channel_access(source_p, msptr) < CHFL_CHANOP)
|
||||
if(get_channel_access(source_p, msptr, CHANROLE_KICK) < CHFL_CHANOP)
|
||||
{
|
||||
if(MyConnect(source_p))
|
||||
{
|
||||
|
|
102
modules/m_grant.c
Normal file
102
modules/m_grant.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* charybdis: an advanced ircd
|
||||
* m_grant: handle services grant commands
|
||||
*/
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "client.h"
|
||||
#include "ircd.h"
|
||||
#include "numeric.h"
|
||||
#include "s_serv.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
#include "modules.h"
|
||||
#include "s_conf.h"
|
||||
#include "hash.h"
|
||||
|
||||
struct flag_list
|
||||
{
|
||||
char *name;
|
||||
int flag;
|
||||
};
|
||||
|
||||
static struct flag_list flaglist[] = {
|
||||
{"kick", CHANROLE_KICK},
|
||||
{"grant", CHANROLE_GRANT},
|
||||
{"mode", CHANROLE_MODE},
|
||||
{"topic", CHANROLE_TOPIC},
|
||||
{"status", CHANROLE_STATUS},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
static int me_grant(struct Client *, struct Client *, int, const char **);
|
||||
|
||||
struct Message grant_msgtab = {
|
||||
"GRANT", 0, 0, 0, MFLG_SLOW,
|
||||
{mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_grant, 4}, mg_ignore}
|
||||
};
|
||||
|
||||
mapi_clist_av1 grant_clist[] = { &grant_msgtab, NULL };
|
||||
DECLARE_MODULE_AV1(grant, NULL, NULL, grant_clist, NULL, NULL, "Charybdis development team");
|
||||
|
||||
/*
|
||||
* me_grant
|
||||
*
|
||||
* parv[1] = channel
|
||||
* parv[2] = target UID
|
||||
* parv[3] = flag spec
|
||||
*/
|
||||
static int
|
||||
me_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
||||
{
|
||||
struct Channel *chptr;
|
||||
struct Client *target_p;
|
||||
struct membership *msptr;
|
||||
char *s, *t, *p;
|
||||
|
||||
if (!(chptr = find_channel(parv[1])))
|
||||
return 0;
|
||||
|
||||
if (!(target_p = find_person(parv[2])))
|
||||
return 0;
|
||||
|
||||
/* Makes no sense to do this for non-local users */
|
||||
if(!MyClient(target_p))
|
||||
return 0;
|
||||
|
||||
if (!(msptr = find_channel_membership(chptr, target_p)))
|
||||
return 0;
|
||||
|
||||
/* Unset */
|
||||
RemoveChanRole(msptr, CHANROLE_UNSET);
|
||||
|
||||
t = LOCAL_COPY(parv[3]);
|
||||
for (s = rb_strtok_r(t, " ", &p); s; s = rb_strtok_r(NULL, " ", &p))
|
||||
{
|
||||
const char *priv = s + 1; /* The actual priv */
|
||||
struct flag_list *fl;
|
||||
int flag = 0;
|
||||
|
||||
/* Go through the flags list... */
|
||||
for(fl = flaglist; fl->name != NULL; fl++)
|
||||
{
|
||||
if (strcasecmp(fl->name, priv) == 0)
|
||||
{
|
||||
flag = fl->flag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ack no flag! */
|
||||
if (!flag)
|
||||
continue;
|
||||
|
||||
if (s[0] == '-')
|
||||
RemoveChanRole(msptr, flag);
|
||||
else if (s[0] == '+')
|
||||
SetChanRole(msptr, flag);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -118,7 +118,7 @@ m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *
|
|||
}
|
||||
|
||||
if(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
|
||||
get_channel_access(source_p, msptr) >= CHFL_CHANOP) &&
|
||||
get_channel_access(source_p, msptr, CHANROLE_TOPIC) >= CHFL_CHANOP) &&
|
||||
(!MyClient(source_p) ||
|
||||
can_send(chptr, source_p, msptr)))
|
||||
{
|
||||
|
|
|
@ -236,6 +236,9 @@ add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
|
|||
msptr->client_p = client_p;
|
||||
msptr->flags = flags;
|
||||
|
||||
/* Default to no chanroles until services says we're something else */
|
||||
msptr->roles = CHANROLE_UNSET;
|
||||
|
||||
rb_dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
|
||||
rb_dlinkAdd(msptr, &msptr->channode, &chptr->members);
|
||||
|
||||
|
|
25
src/chmode.c
25
src/chmode.c
|
@ -187,7 +187,7 @@ cflag_orphan(char c_)
|
|||
}
|
||||
|
||||
int
|
||||
get_channel_access(struct Client *source_p, struct membership *msptr)
|
||||
get_channel_access(struct Client *source_p, struct membership *msptr, int role)
|
||||
{
|
||||
hook_data_channel_approval moduledata;
|
||||
|
||||
|
@ -201,7 +201,24 @@ get_channel_access(struct Client *source_p, struct membership *msptr)
|
|||
moduledata.chptr = msptr->chptr;
|
||||
moduledata.msptr = msptr;
|
||||
moduledata.target = NULL;
|
||||
moduledata.approved = is_chanop(msptr) ? CHFL_CHANOP : CHFL_PEON;
|
||||
|
||||
if (is_chanop(msptr))
|
||||
{
|
||||
/* Their chanrole is unset by GRANT, for backwards compat let them pass */
|
||||
if(HasChanRole(msptr, CHANROLE_UNSET))
|
||||
{
|
||||
moduledata.approved = CHFL_CHANOP;
|
||||
goto finish_access;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if they have the proper role */
|
||||
if(HasChanRole(msptr, role))
|
||||
moduledata.approved = CHFL_CHANOP;
|
||||
else
|
||||
moduledata.approved = CHFL_PEON;
|
||||
|
||||
finish_access:
|
||||
|
||||
call_hook(h_get_channel_access, &moduledata);
|
||||
|
||||
|
@ -1200,7 +1217,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr,
|
|||
if(MyClient(source_p) && !(targptr->mode.mode & MODE_FREETARGET))
|
||||
{
|
||||
if((msptr = find_channel_membership(targptr, source_p)) == NULL ||
|
||||
get_channel_access(source_p, msptr) != CHFL_CHANOP)
|
||||
get_channel_access(source_p, msptr, CHANROLE_MODE) != CHFL_CHANOP)
|
||||
{
|
||||
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
|
||||
me.name, source_p->name, targptr->chname);
|
||||
|
@ -1618,7 +1635,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p,
|
|||
mode_limit = 0;
|
||||
mode_limit_simple = 0;
|
||||
|
||||
alevel = get_channel_access(source_p, msptr);
|
||||
alevel = get_channel_access(source_p, msptr, CHANROLE_MODE);
|
||||
|
||||
/* Hide connecting server on netburst -- jilles */
|
||||
if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p))
|
||||
|
|
|
@ -507,7 +507,7 @@ static const char * replies[] = {
|
|||
/* 479 ERR_BADCHANNAME */ "%s :Illegal channel name",
|
||||
/* 480 ERR_THROTTLE */ ":%s 480 %s %s :Cannot join channel (+j) - throttle exceeded, try again later",
|
||||
/* 481 ERR_NOPRIVILEGES, */ ":Permission Denied - You're not an IRC operator",
|
||||
/* 482 ERR_CHANOPRIVSNEEDED, */ ":%s 482 %s %s :You're not a channel operator",
|
||||
/* 482 ERR_CHANOPRIVSNEEDED, */ ":%s 482 %s %s :You're not a channel operator or have no privilege",
|
||||
/* 483 ERR_CANTKILLSERVER, */ ":You can't kill a server!",
|
||||
/* 484 ERR_ISCHANSERVICE */ ":%s 484 %s %s %s :Cannot kick or deop a network service",
|
||||
/* 485 ERR_BANNEDNICK, */ NULL,
|
||||
|
|
Loading…
Reference in a new issue