Use the m_grant from ircd-seven

Charybdis' rewritten m_grant introduces at least one serious bug without
providing any apparent benefit. I think the best solution here is the
easiest one.

The bug in question is that an empty mode change is triggered after
seven's grant has done its work, and this is necessary in order to
give umodes granted by oper privileges a chance to update. The rewrite
removes this, generating a mode change only if it wants to change the
state of +o, which means the grant victim can keep privileged modes they
no longer have access to, or fail to gain new ones.
This commit is contained in:
Ed Kellett 2019-07-27 13:50:10 +01:00
parent 8b7503c89a
commit c1649fd04d
No known key found for this signature in database
GPG key ID: CB9986DEF342FABC

View file

@ -1,23 +1,8 @@
/*
* Copyright (C) 2006 Jilles Tjoelker
* Copyright (C) 2006 Stephen Bennett <spb@gentoo.org>
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* $Id$
*/
#include "stdinc.h"
@ -30,161 +15,161 @@
#include "s_serv.h"
#include "s_conf.h"
#include "s_newconf.h"
#include "privilege.h"
static int mo_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
static int me_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
static
void set_mode(struct Client *const target,
const char *const str)
{
const char *mode[] =
{
target->name,
target->name,
str,
NULL
static int do_grant(struct Client *source_p, struct Client *target_p, const char *new_privset);
struct Message grant_msgtab = {
"GRANT", 0, 0, 0, MFLG_SLOW,
{ mg_ignore, mg_not_oper, mg_ignore, mg_ignore, {me_grant, 3}, {mo_grant, 3}}
};
user_mode(target, target, 3, mode);
}
mapi_clist_av1 grant_clist[] = { &grant_msgtab, NULL };
DECLARE_MODULE_AV1(grant, NULL, NULL, grant_clist, NULL, NULL, "$Revision$");
static
void set_privset(struct Client *const source,
struct Client *const target,
const char *const privset_name)
extern struct mode_table oper_table[];
static int
mo_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
struct PrivilegeSet *const privset = privilegeset_get(privset_name);
if(!privset)
{
sendto_one_notice(source, ":There is no privilege set named '%s'.", privset_name);
return;
}
struct Client *target_p;
if(IsOper(target) && target->user->privset == privset)
{
sendto_one_notice(source, ":%s already has role of %s.", target->name, privset_name);
return;
}
if(IsOper(target))
{
sendto_one_notice(target, ":%s has changed your role to %s.", source->name, privset_name);
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s has changed %s's role to %s.", get_oper_name(source), target->name, privset_name);
target->user->privset = privset;
return;
}
struct oper_conf oper =
{
.name = (char *)privset->name,
.privset = privset,
};
oper_up(target, &oper);
set_mode(target, "+o");
sendto_one_notice(target, ":%s has granted you the role of %s.", source->name, privset_name);
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s has granted %s the role of %s.", get_oper_name(source), target->name, privset_name);
}
static
void grant_revoke(struct Client *const source,
struct Client *const target)
{
if(!IsOper(target))
{
sendto_one_notice(source, ":You can't deoper someone who isn't an oper.");
return;
}
set_mode(target, "-o");
sendto_one_notice(target, ":%s has deopered you.", source->name);
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s has deopered %s.", get_oper_name(source), target->name);
}
static
void grant(struct MsgBuf *msgbuf, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
if(MyClient(source_p) && !HasPrivilege(source_p, "oper:grant"))
if(!IsOperGrant(source_p))
{
sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "grant");
return;
return 0;
}
if(parc < 3)
target_p = find_named_person(parv[1]);
if (target_p == NULL)
{
sendto_one_notice(source_p, ":usage GRANT: <target nickname> <privilegese name | 'revoke'>");
return;
}
struct Client *const target_p = find_person(parv[1]);
if(!target_p)
{
if(IsPerson(source_p))
sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]);
return;
}
if(!MyClient(source_p) && !find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_GRANT))
{
sendto_one_notice(source_p, ":GRANT failed: You have no shared configuration block on this server.");
return;
sendto_one_numeric(source_p, ERR_NOSUCHNICK,
form_str(ERR_NOSUCHNICK), parv[1]);
return 0;
}
if (MyClient(target_p))
{
if(irccmp(parv[2], "revoke") == 0)
grant_revoke(source_p, target_p);
else
set_privset(source_p, target_p, parv[2]);
do_grant(source_p, target_p, parv[2]);
}
else if(MyClient(source_p))
else
{
sendto_one(target_p, ":%s ENCAP %s GRANT %s %s",
get_id(source_p, target_p),
target_p->servptr->name,
get_id(target_p, target_p),
parv[2]);
get_id(source_p, target_p), target_p->servptr->name,
get_id(target_p, target_p), parv[2]);
}
return;
return 0;
}
struct Message msgtab =
static int me_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
"GRANT", 0, 0, 0, 0,
struct Client *target_p;
target_p = find_person(parv[1]);
if (target_p == NULL)
{
mg_ignore,
mg_not_oper,
mg_ignore,
mg_ignore,
{ grant, 3 },
{ grant, 3 }
sendto_one_numeric(source_p, ERR_NOSUCHNICK,
form_str(ERR_NOSUCHNICK), parv[1]);
return 0;
}
};
mapi_clist_av1 grant_clist[] =
if(!find_shared_conf(source_p->username, source_p->host,
source_p->servptr->name, SHARED_GRANT))
{
&msgtab,
NULL
};
sendto_one(source_p, ":%s NOTICE %s :You don't have an appropriate shared"
"block to grant privilege on this server.", me.name, source_p->name);
return 0;
}
static const char grant_desc[] =
"Provides the grant facility for giving other users specific privilege sets";
do_grant(source_p, target_p, parv[2]);
DECLARE_MODULE_AV2
(
grant,
NULL,
NULL,
grant_clist,
NULL,
NULL,
NULL,
NULL,
grant_desc
);
return 0;
}
static int do_grant(struct Client *source_p, struct Client *target_p, const char *new_privset)
{
int dooper = 0, dodeoper = 0;
struct PrivilegeSet *privset = 0;
if (!strcmp(new_privset, "deoper"))
{
if (!IsAnyOper(target_p))
{
sendto_one_notice(source_p, ":You can't deoper someone who isn't an oper.");
return 0;
}
new_privset = "default";
dodeoper = 1;
sendto_one_notice(target_p, ":%s is deopering you.", source_p->name);
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is deopering %s.", get_oper_name(source_p), target_p->name);
}
else
{
if (!(privset = privilegeset_get(new_privset)))
{
sendto_one_notice(source_p, ":There is no privilege set named '%s'.", new_privset);
return 0;
}
if (privset == target_p->user->privset)
{
sendto_one_notice(source_p, ":%s already has privilege set %s.", target_p->name, target_p->user->privset->name);
return 0;
}
}
if (!dodeoper)
{
if (!IsAnyOper(target_p))
{
sendto_one_notice(target_p, ":%s is opering you with privilege set %s", source_p->name, privset->name);
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is opering %s with privilege set %s", get_oper_name(source_p), target_p->name, privset->name);
dooper = 1;
}
else
{
sendto_one_notice(target_p, ":%s is changing your privilege set to %s", source_p->name, privset->name);
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is changing the privilege set of %s to %s", get_oper_name(source_p), target_p->name, privset->name);
}
if (!IsOper(target_p))
{
dooper = 1;
}
}
if (dodeoper)
{
const char *modeparv[4];
modeparv[0] = modeparv[1] = target_p->name;
modeparv[2] = "-o";
modeparv[3] = NULL;
user_mode(target_p, target_p, 3, modeparv);
}
if (dooper)
{
struct oper_conf oper;
oper.name = "<grant>";
oper.umodes = 0;
oper.snomask = 0;
oper.privset = privset;
oper_up(target_p, &oper);
}
target_p->user->privset = privset;
const char *modeparv[4];
modeparv[0] = modeparv[1] = target_p->name;
modeparv[2] = "+";
modeparv[3] = NULL;
user_mode(target_p, target_p, 3, modeparv);
return 0;
}