]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm-server: Support referrals returned by passdb
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 9 Jun 2021 19:31:56 +0000 (22:31 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 17 Jan 2022 11:52:09 +0000 (13:52 +0200)
src/doveadm/client-connection-tcp.c
src/doveadm/doveadm-cmd.h
src/doveadm/doveadm-mail-server.c
src/doveadm/server-connection.c

index afe7e1d09056e6f8242aed97464e7da173e4bf75..f63d3c32acc7216b89e00d3ef15a8398759f313a 100644 (file)
@@ -157,10 +157,17 @@ static void doveadm_server_restore_logs(void)
 }
 
 static void
-doveadm_cmd_server_post(struct client_connection_tcp *conn, const char *cmd_name)
+doveadm_cmd_server_post(struct client_connection_tcp *conn,
+                       struct doveadm_cmd_context *cctx)
 {
        const char *str = NULL;
 
+       if (cctx->referral != NULL) {
+               o_stream_nsend_str(conn->output, t_strdup_printf(
+                       "\n-REFERRAL %s\n", cctx->referral));
+               return;
+       }
+
        if (doveadm_exit_code == 0) {
                o_stream_nsend(conn->output, "\n+\n", 3);
                return;
@@ -174,7 +181,7 @@ doveadm_cmd_server_post(struct client_connection_tcp *conn, const char *cmd_name
        } else {
                o_stream_nsend_str(conn->output, "\n-\n");
                i_error("BUG: Command '%s' returned unknown error code %d",
-                       cmd_name, doveadm_exit_code);
+                       cctx->cmd->name, doveadm_exit_code);
        }
 }
 
