Add a parameter to IPcheck_connect_fail() to support IAuth IP spoofing.
[ircu2.10.12-pk.git] / ircd / s_auth.c
index b578c43dfde8561ab448c4923775d95f439ad773..924bd50ab13dcc36df46936301348155a327312d 100644 (file)
@@ -52,6 +52,7 @@
 #include "list.h"
 #include "msg.h"       /* for MAXPARA */
 #include "numeric.h"
+#include "numnicks.h"
 #include "querycmds.h"
 #include "random.h"
 #include "res.h"
@@ -83,6 +84,7 @@ enum AuthRequestFlag {
     AR_IAUTH_HURRY,     /**< we told iauth to hurry up */
     AR_IAUTH_USERNAME,  /**< iauth sent a username (preferred or forced) */
     AR_IAUTH_FUSERNAME, /**< iauth sent a forced username */
+    AR_IAUTH_SOFT_DONE, /**< iauth has no objection to client */
     AR_PASSWORD_CHECKED, /**< client password already checked */
     AR_NUM_FLAGS
 };
@@ -527,7 +529,7 @@ static int preregister_user(struct Client *cptr)
     /* Can this ever happen? */
   case ACR_BAD_SOCKET:
     ++ServerStats->is_ref;
-    IPcheck_connect_fail(cptr);
+    IPcheck_connect_fail(cptr, 0);
     return exit_client(cptr, cptr, &me, "Unknown error -- Try again");
   }
   return 0;
@@ -790,7 +792,8 @@ int auth_ping_timeout(struct Client *cptr)
 
   /* Check for iauth timeout. */
   if (FlagHas(&auth->flags, AR_IAUTH_PENDING)) {
-    if (IAuthHas(iauth, IAUTH_REQUIRED)) {
+    if (IAuthHas(iauth, IAUTH_REQUIRED)
+        && !FlagHas(&auth->flags, AR_IAUTH_SOFT_DONE)) {
       sendheader(cptr, REPORT_FAIL_IAUTH);
       return exit_client_msg(cptr, cptr, &me, "Authorization Timeout");
     }
@@ -1019,12 +1022,6 @@ void start_auth(struct Client* client)
   }
   auth->port = remote.port;
 
-  /* Try to start DNS lookup. */
-  start_dns_query(auth);
-
-  /* Try to start ident lookup. */
-  start_auth_query(auth);
-
   /* Set required client inputs for users. */
   if (IsUserPort(client)) {
     cli_user(client) = make_user(client);
@@ -1036,6 +1033,12 @@ void start_auth(struct Client* client)
     start_iauth_query(auth);
   }
 
+  /* Try to start DNS lookup. */
+  start_dns_query(auth);
+
+  /* Try to start ident lookup. */
+  start_auth_query(auth);
+
   /* Add client to GlobalClientList. */
   add_client_to_list(client);
 
@@ -1140,6 +1143,17 @@ void auth_send_exit(struct Client *cptr)
   sendto_iauth(cptr, "D");
 }
 
+/** Forward an XREPLY on to iauth.
+ * @param[in] sptr Source of the XREPLY.
+ * @param[in] routing Routing information for the original XQUERY.
+ * @param[in] reply Contents of the reply.
+ */
+void auth_send_xreply(struct Client *sptr, const char *routing,
+                     const char *reply)
+{
+  sendto_iauth(NULL, "X %#C %s :%s", sptr, routing, reply);
+}
+
 /** Mark that a user has started capabilities negotiation.
  * This blocks authorization until auth_cap_done() is called.
  * @param[in] auth Authorization request for client.
@@ -1188,13 +1202,17 @@ int iauth_do_spawn(struct IAuth *iauth, int automatic)
 
   /* Attempt to allocate a pair of sockets. */
   res = os_socketpair(s_io);
