Rework JOIN handler to make keys, apass, and upass consistent.
authorMichael Poole <mdpoole@troilus.org>
Fri, 2 Sep 2005 01:46:28 +0000 (01:46 +0000)
committerMichael Poole <mdpoole@troilus.org>
Fri, 2 Sep 2005 01:46:28 +0000 (01:46 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1473 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
RELEASE.NOTES
include/channel.h
ircd/channel.c
ircd/m_join.c

index 7303bd7be5d1f4b38863854c5f12c6b0febcd198..83d42f9c4186e92651fff78216130bb7c55ac269 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2005-09-01  Michael Poole <mdpoole@troilus.org>
+
+       * 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 <mdpoole@troilus.org>
 
        * include/channel.h (PASSLEN): Remove; use KEYLEN instead.
index 4a74b41fd00d00fd352bcee962f55befeb346eb6..abdcf2b88256d61628c70c688e46679998954c76 100644 (file)
@@ -1,5 +1,5 @@
 Release notes for ircu2.10.12
-Last updated: 14 Jan 2005
+Last updated: 1 Sep 2005
 Written by Michael Poole <mdpoole@troilus.org>
 Based on earlier documents by Kev <klmitch@mit.edu> and
 Braden <dbtem@yahoo.com>.
@@ -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
index c2c12ea8348a87aed6a153e3c689ac19347099ca..fd01bedc191a325dfcb888589267293429c4bbc9 100644 (file)
@@ -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,
index ea2d72812673a27510307cef6e9e6e5a6a7918fe..85e561285593a8b2e86f8d54d630d5ada1459438 100644 (file)
@@ -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 \<intru@info.polymtl.ca\>
- *
- * @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.
index 469fbd8f0a1ea09a06d14fbf523fb5d4dd1b6fba..70bec20f017e4a40e03a79c87de1ce24749fdb3a 100644 (file)
@@ -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)))