]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: server: Make sure conn->state.data_failed is only set when no previous...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Wed, 20 Jun 2018 12:01:18 +0000 (14:01 +0200)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Wed, 6 Feb 2019 08:08:26 +0000 (10:08 +0200)
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><C+7QBfysKluhIAAAmoV78g>: Panic: Input stream /home/stephan/Maildir/cur/1517515808.M176007P2993.johanna,S=1903,W=1956:2,DFS unexpectedly has references

src/lib-smtp/smtp-server-cmd-data.c
src/lib-smtp/smtp-server-private.h

index ae9bf2576f55ec1bff81b205c8d57ed53669e7a5..ffc8cc9b52014ef22b3fd1a09519a969579821b6 100644 (file)
@@ -147,8 +147,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);
@@ -175,7 +179,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;
 }
@@ -401,6 +418,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) {
@@ -446,6 +465,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;
 
@@ -467,6 +487,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 */
@@ -484,6 +505,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);
index 876c84d20598ec94f6ddb5079839fb24cb8ebb5c..3e012e2331911bc74b41d539a65c81200bf039b3 100644 (file)
@@ -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;