From d44aba8fc161f3c76ab5b1233bf6b73302a8ec4e Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Fri, 2 Sep 2005 01:46:28 +0000 Subject: [PATCH] Rework JOIN handler to make keys, apass, and upass consistent. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1473 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 16 ++++++ RELEASE.NOTES | 11 +++- include/channel.h | 5 -- ircd/channel.c | 95 ------------------------------ ircd/m_join.c | 144 ++++++++++++++++++++++------------------------ 5 files changed, 95 insertions(+), 176 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7303bd7..83d42f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2005-09-01 Michael Poole + + * RELEASE.NOTES: Bump revision date and highlight this change. + + * include/channel.h (MAGIC_OPER_OVERRIDE): Remove. + (can_join): Remove declaration. + + * ircd/channel.c (compall): Remove. + (can_join): Remove. + + * ircd/m_join.c (m_join): Remove redundant check for control + characters (clean_channelname() will get them). Reorganize initial + flags calculation. Accept channel keys like RFC 1459 says; this + requires the old compall()/can_join() logic to modify 'keys', so + inline the code and reorganize it. + 2005-08-30 Michael Poole * include/channel.h (PASSLEN): Remove; use KEYLEN instead. diff --git a/RELEASE.NOTES b/RELEASE.NOTES index 4a74b41..abdcf2b 100644 --- a/RELEASE.NOTES +++ b/RELEASE.NOTES @@ -1,5 +1,5 @@ Release notes for ircu2.10.12 -Last updated: 14 Jan 2005 +Last updated: 1 Sep 2005 Written by Michael Poole Based on earlier documents by Kev and Braden . @@ -10,6 +10,15 @@ implement the P10 protocol. It has been tested to link against ircu2.10.11, but some features (notably IPv6 support and oplevels) are not supported by ircu2.10.11. +Semantic Changes (TAKE NOTE): + +Channel keys and passwords (see the "oplevels" enhancement below) +listed in a JOIN are now only checked against the corresponding +channel. In ircu2.10.11, "JOIN #a,#b key" would attempt to use "key" +as the key for both #a and #b. ircu2.10.12 will only attempt to use +it as the key for #a. ircu2.10.12's behavior matches that documented +in RFC 1459. + Enhancements: The configuration file format has changed to one that is easier to diff --git a/include/channel.h b/include/channel.h index c2c12ea..fd01bed 100644 --- a/include/channel.h +++ b/include/channel.h @@ -172,10 +172,6 @@ typedef enum ChannelGetType { */ #define MAGIC_REMOTE_JOIN_TS 1270080000 -/** - * used in can_join to determine if an oper forced a join on a channel - */ -#define MAGIC_OPER_OVERRIDE 1000 extern const char* const PartFmt1; @@ -383,7 +379,6 @@ extern struct Membership* find_member_link(struct Channel * chptr, const struct Client* cptr); extern int sub1_from_channel(struct Channel* chptr); extern int destruct_channel(struct Channel* chptr); -extern int can_join(struct Client *sptr, struct Channel *chptr, char *key); extern void add_user_to_channel(struct Channel* chptr, struct Client* who, unsigned int flags, int oplevel); extern void make_zombie(struct Membership* member, struct Client* who, diff --git a/ircd/channel.c b/ircd/channel.c index ea2d728..85e5612 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -1182,101 +1182,6 @@ static void send_ban_list(struct Client* cptr, struct Channel* chptr) send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname); } -/** Check a key against a keyring. - * We are now treating the key part of /join channellist key as a key - * ring; that is, we try one key against the actual channel key, and if that - * doesn't work, we try the next one, and so on. -Kev -Texaco - * Returns: 0 on match, 1 otherwise - * This version contributed by SeKs \ - * - * @param key Key to check - * @param keyring Comma separated list of keys - * - * @returns True if the key was found and matches, false otherwise. - */ -static int compall(char *key, char *keyring) -{ - char *p1; - -top: - p1 = key; /* point to the key... */ - while (*p1 && *p1 == *keyring) - { /* step through the key and ring until they - don't match... */ - p1++; - keyring++; - } - - if (!*p1 && (!*keyring || *keyring == ',')) - /* ok, if we're at the end of the and also at the end of one of the keys - in the keyring, we have a match */ - return 0; - - if (!*keyring) /* if we're at the end of the key ring, there - weren't any matches, so we return 1 */ - return 1; - - /* Not at the end of the key ring, so step - through to the next key in the ring: */ - while (*keyring && *(keyring++) != ','); - - goto top; /* and check it against the key */ -} - -/** Returns if a user can join a channel with a specific key. - * - * @param sptr The client trying to join - * @param chptr The channel to join - * @param key The key to use - * - * @returns any error that occurred bit-wise OR'd with MAGIC_OPER_OVERRIDE - * if the oper used the magic key, 0 if no error occurred. - */ -int can_join(struct Client *sptr, struct Channel *chptr, char *key) -{ - int overrideJoin = 0; - - /* - * Now a banned user CAN join if invited -- Nemesi - * Now a user CAN escape channel limit if invited -- bfriendly - * Now a user CAN escape anything if invited -- Isomer - */ - - if (IsInvited(sptr, chptr)) - return 0; - - /* An oper can force a join on a local channel using "OVERRIDE" as the key. - a HACK(4) notice will be sent if he would not have been supposed - to join normally. */ - if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && - !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 && - compall("OVERRIDE",key) == 0) - overrideJoin = MAGIC_OPER_OVERRIDE; - - if (chptr->mode.mode & MODE_INVITEONLY) - return overrideJoin + ERR_INVITEONLYCHAN; - - if (chptr->mode.limit && chptr->users >= chptr->mode.limit) - return overrideJoin + ERR_CHANNELISFULL; - - if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) - return overrideJoin + ERR_NEEDREGGEDNICK; - - if (find_ban(sptr, chptr->banlist)) - return overrideJoin + ERR_BANNEDFROMCHAN; - - /* - * now using compall (above) to test against a whole key ring -Kev - */ - if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key))) - return overrideJoin + ERR_BADCHANNELKEY; - - if (overrideJoin) - return ERR_DONTCHEAT; - - return 0; -} - /** Remove bells and commas from channel name * * @param cn Channel name to clean, modified in place. diff --git a/ircd/m_join.c b/ircd/m_join.c index 469fbd8..70bec20 100644 --- a/ircd/m_join.c +++ b/ircd/m_join.c @@ -171,8 +171,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) struct JoinBuf join; struct JoinBuf create; struct Gline *gline; - unsigned int flags = 0; - int i, j, k = 0; + unsigned int flags; char *p = 0; char *chanlist; char *name; @@ -202,18 +201,6 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) continue; } - /* This checks if the channel contains control codes and rejects em - * until they are gone, then we will do it otherwise - *SOB Mode* - */ - for (k = 0, j = 0; name[j]; j++) - if (IsCntrl(name[j])) - k++; - if (k > 0) - { - send_reply(sptr, ERR_NOSUCHCHANNEL, name); - continue; - } - /* BADCHANed channel */ if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { @@ -221,15 +208,12 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) continue; } - if ((chptr = FindChannel(name))) - { - if (find_member_link(chptr, sptr)) - continue; /* already on channel */ - - flags = CHFL_DEOPPED; - } - else + if (!(chptr = FindChannel(name))) flags = CHFL_CHANOP; + else if (find_member_link(chptr, sptr)) + continue; /* already on channel */ + else + flags = CHFL_DEOPPED; /* disallow creating local channels */ if ((name[0] == '&') && !chptr && !feature_bool(FEAT_LOCAL_CHANNELS)) { @@ -244,62 +228,72 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) } if (chptr) { + char *key = 0; int is_level0_op = 0; - if (!BadPtr(keys) && *chptr->mode.apass) { - /* Don't use compall for the apass, only a single key is allowed. */ - if (strcmp(chptr->mode.apass, keys) == 0) { - is_level0_op = 1; - flags &= ~CHFL_DEOPPED; - flags |= CHFL_CHANOP | CHFL_CHANNEL_MANAGER; - } - else if (*chptr->mode.upass && strcmp(chptr->mode.upass, keys) == 0) { - is_level0_op = 1; - flags &= ~CHFL_DEOPPED; - flags |= CHFL_CHANOP; - } - } + int err = 0; + + /* Check target change limits. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) - continue; /* exceeded target limit */ - else if (!is_level0_op && (i = can_join(sptr, chptr, keys))) { - if (i > MAGIC_OPER_OVERRIDE) - { /* oper overrode mode */ - switch (i - MAGIC_OPER_OVERRIDE) - { - case ERR_CHANNELISFULL: /* figure out which mode */ - i = 'l'; - break; - - case ERR_INVITEONLYCHAN: - i = 'i'; - break; - - case ERR_BANNEDFROMCHAN: - i = 'b'; - break; - - case ERR_BADCHANNELKEY: - i = 'k'; - break; - - case ERR_NEEDREGGEDNICK: - i = 'r'; - break; - - default: - i = '?'; - break; - } - - /* send accountability notice */ - sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " - "(overriding +%c)", sptr, chptr, i); - } - else - { - send_reply(sptr, i, chptr->chname); + continue; + + /* If we have any more keys, take the first for this channel. */ + if (!BadPtr(keys) + && (keys = strchr(key = keys, ','))) + *keys++ = '\0'; + + /* Check Apass/Upass -- since we only ever look at a single + * "key" per channel now, this hampers brute force attacks. */ + if (!BadPtr(key) && !strcmp(key, chptr->mode.apass)) { + is_level0_op = 1; + flags = (flags & ~CHFL_DEOPPED) | CHFL_CHANOP | CHFL_CHANNEL_MANAGER; + } else if (!BadPtr(key) && !strcmp(key, chptr->mode.upass)) { + is_level0_op = 1; + flags = (flags & ~CHFL_DEOPPED) | CHFL_CHANOP; + } else if (IsInvited(sptr, chptr)) { + /* Invites bypass these other checks. */ + } else if (chptr->mode.mode & MODE_INVITEONLY) + err = ERR_INVITEONLYCHAN; + else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit)) + err = ERR_CHANNELISFULL; + else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) + err = ERR_NEEDREGGEDNICK; + else if (find_ban(sptr, chptr->banlist)) + err = ERR_BANNEDFROMCHAN; + else if (*chptr->mode.key && strcmp(chptr->mode.key, key)) + err = ERR_BADCHANNELKEY; + + /* An oper with WALK_LCHAN privilege can join a local channel + * he otherwise could not join by using "OVERRIDE" as the key. + * This will generate a HACK(4) notice, but fails if the oper + * could normally join the channel. */ + if (IsLocalChannel(chptr->chname) + && HasPriv(sptr, PRIV_WALK_LCHAN) + && !is_level0_op + && !BadPtr(key) + && !strcmp("OVERRIDE", key)) + { + switch (err) { + case 0: + send_reply(sptr, ERR_DONTCHEAT, chptr->chname); continue; - } - } /* else if ((i = can_join(sptr, chptr, keys))) */ + case ERR_INVITEONLYCHAN: err = 'i'; break; + case ERR_CHANNELISFULL: err = 'l'; break; + case ERR_BANNEDFROMCHAN: err = 'b'; break; + case ERR_BADCHANNELKEY: err = 'k'; break; + case ERR_NEEDREGGEDNICK: err = 'r'; break; + default: err = '?'; break; + } + /* send accountability notice */ + sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " + "(overriding +%c)", sptr, chptr, err); + err = 0; + } + + /* Is there some reason the user may not join? */ + if (err) { + send_reply(sptr, err, chptr->chname); + continue; + } joinbuf_join(&join, chptr, flags); } else if (!(chptr = get_channel(sptr, name, CGT_CREATE))) -- 2.20.1