]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: server-connection - Replace doveadm_server with doveadm_client_settings
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 29 Jul 2021 17:12:53 +0000 (20:12 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 17 Jan 2022 11:52:09 +0000 (13:52 +0200)
src/doveadm/doveadm-dsync.c
src/doveadm/doveadm-mail-server.c
src/doveadm/doveadm-server.h
src/doveadm/server-connection.c
src/doveadm/server-connection.h

index 4d390d72297f3333e275068d82e772578f3f2a92..455655d976007c92b7f07ef9defb4ae462eec4b7 100644 (file)
@@ -28,7 +28,6 @@
 #include "doveadm-settings.h"
 #include "doveadm-mail.h"
 #include "doveadm-print.h"
-#include "doveadm-server.h"
 #include "client-connection.h"
 #include "server-connection.h"
 #include "dsync/dsync-brain.h"
@@ -896,21 +895,24 @@ dsync_connect_tcp(struct dsync_cmd_context *ctx,
                  const struct master_service_ssl_settings *ssl_set,
                  const char *target, bool ssl, const char **error_r)
 {
-       struct doveadm_server *server;
+       struct doveadm_client_settings conn_set;
        struct server_connection *conn;
        struct ioloop *prev_ioloop, *ioloop;
        const char *p, *error;
 
-       server = p_new(ctx->ctx.pool, struct doveadm_server, 1);
-       server->name = p_strdup(ctx->ctx.pool, target);
-       p = strrchr(server->name, ':');
-       server->hostname = p == NULL ? server->name :
-               p_strdup_until(ctx->ctx.pool, server->name, p);
-       if (p == NULL)
-               server->port = doveadm_settings->doveadm_port;
-       else if (net_str2port(p+1, &server->port) < 0) {
-               *error_r = t_strdup_printf("Invalid port number: %s", p+1);
-               return -1;
+       i_zero(&conn_set);
+       if (strchr(target, '/') != NULL)
+               conn_set.socket_path = target;
+       else {
+               p = strrchr(target, ':');
+               conn_set.hostname = p == NULL ? target :
+                       p_strdup_until(ctx->ctx.pool, target, p);
+               if (p == NULL)
+                       conn_set.port = doveadm_settings->doveadm_port;
+               else if (net_str2port(p+1, &conn_set.port) < 0) {
+                       *error_r = t_strdup_printf("Invalid port number: %s", p+1);
+                       return -1;
+               }
        }
 
        if (ssl) {
@@ -919,13 +921,11 @@ dsync_connect_tcp(struct dsync_cmd_context *ctx,
                                "Couldn't initialize SSL context: %s", error);
                        return -1;
                }
-               server->ssl_flags = AUTH_PROXY_SSL_FLAG_YES;
-               server->ssl_ctx = ctx->ssl_ctx;
+               conn_set.ssl_flags = AUTH_PROXY_SSL_FLAG_YES;
+               conn_set.ssl_ctx = ctx->ssl_ctx;
        }
-       server->username = p_strdup(ctx->ctx.pool,
-                                   ctx->ctx.set->doveadm_username);
-       server->password = p_strdup(ctx->ctx.pool,
-                                   ctx->ctx.set->doveadm_password);
+       conn_set.username = ctx->ctx.set->doveadm_username;
+       conn_set.password = ctx->ctx.set->doveadm_password;
 
        prev_ioloop = current_ioloop;
        ioloop = io_loop_create();
@@ -933,15 +933,15 @@ dsync_connect_tcp(struct dsync_cmd_context *ctx,
 
        if (doveadm_verbose_proctitle) {
                process_title_set(t_strdup_printf(
-                       "[dsync - connecting to %s]", server->name));
+                       "[dsync - connecting to %s]", target));
        }
-       if (server_connection_create(server, &conn, &error) < 0) {
+       if (server_connection_create(&conn_set, &conn, &error) < 0) {
                ctx->error = p_strdup_printf(ctx->ctx.pool,
                        "Couldn't create server connection: %s", error);
        } else {
                if (doveadm_verbose_proctitle) {
                        process_title_set(t_strdup_printf(
-                               "[dsync - running dsync-server on %s]", server->name));
+                               "[dsync - running dsync-server on %s]", target));
                }
 
                dsync_server_run_command(ctx, conn);
index 686da77d47b88639a3907bfe16d6c9b8fe0383c6..863ca368172447471d50a893797a4e07ca6c4e8b 100644 (file)
@@ -45,8 +45,10 @@ struct doveadm_mail_server_cmd {
 };
 
 struct doveadm_server_request {
+       pool_t pool;
        struct doveadm_server *server;
-       char *username;
+       struct doveadm_client_settings set;
+       const char *username;
 };
 
 static HASH_TABLE(char *, struct doveadm_server *) servers;
@@ -63,13 +65,13 @@ static void doveadm_mail_server_handle(struct doveadm_server *server,
 
 static void doveadm_server_request_free(struct doveadm_server_request *request)
 {
-       i_free(request->username);
+       ssl_iostream_context_unref(&request->set.ssl_ctx);
+       pool_unref(&request->pool);
 }
 
 static struct doveadm_server *doveadm_server_get(const char *name)
 {
        struct doveadm_server *server;
-       const char *p;
        char *dup_name;
 
        if (!hash_table_is_created(servers)) {
@@ -84,13 +86,6 @@ static struct doveadm_server *doveadm_server_get(const char *name)
        if (server == NULL) {
                server = p_new(server_pool, struct doveadm_server, 1);
                server->name = dup_name = p_strdup(server_pool, name);
-               server->username = p_strdup(server_pool,
-                                           doveadm_settings->doveadm_username);
-               server->password = p_strdup(server_pool,
-                                           doveadm_settings->doveadm_password);
-               p = strrchr(server->name, ':');
-               server->hostname = p == NULL ? server->name :
-                       p_strdup_until(server_pool, server->name, p);
 
                hash_table_insert(servers, dup_name, server);
        }
@@ -301,11 +296,18 @@ doveadm_cmd_redirect_finish(struct doveadm_mail_server_cmd *servercmd,
 
        server_name = t_strdup_printf("%s:%u", net_ip2addr(ip), port);
        new_server = doveadm_server_get(server_name);
-       new_server->ip = *ip;
-       new_server->ssl_flags = ssl_flags;
-       new_server->port = port;
 
-       if (server_connection_create(new_server, &conn, &error) < 0) {
+       struct doveadm_client_settings conn_set = {
+               .hostname = net_ip2addr(ip),
+               .ip = *ip,
+               .port = port,
+               .username = doveadm_settings->doveadm_username,
+               .password = doveadm_settings->doveadm_password,
+               .ssl_flags = ssl_flags,
+               .log_passthrough = TRUE,
+       };
+
+       if (server_connection_create(&conn_set, &conn, &error) < 0) {
                *error_r = t_strdup_printf(
                        "Failed to create redirect connection to %s: %s",
                        new_server->name, error);
@@ -313,6 +315,7 @@ doveadm_cmd_redirect_finish(struct doveadm_mail_server_cmd *servercmd,
        }
 
        servercmd->conn = conn;
+       servercmd->server = new_server;
        if (servercmd->input != NULL)
                i_stream_seek(servercmd->input, 0);
        server_connection_cmd(conn, servercmd->proxy_ttl,
@@ -374,6 +377,8 @@ static int doveadm_cmd_redirect(struct doveadm_mail_server_cmd *servercmd,
                                const char *destination)
 {
        struct doveadm_server *orig_server = servercmd->server;
+       const struct doveadm_client_settings *client_set =
+               server_connection_get_settings(servercmd->conn);
        struct ip_addr ip;
        in_port_t port;
        const char *destuser, *host, *error;
@@ -386,14 +391,14 @@ static int doveadm_cmd_redirect(struct doveadm_mail_server_cmd *servercmd,
                return -1;
        }
        if (port == 0)
-               port = orig_server->port;
+               port = client_set->port;
 
        if (cmd_ctx->cctx->proxy_redirect_reauth) {
                ret = doveadm_cmd_redirect_relookup(servercmd, &ip, port,
                                                    destuser, &error);
        } else {
                ret = doveadm_cmd_redirect_finish(servercmd, &ip, port,
-                                                 orig_server->ssl_flags,
+                                                 client_set->ssl_flags,
                                                  &error);
        }
        if (ret < 0) {
@@ -535,7 +540,7 @@ static int doveadm_mail_server_request_queue_handle_next(const char **error_r)
        request_copy = *request;
        array_pop_front(&doveadm_server_request_queue);
 
-       if (server_connection_create(request_copy.server, &conn, error_r) < 0) {
+       if (server_connection_create(&request_copy.set, &conn, error_r) < 0) {
                internal_failure = TRUE;
                return -1;
        }
@@ -664,12 +669,19 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
           so undo any sticks we might have added already */
        doveadm_print_unstick_headers();
 
+       struct doveadm_client_settings conn_set = {
+               .socket_path = socket_path,
+               .hostname = proxy_set.host,
+               .ip = proxy_set.host_ip,
+               .port = proxy_set.port,
+               .username = ctx->set->doveadm_username,
+               .password = ctx->set->doveadm_password,
+               .ssl_flags = proxy_set.ssl_flags,
+       };
+
        server_name = socket_path != NULL ? socket_path :
                t_strdup_printf("%s:%u", proxy_set.host, proxy_set.port);
        server = doveadm_server_get(server_name);
-       server->ip = proxy_set.host_ip;
-       server->ssl_flags = proxy_set.ssl_flags;
-       server->port = proxy_set.port;
 
        unsigned int limit = I_MAX(ctx->set->doveadm_worker_count, 1);
        /* Make sure there's space for the new request. Either by creating a
@@ -693,7 +705,7 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
        }
 
        if (server_connections_count() <= limit) {
-               if (server_connection_create(server, &conn, error_r) < 0) {
+               if (server_connection_create(&conn_set, &conn, error_r) < 0) {
                        internal_failure = TRUE;
                        return -1;
                } else {
@@ -702,27 +714,15 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
                }
        } else {
                request = array_append_space(&doveadm_server_request_queue);
-               request->username = i_strdup(proxy_set.username);
+               request->pool = pool_alloconly_create("doveadm server request", 256);
                request->server = server;
+               request->username = p_strdup(request->pool, proxy_set.username);
+               doveadm_client_settings_dup(&conn_set, &request->set, request->pool);
        }
        *error_r = "doveadm server failure";
        return DOVEADM_MAIL_SERVER_FAILED() ? -1 : 1;
 }
 
-static void doveadm_servers_destroy_all_connections(void)
-{
-       struct hash_iterate_context *iter;
-       char *key;
-       struct doveadm_server *server;
-
-       iter = hash_table_iterate_init(servers);
-       while (hash_table_iterate(iter, servers, &key, &server))
-               ssl_iostream_context_unref(&server->ssl_ctx);
-       hash_table_iterate_deinit(&iter);
-
-       server_connections_destroy_all();
-}
-
 void doveadm_mail_server_flush(void)
 {
        struct doveadm_server_request *request;
@@ -755,7 +755,7 @@ void doveadm_mail_server_flush(void)
               server_connections_count() > 0)
                io_loop_run(current_ioloop);
 
-       doveadm_servers_destroy_all_connections();
+       server_connections_destroy_all();
        if (master_service_is_killed(master_service))
                i_error("Aborted");
        if (DOVEADM_MAIL_SERVER_FAILED())
index 0bc6d161a9a9479bdd7d6ae1405462b0adf3da32..46fdaa86f001ae34861eb230cb2abd296d7a351b 100644 (file)
@@ -9,19 +9,6 @@ extern struct doveadm_print_vfuncs doveadm_print_server_vfuncs;
 struct doveadm_server {
        /* hostname:port or UNIX socket path. Used mainly for logging. */
        const char *name;
-       /* If this contains '/', it's a UNIX socket path. Otherwise it's
-          the hostname without port. */
-       const char *hostname;
-       /* Host's IP to use, if known. Otherwise DNS lookup is done. */
-       struct ip_addr ip;
-       /* Port to use for TCP connections. */
-       in_port_t port;
-
-       const char *username, *password;
-
-       /* ssl related settings */
-       enum auth_proxy_ssl_flags ssl_flags;
-       struct ssl_iostream_context *ssl_ctx;
 };
 
 #endif
index 78151a4a37b48dab53ebb02d0e488603561d7a81..428f06e709bd27a13fd7675300212126fc5b5469 100644 (file)
@@ -32,7 +32,8 @@ enum server_reply_state {
 
 struct server_connection {
        struct connection conn;
-       struct doveadm_server *server;
+
+       struct doveadm_client_settings set;
 
        pool_t pool;
        struct timeout *to_destroy;
@@ -66,6 +67,27 @@ static int server_connection_init_ssl(struct server_connection *conn,
                                      const char **error_r);
 static void server_connection_destroy(struct server_connection **_conn);
 
+void doveadm_client_settings_dup(const struct doveadm_client_settings *src,
+                                struct doveadm_client_settings *dest_r,
+                                pool_t pool)
+{
+       i_zero(dest_r);
+
+       dest_r->socket_path = p_strdup(pool, src->socket_path);
+       dest_r->hostname = p_strdup(pool, src->hostname);
+       dest_r->ip = src->ip;
+       dest_r->port = src->port;
+
+       dest_r->username = p_strdup(pool, src->username);
+       dest_r->password = p_strdup(pool, src->password);
+
+       dest_r->ssl_flags = src->ssl_flags;
+       if (src->ssl_ctx != NULL) {
+               dest_r->ssl_ctx = src->ssl_ctx;
+               ssl_iostream_context_ref(dest_r->ssl_ctx);
+       }
+}
+
 static void server_set_print_pending(struct server_connection *conn)
 {
        if (!array_is_created(&print_pending_connections))
@@ -260,16 +282,16 @@ server_connection_authenticate(struct server_connection *conn)
        string_t *plain = t_str_new(128);
        string_t *cmd = t_str_new(128);
 
-       if (*conn->server->password == '\0') {
+       if (*conn->set.password == '\0') {
                e_error(conn->conn.event, "doveadm_password not set, "
                        "can't authenticate to remote server");
                return -1;
        }
 
        str_append_c(plain, '\0');
-       str_append(plain, conn->server->username);
+       str_append(plain, conn->set.username);
        str_append_c(plain, '\0');
-       str_append(plain, conn->server->password);
+       str_append(plain, conn->set.password);
 
        str_append(cmd, "PLAIN\t");
        base64_encode(plain->data, plain->used, cmd);
@@ -307,7 +329,7 @@ static void server_connection_print_log(struct server_connection *conn)
                                "Doveadm server sent invalid log type 0x%02x",
                                line[0]);
                line++;
-               i_log_type(&ctx, "remote(%s): %s", conn->server->name, line);
+               i_log_type(&ctx, "remote(%s): %s", conn->conn.name, line);
        }
 }
 
@@ -377,7 +399,7 @@ static void server_connection_input(struct connection *_conn)
                                return;
                        }
                        if (!conn->ssl_done &&
-                           (conn->server->ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) != 0) {
+                           (conn->set.ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) != 0) {
                                connection_input_halt(&conn->conn);
                                if (conn->conn.minor_version < DOVEADM_PROTO_MINOR_MIN_STARTTLS) {
                                        e_error(conn->conn.event,
@@ -496,28 +518,28 @@ static int server_connection_init_ssl(struct server_connection *conn,
        struct ssl_iostream_settings ssl_set;
        const char *error;
 
-       if (conn->server->ssl_flags == 0)
+       if (conn->set.ssl_flags == 0)
                return 0;
 
        doveadm_get_ssl_settings(&ssl_set, pool_datastack_create());
 
-       if ((conn->server->ssl_flags & AUTH_PROXY_SSL_FLAG_ANY_CERT) != 0)
+       if ((conn->set.ssl_flags & AUTH_PROXY_SSL_FLAG_ANY_CERT) != 0)
                ssl_set.allow_invalid_cert = TRUE;
        if (ssl_set.allow_invalid_cert)
                ssl_set.verbose_invalid_cert = TRUE;
 
-       if (conn->server->ssl_ctx == NULL &&
-           ssl_iostream_client_context_cache_get(&ssl_set,
-                                                 &conn->server->ssl_ctx,
+       if (conn->set.ssl_ctx == NULL &&
+           ssl_iostream_client_context_cache_get(&ssl_set, &conn->set.ssl_ctx,
                                                  &error) < 0) {
                *error_r = t_strdup_printf(
                        "Couldn't initialize SSL client: %s", error);
                return -1;
        }
 
+       const char *hostname =
+               conn->set.hostname != NULL ? conn->set.hostname : "";
        connection_input_halt(&conn->conn);
-       if (io_stream_create_ssl_client(conn->server->ssl_ctx,
-                                       conn->server->hostname, &ssl_set,
+       if (io_stream_create_ssl_client(conn->set.ssl_ctx, hostname, &ssl_set,
                                        &conn->conn.input, &conn->conn.output,
                                        &conn->ssl_iostream, &error) < 0) {
                *error_r = t_strdup_printf(
@@ -554,7 +576,7 @@ static void server_connection_connected(struct connection *_conn, bool success)
                                    server_connection_output, conn);
 
        connection_input_halt(&conn->conn);
-       if (((conn->server->ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0 &&
+       if (((conn->set.ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0 &&
             server_connection_init_ssl(conn, &error) < 0)) {
                e_error(conn->conn.event, "%s", error);
                /* Can't safely destroy the connection here, so delay it */
@@ -588,7 +610,7 @@ static struct connection_settings doveadm_client_set = {
        .client_connect_timeout_msecs = DOVEADM_TCP_CONNECT_TIMEOUT_SECS,
 };
 
-int server_connection_create(struct doveadm_server *server,
+int server_connection_create(const struct doveadm_client_settings *set,
                             struct server_connection **conn_r,
                             const char **error_r)
 {
@@ -596,8 +618,8 @@ int server_connection_create(struct doveadm_server *server,
        pool_t pool;
        int ret;
 
-       i_assert(server->username != NULL);
-       i_assert(server->password != NULL);
+       i_assert(set->username != NULL);
+       i_assert(set->password != NULL);
 
        if (doveadm_clients == NULL) {
                doveadm_clients =
@@ -608,33 +630,32 @@ int server_connection_create(struct doveadm_server *server,
        pool = pool_alloconly_create("doveadm server connection", 1024*16);
        conn = p_new(pool, struct server_connection, 1);
        conn->pool = pool;
-       conn->server = server;
-       if (strchr(server->hostname, '/') != NULL) {
+       doveadm_client_settings_dup(set, &conn->set, pool);
+
+       if (set->socket_path != NULL) {
                connection_init_client_unix(doveadm_clients, &conn->conn,
-                                           server->hostname);
-       } else if (server->ip.family != 0) {
+                                           set->socket_path);
+       } else if (set->ip.family != 0) {
                connection_init_client_ip(doveadm_clients, &conn->conn,
-                                         server->hostname, &server->ip,
-                                         server->port);
+                                         set->hostname, &set->ip, set->port);
        } else {
                struct ip_addr *ips;
                unsigned int ips_count;
 
-               ret = net_gethostbyname(server->hostname, &ips, &ips_count);
+               ret = net_gethostbyname(set->hostname, &ips, &ips_count);
                if (ret != 0) {
                        *error_r = t_strdup_printf(
                                "Lookup of host %s failed: %s",
-                               server->hostname, net_gethosterror(ret));
+                               set->hostname, net_gethosterror(ret));
                        pool_unref(&pool);
                        return -1;
                }
                connection_init_client_ip(doveadm_clients, &conn->conn,
-                                         server->hostname, &ips[0],
-                                         server->port);
+                                         set->hostname, &ips[0], set->port);
        }
        if (connection_client_connect(&conn->conn) < 0) {
                *error_r = t_strdup_printf(
-                       "net_connect(%s) failed: %m", server->name);
+                       "net_connect(%s) failed: %m", conn->conn.name);
                connection_deinit(&conn->conn);
                pool_unref(&pool);
                return -1;
@@ -689,6 +710,7 @@ static void server_connection_destroy(struct server_connection **_conn)
        timeout_remove(&conn->to_destroy);
 
        connection_deinit(&conn->conn);
+       ssl_iostream_context_unref(&conn->set.ssl_ctx);
        pool_unref(&conn->pool);
 }
 
@@ -701,6 +723,12 @@ void server_connection_get_dest(struct server_connection *conn,
        }
 }
 
+const struct doveadm_client_settings *
+server_connection_get_settings(struct server_connection *conn)
+{
+       return &conn->set;
+}
+
 void server_connection_cmd(struct server_connection *conn, int proxy_ttl,
                           const char *line, struct istream *cmd_input,
                           server_cmd_callback_t *callback, void *context)
index c5b37b9cd842edcb0d246a02b7c1f22214cf4253..ccf7fd12fc0a1ebb8b4078b3511aa3ca2ac5aa3a 100644 (file)
@@ -1,9 +1,10 @@
 #ifndef SERVER_CONNECTION_H
 #define SERVER_CONNECTION_H
 
+#include "doveadm-server.h"
+
 #define SERVER_EXIT_CODE_DISCONNECTED 1000
 
-struct doveadm_server;
 struct server_connection;
 struct ssl_iostream;
 
@@ -21,12 +22,40 @@ typedef void server_connection_print_t(const unsigned char *data,
                                       size_t size, bool finished,
                                       void *context);
 
-int server_connection_create(struct doveadm_server *server,
+struct doveadm_client_settings {
+       /* UNIX socket path to connect to, if non-NULL. */
+       const char *socket_path;
+
+       /* Hostname to connect to, if UNIX socket path wasn't specified. */
+       const char *hostname;
+       /* Host's IP to use, if known. Otherwise DNS lookup is done. */
+       struct ip_addr ip;
+       /* Port to use for TCP connections. */
+       in_port_t port;
+
+       /* Username and password for authentication */
+       const char *username, *password;
+
+       /* SSL flags. */
+       enum auth_proxy_ssl_flags ssl_flags;
+       /* SSL context, or NULL to create a new one. */
+       struct ssl_iostream_context *ssl_ctx;
+};
+
+/* Duplicate doveadm client settings. Note that the ssl_ctx is referenced by
+   this call, so it must be unreferenced later. */
+void doveadm_client_settings_dup(const struct doveadm_client_settings *src,
+                                struct doveadm_client_settings *dest_r,
+                                pool_t pool);
+
+int server_connection_create(const struct doveadm_client_settings *set,
                             struct server_connection **conn_r,
                             const char **error_r);
 
 void server_connection_get_dest(struct server_connection *conn,
                                struct ip_addr *ip_r, in_port_t *port_r);
+const struct doveadm_client_settings *
+server_connection_get_settings(struct server_connection *conn);
 
 void server_connection_set_print(struct server_connection *conn,
                                 server_connection_print_t *callback,