Fix SF bug #2694761 (iauth class assignment did not work correctly).
authorMichael Poole <mdpoole@troilus.org>
Sun, 5 Jul 2009 03:00:52 +0000 (03:00 +0000)
committerMichael Poole <mdpoole@troilus.org>
Sun, 5 Jul 2009 03:00:52 +0000 (03:00 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1914 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
ircd/s_auth.c
tools/iauth-test

index 67592a96a4514fb803d5b3fc92bacfe1b6157081..a865be6bff5b7b296bbc42df35b065f6bd62a58f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2009-07-04  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_auth.c (find_conf_client): New function.
+       (preregister_user): Use it to avoid assigning a second conf class
+       on client connection.
+       (auth_ping_timeout): Send the "T" message only if we do not kill
+       the client (and thus send a "D" message).
+       (auth_find_classs_conf): Do not allow IAuth to select a disabled
+       class.  Unlink new conf items from GlobalConfList.
+       (iauth_cmd_done_client): Handle failures from attach_conf().
+       (iauth_parse): Behave decently when a client is killed by the
+       message handler.
+
+       * tools/iauth-test (%handlers): Add entries to help test this.
+
 2009-07-04  Michael Poole <mdpoole@troilus.org>
 
        * include/channel.h (RevealDelayedJoinIfNeeded): Declare.
index 6ea836168567b716a28a7987bf5d8b7c6de16b86..b578c43dfde8561ab448c4923775d95f439ad773 100644 (file)
@@ -461,6 +461,26 @@ auth_verify_hostname(const char *host, int maxlen)
   return 1; /* it's a valid hostname */
 }
 
+/** Check whether a client already has a CONF_CLIENT configuration
+ * item.
+ *
+ * @return A pointer to the client's first CONF_CLIENT, or NULL if
+ *   there are none.
+ */
+static struct ConfItem *find_conf_client(struct Client *cptr)
+{
+  struct SLink *list;
+
+  for (list = cli_confs(cptr); list != NULL; list = list->next) {
+    struct ConfItem *aconf;
+    aconf = list->value.aconf;
+    if (aconf->status & CONF_CLIENT)
+      return aconf;
+  }
+
+  return NULL;
+}
+
 /** Assign a client to a connection class.
  * @param[in] cptr Client to assign to a class.
  * @return Zero if client is kept, CPTR_KILLED if rejected.
@@ -473,6 +493,10 @@ static int preregister_user(struct Client *cptr)
   ircd_strncpy(cli_user(cptr)->host, cli_sockhost(cptr), HOSTLEN);
   ircd_strncpy(cli_user(cptr)->realhost, cli_sockhost(cptr), HOSTLEN);
 
+  if (find_conf_client(cptr)) {
+    return 0;
+  }
+
   switch (conf_check_client(cptr))
   {
   case ACR_OK:
@@ -766,11 +790,11 @@ int auth_ping_timeout(struct Client *cptr)
 
   /* Check for iauth timeout. */
   if (FlagHas(&auth->flags, AR_IAUTH_PENDING)) {
-    sendto_iauth(cptr, "T");
     if (IAuthHas(iauth, IAUTH_REQUIRED)) {
       sendheader(cptr, REPORT_FAIL_IAUTH);
       return exit_client_msg(cptr, cptr, &me, "Authorization Timeout");
     }
+    sendto_iauth(cptr, "T");
     FlagClr(&auth->flags, AR_IAUTH_PENDING);
     return check_auth_finished(auth);
   }
@@ -1805,7 +1829,7 @@ static struct ConfItem *auth_find_class_conf(const char *class_name)
 
   /* Make sure the configuration class is valid. */
   class = find_class(class_name);
-  if (!class)
+  if (!class || !class->valid)
     return NULL;
 
   /* Look for an existing ConfItem for the class. */
@@ -1822,6 +1846,13 @@ static struct ConfItem *auth_find_class_conf(const char *class_name)
                            ConClass(class));
       return NULL;
     }
