From: Stephan Bosch Date: Wed, 20 Jun 2018 12:01:18 +0000 (+0200) Subject: lib-smtp: server: Make sure conn->state.data_failed is only set when no previous... X-Git-Tag: 2.3.9~1686 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1957acf81402787f3a65ab83f34686a7e262f7fe;p=thirdparty%2Fdovecot%2Fcore.git lib-smtp: server: Make sure conn->state.data_failed is only set when no previous BDAT/BURL is pending. Otherwise, the server would sometimes send 503 error for the first BDAT/BURL command, while a subsequent command was actually failing earlier than the initial one completed. Additionally, this caused a panic crash. Panic was: submission(stephan)<8353>: Panic: Input stream /home/stephan/Maildir/cur/1517515808.M176007P2993.johanna,S=1903,W=1956:2,DFS unexpectedly has references --- diff --git a/src/lib-smtp/smtp-server-cmd-data.c b/src/lib-smtp/smtp-server-cmd-data.c index 122aa5a2d9..f37d1471e4 100644 --- a/src/lib-smtp/smtp-server-cmd-data.c +++ b/src/lib-smtp/smtp-server-cmd-data.c @@ -146,8 +146,12 @@ static void cmd_data_destroy(struct smtp_server_cmd_ctx *cmd) static void cmd_data_replied(struct smtp_server_cmd_ctx *cmd) { + struct smtp_server_connection *conn = cmd->conn; struct smtp_server_command *command = cmd->cmd; + i_assert(conn->state.pending_data_cmds > 0); + conn->state.pending_data_cmds--; + smtp_server_command_input_lock(cmd); if (!smtp_server_command_replied_success(command)) smtp_server_command_input_unlock(cmd); @@ -174,7 +178,20 @@ static void cmd_data_chunk_replied(struct smtp_server_cmd_ctx *cmd) i_assert(data_cmd != NULL); + i_assert(conn->state.pending_data_cmds > 0); + conn->state.pending_data_cmds--; + i_assert(smtp_server_command_is_replied(command)); + if (!smtp_server_command_replied_success(command) && + conn->state.pending_data_cmds == 0) + conn->state.data_failed = TRUE; +} + +static void cmd_data_chunk_completed(struct smtp_server_cmd_ctx *cmd) +{ + struct smtp_server_connection *conn = cmd->conn; + struct smtp_server_command *command = cmd->cmd; + if (!smtp_server_command_replied_success(command)) conn->state.data_failed = TRUE; } @@ -387,6 +404,8 @@ static void cmd_data_start_input(struct smtp_server_cmd_ctx *cmd, if (data_cmd->chunk_last) command->hook_completed = cmd_data_completed; + else + command->hook_completed = cmd_data_chunk_completed; if (conn->state.pending_mail_cmds == 0 && conn->state.pending_rcpt_cmds == 0) { @@ -432,6 +451,7 @@ static void cmd_data_start(struct smtp_server_cmd_ctx *cmd) void smtp_server_cmd_data(struct smtp_server_cmd_ctx *cmd, const char *params) { + struct smtp_server_connection *conn = cmd->conn; struct smtp_server_command *command = cmd->cmd; struct cmd_data_context *data_cmd; @@ -453,6 +473,7 @@ void smtp_server_cmd_data(struct smtp_server_cmd_ctx *cmd, command->hook_next = cmd_data_start; command->hook_replied = cmd_data_replied; command->hook_destroy = cmd_data_destroy; + conn->state.pending_data_cmds++; } /* BDAT/B... commands */ @@ -470,6 +491,7 @@ void smtp_server_connection_data_chunk_init(struct smtp_server_cmd_ctx *cmd) command->hook_replied = cmd_data_chunk_replied; command->hook_destroy = cmd_data_destroy; + conn->state.pending_data_cmds++; if (!conn->state.data_failed && conn->state.data_chain == NULL) { i_assert(data_cmd->chunk_first); diff --git a/src/lib-smtp/smtp-server-private.h b/src/lib-smtp/smtp-server-private.h index 876c84d205..3e012e2331 100644 --- a/src/lib-smtp/smtp-server-private.h +++ b/src/lib-smtp/smtp-server-private.h @@ -106,6 +106,7 @@ struct smtp_server_state_data { time_t timestamp; unsigned int pending_mail_cmds, pending_rcpt_cmds; + unsigned int pending_data_cmds; struct smtp_server_transaction *trans; struct istream *data_input, *data_chain_input;