]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: client: Make smtp_client_connection_commands_fail_reply() more reliable...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sat, 23 Dec 2017 21:04:13 +0000 (22:04 +0100)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 13 Mar 2018 05:01:59 +0000 (07:01 +0200)
Copy the current lists of queued and waiting commands and reference each command before calling smtp_client_command_fail_reply().
Failing one command can cause other dependent commands to be aborted (in a transaction or from submission service), which could have caused trouble in this function.
Problems would likely occur at connection disconnect.

src/lib-smtp/smtp-client-command.c
src/lib-smtp/smtp-client-connection.c
src/lib-smtp/smtp-client-private.h

index 42477f9f4130da9f9ebd880d21f251c0a065394b..8ea5dcce38c022fd888d734b6026aac913a3ea58 100644 (file)
@@ -313,6 +313,37 @@ void smtp_client_command_fail(struct smtp_client_command **_cmd,
        smtp_client_command_fail_reply(_cmd, &reply);
 }
 
+void smtp_client_commands_list_fail_reply(
+       struct smtp_client_command *cmds_list, unsigned int cmds_list_count,
+       const struct smtp_reply *reply)
+{
+       struct smtp_client_command *cmd;
+       ARRAY(struct smtp_client_command *) cmds_arr;
+       struct smtp_client_command **cmds;
+       unsigned int count, i;
+
+       if (cmds_list == NULL)
+               return;
+       i_assert(cmds_list_count > 0);
+
+       /* copy the array and reference the commands to be robust against more
+          than one command disappearing from the list */
+       t_array_init(&cmds_arr, cmds_list_count);
+       for (cmd = cmds_list; cmd != NULL; cmd = cmd->next) {
+               smtp_client_command_ref(cmd);
+               array_append(&cmds_arr, &cmd, 1);
+       }
+
+       cmds = array_get_modifiable(&cmds_arr, &count);
+       for (i = 0; i < count; i++) {
+               cmd = cmds[i];
+               /* fail the reply */
+               smtp_client_command_fail_reply(&cmds[i], reply);
+               /* drop our reference */
+               smtp_client_command_unref(&cmd);
+       }
+}
+
 void smtp_client_command_set_abort_callback(struct smtp_client_command *cmd,
        void (*callback)(void *context), void *context)
 {
index a361794bde46798984061329cc422918bee54fbf..d74c8555ad220e874d5f87151a231b9989e96b83 100644 (file)
@@ -145,23 +145,10 @@ static void
 smtp_client_connection_commands_fail_reply(struct smtp_client_connection *conn,
        const struct smtp_reply *reply)
 {
-       struct smtp_client_command *cmd, *cmd_next = NULL;
-
-       cmd = conn->cmd_wait_list_head;
-       while (cmd != NULL) {
-               i_assert(conn->cmd_wait_list_count > 0);
-               cmd_next = cmd->next;
-               smtp_client_command_fail_reply(&cmd, reply);
-               cmd = cmd_next;
-       }
-
-       cmd = conn->cmd_send_queue_head;
-       while (cmd != NULL) {
-               i_assert(conn->cmd_send_queue_count > 0);
-               cmd_next = cmd->next;
-               smtp_client_command_fail_reply(&cmd, reply);
-               cmd = cmd_next;
-       }
+       smtp_client_commands_list_fail_reply(conn->cmd_wait_list_head,
+                                            conn->cmd_wait_list_count, reply);
+       smtp_client_commands_list_fail_reply(conn->cmd_send_queue_head,
+                                            conn->cmd_send_queue_count, reply);
 }
 
 static void
index f68276515374810d9812bc92d88ef654475d31c6..c399d8b120122cde915eaea45fe3dc2988f44a30 100644 (file)
@@ -190,10 +190,14 @@ void smtp_client_command_free(struct smtp_client_command *cmd);
 int smtp_client_command_send_more(struct smtp_client_connection *conn);
 int smtp_client_command_input_reply(struct smtp_client_command *cmd,
                                    const struct smtp_reply *reply);
+
 void smtp_client_command_fail(struct smtp_client_command **_cmd,
                              unsigned int status, const char *error);
 void smtp_client_command_fail_reply(struct smtp_client_command **_cmd,
                                    const struct smtp_reply *reply);
+void smtp_client_commands_list_fail_reply(
+       struct smtp_client_command *cmds_list, unsigned int cmds_list_count,
+       const struct smtp_reply *reply);
 
 /*
  * Transaction