]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
submission-login: Implicitly login using EXTERNAL mechanism upon MAIL if enabled.
authorStephan Bosch <stephan.bosch@open-xchange.com>
Wed, 27 Jan 2021 01:20:53 +0000 (02:20 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 5 Nov 2021 06:49:45 +0000 (06:49 +0000)
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

src/submission-login/client-authenticate.c
src/submission-login/client-authenticate.h
src/submission-login/client.c
src/submission-login/submission-login-settings.c
src/submission-login/submission-login-settings.h
src/submission/main.c
src/submission/submission-client.c
src/submission/submission-client.h
src/submission/submission-settings.c

index f51a5c91110ab0c0dea392130c59d901ab8a4420..18db1239975e1c7b97a292f4fa2f685d3db98578 100644 (file)
@@ -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", "=");
+}
index 80384e4ab1900234a42bebefee3dca374d61e256..8353b49f31b9afcfc770e8dba26f80bf9384c2d3 100644 (file)
@@ -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
index 7e5c170566a38def91dd2e883e0be55b0bf5913c..9922c9d438dc014ed3b3b6935cb4d635b73ea6a2 100644 (file)
@@ -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)
index 4a6f211820628394668b624e3aa176924d09395f..316748f1f18e379b552f2313252fd4024b188cbc 100644 (file)
@@ -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
 };
 
+/* <settings checks> */
+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;
 }
+/* </settings checks> */
index 911d6a56eefbc8a372767ea762610b35e7ec46ce..03a40a961ff815f9ca78fb41c1f3643d1ef6ff45 100644 (file)
@@ -1,12 +1,21 @@
 #ifndef SUBMISSION_LOGIN_SETTINGS_H
 #define SUBMISSION_LOGIN_SETTINGS_H
 
+/* <settings checks> */
+enum submission_login_client_workarounds {
+       SUBMISSION_LOGIN_WORKAROUND_IMPLICIT_AUTH_EXTERNAL      = BIT(0),
+};
+/* </settings checks> */
+
 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[];
index 195bce2c627e4d9d72c05abd37bc8e4a6a285d3d..d335716dab183281afafb1870a857a810c1afb86 100644 (file)
@@ -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);
index 6627e117a0b76686f3bc673180308bb18e013762..2ced1632649703bec117372ffa3d561d63065f4a 100644 (file)
@@ -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) {
index 76776ed732a6b67d89d2e224711e98228400e575..4bafd0376839db039eac32fb141d55f0170bd754 100644 (file)
@@ -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);
 
index c4dd3dbbff9a937884495331781821f673fe8fbb..0b96e1709e3266a420fd9a1cf6cf7db2441f7107 100644 (file)
@@ -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 }
 };