cap: substantial rewrite leveraging the ircd capabilities framework for client caps

This commit is contained in:
William Pitcock 2016-02-27 01:41:36 -06:00
parent ba83226733
commit 32df5e96a6
7 changed files with 101 additions and 102 deletions

View file

@ -38,6 +38,7 @@ struct CapabilityEntry {
void *ownerdata;
};
extern struct CapabilityEntry *capability_find(struct CapabilityIndex *idx, const char *cap);
extern unsigned int capability_get(struct CapabilityIndex *idx, const char *cap, void **ownerdata);
extern unsigned int capability_put(struct CapabilityIndex *idx, const char *cap, void *ownerdata);
extern unsigned int capability_put_anonymous(struct CapabilityIndex *idx);

View file

@ -445,18 +445,6 @@ struct ListClient
UMODE_WALLOP | UMODE_LOCOPS)
#define DEFAULT_OPER_SNOMASK SNO_GENERAL
/* XXX make clicap a registry */
#define CLICAP_MULTI_PREFIX 0x0001
#define CLICAP_SASL 0x0002
#define CLICAP_ACCOUNT_NOTIFY 0x0004
#define CLICAP_EXTENDED_JOIN 0x0008
#define CLICAP_AWAY_NOTIFY 0x0010
#define CLICAP_TLS 0x0020
#define CLICAP_USERHOST_IN_NAMES 0x0040
#define CLICAP_CAP_NOTIFY 0x0080
#define CLICAP_CHGHOST 0x0100
#define CLICAP_ACCOUNT_TAG 0x0200
/*
* flags macros.
*/

View file

@ -51,6 +51,28 @@ struct Channel;
extern struct CapabilityIndex *serv_capindex;
extern struct CapabilityIndex *cli_capindex;
/* register client capabilities with this structure for 3.2 enhanced capability negotiation */
#define CLICAP_FLAGS_STICKY 0x001
#define CLICAP_FLAGS_REQACK 0x002
struct ClientCapability {
int (*visible)(void); /* whether or not to display the capability. set to NULL or true return value = displayed */
const char *(*data)(void); /* any custom data for the capability. set to NULL or return NULL = no data */
unsigned int flags;
};
/* builtin client capabilities */
extern unsigned int CLICAP_MULTI_PREFIX;
extern unsigned int CLICAP_SASL;
extern unsigned int CLICAP_ACCOUNT_NOTIFY;
extern unsigned int CLICAP_EXTENDED_JOIN;
extern unsigned int CLICAP_AWAY_NOTIFY;
extern unsigned int CLICAP_TLS;
extern unsigned int CLICAP_USERHOST_IN_NAMES;
extern unsigned int CLICAP_CAP_NOTIFY;
extern unsigned int CLICAP_CHGHOST;
extern unsigned int CLICAP_ACCOUNT_TAG;
/*
* XXX: this is kind of ugly, but this allows us to have backwards
* API-compatibility.

View file

@ -25,6 +25,16 @@
static rb_dlink_list capability_indexes = { NULL, NULL, 0 };
struct CapabilityEntry *
capability_find(struct CapabilityIndex *idx, const char *cap)
{
s_assert(idx != NULL);
if (cap == NULL)
return NULL;
return irc_dictionary_retrieve(idx->cap_dict, cap);
}
unsigned int
capability_get(struct CapabilityIndex *idx, const char *cap, void **ownerdata)
{

View file

@ -95,6 +95,16 @@ unsigned int CAP_EOPMOD;
unsigned int CAP_BAN;
unsigned int CAP_MLOCK;
unsigned int CLICAP_MULTI_PREFIX;
unsigned int CLICAP_SASL;
unsigned int CLICAP_ACCOUNT_NOTIFY;
unsigned int CLICAP_EXTENDED_JOIN;
unsigned int CLICAP_AWAY_NOTIFY;
unsigned int CLICAP_TLS;
unsigned int CLICAP_USERHOST_IN_NAMES;
unsigned int CLICAP_CAP_NOTIFY;
unsigned int CLICAP_CHGHOST;
/*
* initialize our builtin capability table. --nenolod
*/
@ -132,6 +142,16 @@ init_builtin_capabs(void)
capability_require(serv_capindex, "ENCAP");
cli_capindex = capability_index_create("client capabilities");
CLICAP_MULTI_PREFIX = capability_put(cli_capindex, "multi-prefix", NULL);
CLICAP_SASL = capability_put(cli_capindex, "sasl", NULL);
CLICAP_ACCOUNT_NOTIFY = capability_put(cli_capindex, "account-notify", NULL);
CLICAP_EXTENDED_JOIN = capability_put(cli_capindex, "extended-join", NULL);
CLICAP_AWAY_NOTIFY = capability_put(cli_capindex, "away-notify", NULL);
CLICAP_TLS = capability_put(cli_capindex, "tls", NULL);
CLICAP_USERHOST_IN_NAMES = capability_put(cli_capindex, "userhost-in-names", NULL);
CLICAP_CAP_NOTIFY = capability_put(cli_capindex, "cap-notify", NULL);
CLICAP_CHGHOST = capability_put(cli_capindex, "chghost", NULL);
}
static CNCB serv_connect_callback;

