]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
pop3-login: Fix handling commands that are sent in multiple IP packets
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 15 Jul 2020 09:42:59 +0000 (12:42 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Tue, 28 Jul 2020 10:27:55 +0000 (13:27 +0300)
This happened especially if the commands were long, like XCLIENT.

This got broken by recent pop3-login changes.

src/pop3-login/client-authenticate.c
src/pop3-login/client-authenticate.h
src/pop3-login/client.c
src/pop3-login/client.h

index e50e45c1d1fec86f198ba00c3a2128ec04d72f76..21716d34b43cda52c33e2d732cf4d9127dac7e93 100644 (file)
@@ -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;
-
        /* <auth mechanism name> [<initial SASL response>] */
        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);
 }
index b0a4b9d946fff72a819e61348e7ae2c1afaebe4f..f9b6fa6bf308829b7666611892610fcac462aca0 100644 (file)
@@ -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
index 082b5e389a32ce95b32922ea6d7284368043c33f..861b7ee1a1b6a7c9738f769147aee2ca41616ff5 100644 (file)
@@ -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);
 }
index f052623a9f244c59a0844d21f824b9c72030d87a..3823685821041ad30ad9855ceb0de5f866872066 100644 (file)
@@ -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;