mirror of
https://github.com/matrix-construct/construct
synced 2024-11-16 06:51:08 +01:00
cap: substantial rewrite leveraging the ircd capabilities framework for client caps
This commit is contained in:
parent
ba83226733
commit
32df5e96a6
7 changed files with 101 additions and 102 deletions
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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$");
|
||||
|
|
121
modules/m_cap.c
121
modules/m_cap.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue