]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: client: Make smtp_client_connection_commands_abort() more reliable by copyi...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sat, 23 Dec 2017 21:14:16 +0000 (22:14 +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_abort().
Aborting 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.

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

index 8ea5dcce38c022fd888d734b6026aac913a3ea58..cae29e809a160bbc333a14dcefaf56467e814620 100644 (file)
@@ -313,6 +313,36 @@ void smtp_client_command_fail(struct smtp_client_command **_cmd,
        smtp_client_command_fail_reply(_cmd, &reply);
 }
 
+void smtp_client_commands_list_abort(struct smtp_client_command *cmds_list,
+                                    unsigned int cmds_list_count)
+{
+       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_abort(&cmds[i]);
+               /* drop our reference */
+               smtp_client_command_unref(&cmd);
+       }
+}
+
 void smtp_client_commands_list_fail_reply(
        struct smtp_client_command *cmds_list, unsigned int cmds_list_count,
        const struct smtp_reply *reply)
index d74c8555ad220e874d5f87151a231b9989e96b83..fb238b805faaa954a3126eff857ffb764b2e88a4 100644 (file)
@@ -122,23 +122,10 @@ smtp_client_connection_error(struct smtp_client_connection *conn,
 static void
 smtp_client_connection_commands_abort(struct smtp_client_connection *conn)
 {
-       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_abort(&cmd);
-               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_abort(&cmd);
-               cmd = cmd_next;
-       }
+       smtp_client_commands_list_abort(conn->cmd_wait_list_head,
+                                       conn->cmd_wait_list_count);
+       smtp_client_commands_list_abort(conn->cmd_send_queue_head,
+                                       conn->cmd_send_queue_count);
 }
 
 static void
index c399d8b120122cde915eaea45fe3dc2988f44a30..d10aa134bb87936b7d8bb9a8c9852a974195ceba 100644 (file)
@@ -195,6 +195,9 @@ 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_abort(struct smtp_client_command *cmds_list,
+                                    unsigned int cmds_list_count);
 void smtp_client_commands_list_fail_reply(
        struct smtp_client_command *cmds_list, unsigned int cmds_list_count,
        const struct smtp_reply *reply);