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.
 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
 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>.
 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.
 
 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
 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
 
  */
 #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;
 
 
 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);
                                            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,
 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);
 }
 
   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.
 /** 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;
   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;
   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;
     }
 
       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)) {
     /* 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;
     }
 
       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;
       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)) {
 
     /* 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) {
     }
 
     if (chptr) {
+      char *key = 0;
       int is_level0_op = 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))
       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;
           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)))
 
       joinbuf_join(&join, chptr, flags);
     } else if (!(chptr = get_channel(sptr, name, CGT_CREATE)))