Fix possible SMTP desync if a timeout strikes
authorTim Düsterhus <duesterhus@woltlab.com>
Fri, 9 Sep 2022 09:34:07 +0000 (11:34 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Fri, 9 Sep 2022 09:39:58 +0000 (11:39 +0200)
see 9ae8a0e5da751e2abfcb00a621056c3a15ed009f

wcfsetup/install/files/lib/system/email/transport/SmtpEmailTransport.class.php

index e64735c6a9a0afdb59925ef0a9a121d22b36f338..cc2fd2293fbe91dcb63bcde54acbd40cd765460f 100644 (file)
@@ -219,6 +219,22 @@ class SmtpEmailTransport implements IStatusReportingEmailTransport
                     throw new TransientFailure("Unexpected EOF / connection close from SMTP server.");
                 }
                 if ($data === false) {
+                    // fgets returning false without feof returning true indicates that
+                    // the read timeout struck. The connection will still be usable, though.
+                    //
+                    // We must tear down the connection to avoid a desync when the SMTP server
+                    // sends the response to whatever command is currently waiting for the
+                    // response when we already attempt to deliver a new mail:
+                    //
+                    // RCPT TO:<foo@example.com>
+                    // -> timeout strikes
+                    // RSET
+                    // -> SMTP server belatedly responds to the RCPT TO, the response will
+                    //    be interpreted as the response to the RSET.
+                    // MAIL FROM:<bar@example.com>
+                    // -> SMTP server responds to the RSET
+                    $this->disconnect();
+
                     throw new TransientFailure("Failed to read from SMTP server.");
                 }