From d8c3cfca79fdcb044d3760f0b09f463598f63deb Mon Sep 17 00:00:00 2001 From: Aki Tuomi Date: Tue, 30 Jun 2020 14:02:34 +0300 Subject: [PATCH] pop3-login: Read SASL-IR properly This fixes issue where login would fail if SASL-IR message would be too long. --- src/pop3-login/client-authenticate.c | 83 ++++++++++++++++------------ src/pop3-login/client-authenticate.h | 2 +- src/pop3-login/client.c | 15 ++++- src/pop3-login/client.h | 2 + 4 files changed, 64 insertions(+), 38 deletions(-) diff --git a/src/pop3-login/client-authenticate.c b/src/pop3-login/client-authenticate.c index a42ea23f34..0f5531be0a 100644 --- a/src/pop3-login/client-authenticate.c +++ b/src/pop3-login/client-authenticate.c @@ -76,46 +76,61 @@ void pop3_client_auth_result(struct client *client, } } -bool cmd_auth(struct pop3_client *pop3_client, const char *args) +int cmd_auth(struct pop3_client *pop3_client, bool *parsed_r) { + /* NOTE: This command's input is handled specially because the + SASL-IR can be large. */ struct client *client = &pop3_client->common; - const struct auth_mech_desc *mech; - const char *mech_name, *init_resp, *p; - - if (*args == '\0') { - /* Old-style SASL discovery, used by MS Outlook */ - unsigned int i, count; - - client_send_raw(client, "+OK\r\n"); - mech = sasl_server_get_advertised_mechs(client, &count); - for (i = 0; i < count; i++) { - client_send_raw(client, mech[i].name); - client_send_raw(client, "\r\n"); + const unsigned char *data; + size_t i, size; + int ret; + + *parsed_r = FALSE; + + /* [] */ + if (!pop3_client->auth_mech_name_parsed) { + data = i_stream_get_data(client->input, &size); + for (i = 0; i < size; i++) { + if (data[i] == ' ' || + data[i] == '\r' || data[i] == '\n') + break; } - client_send_raw(client, ".\r\n"); - return TRUE; - } - - /* */ - p = strchr(args, ' '); - if (p == NULL) { - mech_name = args; - /* no initial response */ - init_resp = NULL; - } else { - mech_name = t_strdup_until(args, p); - init_resp = p + 1; - if (*init_resp == '\0') { - /* no initial response */ - init_resp = NULL; - } else if (strcmp(init_resp, "=") == 0) { - /* empty initial response */ - init_resp = ""; + if (i == size) + return 0; + if (i == 0) { + /* Old-style SASL discovery, used by MS Outlook */ + unsigned int i, count; + const struct auth_mech_desc *mech; + + client_send_raw(client, "+OK\r\n"); + mech = sasl_server_get_advertised_mechs(client, &count); + for (i = 0; i < count; i++) { + client_send_raw(client, mech[i].name); + client_send_raw(client, "\r\n"); + } + client_send_raw(client, ".\r\n"); + *parsed_r = TRUE; + return 1; } + i_free(client->auth_mech_name); + client->auth_mech_name = i_strndup(data, i); + pop3_client->auth_mech_name_parsed = TRUE; + if (data[i] == ' ') + i++; + i_stream_skip(client->input, i); } - (void)client_auth_begin(client, mech_name, init_resp); - return TRUE; + /* get SASL-IR, if any */ + if ((ret = client_auth_read_line(client)) <= 0) + return ret; + + const char *ir = NULL; + if (client->auth_response->used > 0) + ir = t_strdup(str_c(client->auth_response)); + + *parsed_r = TRUE; + pop3_client->auth_mech_name_parsed = FALSE; + return client_auth_begin(client, t_strdup(client->auth_mech_name), ir); } bool cmd_user(struct pop3_client *pop3_client, const char *args) diff --git a/src/pop3-login/client-authenticate.h b/src/pop3-login/client-authenticate.h index e1eb55cd0f..b0a4b9d946 100644 --- a/src/pop3-login/client-authenticate.h +++ b/src/pop3-login/client-authenticate.h @@ -9,7 +9,7 @@ void pop3_client_auth_result(struct client *client, bool cmd_capa(struct pop3_client *client, const char *args); bool cmd_user(struct pop3_client *client, const char *args); bool cmd_pass(struct pop3_client *client, const char *args); -bool cmd_auth(struct pop3_client *client, const char *args); +int cmd_auth(struct pop3_client *client, bool *parsed_r); bool cmd_apop(struct pop3_client *client, const char *args); #endif diff --git a/src/pop3-login/client.c b/src/pop3-login/client.c index cae6442046..1cef4cc4eb 100644 --- a/src/pop3-login/client.c +++ b/src/pop3-login/client.c @@ -95,8 +95,6 @@ static bool client_command_execute(struct pop3_client *client, const char *cmd, return cmd_user(client, args); if (strcmp(cmd, "PASS") == 0) return cmd_pass(client, args); - if (strcmp(cmd, "AUTH") == 0) - return cmd_auth(client, args); if (strcmp(cmd, "APOP") == 0) return cmd_apop(client, args); if (strcmp(cmd, "STLS") == 0) @@ -164,8 +162,19 @@ static bool pop3_client_input_next_cmd(struct client *client) const char *cmd, *args; bool parsed; - if (!client_read_cmd_name(client, &cmd)) + if (!pop3_client->authenticating && !client_read_cmd_name(client, &cmd)) return FALSE; + + if (pop3_client->authenticating || + strcmp(cmd, "AUTH") == 0) { + pop3_client->authenticating = TRUE; + int ret = cmd_auth(pop3_client, &parsed); + if (ret == 0 || !parsed) + return FALSE; + pop3_client->authenticating = !parsed; + return parsed; + } + if ((args = i_stream_next_line(client->input)) == NULL) return FALSE; diff --git a/src/pop3-login/client.h b/src/pop3-login/client.h index 498fe82e19..7a24f54fa1 100644 --- a/src/pop3-login/client.h +++ b/src/pop3-login/client.h @@ -23,6 +23,8 @@ struct pop3_client { unsigned int apop_server_pid, apop_connect_uid; enum pop3_proxy_state proxy_state; bool proxy_xclient; + bool auth_mech_name_parsed; + bool authenticating; }; enum pop3_cmd_reply { -- 2.47.3