]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: Add support for proxy destination referrals from initial backend.
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 14 Jun 2021 16:57:12 +0000 (19:57 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 17 Jan 2022 11:52:09 +0000 (13:52 +0200)
This mimics login referral support.

src/doveadm/doveadm-cmd.c
src/doveadm/doveadm-mail-server.c
src/doveadm/doveadm.h
src/doveadm/server-connection.c

index 9e5f39c586217b87752754e8dd9db4d3f198e245..611baf819a457fb553614000c47c113363e003fe 100644 (file)
@@ -43,6 +43,7 @@ static const struct exit_code_str {
        { EX_PROTOCOL, "PROTOCOL" },
        { EX_DATAERR, "DATAERR" },
        { DOVEADM_EX_NOREPLICATE, "NOREPLICATE" },
+       { DOVEADM_EX_REFERRAL, "REFERRAL" },
        { DOVEADM_EX_NOTFOUND, "NOTFOUND" }
 };
 
index 18956db1982c03301f51247fcd2eb9110f3f43c6..89a3540f13f6059eecc097d3f563740e6bee480b 100644 (file)
@@ -6,8 +6,10 @@
 #include "str.h"
 #include "strescape.h"
 #include "ioloop.h"
+#include "istream.h"
 #include "master-service.h"
 #include "iostream-ssl.h"
+#include "auth-proxy.h"
 #include "auth-master.h"
 #include "mail-storage.h"
 #include "mail-storage-service.h"
@@ -26,6 +28,8 @@
 struct doveadm_mail_server_cmd {
        struct server_connection *conn;
        char *username;
+       char *cmdline;
+       struct istream *input;
 };
 
 static HASH_TABLE(char *, struct doveadm_server *) servers;
@@ -33,6 +37,8 @@ static pool_t server_pool;
 static struct doveadm_mail_cmd_context *cmd_ctx;
 static bool internal_failure = FALSE;
 
+static void doveadm_cmd_callback(const struct doveadm_server_reply *reply,
+                                void *context);
 static void doveadm_mail_server_handle(struct server_connection *conn,
                                       const char *username);
 
@@ -94,10 +100,51 @@ static void doveadm_mail_server_cmd_free(struct doveadm_mail_server_cmd **_cmd)
        if (cmd == NULL)
                return;
 
+       i_stream_unref(&cmd->input);
+       i_free(cmd->cmdline);
        i_free(cmd->username);
        i_free(cmd);
 }
 
+static int doveadm_cmd_redirect(struct doveadm_mail_server_cmd *servercmd,
+                               const char *destination)
+{
+       struct doveadm_server *orig_server, *new_server;
+       struct server_connection *conn;
+       struct ip_addr ip;
+       in_port_t port;
+       const char *destuser, *host, *error;
+
+       orig_server = server_connection_get_server(servercmd->conn);
+       if (!auth_proxy_parse_redirect(destination, &destuser,
+                                      &host, &ip, &port)) {
+               i_error("%s: Invalid redirect destination: %s",
+                       orig_server->name, destination);
+               return -1;
+       }
+
+       new_server = doveadm_server_get(destination);
+       new_server->ip = ip;
+       new_server->ssl_flags = orig_server->ssl_flags;
+       new_server->port = port != 0 ? port : orig_server->port;
+
+       conn = doveadm_server_find_unused_conn(new_server);
+       if (conn == NULL) {
+               if (server_connection_create(new_server, &conn, &error) < 0) {
+                       i_error("%s: Failed to create redirect connection: %s",
+                               new_server->name, error);
+                       return -1;
+               }
+       }
+
+       servercmd->conn = conn;
+       if (servercmd->input != NULL)
+               i_stream_seek(servercmd->input, 0);
+       server_connection_cmd(conn, servercmd->cmdline, servercmd->input,
+                             doveadm_cmd_callback, servercmd);
+       return 0;
+}
+
 static void doveadm_cmd_callback(const struct doveadm_server_reply *reply,
                                 void *context)
 {
@@ -122,6 +169,13 @@ static void doveadm_cmd_callback(const struct doveadm_server_reply *reply,
                if (cmd_ctx->exit_code == 0)
                        cmd_ctx->exit_code = EX_NOUSER;
                break;
+       case DOVEADM_EX_REFERRAL:
+               if (doveadm_cmd_redirect(servercmd, reply->error) < 0) {
+                       internal_failure = TRUE;
+                       io_loop_stop(current_ioloop);
+                       doveadm_mail_server_cmd_free(&servercmd);
+               }
+               return;
        default:
                if (cmd_ctx->exit_code == 0 || reply->exit_code == EX_TEMPFAIL)
                        cmd_ctx->exit_code = reply->exit_code;
@@ -172,6 +226,10 @@ static void doveadm_mail_server_handle(struct server_connection *conn,
        servercmd = i_new(struct doveadm_mail_server_cmd, 1);
        servercmd->conn = conn;
        servercmd->username = i_strdup(username);
+       servercmd->cmdline = i_strdup(str_c(cmd));
+       servercmd->input = cmd_ctx->cmd_input;
+       if (servercmd->input != NULL)
+               i_stream_ref(servercmd->input);
        server_connection_cmd(conn, str_c(cmd), cmd_ctx->cmd_input,
                              doveadm_cmd_callback, servercmd);
 }
index d4f74e555f8cd00b6ae52b25cf86f912d3095fd1..64173c87e01d177a186dac5d594743f702c3179a 100644 (file)
@@ -12,6 +12,7 @@
 #define DOVEADM_EX_UNKNOWN -1
 
 #define DOVEADM_EX_NOREPLICATE 1001
+#define DOVEADM_EX_REFERRAL 1002
 
 enum doveadm_client_type {
        DOVEADM_CONNECTION_TYPE_CLI = 0,
index 056584bd1cf8fd8d05adae2e8eb858597fab2276..fc277c24258f100abe4df032f86ab930c39fd878 100644 (file)
@@ -644,7 +644,7 @@ void server_connection_destroy(struct server_connection **_conn)
 
        i_stream_destroy(&conn->input);
        o_stream_destroy(&conn->output);
-       i_stream_destroy(&conn->cmd_input);
+       i_stream_unref(&conn->cmd_input);
        /* close cmd_output after its parent, so the "." isn't sent */
        o_stream_destroy(&conn->cmd_output);
        ssl_iostream_destroy(&conn->ssl_iostream);