From: Timo Sirainen Date: Wed, 15 Jul 2020 09:42:59 +0000 (+0300) Subject: pop3-login: Fix handling commands that are sent in multiple IP packets X-Git-Tag: 2.3.11.3~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2c42881c056e5ab2e2e14b2f800d6dc72026399b;p=thirdparty%2Fdovecot%2Fcore.git pop3-login: Fix handling commands that are sent in multiple IP packets This happened especially if the commands were long, like XCLIENT. This got broken by recent pop3-login changes. --- diff --git a/src/pop3-login/client-authenticate.c b/src/pop3-login/client-authenticate.c index e50e45c1d1..21716d34b4 100644 --- a/src/pop3-login/client-authenticate.c +++ b/src/pop3-login/client-authenticate.c @@ -76,7 +76,7 @@ void pop3_client_auth_result(struct client *client, } } -int cmd_auth(struct pop3_client *pop3_client, bool *parsed_r) +int cmd_auth(struct pop3_client *pop3_client) { /* NOTE: This command's input is handled specially because the SASL-IR can be large. */ @@ -85,8 +85,6 @@ int cmd_auth(struct pop3_client *pop3_client, bool *parsed_r) size_t i, size; int ret; - *parsed_r = FALSE; - /* [] */ if (!pop3_client->auth_mech_name_parsed) { data = i_stream_get_data(client->input, &size); @@ -109,7 +107,6 @@ int cmd_auth(struct pop3_client *pop3_client, bool *parsed_r) client_send_raw(client, "\r\n"); } client_send_raw(client, ".\r\n"); - *parsed_r = TRUE; (void)i_stream_read_next_line(client->input); return 1; } @@ -121,7 +118,6 @@ int cmd_auth(struct pop3_client *pop3_client, bool *parsed_r) i_stream_skip(client->input, i); } - client->authenticating = TRUE; /* get SASL-IR, if any */ if ((ret = client_auth_read_line(client)) <= 0) return ret; @@ -130,7 +126,6 @@ int cmd_auth(struct pop3_client *pop3_client, bool *parsed_r) 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); } diff --git a/src/pop3-login/client-authenticate.h b/src/pop3-login/client-authenticate.h index b0a4b9d946..f9b6fa6bf3 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); -int cmd_auth(struct pop3_client *client, bool *parsed_r); +int cmd_auth(struct pop3_client *client); 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 082b5e389a..861b7ee1a1 100644 --- a/src/pop3-login/client.c +++ b/src/pop3-login/client.c @@ -117,16 +117,7 @@ static bool client_command_execute(struct pop3_client *client, const char *cmd, static void pop3_client_input(struct client *client) { - if (client->authenticating) { - struct pop3_client *pop3_client = - container_of(client, struct pop3_client, common); - bool parsed; - cmd_auth(pop3_client, &parsed); - if (!parsed) - client->authenticating = FALSE; - else - return; - } + i_assert(!client->authenticating); if (!client_read(client)) return; @@ -176,22 +167,28 @@ static bool pop3_client_input_next_cmd(struct client *client) { struct pop3_client *pop3_client = (struct pop3_client *)client; const char *cmd, *args; - bool parsed; - if (!client_read_cmd_name(client, &cmd)) - return FALSE; + if (pop3_client->current_cmd == NULL) { + if (!client_read_cmd_name(client, &cmd)) + return FALSE; + pop3_client->current_cmd = i_strdup(cmd); + } - if (strcmp(cmd, "AUTH") == 0) { - int ret = cmd_auth(pop3_client, &parsed); - if (ret == 0 || !parsed) + if (strcmp(pop3_client->current_cmd, "AUTH") == 0) { + if (cmd_auth(pop3_client) <= 0) { + /* Need more input / destroyed. We also get here when + SASL authentication is actually started. */ return FALSE; - return parsed; + } + /* AUTH command finished already (SASL probe or ERR reply) */ + i_free(pop3_client->current_cmd); + return TRUE; } if ((args = i_stream_next_line(client->input)) == NULL) return FALSE; - if (client_command_execute(pop3_client, cmd, args)) + if (client_command_execute(pop3_client, pop3_client->current_cmd, args)) client->bad_counter = 0; else if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) { client_send_reply(client, POP3_CMD_REPLY_ERROR, @@ -200,6 +197,7 @@ static bool pop3_client_input_next_cmd(struct client *client) "Disconnected: Too many bad commands"); return FALSE; } + i_free(pop3_client->current_cmd); return TRUE; } @@ -220,6 +218,7 @@ static void pop3_client_destroy(struct client *client) { struct pop3_client *pop3_client = (struct pop3_client *)client; + i_free_and_null(pop3_client->current_cmd); i_free_and_null(pop3_client->last_user); i_free_and_null(pop3_client->apop_challenge); } diff --git a/src/pop3-login/client.h b/src/pop3-login/client.h index f052623a9f..3823685821 100644 --- a/src/pop3-login/client.h +++ b/src/pop3-login/client.h @@ -18,6 +18,7 @@ enum pop3_proxy_state { struct pop3_client { struct client common; + char *current_cmd; char *last_user; char *apop_challenge; unsigned int apop_server_pid, apop_connect_uid;