View file

@ -41,6 +41,8 @@ mapi_hfn_list_av1 cap_account_tag_hfnlist[] = {
{ NULL, NULL }
};
unsigned int CLICAP_ACCOUNT_TAG = 0;
static void
cap_account_tag_process(hook_data *data)
{
@ -50,4 +52,17 @@ cap_account_tag_process(hook_data *data)
msgbuf_append_tag(msgbuf, "account", data->client->user->suser, CLICAP_ACCOUNT_TAG);
}
DECLARE_MODULE_AV1(cap_account_tag, NULL, NULL, NULL, NULL, cap_account_tag_hfnlist, "$Revision$");
static int
_modinit(void)
{
CLICAP_ACCOUNT_TAG = capability_put(cli_capindex, "account-tag", NULL);
return 0;
}
static void
_moddeinit(void)
{
capability_orphan(cli_capindex, "account-tag");
}
DECLARE_MODULE_AV1(cap_account_tag, _modinit, _moddeinit, NULL, NULL, cap_account_tag_hfnlist, "$Revision$");

View file

@ -2,6 +2,7 @@
*
* Copyright (C) 2005 Lee Hardy <lee@leeh.co.uk>
* Copyright (C) 2005 ircd-ratbox development team
* Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -26,8 +27,6 @@
* 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: m_cap.c 676 2006-02-03 20:05:09Z gxti $
*/
#include "stdinc.h"
@ -48,7 +47,6 @@
typedef int (*bqcmp)(const void *, const void *);
static int m_cap(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
static int modinit(void);
struct Message cap_msgtab = {
"CAP", 0, 0, 0, 0,
@ -56,57 +54,10 @@ struct Message cap_msgtab = {
};
mapi_clist_av1 cap_clist[] = { &cap_msgtab, NULL };
DECLARE_MODULE_AV1(cap, modinit, NULL, cap_clist, NULL, NULL, "$Revision: 676 $");
DECLARE_MODULE_AV1(cap, NULL, NULL, cap_clist, NULL, NULL, "$Revision: 676 $");
#define _CLICAP(name, capserv, capclient, caprequired, flags) \
{ (name), (capserv), (capclient), (caprequired), (flags), sizeof(name) - 1 }
#define CLICAP_FLAGS_STICKY 0x001
static struct clicap
{
const char *name;
int cap_serv; /* for altering s->c */
int cap_cli; /* for altering c->s */
int cap_required_serv; /* required dependency cap */
int flags;
int namelen;
} clicap_list[] = {
_CLICAP("multi-prefix", CLICAP_MULTI_PREFIX, 0, 0, 0),
_CLICAP("sasl", CLICAP_SASL, 0, 0, CLICAP_FLAGS_STICKY),
_CLICAP("account-notify", CLICAP_ACCOUNT_NOTIFY, 0, 0, 0),
_CLICAP("extended-join", CLICAP_EXTENDED_JOIN, 0, 0, 0),
_CLICAP("away-notify", CLICAP_AWAY_NOTIFY, 0, 0, 0),
_CLICAP("tls", CLICAP_TLS, 0, 0, 0),
_CLICAP("userhost-in-names", CLICAP_USERHOST_IN_NAMES, 0, 0, 0),
_CLICAP("cap-notify", CLICAP_CAP_NOTIFY, 0, 0, 0),
_CLICAP("chghost", CLICAP_CHGHOST, 0, 0, 0),
_CLICAP("account-tag", CLICAP_ACCOUNT_TAG, 0, 0, 0),
};
#define CLICAP_LIST_LEN (sizeof(clicap_list) / sizeof(struct clicap))
static int clicap_sort(struct clicap *, struct clicap *);
static int
modinit(void)
{
qsort(clicap_list, CLICAP_LIST_LEN, sizeof(struct clicap),
(bqcmp) clicap_sort);
return 0;
}
static int
clicap_sort(struct clicap *one, struct clicap *two)
{
return irccmp(one->name, two->name);
}
static int
clicap_compare(const char *name, struct clicap *cap)
{
return irccmp(name, cap->name);
}
#define IsCapableEntry(c, e) IsCapable(c, 1 << (e)->value)
#define HasCapabilityFlag(c, f) (c->ownerdata != NULL && (((struct ClientCapability *)c->ownerdata)->flags & (f)) == f)
/* clicap_find()
* Used iteratively over a buffer, extracts individual cap tokens.
@ -116,12 +67,12 @@ clicap_compare(const char *name, struct clicap *cap)
* int pointer to whether we finish with success
* Ouputs: Cap entry if found, NULL otherwise.
*/
static struct clicap *
static struct CapabilityEntry *
clicap_find(const char *data, int *negate, int *finished)
{
static char buf[BUFSIZE];
static char *p;
struct clicap *cap;
struct CapabilityEntry *cap;
char *s;
*negate = 0;
@ -158,8 +109,7 @@ clicap_find(const char *data, int *negate, int *finished)
if((s = strchr(p, ' ')))
*s++ = '\0';
if((cap = bsearch(p, clicap_list, CLICAP_LIST_LEN,
sizeof(struct clicap), (bqcmp) clicap_compare)))
if((cap = capability_find(cli_capindex, p)) != NULL)
{
if(s)
p = s;
@ -186,7 +136,8 @@ clicap_generate(struct Client *source_p, const char *subcmd, int flags, int clea
char *p;
int buflen = 0;
int curlen, mlen;
size_t i;
struct CapabilityEntry *entry;
struct DictionaryIter iter;
mlen = sprintf(buf, ":%s CAP %s %s",
me.name,
@ -203,18 +154,18 @@ clicap_generate(struct Client *source_p, const char *subcmd, int flags, int clea
return;
}
for(i = 0; i < CLICAP_LIST_LEN; i++)
DICTIONARY_FOREACH(entry, &iter, cli_capindex->cap_dict)
{
if(flags)
{
if(!IsCapable(source_p, clicap_list[i].cap_serv))
if(!IsCapableEntry(source_p, entry))
continue;
/* they are capable of this, check sticky */
else if(clear && clicap_list[i].flags & CLICAP_FLAGS_STICKY)
else if(clear && HasCapabilityFlag(entry, CLICAP_FLAGS_STICKY))
continue;
}
if (clicap_list[i].cap_serv == CLICAP_SASL)
if ((1 << entry->value) == CLICAP_SASL)
{
struct Client *agent_p = NULL;
@ -227,7 +178,7 @@ clicap_generate(struct Client *source_p, const char *subcmd, int flags, int clea
}
/* \r\n\0, possible "-~=", space, " *" */
if(buflen + clicap_list[i].namelen >= BUFSIZE - 10)
if(buflen + strlen(entry->cap) >= BUFSIZE - 10)
{
/* remove our trailing space -- if buflen == mlen
* here, we didnt even succeed in adding one.
@ -248,7 +199,7 @@ clicap_generate(struct Client *source_p, const char *subcmd, int flags, int clea
buflen++;
}
curlen = sprintf(p, "%s ", clicap_list[i].name);
curlen = sprintf(p, "%s ", entry->cap);
p += curlen;
buflen += curlen;
}
@ -265,7 +216,7 @@ clicap_generate(struct Client *source_p, const char *subcmd, int flags, int clea
static void
cap_ack(struct Client *source_p, const char *arg)
{
struct clicap *cap;
struct CapabilityEntry *cap;
int capadd = 0, capdel = 0;
int finished = 0, negate;
@ -276,19 +227,19 @@ cap_ack(struct Client *source_p, const char *arg)
cap = clicap_find(NULL, &negate, &finished))
{
/* sent an ACK for something they havent REQd */
if(!IsCapable(source_p, cap->cap_serv))
if(!IsCapableEntry(source_p, cap))
continue;
if(negate)
{
/* dont let them ack something sticky off */
if(cap->flags & CLICAP_FLAGS_STICKY)
if(HasCapabilityFlag(cap, CLICAP_FLAGS_STICKY))
continue;
capdel |= cap->cap_cli;
capdel |= (1 << cap->value);
}
else
capadd |= cap->cap_cli;
capadd |= (1 << cap->value);
}
source_p->localClient->caps |= capadd;
@ -301,12 +252,7 @@ cap_clear(struct Client *source_p, const char *arg)
clicap_generate(source_p, "ACK",
source_p->localClient->caps ? source_p->localClient->caps : -1, 1);
/* XXX - sticky capabs */
#ifdef CLICAP_STICKY
source_p->localClient->caps = source_p->localClient->caps & CLICAP_STICKY;
#else
source_p->localClient->caps = 0;
#endif
}
static void
@ -346,7 +292,7 @@ cap_req(struct Client *source_p, const char *arg)
{
char buf[BUFSIZE];
char pbuf[2][BUFSIZE];
struct clicap *cap;
struct CapabilityEntry *cap;
int buflen, plen;
int i = 0;
int capadd = 0, capdel = 0;
@ -367,11 +313,13 @@ cap_req(struct Client *source_p, const char *arg)
for(cap = clicap_find(arg, &negate, &finished); cap;
cap = clicap_find(NULL, &negate, &finished))
{
size_t namelen = strlen(cap->cap);
/* filled the first array, but cant send it in case the
* request fails. one REQ should never fill more than two
* buffers --fl
*/
if(buflen + plen + cap->namelen + 6 >= BUFSIZE)
if(buflen + plen + namelen + 6 >= BUFSIZE)
{
pbuf[1][0] = '\0';
plen = 0;
@ -380,7 +328,7 @@ cap_req(struct Client *source_p, const char *arg)
if(negate)
{
if(cap->flags & CLICAP_FLAGS_STICKY)
if(HasCapabilityFlag(cap, CLICAP_FLAGS_STICKY))
{
finished = 0;
break;
@ -389,17 +337,11 @@ cap_req(struct Client *source_p, const char *arg)
strcat(pbuf[i], "-");
plen++;
capdel |= cap->cap_serv;
capdel |= (1 << cap->value);
}
else
{
if(cap->cap_required_serv && !((capadd & cap->cap_required_serv) == cap->cap_required_serv || IsCapable(source_p, cap->cap_required_serv)))
{
finished = 0;
break;
}
if (cap->cap_serv == CLICAP_SASL)
if ((1 << cap->value) == CLICAP_SASL)
{
struct Client *agent_p = NULL;
@ -417,19 +359,20 @@ cap_req(struct Client *source_p, const char *arg)
}
}
capadd |= cap->cap_serv;
capadd |= (1 << cap->value);
}
if(cap->cap_cli)
/* XXX this probably should exclude REQACK'd caps from capadd/capdel, but keep old behaviour for now */
if(HasCapabilityFlag(cap, CLICAP_FLAGS_REQACK))
{
strcat(pbuf[i], "~");
plen++;
}
strcat(pbuf[i], cap->name);
strcat(pbuf[i], cap->cap);
if (!finished) {
strcat(pbuf[i], " ");
plen += (cap->namelen + 1);
plen += (namelen + 1);
}
}