1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-09 17:43:12 +02:00

No clean_channelname() anymore but a valid_channelname() function. Also,

deal with servers with different set::allowed-channelchars settings:
* We reject the link if set::allowed-channelchars settings differ between
  UnrealIRCd 5 servers.
* For the case where you have a mixed network consisting of UnrealIRCd 4.x
  and UnrealIRCd 5.x servers we try not to desync, BUT will not allow
  anyone to join the invalid channels locally. For IRCOps a message is
  printed with additional information on such a failed JOIN attempt.
See https://www.unrealircd.org/docs/Set_block#set::allowed-channelchars
for the different settings, which are best and U4<->U5 advice.
This commit is contained in:
Bram Matthys
2019-10-09 17:55:23 +02:00
parent fbbd915403
commit 22dec96f9a
11 changed files with 128 additions and 100 deletions
+2 -1
View File
@@ -178,7 +178,7 @@ extern int check_tkls(Client *cptr);
/* for services */
extern void del_invite(Client *, Channel *);
extern void send_user_joins(Client *, Client *);
extern void clean_channelname(char *);
extern int valid_channelname(const char *);
extern long get_access(Client *, Channel *);
extern int ban_check_mask(Client *, Channel *, char *, int, char **, char **, int);
extern int extban_is_ok_nuh_extban(Client *, Channel *, char *, int, int, int);
@@ -949,3 +949,4 @@ extern void utf8_test(void);
extern MODVAR int non_utf8_nick_chars_in_use;
extern void short_motd(Client *client);
extern int should_show_connect_info(Client *client);
extern void send_invalid_channelname(Client *client, char *channelname);
+51 -24
View File
@@ -62,7 +62,6 @@ char cmodestring[512];
char *clean_ban_mask(char *, int, Client *);
void channel_modes(Client *client, char *mbuf, char *pbuf, size_t mbuf_size, size_t pbuf_size, Channel *channel);
int sub1_from_channel(Channel *);
void clean_channelname(char *);
void del_invite(Client *, Channel *);
inline int op_can_override(char* acl, Client *client,Channel *channel,void* extra)
@@ -866,54 +865,52 @@ int find_invex(Channel *channel, Client *client)
* You must call this before creating a new channel,
* eg in case of /JOIN.
*/
void clean_channelname(char *cname)
int valid_channelname(const char *cname)
{
char *ch = cname;
char *end;
const char *p;
/* Channel name must start with a dash */
if (*cname != '#')
return 0;
if (strlen(cname) > CHANNELLEN)
return 0;
if (iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_ANY)
{
/* The default up to and including UnrealIRCd 4 */
for (; *ch; ch++)
for (p = cname; *p; p++)
{
if (*ch < 33 || *ch == ',' || *ch == ':')
{
*ch = '\0';
break;
}
if (*p < 33 || *p == ',' || *p == ':')
return 0;
}
} else
if (iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_ASCII)
{
/* The strict setting: only allow ASCII 32-128, except some chars */
for (; *ch; ch++)
for (p = cname; *p; p++)
{
if (*ch < 33 || *ch == ',' || *ch == ':' || *ch > 127)
{
*ch = '\0';
break;
}
if (*p < 33 || *p == ',' || *p == ':' || *p > 127)
return 0;
}
} else
if (iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_UTF8)
{
/* Only allow UTF8, and also disallow some chars */
for (; *ch; ch++)
for (p = cname; *p; p++)
{
if (*ch < 33 || *ch == ',' || *ch == ':')
{
*ch = '\0';
break;
}
if (*p < 33 || *p == ',' || *p == ':')
return 0;
}
/* And run it through the UTF8 validator */
if (!unrl_utf8_validate(cname, (const char **)&end))
*end = '\0';
if (!unrl_utf8_validate(cname, (const char **)&p))
return 0;
} else
{
/* Impossible */
abort();
}
return 1; /* Valid */
}
/*
@@ -1366,3 +1363,33 @@ int invisible_user_in_channel(Client *target, Channel *channel)
return 0;
}
/** Send a message to the user that (s)he is using an invalid channel name.
* This is usually called after an if (MyUser(client) && !valid_channelname(name)).
* @param client The client to send the message to.
* @param channelname The (invalid) channel that the user tried to join.
*/
void send_invalid_channelname(Client *client, char *channelname)
{
char *reason;
if (strlen(channelname) > CHANNELLEN)
{
reason = "Channel name is too long";
} else {
switch(iConf.allowed_channelchars)
{
case ALLOWED_CHANNELCHARS_ASCII:
reason = "Channel name contains illegal characters (must be ASCII)";
break;
case ALLOWED_CHANNELCHARS_UTF8:
reason = "Channel name contains illegal characters (must be valid UTF8)";
break;
case ALLOWED_CHANNELCHARS_ANY:
default:
reason = "Channel name contains illegal characters";
}
}
sendnumeric(client, ERR_FORBIDDENCHANNEL, channelname, reason);
}
+1 -4
View File
@@ -9090,7 +9090,6 @@ int _test_offchans(ConfigFile *conf, ConfigEntry *ce)
{
int errors = 0;
ConfigEntry *cep, *cep2;
char checkchan[CHANNELLEN + 1];
if (!ce->ce_entries)
{
@@ -9107,9 +9106,7 @@ int _test_offchans(ConfigFile *conf, ConfigEntry *ce)
errors++;
continue;
}
strcpy(checkchan, cep->ce_varname); /* safe */
clean_channelname(checkchan);
if (strcmp(checkchan, cep->ce_varname) || (*cep->ce_varname != '#'))
if (!valid_channelname(cep->ce_varname))
{
config_error("%s:%i: official-channels: '%s' is not a valid channel name.",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
+7 -24
View File
@@ -120,23 +120,16 @@ int cmodeL_is_ok(Client *client, Channel *channel, char mode, char *para, int ty
if (type == EXCHK_PARAM)
{
/* Check parameter.. syntax is +L #channel */
char buf[CHANNELLEN+1], *p;
if (strchr(para, ','))
return EX_DENY; /* multiple channels not permitted */
if (!IsChannelName(para))
if (!valid_channelname(para))
{
if (MyUser(client))
sendnumeric(client, ERR_NOSUCHCHANNEL, para);
return EX_DENY;
}
/* This needs to be exactly the same as in conv_param... */
strlcpy(buf, para, sizeof(buf));
clean_channelname(buf);
if ((p = strchr(buf, ':')))
*p = '\0';
if (find_channel(buf, NULL) == channel)
if (find_channel(para, NULL) == channel)
{
if (MyUser(client))
sendnumeric(client, ERR_CANNOTCHANGECHANMODE, 'L',
@@ -178,20 +171,14 @@ char *cmodeL_get_param(void *r_in)
/** Convert parameter to something proper.
* NOTE: client may be NULL
*/
char *cmodeL_conv_param(char *param_in, Client *client)
char *cmodeL_conv_param(char *param, Client *client)
{
static char buf[CHANNELLEN+1];
char *p;
strlcpy(buf, param_in, sizeof(buf));
clean_channelname(buf);
if ((p = strchr(buf, ':')))
*p = '\0';
if (!valid_channelname(param))
return NULL;
if (*buf == '\0')
strcpy(buf, "#<INVALID>"); /* better safe than sorry */
return buf;
return param;
}
void cmodeL_free_param(void *r)
@@ -287,13 +274,9 @@ char *extban_link_conv_param(char *param)
return NULL;
*matchby++ = '\0';
if (*chan != '#' || strchr(param, ','))
if (!valid_channelname(chan))
return NULL;
if (strlen(chan) > CHANNELLEN)
chan[CHANNELLEN] = '\0';
clean_channelname(chan);
// Possibly stack multiple extbans, this is a little convoluted due to extban API limitations
snprintf(tmpmask, sizeof(tmpmask), "~?:%s", matchby);
newmask = extban_conv_param_nuh_or_extban(tmpmask);
+2 -4
View File
@@ -80,10 +80,8 @@ char *extban_inchannel_conv_param(char *para)
if ((*chan != '#') && (*chan != '*') && (*chan != '?'))
return NULL;
if (strlen(chan) > CHANNELLEN)
chan[CHANNELLEN] = '\0';
clean_channelname(chan);
if (!valid_channelname(chan))
return NULL;
p = strchr(chan, ':'); /* ~r:#chan:*.blah.net is not allowed (for now) */
if (p)
+5 -2
View File
@@ -93,8 +93,11 @@ CMD_FUNC(cmd_invite)
return;
}
if (MyConnect(client))
clean_channelname(parv[2]);
if (MyConnect(client) && !valid_channelname(parv[2]))
{
sendnumeric(client, ERR_NOSUCHCHANNEL, parv[2]);
return;
}
if (!(channel = find_channel(parv[2], NULL)))
{
+40 -27
View File
@@ -360,11 +360,11 @@ void _join_channel(Channel *channel, Client *client, MessageTag *recv_mtags, int
*/
void _do_join(Client *client, int parc, char *parv[])
{
char jbuf[BUFSIZE];
char jbuf[BUFSIZE], jbuf2[BUFSIZE];
Membership *lp;
Channel *channel;
char *name, *key = NULL;
int i, flags = 0, ishold;
int i, flags = 0, ishold;
char *p = NULL, *p2 = NULL;
TKL *tklban;
int ntargets = 0;
@@ -394,30 +394,40 @@ void _do_join(Client *client, int parc, char *parv[])
** Rebuild list of channels joined to be the actual result of the
** JOIN. Note that "JOIN 0" is the destructive problem.
*/
for (i = 0, name = strtoken(&p, parv[1], ","); name;
name = strtoken(&p, NULL, ","))
for (i = 0, name = strtoken(&p, parv[1], ",");
name;
i++, name = strtoken(&p, NULL, ","))
{
if (MyUser(client) && (++ntargets > maxtargets))
{
sendnumeric(client, ERR_TOOMANYTARGETS, name, maxtargets, "JOIN");
break;
}
/* pathological case only on longest channel name.
** If not dealt with here, causes desynced channel ops
** since ChannelExists() doesn't see the same channel
** as one being joined. cute bug. Oct 11 1997, Dianora/comstud
** Copied from Dianora's "hybrid 5" ircd.
*/
if (strlen(name) > CHANNELLEN) /* same thing is done in get_channel() */
name[CHANNELLEN] = '\0';
if (MyConnect(client))
clean_channelname(name);
if (*name == '0' && !atoi(name))
{
(void)strcpy(jbuf, "0");
i = 1;
/* UnrealIRCd 5: we only support "JOIN 0",
* "JOIN 0,#somechan" etc... so only at the beginning.
* We do not support it half-way like "JOIN #a,0,#b"
* since that doesn't make sense, unless you are flooding...
* We still support it in remote joins for compatibility.
*/
if (MyUser(client) && (i != 0))
continue;
strlcpy(jbuf, "0", sizeof(jbuf));
continue;
} else
if (MyConnect(client) && !valid_channelname(name))
{
send_invalid_channelname(client, name);
if (IsOper(client) && find_channel(name, NULL))
{
/* Give IRCOps a bit more information */
sendnotice(client, "Channel '%s' is unjoinable because it contains illegal characters. "
"However, it does exist because another server in your "
"network, which has a more loose restriction, created it. "
"See https://www.unrealircd.org/docs/Set_block#set::allowed-channelchars",
name);
}
continue;
}
else if (!IsChannelName(name))
@@ -427,22 +437,25 @@ void _do_join(Client *client, int parc, char *parv[])
continue;
}
if (*jbuf)
(void)strlcat(jbuf, ",", sizeof jbuf);
(void)strlncat(jbuf, name, sizeof jbuf, sizeof(jbuf) - i - 1);
i += strlen(name) + 1;
strlcat(jbuf, ",", sizeof jbuf);
strlcat(jbuf, name, sizeof(jbuf));
}
/* This strcpy should be safe since jbuf contains the "filtered"
* result of parv[1] which should never be larger than the source.
/* We are going to overwrite 'jbuf' with the calls to strtoken()
* a few lines further down. Copy it to 'jbuf2' and make that
* the new parv[1].
*/
(void)strcpy(parv[1], jbuf);
strlcpy(jbuf2, jbuf, sizeof(jbuf2));
parv[1] = jbuf2;
p = NULL;
if (parv[2])
key = strtoken(&p2, parv[2], ",");
parv[2] = NULL; /* for cmd_names call later, parv[parc] must == NULL */
for (name = strtoken(&p, jbuf, ","); name;
key = (key) ? strtoken(&p2, NULL, ",") : NULL,
name = strtoken(&p, NULL, ","))
for (name = strtoken(&p, jbuf, ",");
name;
key = key ? strtoken(&p2, NULL, ",") : NULL, name = strtoken(&p, NULL, ","))
{
MessageTag *mtags = NULL;
+3 -8
View File
@@ -79,17 +79,12 @@ CMD_FUNC(cmd_knock)
return;
}
if (MyConnect(client))
clean_channelname(parv[1]);
/* bugfix for /knock PRv Please? */
if (*parv[1] != '#')
if (MyConnect(client) && !valid_channelname(parv[1]))
{
sendnumeric(client, ERR_CANNOTKNOCK,
parv[1], "Remember to use a # prefix in channel name");
sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]);
return;
}
if (!(channel = find_channel(parv[1], NULL)))
{
sendnumeric(client, ERR_CANNOTKNOCK, parv[1], "Channel does not exist!");
+4
View File
@@ -369,6 +369,10 @@ int send_list(Client *client)
if (!IsOper(client) && iConf.hide_list && Find_channel_allowed(client, channel->chname))
continue;
/* Similarly, hide unjoinable channels for non-ircops since it would be confusing */
if (!IsOper(client) && !valid_channelname(channel->chname))
continue;
/* Much more readable like this -- codemastr */
if ((!lopt->showall))
{
+5 -2
View File
@@ -120,8 +120,11 @@ CMD_FUNC(cmd_mode)
return;
}
if (MyConnect(client))
clean_channelname(parv[1]);
if (MyConnect(client) && !valid_channelname(parv[1]))
{
sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]);
return;
}
if (parc < 3)
{
+8 -4
View File
@@ -157,8 +157,11 @@ CMD_FUNC(cmd_sajoin)
}
if (strlen(name) > CHANNELLEN)
name[CHANNELLEN] = 0;
clean_channelname(name);
{
sendnotice(client, "Channel name too long: %s", name);
continue;
}
if (*name == '0' && !atoi(name) && !sjmode)
{
(void)strcpy(jbuf, "0");
@@ -166,9 +169,10 @@ CMD_FUNC(cmd_sajoin)
parted = 1;
continue;
}
if (*name == '0' || !IsChannelName(name))
if (!valid_channelname(name))
{
sendnumeric(client, ERR_NOSUCHCHANNEL, name);
send_invalid_channelname(client, name);
continue;
}