@@ -186,7 +193,7 @@ doveadm_cmd_server_run_ver2(struct client_connection_tcp *conn,
        i_getopt_reset();
        if (doveadm_cmdline_run(argc, argv, cctx) < 0)
                doveadm_exit_code = EX_USAGE;
-       doveadm_cmd_server_post(conn, cctx->cmd->name);
+       doveadm_cmd_server_post(conn, cctx);
 }
 
 static int doveadm_cmd_handle(struct client_connection_tcp *conn,
index 2f44f76c903d1eac52ec88a1e9343cd570d1d16b..f203a8ae2fb896106e6dfe3c268d373225782bb7 100644 (file)
@@ -81,6 +81,10 @@ struct doveadm_cmd_context {
        enum doveadm_client_type conn_type;
        struct istream *input;
        struct ostream *output;
+
+       /* non-NULL if doveadm-server should return referral to another
+          server instead. */
+       const char *referral;
 };
 
 ARRAY_DEFINE_TYPE(doveadm_cmd_ver2, struct doveadm_cmd_ver2);
index 89a3540f13f6059eecc097d3f563740e6bee480b..e65a25e6e6555d86e503bd4a70d330dcb7c0f590 100644 (file)
@@ -251,6 +251,7 @@ doveadm_mail_server_user_get_host(struct doveadm_mail_cmd_context *ctx,
                                  const char **user_r, const char **host_r,
                                  struct ip_addr *hostip_r, in_port_t *port_r,
                                  enum doveadm_proxy_ssl_flags *ssl_flags_r,
+                                 const char **referral_r,
                                  const char **error_r)
 {
        struct auth_master_connection *auth_conn;
@@ -259,12 +260,13 @@ doveadm_mail_server_user_get_host(struct doveadm_mail_cmd_context *ctx,
        const char *auth_socket_path, *proxy_host, *proxy_hostip, *const *fields;
        unsigned int i;
        in_port_t proxy_port;
-       bool proxying;
+       bool proxying, nologin;
        int ret;
 
        *user_r = input->username;
        *host_r = ctx->set->doveadm_socket_path;
        *port_r = ctx->set->doveadm_port;
+       *referral_r = NULL;
 
        if (ctx->set->doveadm_port == 0)
                return 0;
@@ -300,7 +302,7 @@ doveadm_mail_server_user_get_host(struct doveadm_mail_cmd_context *ctx,
                   so just continue with the default host */
        } else {
                proxy_host = NULL; proxy_hostip = NULL; proxying = FALSE;
-               proxy_port = ctx->set->doveadm_port;
+               proxy_port = ctx->set->doveadm_port; nologin = FALSE;
                for (i = 0; fields[i] != NULL; i++) {
                        const char *p, *key, *value;
 
@@ -315,6 +317,8 @@ doveadm_mail_server_user_get_host(struct doveadm_mail_cmd_context *ctx,
 
                        if (strcmp(key, "proxy") == 0)
                                proxying = TRUE;
+                       else if (strcmp(key, "nologin") == 0)
+                               nologin = TRUE;
                        else if (strcmp(key, "host") == 0)
                                proxy_host = value;
                        else if (strcmp(key, "hostip") == 0)
@@ -343,9 +347,21 @@ doveadm_mail_server_user_get_host(struct doveadm_mail_cmd_context *ctx,
                                                   auth_socket_path, proxy_hostip);
                        ret = -1;
                }
-               if (!proxying)
-                       ret = 0;
-               else if (proxy_host == NULL) {
+               if (!proxying) {
+                       if (!nologin)
+                               ret = 0;
+                       else if (proxy_host == NULL) {
+                               /* Allow accessing nologin users via doveadm
+                                  protocol, since it's only admins that access
+                                  them. */
+                               ret = 0;
+                       } else {
+                               /* Referral */
+                               *referral_r = t_strdup_printf("%s@%s",
+                                       *user_r, proxy_host);
+                               ret = 1;
+                       }
+               } else if (proxy_host == NULL) {
                        *error_r = t_strdup_printf("%s: Proxy is missing destination host",
                                                   auth_socket_path);
                        if (strstr(auth_socket_path, "/auth-userdb") != NULL) {
@@ -369,7 +385,7 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
 {
        struct doveadm_server *server;
        struct server_connection *conn;
-       const char *user, *host;
+       const char *user, *host, *referral;
        struct ip_addr hostip;
        enum doveadm_proxy_ssl_flags ssl_flags = 0;
        char *username_dup;
@@ -381,7 +397,7 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
 
        i_zero(&hostip);
        ret = doveadm_mail_server_user_get_host(ctx, input, &user, &host, &hostip,
-                                               &port, &ssl_flags, error_r);
+                                               &port, &ssl_flags, &referral, error_r);
        if (ret < 0)
                return ret;
        if (ret == 0 &&
@@ -389,6 +405,10 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
                /* run it ourself */
                return 0;
        }
+       if (referral != NULL) {
+               ctx->cctx->referral = referral;
+               return 1;
+       }
 
        /* server sends the sticky headers for each row as well,
           so undo any sticks we might have added already */
index fc277c24258f100abe4df032f86ab930c39fd878..4887acd241713fc855913095dabce898a1df4288 100644 (file)
@@ -426,14 +426,27 @@ static void
 server_connection_input_cmd_error(struct server_connection *conn,
                                  const char *line)
 {
+       const char *code, *args = strchr(line, ' ');
+       if (args != NULL)
+               code = t_strdup_until(line, args++);
+       else {
+               code = line;
+               args = "";
+       }
        struct doveadm_server_reply reply = {
-               .exit_code = doveadm_str_to_exit_code(line),
+               .exit_code = doveadm_str_to_exit_code(code),
                .error = line,
        };
-       if (reply.exit_code == DOVEADM_EX_UNKNOWN &&
-           str_to_int(line, &reply.exit_code) < 0) {
-               /* old doveadm-server */
-               reply.exit_code = EX_TEMPFAIL;
+       switch (reply.exit_code) {
+       case DOVEADM_EX_REFERRAL:
+               reply.error = args;
+               break;
+       case DOVEADM_EX_UNKNOWN:
+               if (str_to_int(line, &reply.exit_code) < 0) {
+                       /* old doveadm-server */
+                       reply.exit_code = EX_TEMPFAIL;
+               }
+               break;
        }
        server_connection_callback(conn, &reply);
 }