From: Stephan Bosch Date: Wed, 27 Jan 2021 01:20:53 +0000 (+0100) Subject: submission-login: Implicitly login using EXTERNAL mechanism upon MAIL if enabled. X-Git-Tag: 2.3.18~158 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=17efe7a4041358535ede7d78ecc139ea57ece50c;p=thirdparty%2Fdovecot%2Fcore.git submission-login: Implicitly login using EXTERNAL mechanism upon MAIL if enabled. This is a workaround for TLS clients that present a valid client certificate, yet don't authenticate explicitly. This is enabled by setting: submission_client_workarounds = implicit-auth-external --- diff --git a/src/submission-login/client-authenticate.c b/src/submission-login/client-authenticate.c index f51a5c9111..18db123997 100644 --- a/src/submission-login/client-authenticate.c +++ b/src/submission-login/client-authenticate.c @@ -263,7 +263,8 @@ void submission_client_auth_send_challenge(struct client *client, } static void -cmd_auth_set_master_data_prefix(struct submission_client *subm_client) +cmd_auth_set_master_data_prefix(struct submission_client *subm_client, + const char *mail_params) ATTR_NULL(2) { struct client *client = &subm_client->common; struct smtp_server_helo_data *helo; @@ -286,6 +287,13 @@ cmd_auth_set_master_data_prefix(struct submission_client *subm_client) buffer_append(buf, proxy.helo, strlen(proxy.helo)); buffer_append_c(buf, '\0'); + /* Pass MAIL command to post-login service if any. */ + if (mail_params != NULL) { + buffer_append(buf, "MAIL ", 5); + buffer_append(buf, mail_params, strlen(mail_params)); + buffer_append(buf, "\r\n", 2); + } + i_free(client->master_data_prefix); client->master_data_prefix_len = buf->used; client->master_data_prefix = buffer_free_without_data(&buf); @@ -297,7 +305,7 @@ int cmd_auth(void *conn_ctx, struct smtp_server_cmd_ctx *cmd, struct submission_client *subm_client = conn_ctx; struct client *client = &subm_client->common; - cmd_auth_set_master_data_prefix(subm_client); + cmd_auth_set_master_data_prefix(subm_client, NULL); i_assert(subm_client->pending_auth == NULL); subm_client->pending_auth = cmd; @@ -305,3 +313,33 @@ int cmd_auth(void *conn_ctx, struct smtp_server_cmd_ctx *cmd, (void)client_auth_begin(client, data->sasl_mech, data->initial_response); return 0; } + +void cmd_mail(struct smtp_server_cmd_ctx *cmd, const char *params) +{ + struct smtp_server_connection *conn = cmd->conn; + struct submission_client *subm_client = + smtp_server_connection_get_context(conn); + struct client *client = &subm_client->common; + enum submission_login_client_workarounds workarounds = + subm_client->set->parsed_workarounds; + + if (HAS_NO_BITS(workarounds, + SUBMISSION_LOGIN_WORKAROUND_IMPLICIT_AUTH_EXTERNAL) || + sasl_server_find_available_mech(client, "EXTERNAL") == NULL) { + smtp_server_command_fail(cmd->cmd, 530, "5.7.0", + "Authentication required."); + return; + } + + e_debug(cmd->event, + "Performing implicit EXTERNAL authentication"); + + smtp_server_command_input_lock(cmd); + + cmd_auth_set_master_data_prefix(subm_client, params); + + i_assert(subm_client->pending_auth == NULL); + subm_client->pending_auth = cmd; + + (void)client_auth_begin_implicit(client, "EXTERNAL", "="); +} diff --git a/src/submission-login/client-authenticate.h b/src/submission-login/client-authenticate.h index 80384e4ab1..8353b49f31 100644 --- a/src/submission-login/client-authenticate.h +++ b/src/submission-login/client-authenticate.h @@ -16,4 +16,6 @@ int cmd_auth_continue(void *conn_ctx, struct smtp_server_cmd_ctx *cmd, int cmd_auth(void *conn_ctx, struct smtp_server_cmd_ctx *cmd, struct smtp_server_cmd_auth *data); +void cmd_mail(struct smtp_server_cmd_ctx *cmd, const char *params); + #endif diff --git a/src/submission-login/client.c b/src/submission-login/client.c index 7e5c170566..9922c9d438 100644 --- a/src/submission-login/client.c +++ b/src/submission-login/client.c @@ -264,6 +264,8 @@ static void submission_login_init(void) It's not very useful. */ smtp_server_set.no_state_in_reason = TRUE; smtp_server = smtp_server_init(&smtp_server_set); + smtp_server_command_override(smtp_server, "MAIL", cmd_mail, + SMTP_SERVER_CMD_FLAG_PREAUTH); } static void submission_login_deinit(void) diff --git a/src/submission-login/submission-login-settings.c b/src/submission-login/submission-login-settings.c index 4a6f211820..316748f1f1 100644 --- a/src/submission-login/submission-login-settings.c +++ b/src/submission-login/submission-login-settings.c @@ -61,6 +61,7 @@ static const struct setting_define submission_login_setting_defines[] = { DEF(STR, hostname), DEF(SIZE, submission_max_mail_size), + DEF(STR, submission_client_workarounds), DEF(STR, submission_backend_capabilities), SETTING_DEFINE_LIST_END @@ -70,6 +71,7 @@ static const struct submission_login_settings submission_login_default_settings .hostname = "", .submission_max_mail_size = 0, + .submission_client_workarounds = "", .submission_backend_capabilities = NULL }; @@ -87,9 +89,7 @@ const struct setting_parser_info submission_login_setting_parser_info = { .struct_size = sizeof(struct submission_login_settings), .parent_offset = SIZE_MAX, -#ifndef CONFIG_BINARY .check_func = submission_login_settings_check, -#endif .dependencies = submission_login_setting_dependencies }; @@ -99,13 +99,66 @@ const struct setting_parser_info *submission_login_setting_roots[] = { NULL }; +/* */ +struct submission_login_client_workaround_list { + const char *name; + enum submission_login_client_workarounds num; +}; + +/* These definitions need to be kept in sync with equivalent definitions present + in src/submission/submission-settings.c. Workarounds that are not relevant + to the submission-login service are defined as 0 here to prevent "Unknown + workaround" errors below. */ +static const struct submission_login_client_workaround_list +submission_login_client_workaround_list[] = { + { "whitespace-before-path", 0}, + { "mailbox-for-path", 0 }, + { "implicit-auth-external", + SUBMISSION_LOGIN_WORKAROUND_IMPLICIT_AUTH_EXTERNAL }, + { NULL, 0 } +}; + +static int +submission_login_settings_parse_workarounds( + struct submission_login_settings *set, const char **error_r) +{ + enum submission_login_client_workarounds client_workarounds = 0; + const struct submission_login_client_workaround_list *list; + const char *const *str; + + str = t_strsplit_spaces(set->submission_client_workarounds, " ,"); + for (; *str != NULL; str++) { + list = submission_login_client_workaround_list; + for (; list->name != NULL; list++) { + if (strcasecmp(*str, list->name) == 0) { + client_workarounds |= list->num; + break; + } + } + if (list->name == NULL) { + *error_r = t_strdup_printf( + "submission_client_workarounds: " + "Unknown workaround: %s", *str); + return -1; + } + } + set->parsed_workarounds = client_workarounds; + return 0; +} + static bool -submission_login_settings_check(void *_set, pool_t pool, - const char **error_r ATTR_UNUSED) +submission_login_settings_check(void *_set, pool_t pool ATTR_UNUSED, + const char **error_r) { struct submission_login_settings *set = _set; + if (submission_login_settings_parse_workarounds(set, error_r) < 0) + return FALSE; + +#ifndef CONFIG_BINARY if (*set->hostname == '\0') set->hostname = p_strdup(pool, my_hostdomain()); +#endif return TRUE; } +/* */ diff --git a/src/submission-login/submission-login-settings.h b/src/submission-login/submission-login-settings.h index 911d6a56ee..03a40a961f 100644 --- a/src/submission-login/submission-login-settings.h +++ b/src/submission-login/submission-login-settings.h @@ -1,12 +1,21 @@ #ifndef SUBMISSION_LOGIN_SETTINGS_H #define SUBMISSION_LOGIN_SETTINGS_H +/* */ +enum submission_login_client_workarounds { + SUBMISSION_LOGIN_WORKAROUND_IMPLICIT_AUTH_EXTERNAL = BIT(0), +}; +/* */ + struct submission_login_settings { const char *hostname; /* submission: */ uoff_t submission_max_mail_size; + const char *submission_client_workarounds; const char *submission_backend_capabilities; + + enum submission_login_client_workarounds parsed_workarounds; }; extern const struct setting_parser_info *submission_login_setting_roots[]; diff --git a/src/submission/main.c b/src/submission/main.c index 195bce2c62..d335716dab 100644 --- a/src/submission/main.c +++ b/src/submission/main.c @@ -140,12 +140,15 @@ extract_input_data_field(const unsigned char **data, size_t *data_len, static int client_create_from_input(const struct mail_storage_service_input *input, + enum mail_auth_request_flags login_flags, int fd_in, int fd_out, const buffer_t *input_buf, const char **error_r) { struct mail_storage_service_user *user; struct mail_user *mail_user; struct submission_settings *set; + bool no_greeting = HAS_ALL_BITS(login_flags, + MAIL_AUTH_REQUEST_FLAG_IMPLICIT); const char *errstr; const char *helo = NULL; struct smtp_proxy_data proxy_data; @@ -206,7 +209,8 @@ client_create_from_input(const struct mail_storage_service_input *input, } (void)client_create(fd_in, fd_out, mail_user, - user, set, helo, &proxy_data, data, data_len); + user, set, helo, &proxy_data, data, data_len, + no_greeting); return 0; } @@ -232,7 +236,7 @@ static void main_stdio_run(const char *username) input_buf = input_base64 == NULL ? NULL : t_base64_decode_str(input_base64); - if (client_create_from_input(&input, STDIN_FILENO, STDOUT_FILENO, + if (client_create_from_input(&input, 0, STDIN_FILENO, STDOUT_FILENO, input_buf, &error) < 0) i_fatal("%s", error); } @@ -262,7 +266,8 @@ login_client_connected(const struct master_login_client *login_client, buffer_create_from_const_data(&input_buf, login_client->data, login_client->auth_req.data_size); - if (client_create_from_input(&input, login_client->fd, login_client->fd, + if (client_create_from_input(&input, flags, + login_client->fd, login_client->fd, &input_buf, &error) < 0) { int fd = login_client->fd; i_error("%s", error); diff --git a/src/submission/submission-client.c b/src/submission/submission-client.c index 6627e117a0..2ced163264 100644 --- a/src/submission/submission-client.c +++ b/src/submission/submission-client.c @@ -179,7 +179,8 @@ client_create(int fd_in, int fd_out, struct mail_user *user, struct mail_storage_service_user *service_user, const struct submission_settings *set, const char *helo, const struct smtp_proxy_data *proxy_data, - const unsigned char *pdata, unsigned int pdata_len) + const unsigned char *pdata, unsigned int pdata_len, + bool no_greeting) { enum submission_client_workarounds workarounds = set->parsed_workarounds; @@ -212,6 +213,7 @@ client_create(int fd_in, int fd_out, struct mail_user *user, smtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS; smtp_set.max_message_size = set->submission_max_mail_size; smtp_set.rawlog_dir = set->rawlog_dir; + smtp_set.no_greeting = no_greeting; smtp_set.debug = user->mail_debug; if ((workarounds & SUBMISSION_WORKAROUND_WHITESPACE_BEFORE_PATH) != 0) { diff --git a/src/submission/submission-client.h b/src/submission/submission-client.h index 76776ed732..4bafd03768 100644 --- a/src/submission/submission-client.h +++ b/src/submission/submission-client.h @@ -137,7 +137,8 @@ client_create(int fd_in, int fd_out, struct mail_user *user, struct mail_storage_service_user *service_user, const struct submission_settings *set, const char *helo, const struct smtp_proxy_data *proxy_data, - const unsigned char *pdata, unsigned int pdata_len); + const unsigned char *pdata, unsigned int pdata_len, + bool no_greeting); void client_destroy(struct client **client, const char *prefix, const char *reason) ATTR_NULL(2, 3); diff --git a/src/submission/submission-settings.c b/src/submission/submission-settings.c index c4dd3dbbff..0b96e1709e 100644 --- a/src/submission/submission-settings.c +++ b/src/submission/submission-settings.c @@ -161,12 +161,17 @@ struct submission_client_workaround_list { enum submission_client_workarounds num; }; +/* These definitions need to be kept in sync with equivalent definitions present + in src/submission-login/submission-login-settings.c. Workarounds that are not + relevant to the submission service are defined as 0 here to prevent "Unknown + workaround" errors below. */ static const struct submission_client_workaround_list submission_client_workaround_list[] = { { "whitespace-before-path", SUBMISSION_WORKAROUND_WHITESPACE_BEFORE_PATH }, { "mailbox-for-path", SUBMISSION_WORKAROUND_MAILBOX_FOR_PATH }, + { "implicit-auth-external", 0 }, { NULL, 0 } };