From 10b8040903b1d1591f1d44552ff466c8789b8814 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sun, 7 Aug 2011 22:11:20 +0300 Subject: [PATCH] doveadm-server: Many fixes to make it actually work properly. --- src/doveadm/client-connection.c | 14 ++++-- src/doveadm/doveadm-mail-server.c | 4 +- src/doveadm/doveadm-mail.c | 1 + src/doveadm/doveadm-mail.h | 2 + src/doveadm/doveadm-print-server.c | 3 ++ src/doveadm/server-connection.c | 78 ++++++++++++++++++++++++------ 6 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/doveadm/client-connection.c b/src/doveadm/client-connection.c index 4ee66c532d..2cf38406bb 100644 --- a/src/doveadm/client-connection.c +++ b/src/doveadm/client-connection.c @@ -60,6 +60,8 @@ doveadm_mail_cmd_server(const char *cmd_name, service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG; ctx = doveadm_mail_cmd_init(cmd, set); + ctx->full_args = (const void *)argv; + getopt_args = t_strconcat("Au:", ctx->getopt_args, NULL); while ((c = getopt(argc, argv, getopt_args)) > 0) { switch (c) { @@ -83,7 +85,7 @@ doveadm_mail_cmd_server(const char *cmd_name, } } - argv += optind-1; + argv += optind; optind = 1; if (argv[0] != NULL && cmd->usage_args == NULL) { @@ -153,8 +155,9 @@ static bool client_handle_command(struct client_connection *conn, char **args) flags = args[0]; input.username = args[1]; cmd_name = args[2]; - args += 3; - argc -= 3; + /* leave the command name as args[0] so getopt() works */ + args += 2; + argc -= 2; doveadm_debug = FALSE; doveadm_verbose = FALSE; @@ -264,10 +267,13 @@ static void client_connection_input(struct client_connection *conn) } if (!conn->authenticated) { if ((ret = client_connection_authenticate(conn)) <= 0) { - if (ret < 0) + if (ret < 0) { + o_stream_send(conn->output, "-\n", 2); client_connection_destroy(&conn); + } return; } + o_stream_send(conn->output, "+\n", 2); conn->authenticated = TRUE; } diff --git a/src/doveadm/doveadm-mail-server.c b/src/doveadm/doveadm-mail-server.c index 873adfbea3..e6fd0f3e20 100644 --- a/src/doveadm/doveadm-mail-server.c +++ b/src/doveadm/doveadm-mail-server.c @@ -125,9 +125,9 @@ static void doveadm_mail_server_handle(struct server_connection *conn, str_tabescape_write(cmd, username); str_append_c(cmd, '\t'); str_tabescape_write(cmd, cmd_ctx->cmd->name); - for (i = 0; cmd_ctx->args[i] != NULL; i++) { + for (i = 0; cmd_ctx->full_args[i] != NULL; i++) { str_append_c(cmd, '\t'); - str_tabescape_write(cmd, cmd_ctx->args[i]); + str_tabescape_write(cmd, cmd_ctx->full_args[i]); } str_append_c(cmd, '\n'); server_connection_cmd(conn, str_c(cmd), doveadm_cmd_callback, conn); diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index 977be31da4..513565293f 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -366,6 +366,7 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[]) service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG; ctx = doveadm_mail_cmd_init(cmd, doveadm_settings); + ctx->full_args = (const void *)argv; getopt_args = t_strconcat("AS:u:", ctx->getopt_args, NULL); username = getenv("USER"); diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index f12c0dada5..aadea6a025 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -37,6 +37,8 @@ struct doveadm_mail_cmd_context { pool_t pool; const struct doveadm_mail_cmd *cmd; const char *const *args; + /* args including -options */ + const char *const *full_args; const char *getopt_args; const struct doveadm_settings *set; diff --git a/src/doveadm/doveadm-print-server.c b/src/doveadm/doveadm-print-server.c index 6bd03bbe15..57fa7a4d1d 100644 --- a/src/doveadm/doveadm-print-server.c +++ b/src/doveadm/doveadm-print-server.c @@ -65,6 +65,9 @@ doveadm_print_server_print_stream(const unsigned char *value, size_t size) static void doveadm_print_server_flush(void) { + if (doveadm_client == NULL) + return; + o_stream_send(client_connection_get_output(doveadm_client), str_data(ctx.str), str_len(ctx.str)); str_truncate(ctx.str, 0); diff --git a/src/doveadm/server-connection.c b/src/doveadm/server-connection.c index e264854456..549ecef6f6 100644 --- a/src/doveadm/server-connection.c +++ b/src/doveadm/server-connection.c @@ -9,6 +9,9 @@ #include "ostream.h" #include "str.h" #include "strescape.h" +#include "master-service.h" +#include "master-service-settings.h" +#include "settings-parser.h" #include "doveadm-print.h" #include "doveadm-util.h" #include "doveadm-server.h" @@ -28,11 +31,15 @@ enum server_reply_state { struct server_connection { struct doveadm_server *server; + pool_t pool; + struct doveadm_settings *set; + int fd; struct io *io; struct istream *input; struct ostream *output; + const char *delayed_cmd; server_cmd_callback_t *callback; void *context; @@ -157,21 +164,26 @@ server_connection_authenticate(struct server_connection *conn) string_t *plain = t_str_new(128); string_t *cmd = t_str_new(128); - if (*doveadm_settings->doveadm_password == '\0') { - i_error("doveadm_password not set, can't authenticate"); + if (*conn->set->doveadm_password == '\0') { + i_error("doveadm_password not set, " + "can't authenticate to remote server"); return -1; } str_append_c(plain, '\0'); str_append(plain, "doveadm"); str_append_c(plain, '\0'); - str_append(plain, doveadm_settings->doveadm_password); + str_append(plain, conn->set->doveadm_password); str_append(cmd, "PLAIN\t"); base64_encode(plain->data, plain->used, cmd); str_append_c(cmd, '\n'); o_stream_send(conn->output, cmd->data, cmd->used); + if (conn->delayed_cmd != NULL) { + o_stream_send_str(conn->output, conn->delayed_cmd); + conn->delayed_cmd = NULL; + } return 0; } @@ -209,12 +221,9 @@ static void server_connection_input(struct server_connection *conn) server_connection_destroy(&conn); return; } - data = i_stream_get_data(conn->input, &size); - if (size == 0) - return; if (!conn->authenticated) { - if ((line = i_stream_next_line(conn->input)) != NULL) + if ((line = i_stream_next_line(conn->input)) == NULL) return; if (strcmp(line, "+") == 0) conn->authenticated = TRUE; @@ -225,6 +234,10 @@ static void server_connection_input(struct server_connection *conn) } } + data = i_stream_get_data(conn->input, &size); + if (size == 0) + return; + switch (conn->state) { case SERVER_REPLY_STATE_DONE: i_error("doveadm server sent unexpected input"); @@ -243,22 +256,53 @@ static void server_connection_input(struct server_connection *conn) server_connection_callback(conn, SERVER_CMD_REPLY_OK); else if (data[0] == '-' && data[1] == '\n') server_connection_callback(conn, SERVER_CMD_REPLY_FAIL); - else { + else i_error("doveadm server sent broken input"); - server_connection_destroy(&conn); - return; - } + /* we're finished, close the connection */ + server_connection_destroy(&conn); break; } } +static int server_connection_read_settings(struct server_connection *conn) +{ + const struct setting_parser_info *set_roots[] = { + &doveadm_setting_parser_info, + NULL + }; + struct master_service_settings_input input; + struct master_service_settings_output output; + const char *error; + unsigned int port; + void *set; + + memset(&input, 0, sizeof(input)); + input.roots = set_roots; + input.service = "doveadm"; + + (void)net_getsockname(conn->fd, &input.local_ip, &port); + (void)net_getpeername(conn->fd, &input.remote_ip, &port); + + if (master_service_settings_read(master_service, &input, + &output, &error) < 0) { + i_error("Error reading configuration: %s", error); + return -1; + } + set = master_service_settings_get_others(master_service)[0]; + conn->set = settings_dup(&doveadm_setting_parser_info, set, conn->pool); + return 0; +} + struct server_connection * server_connection_create(struct doveadm_server *server) { #define DOVEADM_SERVER_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n" struct server_connection *conn; + pool_t pool; - conn = i_new(struct server_connection, 1); + pool = pool_alloconly_create("doveadm server connection", 1024*16); + conn = p_new(pool, struct server_connection, 1); + conn->pool = pool; conn->server = server; conn->fd = doveadm_connect(server->name); net_set_nonblock(conn->fd, TRUE); @@ -269,6 +313,7 @@ server_connection_create(struct doveadm_server *server) o_stream_send_str(conn->output, DOVEADM_SERVER_HANDSHAKE); array_append(&conn->server->connections, &conn, 1); + server_connection_read_settings(conn); return conn; } @@ -301,7 +346,7 @@ void server_connection_destroy(struct server_connection **_conn) io_remove(&conn->io); if (close(conn->fd) < 0) i_error("close(server) failed: %m"); - i_free(conn); + pool_unref(&conn->pool); } struct doveadm_server * @@ -313,8 +358,13 @@ server_connection_get_server(struct server_connection *conn) void server_connection_cmd(struct server_connection *conn, const char *line, server_cmd_callback_t *callback, void *context) { + i_assert(conn->delayed_cmd == NULL); + conn->state = SERVER_REPLY_STATE_PRINT; - o_stream_send_str(conn->output, line); + if (conn->authenticated) + o_stream_send_str(conn->output, line); + else + conn->delayed_cmd = p_strdup(conn->pool, line); conn->callback = callback; conn->context = context; } -- 2.47.3