added possibility to recover connections using Login on Connect
authorpk910 <philipp@zoelle1.de>
Tue, 25 Dec 2012 18:33:23 +0000 (19:33 +0100)
committerpk910 <philipp@zoelle1.de>
Tue, 25 Dec 2012 18:49:47 +0000 (19:49 +0100)
include/s_auth.h
ircd/m_nick.c
ircd/s_auth.c
ircd/s_user.c

index cc34ae4c17d3bc6901fb06ce2cb423755f1b56a0..11006175c687f5cce2f89fce3a3b242e20fe1b5e 100644 (file)
@@ -38,6 +38,7 @@ extern int EmptyPassString(char* password);
 extern int auth_ping_timeout(struct Client *);
 extern int auth_set_pong(struct AuthRequest *auth, unsigned int cookie);
 extern int auth_set_user(struct AuthRequest *auth, const char *username, const char *hostname, const char *servername, const char *userinfo);
+extern int auth_set_recover_client(struct AuthRequest *auth, struct Client *zombie);
 extern int auth_set_nick(struct AuthRequest *auth, const char *nickname);
 extern int auth_set_password(struct AuthRequest *auth, char *password);
 extern int auth_cap_start(struct AuthRequest *auth);
index 3c069f7b68ffbd161193c3f80bd803c974a988e5..fd1cb0c29280381ba1b037227c67956a02bf1500 100644 (file)
@@ -96,6 +96,7 @@
 #include "s_debug.h"
 #include "s_misc.h"
 #include "s_user.h"
+#include "s_auth.h"
 #include "send.h"
 #include "sys.h"
 
@@ -256,6 +257,14 @@ int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     exit_client(cptr, acptr, &me, "Overridden by other sign on");
     return set_nick_name(cptr, sptr, nick, parc, parv, 0);
   }
+  /*
+   * If the Nickname is in use by a Zombie, wait for possible LOC information
+   * to recover the zombie connection...
+   */
+  if(IsNotConn(acptr) && !(cli_name(sptr))[0]) {
+    auth_set_recover_client(cli_auth(sptr), acptr);
+    return set_nick_name(cptr, sptr, nick, parc, parv, 1);
+  }
   /*
    * NICK is coming from local client connection. Just
    * send error reply and ignore the command.
index 71c86385db89e66b589a99c4abae9ecc37da5a65..112fdc8cf87946de03e7f64cbc02b1fb7ed72ee0 100644 (file)
@@ -84,6 +84,7 @@ enum AuthRequestFlag {
     AR_NEEDS_USER,      /**< user must send USER command */
     AR_NEEDS_NICK,      /**< user must send NICK command */
     AR_LAST_SCAN = AR_NEEDS_NICK, /**< maximum flag to scan through */
+    AR_ZOMBIE_RECOVER,  /**< nick of user is already taken by a zombie - try to recover */
     AR_IAUTH_PENDING,   /**< iauth request sent, waiting for response */
     AR_IAUTH_HURRY,     /**< we told iauth to hurry up */
     AR_IAUTH_USERNAME,  /**< iauth sent a username (preferred or forced) */
@@ -109,6 +110,7 @@ struct AuthRequest {
   unsigned int        cookie;     /**< cookie the user must PONG */
   unsigned short      port;       /**< client's remote port number */
   unsigned int        numeric;    /**< unregistered client numeric */
+  struct Client*      recover_client; /**< zombie client to be recovered later */
   char                loc_user[ACCOUNTLEN];
   char                loc_pass[PASSWDLEN];
 };
@@ -134,6 +136,7 @@ static struct {
   MSG("NOTICE AUTH :*** Checking login\r\n"),
   MSG("NOTICE AUTH :*** Login rejected\r\n"),
   MSG("NOTICE AUTH :*** Login accepted\r\n"),
+  MSG("NOTICE AUTH :*** Nickname in Use by Zombie - try to recover\r\n"),
 #undef MSG
 };
 