+    /* make_conf() "helpfully" links the conf into GlobalConfList,
+     * which we do not want, so undo that.  (Ugh.)
+     */
+    if (aconf == GlobalConfList) {
+      GlobalConfList = aconf->next;
+    }
+    /* Back to business as usual. */
     aconf->conn_class = class;
     aconf->next = aconf_list;
     aconf_list = aconf;
@@ -1835,7 +1866,7 @@ static struct ConfItem *auth_find_class_conf(const char *class_name)
  * @param[in] cli Client referenced by command.
  * @param[in] parc Number of parameters.
  * @param[in] params Optional class name for client.
- * @return One.
+ * @return Negative (CPTR_KILLED) if the connection is refused, one otherwise.
  */
 static int iauth_cmd_done_client(struct IAuth *iauth, struct Client *cli,
                                 int parc, char **params)
@@ -1851,9 +1882,24 @@ static int iauth_cmd_done_client(struct IAuth *iauth, struct Client *cli,
     struct ConfItem *aconf;
 
     aconf = auth_find_class_conf(params[0]);
-    if (aconf)
-      attach_conf(cli, aconf);
-    else
+    if (aconf) {
+      enum AuthorizationCheckResult acr;
+
+      acr = attach_conf(cli, aconf);
+      switch (acr) {
+      case ACR_OK:
+        /* There should maybe be some way to set FLAG_DOID here.. */
+        break;
+      case ACR_TOO_MANY_IN_CLASS:
+        ++ServerStats->is_ref;
+        return exit_client(cli, cli, &me,
+                           "Sorry, your connection class is full - try "
+                           "again later or try another server");
+      default:
+        log_write(LS_IAUTH, L_ERROR, 0, "IAuth: Unexpected AuthorizationCheckResult %d from attach_conf()", acr);
+        break;
+      }
+    } else
       sendto_opmask_butone_ratelimited(NULL, SNO_AUTH, &warn_time,
                                        "iauth tried to use undefined class [%s]",
                                        params[0]);
@@ -1867,7 +1913,8 @@ static int iauth_cmd_done_client(struct IAuth *iauth, struct Client *cli,
  * @param[in] cli Client referenced by command.
  * @param[in] parc Number of parameters.
  * @param[in] params Account name and optional class name for client.
- * @return Non-zero if \a cli authorization should be checked for completion.
+ * @return Negative if the connection is refused, otherwise non-zero
+ *   if \a cli authorization should be checked for completion.
  */
 static int iauth_cmd_done_account(struct IAuth *iauth, struct Client *cli,
                                  int parc, char **params)
@@ -2048,7 +2095,7 @@ static void iauth_parse(struct IAuth *iauth, char *message)
        /* Report mismatch to iauth. */
        sendto_iauth(cli, "E Mismatch :[%s] != [%s]", params[1],
                     ircd_ntoa(&cli_ip(cli)));
-      else if (handler(iauth, cli, parc - 3, params + 3))
+      else if (handler(iauth, cli, parc - 3, params + 3) > 0)
        /* Handler indicated a possible state change. */
        check_auth_finished(auth);
     }
index 78e80ab7f9dce0fa52a1d5c641f87ca8ccf72bb6..c3dd1f25e15b7d3fd482c94dcf49b02889b2b2c2 100755 (executable)
@@ -155,6 +155,8 @@ my %handlers = (
                 '127.0.0.2'  => { C_reply => 'R account-1' },
                 '127.0.0.3'  => { C_reply => 'k' },
                 '127.0.0.4'  => { C_reply => 'K' },
+                '127.0.0.5'  => { C_reply => 'D Specials' },
+                '127.0.0.6'  => { C_reply => 'R account-1 Specials' },
                 '127.0.0.15' => { },
                 '127.0.0.16' => { H_reply => 'D' },
                 '127.0.0.17' => { H_reply => 'R account-2' },