From: Stephan Bosch Date: Sat, 23 Dec 2017 21:14:16 +0000 (+0100) Subject: lib-smtp: client: Make smtp_client_connection_commands_abort() more reliable by copyi... X-Git-Tag: 2.3.1~66 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=18f762ed72040a2ff0edff1944ffc77cadba2632;p=thirdparty%2Fdovecot%2Fcore.git lib-smtp: client: Make smtp_client_connection_commands_abort() more reliable by copying the command lists. 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. --- diff --git a/src/lib-smtp/smtp-client-command.c b/src/lib-smtp/smtp-client-command.c index 8ea5dcce38..cae29e809a 100644 --- a/src/lib-smtp/smtp-client-command.c +++ b/src/lib-smtp/smtp-client-command.c @@ -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) diff --git a/src/lib-smtp/smtp-client-connection.c b/src/lib-smtp/smtp-client-connection.c index d74c8555ad..fb238b805f 100644 --- a/src/lib-smtp/smtp-client-connection.c +++ b/src/lib-smtp/smtp-client-connection.c @@ -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 diff --git a/src/lib-smtp/smtp-client-private.h b/src/lib-smtp/smtp-client-private.h index c399d8b120..d10aa134bb 100644 --- a/src/lib-smtp/smtp-client-private.h +++ b/src/lib-smtp/smtp-client-private.h @@ -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);