@@ -150,7 +153,8 @@ typedef enum {
   REPORT_INVAL_DNS,
   REPORT_DO_LOC,
   REPORT_FAIL_LOC,
-  REPORT_DONE_LOC
+  REPORT_DONE_LOC,
+  REPORT_ZOMBIE_RECOVER
 } ReportType;
 
 /** Sends response \a r (from #ReportType) to client \a c. */
@@ -557,10 +561,27 @@ static int check_auth_finished(struct AuthRequest *auth)
 
   if (IsUserPort(auth->client))
   {
+    if(FlagHas(&auth->flags, AR_ZOMBIE_RECOVER)) {
+      /* check if able to recover connection */
+      if(!IsAccount(auth->client) || ircd_strcmp(cli_user(auth->client)->account, cli_user(auth->recover_client)->account)) {
+        send_reply(auth->client, ERR_RECOVERDENIED, cli_name(auth->recover_client), "auth missmatch");
+        
+        /* reset nickname */
+        FlagSet(&auth->flags, AR_NEEDS_NICK);
+        send_reply(auth->client, ERR_NICKNAMEINUSE, cli_name(auth->recover_client));
+        hRemClient(auth->client);
+        (cli_name(auth->client))[0] = '\0';
+        return 0;
+      }
+    }
     memset(cli_passwd(auth->client), 0, sizeof(cli_passwd(auth->client)));
     res = auth_set_username(auth);
     if (res == 0)
       res = register_user(auth->client, auth->client);
+    if (res == 0 && FlagHas(&auth->flags, AR_ZOMBIE_RECOVER)) {
+      unzombie_client(&me, &me, auth->client, auth->recover_client);
+      auth->client = auth->recover_client;
+    }
   }
   else
     res = 0;
@@ -1404,6 +1425,17 @@ int auth_set_user(struct AuthRequest *auth, const char *username, const char *ho
   return check_auth_finished(auth);
 }
 
+/** Set Zombie Client that should be recovered later
+ */
+int auth_set_recover_client(struct AuthRequest *auth, struct Client *zombie)
+{
+  assert(auth != NULL);
+  FlagSet(&auth->flags, AR_ZOMBIE_RECOVER);
+  auth->recover_client = zombie;
+  
+  sendheader(auth->client, REPORT_ZOMBIE_RECOVER);
+}
+
 /** Handle authorization-related aspects of initial nickname selection.
  * This is called after verifying that the nickname is available.
  * @param[in] auth Authorization request for client.
@@ -1414,6 +1446,7 @@ int auth_set_nick(struct AuthRequest *auth, const char *nickname)
 {
   assert(auth != NULL);
   FlagClr(&auth->flags, AR_NEEDS_NICK);
+
   /*
    * If the client hasn't gotten a cookie-ping yet,
    * choose a cookie and send it. -record!jegelhof@cloud9.net
index 2c9a9bce35be8aeaa46866eab9ef0925ba10f38e..96d88a15e3db5ab173052a8a5c78159063c90e8f 100644 (file)
@@ -728,7 +728,23 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
   }
   else {
     /* Local client setting NICK the first time */
-    strcpy(cli_name(sptr), nick);
+    if(!force)
+      strcpy(cli_name(sptr), nick);
+    else {
+      /* use a "temponary" nick here (we'll switch later) */
+      char tmpnick[NICKLEN + 2];
+      int tmpnickend; 
+      strcpy(tmpnick, nick);
+      /* we need at least 10 characters */
+      if (strlen(tmpnick) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN)) - 10)
+        tmpnick[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))-10] = '\0';
+      tmpnickend = strlen(tmpnick);
+      
+      do { /* get a non-used nick... */
+        sprintf(tmpnick + tmpnickend, "[rz%d]", ircrandom() % 10000);
+      } while(FindClient(tmpnick));
+      strcpy(cli_name(sptr), tmpnick);
+    }
     hAddClient(sptr);
     return auth_set_nick(cli_auth(sptr), nick);
   }