From 9814a40148a587baec065adb5c47325d2fa2d559 Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Thu, 4 Oct 2018 01:37:24 +0200 Subject: [PATCH] submission: Add submission_backend_capabilities setting. This can be used to specify which capabilities the (relay) backend supports, avoiding the need to query the backend explicitly before the EHLO reply is sent to the client. --- src/submission/submission-backend-relay.c | 25 ++++----- src/submission/submission-backend-relay.h | 1 + src/submission/submission-client.c | 64 ++++++++++++++++++++++- src/submission/submission-client.h | 6 +++ src/submission/submission-commands.c | 14 ++--- src/submission/submission-settings.c | 4 ++ src/submission/submission-settings.h | 3 ++ 7 files changed, 94 insertions(+), 23 deletions(-) diff --git a/src/submission/submission-backend-relay.c b/src/submission/submission-backend-relay.c index ace0519801..43244d1b98 100644 --- a/src/submission/submission-backend-relay.c +++ b/src/submission/submission-backend-relay.c @@ -166,6 +166,8 @@ int cmd_helo_relay(struct client *client, struct smtp_server_cmd_ctx *cmd, struct submission_backend_relay *backend = &client->backend; struct relay_cmd_helo_context *helo; + client_proxy_start(client); + helo = p_new(cmd->pool, struct relay_cmd_helo_context, 1); helo->backend = backend; helo->cmd = cmd; @@ -319,6 +321,8 @@ int cmd_mail_relay(struct client *client, struct smtp_server_cmd_ctx *cmd, relay_cmd_mail_update_xclient(backend); + client_proxy_start(client); + /* queue command (pipeline) */ mail_cmd = p_new(cmd->pool, struct relay_cmd_mail_context, 1); mail_cmd->backend = backend; @@ -793,7 +797,6 @@ static void client_proxy_ready_cb(const struct smtp_reply *reply, { struct client *client = context; struct submission_backend_relay *backend = &client->backend; - enum smtp_capability caps; /* check relay status */ if ((reply->status / 100) != 2) { @@ -804,25 +807,23 @@ static void client_proxy_ready_cb(const struct smtp_reply *reply, return; } - /* propagate capabilities */ - caps = smtp_client_connection_get_capabilities(backend->conn); - caps |= SMTP_CAPABILITY_AUTH | SMTP_CAPABILITY_PIPELINING | - SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES | - SMTP_CAPABILITY_CHUNKING | SMTP_CAPABILITY_BURL | - SMTP_CAPABILITY_VRFY; - caps &= SUBMISSION_SUPPORTED_SMTP_CAPABILITIES; - smtp_server_connection_set_capabilities(client->conn, caps); - - /* now that we know our capabilities, commence server protocol dialog */ - smtp_server_connection_resume(client->conn); + /* notify the client about the fact that we're ready and propagate our + capabilities */ + client_default_backend_started(client, + smtp_client_connection_get_capabilities(backend->conn)); } void client_proxy_start(struct client *client) { struct submission_backend_relay *backend = &client->backend; + if (backend->started) + return; + smtp_client_connection_connect(backend->conn, client_proxy_ready_cb, client); + + backend->started = TRUE; } /* try to proxy pipelined commands in a similarly pipelined fashion */ diff --git a/src/submission/submission-backend-relay.h b/src/submission/submission-backend-relay.h index 9aa6d0f8a6..94fe6b9f10 100644 --- a/src/submission/submission-backend-relay.h +++ b/src/submission/submission-backend-relay.h @@ -28,6 +28,7 @@ struct submission_backend_relay { struct smtp_client_connection *conn; bool xclient_sent:1; + bool started:1; }; void client_proxy_create(struct client *client, diff --git a/src/submission/submission-client.c b/src/submission/submission-client.c index f0d9c655dc..976c8180a4 100644 --- a/src/submission/submission-client.c +++ b/src/submission/submission-client.c @@ -69,6 +69,58 @@ static const char *client_remote_id(struct client *client) return addr; } +static void client_parse_backend_capabilities(struct client *client) +{ + const struct submission_settings *set = client->set; + const char *const *str; + + client->backend_capabilities = SMTP_CAPABILITY_NONE; + if (set->submission_backend_capabilities == NULL) + return; + + str = t_strsplit_spaces(set->submission_backend_capabilities, " ,"); + for (; *str != NULL; str++) { + enum smtp_capability cap = smtp_capability_find_by_name(*str); + + if (cap == SMTP_CAPABILITY_NONE) { + i_warning("Unknown SMTP capability in submission_backend_capabilities: " + "%s", *str); + continue; + } + + client->backend_capabilities |= cap; + } + + client->backend_capabilities_configured = TRUE; +} + +void client_apply_backend_capabilities(struct client *client) +{ + enum smtp_capability caps = client->backend_capabilities; + + /* propagate capabilities */ + caps |= SMTP_CAPABILITY_AUTH | SMTP_CAPABILITY_PIPELINING | + SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES | + SMTP_CAPABILITY_CHUNKING | SMTP_CAPABILITY_BURL | + SMTP_CAPABILITY_VRFY; + caps &= SUBMISSION_SUPPORTED_SMTP_CAPABILITIES; + smtp_server_connection_set_capabilities(client->conn, caps); +} + +void client_default_backend_started(struct client *client, + enum smtp_capability caps) +{ + /* propagate capabilities from backend to frontend */ + if (!client->backend_capabilities_configured) { + client->backend_capabilities = caps; + client_apply_backend_capabilities(client); + + /* resume the server now that we have the backend + capabilities */ + smtp_server_connection_resume(client->conn); + } +} + static void client_init_urlauth(struct client *client) { static const char *access_apps[] = { "submit+", NULL }; @@ -132,17 +184,25 @@ struct client *client_create(int fd_in, int fd_out, SMTP_SERVER_WORKAROUND_MAILBOX_FOR_PATH; } + client_parse_backend_capabilities(client); + client->conn = smtp_server_connection_create(smtp_server, fd_in, fd_out, user->conn.remote_ip, user->conn.remote_port, FALSE, &smtp_set, &smtp_callbacks, client); client_proxy_create(client, set); - client_proxy_start(client); smtp_server_connection_login(client->conn, client->user->username, helo, pdata, pdata_len, user->conn.ssl_secured); - smtp_server_connection_start_pending(client->conn); + + if (client->backend_capabilities_configured) { + client_apply_backend_capabilities(client); + smtp_server_connection_start(client->conn); + } else { + client_proxy_start(client); + smtp_server_connection_start_pending(client->conn); + } mail_set = mail_user_set_get_storage_set(user); if (*set->imap_urlauth_host != '\0' && diff --git a/src/submission/submission-client.h b/src/submission/submission-client.h index 6c977fb699..71d73b4d17 100644 --- a/src/submission/submission-client.h +++ b/src/submission/submission-client.h @@ -36,12 +36,14 @@ struct client { struct smtp_server_stats stats; + enum smtp_capability backend_capabilities; struct submission_backend_relay backend; bool standalone:1; bool disconnected:1; bool destroyed:1; bool anvil_sent:1; + bool backend_capabilities_configured:1; }; extern struct client *submission_clients; @@ -61,6 +63,10 @@ void client_disconnect(struct client *client, const char *prefix, typedef void (*client_input_callback_t)(struct client *context); +void client_apply_backend_capabilities(struct client *client); +void client_default_backend_started(struct client *client, + enum smtp_capability caps); + const char *client_state_get_name(struct client *client); uoff_t client_get_max_mail_size(struct client *client); diff --git a/src/submission/submission-commands.c b/src/submission/submission-commands.c index 055a05c68e..fec5e02b79 100644 --- a/src/submission/submission-commands.c +++ b/src/submission/submission-commands.c @@ -11,8 +11,6 @@ #include "imap-msgpart-url.h" #include "imap-urlauth.h" #include "imap-urlauth-fetch.h" -#include "smtp-client.h" -#include "smtp-client-connection.h" #include "submission-recipient.h" #include "submission-commands.h" @@ -26,9 +24,7 @@ void submission_helo_reply_submit(struct smtp_server_cmd_ctx *cmd, struct smtp_server_cmd_helo *data) { struct client *client = smtp_server_connection_get_context(cmd->conn); - struct submission_backend_relay *backend = &client->backend; - enum smtp_capability proxy_caps = - smtp_client_connection_get_capabilities(backend->conn); + enum smtp_capability backend_caps = client->backend_capabilities; struct smtp_server_reply *reply; uoff_t cap_size; @@ -51,16 +47,16 @@ void submission_helo_reply_submit(struct smtp_server_cmd_ctx *cmd, client->set->imap_urlauth_port); } - if ((proxy_caps & SMTP_CAPABILITY_8BITMIME) != 0) + if ((backend_caps & SMTP_CAPABILITY_8BITMIME) != 0) smtp_server_reply_ehlo_add(reply, "8BITMIME"); smtp_server_reply_ehlo_add(reply, "AUTH"); - if ((proxy_caps & SMTP_CAPABILITY_BINARYMIME) != 0 && - (proxy_caps & SMTP_CAPABILITY_CHUNKING) != 0) + if ((backend_caps & SMTP_CAPABILITY_BINARYMIME) != 0 && + (backend_caps & SMTP_CAPABILITY_CHUNKING) != 0) smtp_server_reply_ehlo_add(reply, "BINARYMIME"); smtp_server_reply_ehlo_add_param(reply, "BURL", "%s", str_c(burl_params)); smtp_server_reply_ehlo_add(reply, "CHUNKING"); - if ((proxy_caps & SMTP_CAPABILITY_DSN) != 0) + if ((backend_caps & SMTP_CAPABILITY_DSN) != 0) smtp_server_reply_ehlo_add(reply, "DSN"); smtp_server_reply_ehlo_add(reply, "ENHANCEDSTATUSCODES"); diff --git a/src/submission/submission-settings.c b/src/submission/submission-settings.c index ed962851fc..99fdfb0082 100644 --- a/src/submission/submission-settings.c +++ b/src/submission/submission-settings.c @@ -70,6 +70,8 @@ static const struct setting_define submission_setting_defines[] = { DEF(SET_STR, submission_client_workarounds), DEF(SET_STR, submission_logout_format), + DEF(SET_STR, submission_backend_capabilities), + DEF(SET_STR, submission_relay_host), DEF(SET_IN_PORT, submission_relay_port), DEF(SET_BOOL, submission_relay_trusted), @@ -107,6 +109,8 @@ static const struct submission_settings submission_default_settings = { .submission_client_workarounds = "", .submission_logout_format = "in=%i out=%o", + .submission_backend_capabilities = NULL, + .submission_relay_host = "", .submission_relay_port = 25, .submission_relay_trusted = FALSE, diff --git a/src/submission/submission-settings.h b/src/submission/submission-settings.h index c033c7dc8c..691cd8970e 100644 --- a/src/submission/submission-settings.h +++ b/src/submission/submission-settings.h @@ -25,6 +25,9 @@ struct submission_settings { const char *submission_client_workarounds; const char *submission_logout_format; + /* submission backend: */ + const char *submission_backend_capabilities; + /* submission relay: */ const char *submission_relay_host; in_port_t submission_relay_port; -- 2.47.3