-  if (res)
-    return errno;
+  if (res) {
+    res = errno;
+    Debug((DEBUG_INFO, "Unable to create IAuth socketpair: %s", strerror(res)));
+    return res;
+  }
 
   /* Mark the parent's side of the pair (element 0) as non-blocking. */
   res = os_set_nonblocking(s_io[0]);
   if (!res) {
     res = errno;
+    Debug((DEBUG_INFO, "Unable to make IAuth socket non-blocking: %s", strerror(res)));
     close(s_io[1]);
     close(s_io[0]);
     return res;
@@ -1205,6 +1223,7 @@ int iauth_do_spawn(struct IAuth *iauth, int automatic)
                    SS_CONNECTED, SOCK_EVENT_READABLE, s_io[0]);
   if (!res) {
     res = errno;
+    Debug((DEBUG_INFO, "Unable to register IAuth socket: %s", strerror(res)));
     close(s_io[1]);
     close(s_io[0]);
     return res;
@@ -1214,6 +1233,7 @@ int iauth_do_spawn(struct IAuth *iauth, int automatic)
   res = os_socketpair(s_err);
   if (res) {
     res = errno;
+    Debug((DEBUG_INFO, "Unable to create IAuth stderr: %s", strerror(res)));
     socket_del(i_socket(iauth));
     close(s_io[1]);
     close(s_io[0]);
@@ -1224,6 +1244,7 @@ int iauth_do_spawn(struct IAuth *iauth, int automatic)
   res = os_set_nonblocking(s_err[0]);
   if (!res) {
     res = errno;
+    Debug((DEBUG_INFO, "Unable to make IAuth stderr non-blocking: %s", strerror(res)));
     close(s_err[1]);
     close(s_err[0]);
     socket_del(i_socket(iauth));
@@ -1237,6 +1258,7 @@ int iauth_do_spawn(struct IAuth *iauth, int automatic)
                    SS_CONNECTED, SOCK_EVENT_READABLE, s_err[0]);
   if (!res) {
     res = errno;
+    Debug((DEBUG_INFO, "Unable to register IAuth stderr: %s", strerror(res)));
     close(s_err[1]);
     close(s_err[0]);
     socket_del(i_socket(iauth));
@@ -1250,6 +1272,7 @@ int iauth_do_spawn(struct IAuth *iauth, int automatic)
   if (cpid < 0) {
     /* Error forking the child, still in parent. */
     res = errno;
+    Debug((DEBUG_INFO, "Unable to fork IAuth child: %s", strerror(res)));
     socket_del(i_stderr(iauth));
     close(s_err[1]);
     close(s_err[0]);
@@ -1309,17 +1332,15 @@ int auth_spawn(int argc, char *argv[])
         same = 0;
     }
     /* Check that we have no more pre-existing arguments. */
-    if (iauth->i_argv[ii])
+    if (same && iauth->i_argv[ii])
       same = 0;
-    /* If they are the same and still connected, clear the "closing" flag and exit.*/
+    /* If they are the same and still connected, clear the "closing" flag and exit. */
     if (same && i_GetConnected(iauth)) {
+      Debug((DEBUG_INFO, "Reusing existing IAuth process"));
       IAuthClr(iauth, IAUTH_CLOSING);
       return 2;
     }
-    /* Deallocate old argv elements. */
-    for (ii = 0; iauth->i_argv[ii]; ++ii)
-      MyFree(iauth->i_argv[ii]);
-    MyFree(iauth->i_argv);
+    auth_close_unused();
   }
 
   /* Need to initialize a new connection. */
@@ -1807,7 +1828,7 @@ static int iauth_cmd_ip_address(struct IAuth *iauth, struct Client *cli,
     memcpy(&auth->original, &cli_ip(cli), sizeof(auth->original));
 
   /* Undo original IP connection in IPcheck. */
-  IPcheck_connect_fail(cli);
+  IPcheck_connect_fail(cli, 1);
   ClearIPChecked(cli);
 
   /* Update the IP and charge them as a remote connect. */
@@ -1861,6 +1882,22 @@ static struct ConfItem *auth_find_class_conf(const char *class_name)
   return aconf;
 }
 
+/** Tentatively accept a client in IAuth.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters.
+ * @param[in] params Optional class name for client.
+ * @return Negative (CPTR_KILLED) if the connection is refused, one otherwise.
+ */
+static int iauth_cmd_soft_done(struct IAuth *iauth, struct Client *cli,
+                              int parc, char **params)
+{
+  /* Clear iauth pending flag. */
+  assert(cli_auth(cli) != NULL);
+  FlagSet(&cli_auth(cli)->flags, AR_IAUTH_SOFT_DONE);
+  return 1;
+}
+
 /** Accept a client in IAuth.
  * @param[in] iauth Active IAuth session.
  * @param[in] cli Client referenced by command.
@@ -1934,8 +1971,10 @@ static int iauth_cmd_done_account(struct IAuth *iauth, struct Client *cli,
   }
   /* If account has a creation timestamp, use it. */
   assert(cli_user(cli) != NULL);
-  if (params[0][len] == ':')
+  if (params[0][len] == ':') {
     cli_user(cli)->acc_create = strtoul(params[0] + len + 1, NULL, 10);
+    params[0][len] = '\0';
+  }
 
   /* Copy account name to User structure. */
   ircd_strncpy(cli_user(cli)->account, params[0], ACCOUNTLEN);
@@ -1997,6 +2036,55 @@ static int iauth_cmd_challenge(struct IAuth *iauth, struct Client *cli,
   return 0;
 }
 
+/** Send an extension query to a specified remote server.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (3).
+ * @param[in] params Remote server, routing information, and query.
+ * @return Zero.
+ */
+static int iauth_cmd_xquery(struct IAuth *iauth, struct Client *cli,
+                           int parc, char **params)
+{
+  char *serv;
+  const char *routing;
+  const char *query;
+  struct Client *acptr;
+
+  /* Process parameters */
+  if (EmptyString(params[0])) {
+    sendto_iauth(cli, "E Missing :Missing server parameter");
+    return 0;
+  } else
+    serv = params[0];
+
+  if (EmptyString(params[1])) {
+    sendto_iauth(cli, "E Missing :Missing routing parameter");
+    return 0;
+  } else
+    routing = params[1];
+
+  if (EmptyString(params[2])) {
+    sendto_iauth(cli, "E Missing :Missing query parameter");
+    return 0;
+  } else
+    query = params[2];
+
+  /* Try to find the specified server */
+  if (!(acptr = find_match_server(serv))) {
+    sendto_iauth(cli, "x %s %s :Server not online", serv, routing);
+    return 0;
+  }
+
+  /* If it's to us, do nothing; otherwise, forward the query */
+  if (!IsMe(acptr))
+    /* The "iauth:" prefix helps ircu route the reply to iauth */
+    sendcmdto_one(&me, CMD_XQUERY, acptr, "%C iauth:%s :%s", acptr, routing,
+                 query);
+
+  return 0;
+}
+
 /** Parse a \a message from \a iauth.
  * @param[in] iauth Active IAuth session.
  * @param[in] message Message to be parsed.
@@ -2021,6 +2109,7 @@ static void iauth_parse(struct IAuth *iauth, char *message)
   case 'A': handler = iauth_cmd_config; has_cli = 0; break;
   case 's': handler = iauth_cmd_newstats; has_cli = 0; break;
   case 'S': handler = iauth_cmd_stats; has_cli = 0; break;
+  case 'X': handler = iauth_cmd_xquery; has_cli = 0; break;
   case 'o': handler = iauth_cmd_username_forced; has_cli = 1; break;
   case 'U': handler = iauth_cmd_username_good; has_cli = 1; break;
   case 'u': handler = iauth_cmd_username_bad; has_cli = 1; break;
@@ -2028,6 +2117,7 @@ static void iauth_parse(struct IAuth *iauth, char *message)
   case 'I': handler = iauth_cmd_ip_address; has_cli = 1; break;
   case 'M': handler = iauth_cmd_usermode; has_cli = 1; break;
   case 'C': handler = iauth_cmd_challenge; has_cli = 1; break;
+  case 'd': handler = iauth_cmd_soft_done; has_cli = 1; break;
   case 'D': handler = iauth_cmd_done_client; has_cli = 1; break;
   case 'R': handler = iauth_cmd_done_account; has_cli = 1; break;
   case 'k': /* The 'k' command indicates the user should be booted