1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-01 19:06:38 +02:00

- Add CAP support. Currently implemented are: multi-prefix (NAMESX), and

userhost-in-names (UHNAMES). Patch from nenotopia (#4018, #4066)
This commit is contained in:
Bram Matthys
2012-01-20 21:25:59 +01:00
parent 2b0d66498d
commit d530dbd43d
10 changed files with 471 additions and 7 deletions
+2
View File
@@ -2348,3 +2348,5 @@
and also means nothing will change in a non-ESVID scenario.
- Fix misuse of stdarg.h macros when calling vsyslog() (#4065 by Jimini).
- Ditch vsyslog() as it's only a waste of CPU, inspired by #4065.
- Add CAP support. Currently implemented are: multi-prefix (NAMESX), and
userhost-in-names (UHNAMES). Patch from nenotopia (#4018, #4066).
+2
View File
@@ -53,6 +53,8 @@
#define ERR_NOSUCHSERVICE 408
#define ERR_NOORIGIN 409
#define ERR_INVALIDCAPCMD 410
#define ERR_NORECIPIENT 411
#define ERR_NOTEXTTOSEND 412
#define ERR_NOTOPLEVEL 413
+1
View File
@@ -367,6 +367,7 @@ typedef unsigned int u_int32_t; /* XXX Hope this works! */
#define PROTO_NAMESX 0x4000 /* Send all rights in NAMES output */
#define PROTO_CLK 0x8000 /* Send cloaked host in the NICK command (regardless of +x/-x) */
#define PROTO_UHNAMES 0x10000 /* Send n!u@h in NAMES */
#define PROTO_CLICAP 0x20000 /* client capability negotiation in process */
/*
* flags macros.
+5 -2
View File
@@ -219,7 +219,7 @@ MOD_FILES=SRC/MODULES/L_COMMANDS.C SRC/MODULES/M_CHGHOST.C SRC/MODULES/M_SDESC.C
SRC/MODULES/M_WATCH.C SRC/MODULES/M_PART.C SRC/MODULES/M_JOIN.C \
SRC/MODULES/M_MOTD.C SRC/MODULES/M_OPERMOTD.C SRC/MODULES/M_BOTMOTD.C \
SRC/MODULES/M_LUSERS.C SRC/MODULES/M_NAMES.C SRC/MODULES/M_SVSNOLAG.C \
SRC/MODULES/M_STARTTLS.C SRC/MODULES/M_NOPOST.C SRC/MODULES/M_ISSECURE.C
SRC/MODULES/M_STARTTLS.C SRC/MODULES/M_NOPOST.C SRC/MODULES/M_ISSECURE.C SRC/MODULES/M_CAP.C
DLL_FILES=SRC/MODULES/M_CHGHOST.DLL SRC/MODULES/M_SDESC.DLL SRC/MODULES/M_SETIDENT.DLL \
SRC/MODULES/M_SETNAME.DLL SRC/MODULES/M_SETHOST.DLL SRC/MODULES/M_CHGIDENT.DLL \
@@ -256,7 +256,7 @@ DLL_FILES=SRC/MODULES/M_CHGHOST.DLL SRC/MODULES/M_SDESC.DLL SRC/MODULES/M_SETIDE
SRC/MODULES/M_MOTD.DLL SRC/MODULES/M_OPERMOTD.DLL SRC/MODULES/M_BOTMOTD.DLL \
SRC/MODULES/M_LUSERS.DLL SRC/MODULES/M_NAMES.DLL SRC/MODULES/M_SVSNOLAG.DLL \
SRC/MODULES/M_STARTTLS.DLL \
SRC/MODULES/M_NOPOST.DLL SRC/MODULES/M_ISSECURE.DLL \
SRC/MODULES/M_NOPOST.DLL SRC/MODULES/M_ISSECURE.DLL SRC/MODULES/M_CAP.DLL \
SRC/MODULES/CLOAK.DLL
@@ -825,6 +825,9 @@ src/modules/m_nopost.dll: src/modules/m_nopost.c $(INCLUDES)
src/modules/m_issecure.dll: src/modules/m_issecure.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/m_issecure.c $(MODLFLAGS)
src/modules/m_cap.dll: src/modules/m_cap.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/m_cap.c $(MODLFLAGS)
dummy:
+9 -2
View File
@@ -54,7 +54,7 @@ R_MODULES= \
m_connect.so m_dccallow.so m_userip.so m_nick.so m_user.so \
m_mode.so m_watch.so m_part.so m_join.so m_motd.so m_opermotd.so \
m_botmotd.so m_lusers.so m_names.so m_svsnolag.so m_addmotd.so \
m_svslusers.so m_starttls.so m_nopost.so m_issecure.so
m_svslusers.so m_starttls.so m_nopost.so m_issecure.so m_cap.so
#note change of .c to .o
COMMANDS=m_sethost.o m_chghost.o m_chgident.o m_setname.o m_setident.o \
@@ -77,7 +77,7 @@ COMMANDS=m_sethost.o m_chghost.o m_chgident.o m_setname.o m_setident.o \
m_connect.o m_dccallow.o m_userip.o m_nick.o m_user.o \
m_mode.o m_watch.o m_part.o m_join.o m_motd.o m_opermotd.o \
m_botmotd.o m_lusers.o m_names.o m_svsnolag.o m_starttls.o \
m_nopost.o m_issecure.o
m_nopost.o m_issecure.o m_cap.o
MODULES=commands.so cloak.so $(R_MODULES)
@@ -419,6 +419,9 @@ m_nopost.o: m_nopost.c $(INCLUDES)
m_issecure.o: m_issecure.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -c m_issecure.c
m_cap.o: m_cap.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -c m_cap.c
#############################################################################
# .so's section
#############################################################################
@@ -843,6 +846,10 @@ m_issecure.so: m_issecure.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o m_issecure.so m_issecure.c
m_cap.so: m_cap.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o m_cap.so m_cap.c
#############################################################################
# and now the remaining modules...
#############################################################################
+4
View File
@@ -178,6 +178,7 @@ extern int m_svsnolag_Load(int module_load);
extern int m_starttls_Load(int module_load);
extern int m_nopost_Load(int module_load);
extern int m_issecure_Load(int module_load);
extern int m_cap_Load(int module_load);
#ifdef GUEST
extern int m_guest_Load(int module_load);
#endif
@@ -217,6 +218,7 @@ extern int m_lusers_Unload(), m_names_Unload(), m_svsnolag_Unload();
extern int m_starttls_Unload();
extern int m_nopost_Unload();
extern int m_issecure_Unload();
extern int m_cap_Unload();
#ifdef GUEST
extern int m_guest_Unload();
#endif
@@ -477,6 +479,7 @@ int l_commands_Load(int module_load)
m_starttls_Load(module_load);
m_nopost_Load(module_load);
m_issecure_Load(module_load);
m_cap_Load(module_load);
#ifdef GUEST
m_guest_Load(module_load);
#endif
@@ -592,6 +595,7 @@ int l_commands_Unload(int module_unload)
m_starttls_Unload();
m_nopost_Unload();
m_issecure_Unload();
m_cap_Unload();
#ifdef GUEST
m_guest_Unload();
#endif
+442
View File
@@ -0,0 +1,442 @@
/*
* IRC - Internet Relay Chat, src/modules/m_cap.c
* (C) 2012 The UnrealIRCd Team
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "proto.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif
typedef int (*bqcmp)(const void *, const void *);
DLLFUNC int m_cap(aClient *cptr, aClient *sptr, int parc, char *parv[]);
#define MSG_CAP "CAP"
#define TOK_CAP "CA"
ModuleHeader MOD_HEADER(m_cap)
= {
"m_cap", /* Name of module */
"$Id$", /* Version */
"command /cap", /* Short description of module */
"3.2-b8-1",
NULL
};
struct clicap {
const char *name;
int cap;
int flags;
};
#define CLICAP_FLAGS_NONE 0x0
#define CLICAP_FLAGS_STICKY 0x1
#define CLICAP_FLAGS_CLIACK 0x2
static struct clicap clicap_table[] = {
{"multi-prefix", PROTO_NAMESX, CLICAP_FLAGS_NONE},
{"userhost-in-names", PROTO_UHNAMES, CLICAP_FLAGS_NONE},
};
#define CLICAP_TABLE_SIZE (sizeof(clicap_table) / sizeof(struct clicap))
static int clicap_compare(const char *name, struct clicap *cap)
{
return strcmp(name, cap->name);
}
static struct clicap *clicap_find(const char *data, int *negate, int *finished)
{
static char buf[BUFSIZE];
static char *p;
struct clicap *cap;
char *s;
*negate = 0;
if (data)
{
strlcpy(buf, data, sizeof(buf));
p = buf;
}
if (*finished)
return NULL;
/* skip any whitespace */
while(*p && isspace(*p))
p++;
if (BadPtr(p))
{
*finished = 1;
return NULL;
}
if(*p == '-')
{
*negate = 1;
p++;
/* someone sent a '-' without a parameter.. */
if(*p == '\0')
return NULL;
}
if((s = strchr(p, ' ')))
*s++ = '\0';
if((cap = bsearch(p, clicap_table, CLICAP_TABLE_SIZE,
sizeof(struct clicap), (bqcmp) clicap_compare)))
{
if(s)
p = s;
else
*finished = 1;
}
return cap;
}
static void clicap_generate(aClient *sptr, const char *subcmd, int flags, int clear)
{
char buf[BUFSIZE];
char capbuf[BUFSIZE];
char *p;
int buflen = 0;
int curlen, mlen;
size_t i;
mlen = snprintf(buf, BUFSIZE, ":%s CAP %s %s", me.name, BadPtr(sptr->name) ? "*" : sptr->name, subcmd);
p = capbuf;
buflen = mlen;
if (flags == -1)
{
sendto_one(sptr, "%s :", buf);
return;
}
for (i = 0; i < CLICAP_TABLE_SIZE; i++)
{
if (flags)
{
if (!CHECKPROTO(sptr, clicap_table[i].cap))
continue;
else if (clear && clicap_table[i].flags & CLICAP_FLAGS_STICKY)
continue;
}
/* \r\n\0, possible "-~=", space, " *" */
if (buflen + strlen(clicap_table[i].name) >= BUFSIZE - 10)
{
if (buflen != mlen)
*(p - 1) = '\0';
else
*p = '\0';
sendto_one(sptr, "%s * :%s", buf, capbuf);
p = capbuf;
buflen = mlen;
}
if (clear)
{
*p++ = '-';
buflen++;
if (clicap_table[i].flags & CLICAP_FLAGS_CLIACK &&
CHECKPROTO(sptr, clicap_table[i].cap))
{
*p++ = '~';
buflen++;
}
}
else
{
if (clicap_table[i].flags & CLICAP_FLAGS_STICKY)
{
*p++ = '=';
buflen++;
}
if (clicap_table[i].flags & CLICAP_FLAGS_CLIACK &&
!CHECKPROTO(sptr, clicap_table[i].cap))
{
*p++ = '~';
buflen++;
}
}
curlen = snprintf(p, (capbuf + BUFSIZE) - p, "%s ", clicap_table[i].name);
p += curlen;
buflen += curlen;
}
if (buflen != mlen)
*(p - 1) = '\0';
else
*p = '\0';
sendto_one(sptr, "%s :%s", buf, capbuf);
}
static void cap_ack(aClient *sptr, const char *arg)
{
struct clicap *cap;
int capadd = 0, capdel = 0;
int finished = 0, negate;
if (BadPtr(arg))
return;
for(cap = clicap_find(arg, &negate, &finished); cap;
cap = clicap_find(NULL, &negate, &finished))
{
/* sent an ACK for something they havent REQd */
if(!CHECKPROTO(sptr, cap->cap))
continue;
if(negate)
{
/* dont let them ack something sticky off */
if(cap->flags & CLICAP_FLAGS_STICKY)
continue;
capdel |= cap->cap;
}
else
capadd |= cap->cap;
}
sptr->proto |= capadd;
sptr->proto &= ~capdel;
}
static void cap_clear(aClient *sptr, const char *arg)
{
clicap_generate(sptr, "ACK", sptr->proto ? sptr->proto : -1, 1);
sptr->proto = 0;
}
static void cap_end(aClient *sptr, const char *arg)
{
if (IsRegisteredUser(sptr))
return;
sptr->proto &= ~PROTO_CLICAP;
if (sptr->name[0] && sptr->user != NULL)
register_user(sptr, sptr, sptr->name, sptr->user->username, NULL, NULL, NULL);
}
static void cap_list(aClient *sptr, const char *arg)
{
clicap_generate(sptr, "LIST", sptr->proto ? sptr->proto : -1, 0);
}
static void cap_ls(aClient *sptr, const char *arg)
{
if (!IsRegisteredUser(sptr))
sptr->proto |= PROTO_CLICAP;
clicap_generate(sptr, "LS", 0, 0);
}
static void cap_req(aClient *sptr, const char *arg)
{
char buf[BUFSIZE];
char pbuf[2][BUFSIZE];
struct clicap *cap;
int buflen, plen;
int i = 0;
int capadd = 0, capdel = 0;
int finished = 0, negate;
if (!IsRegisteredUser(sptr))
sptr->proto |= PROTO_CLICAP;
if (BadPtr(arg))
return;
buflen = snprintf(buf, sizeof(buf), ":%s CAP %s ACK",
me.name, BadPtr(sptr->name) ? "*" : sptr->name);
pbuf[0][0] = '\0';
plen = 0;
for(cap = clicap_find(arg, &negate, &finished); cap;
cap = clicap_find(NULL, &negate, &finished))
{
/* 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 + strlen(cap->name) + 6 >= BUFSIZE)
{
pbuf[1][0] = '\0';
plen = 0;
i = 1;
}
if (negate)
{
if (cap->flags & CLICAP_FLAGS_STICKY)
{
finished = 0;
break;
}
strcat(pbuf[i], "-");
plen++;
capdel |= cap->cap;
}
else
{
if (cap->flags & CLICAP_FLAGS_STICKY)
{
strcat(pbuf[i], "=");
plen++;
}
capadd |= cap->cap;
}
if (cap->flags & CLICAP_FLAGS_CLIACK)
{
strcat(pbuf[i], "~");
plen++;
}
strcat(pbuf[i], cap->name);
strcat(pbuf[i], " ");
plen += (strlen(cap->name) + 1);
}
if (!finished)
{
sendto_one(sptr, ":%s CAP %s NAK :%s", me.name, BadPtr(sptr->name) ? "*" : sptr->name, arg);
return;
}
if (i)
{
sendto_one(sptr, "%s * :%s", buf, pbuf[0]);
sendto_one(sptr, "%s :%s", buf, pbuf[1]);
}
else
sendto_one(sptr, "%s :%s", buf, pbuf[0]);
sptr->proto |= capadd;
sptr->proto &= ~capdel;
}
struct clicap_cmd {
const char *cmd;
void (*func)(struct Client *source_p, const char *arg);
};
static struct clicap_cmd clicap_cmdtable[] = {
{ "ACK", cap_ack },
{ "CLEAR", cap_clear },
{ "END", cap_end },
{ "LIST", cap_list },
{ "LS", cap_ls },
{ "REQ", cap_req },
};
static int clicap_cmd_search(const char *command, struct clicap_cmd *entry)
{
return strcmp(command, entry->cmd);
}
DLLFUNC int m_cap(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
struct clicap_cmd *cmd;
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, BadPtr(sptr->name) ? "*" : sptr->name,
"CAP");
return 0;
}
if(!(cmd = bsearch(parv[1], clicap_cmdtable,
sizeof(clicap_cmdtable) / sizeof(struct clicap_cmd),
sizeof(struct clicap_cmd), (bqcmp) clicap_cmd_search)))
{
sendto_one(sptr, err_str(ERR_INVALIDCAPCMD),
me.name, BadPtr(sptr->name) ? "*" : sptr->name,
parv[1]);
return 0;
}
(cmd->func)(sptr, parv[2]);
return 0;
}
/* This is called on module init, before Server Ready */
DLLFUNC int MOD_INIT(m_cap)(ModuleInfo *modinfo)
{
MARK_AS_OFFICIAL_MODULE(modinfo);
CommandAdd(modinfo->handle, MSG_CAP, TOK_CAP, m_cap, MAXPARA, M_UNREGISTERED|M_USER);
return MOD_SUCCESS;
}
/* Is first run when server is 100% ready */
DLLFUNC int MOD_LOAD(m_cap)(int module_load)
{
return MOD_SUCCESS;
}
/* Called when module is unloaded */
DLLFUNC int MOD_UNLOAD(m_cap)(int module_unload)
{
return MOD_SUCCESS;
}
+1 -1
View File
@@ -736,7 +736,7 @@ DLLFUNC CMD_FUNC(m_nick)
}
/* This had to be copied here to avoid problems.. */
(void)strcpy(sptr->name, nick);
if (sptr->user && IsNotSpoof(sptr))
if (sptr->user && IsNotSpoof(sptr) && !CHECKPROTO(sptr, PROTO_CLICAP))
{
/*
** USER already received, now we have NICK.
+4 -1
View File
@@ -203,7 +203,10 @@ DLLFUNC CMD_FUNC(m_user)
strlcpy(user->svid, sstamp, sizeof(user->svid));
strlcpy(sptr->info, realname, sizeof(sptr->info));
if (sptr->name[0] && (IsServer(cptr) ? 1 : IsNotSpoof(sptr)))
if (sptr->name[0] &&
(IsServer(cptr) ? 1 : IsNotSpoof(sptr)) &&
(!MyConnect(sptr) || (MyConnect(sptr) && !CHECKPROTO(sptr, PROTO_CLICAP)))
)
/* NICK and no-spoof already received, now we have USER... */
{
if (USE_BAN_VERSION && MyConnect(sptr))
+1 -1
View File
@@ -454,7 +454,7 @@ static char *replies[] = {
/* 407 ERR_TOOMANYTARGETS */ ":%s 407 %s %s :Duplicate recipients. No message delivered",
/* 408 */ NULL, /* rfc2812, bahamut */
/* 409 ERR_NOORIGIN */ ":%s 409 %s :No origin specified",
/* 410 */ NULL,
/* 410 ERR_INVALIDCAPCMD */ ":%s 410 %s %s :Invalid CAP subcommand",
/* 411 ERR_NORECIPIENT */ ":%s 411 %s :No recipient given (%s)",
/* 412 ERR_NOTEXTTOSEND */ ":%s 412 %s :No text to send",
/* 413 ERR_NOTOPLEVEL */ ":%s 413 %s %s :No toplevel domain specified",