]> 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)
committerStephan Bosch <stephan.bosch@dovecot.fi>
Sat, 23 Dec 2017 21:19:50 +0000 (22:19 +0100)
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 617d8ad9528c576921828ed0994f27f4c912a868..3695266652c6c987d50f3e0d50f57d4086bf9648 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 90e3a4636f5d37c6a5ee3554f36899e889d37868..b7e12bd5b26d5b140fb66922238782b8f092f11f 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 cdf1c1fea52e7b592d1bcacb066125a0e06929de..be2014a351e4d3b5153620ebe6ada34a742007be 100644 (file)
@@ -189,10 +189,14 @@ int smtp_client_command_send_more(struct smtp_client_connection *conn,
                                  const char **error_r);
 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