]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.4.7 v3.4.7
authorWietse Venema <wietse@porcupine.org>
Sat, 21 Sep 2019 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sun, 22 Sep 2019 20:37:24 +0000 (16:37 -0400)
postfix/HISTORY
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/tlsproxy/tlsproxy.c
postfix/src/tlsproxy/tlsproxy.h
postfix/src/util/vstream_tweak.c
postfix/src/xsasl/xsasl_dovecot_server.c

index bf78705c30826e70292f1b34af2a94c5e08a504f..e9effeeeea8d3b989aa8f85545d135035fa28fdf 100644 (file)
@@ -24248,3 +24248,48 @@ Apologies for any names omitted.
        handshake failure, causing stale numbers to be reported.
        The command counts are now reset in the function that reports
        the counts. File: smtpd/smtpd.c.
+
+20190723
+
+       Bugfix: the documentation said tls_fast_shutdown_enable,
+       but the code said tls_fast_shutdown. Viktor Dukhovni. Changed
+       the code because no-one is expected to override the default.
+       File: global/mail_params.h.
+
+20190820
+
+       Workaround for poor TCP loopback performance on LINUX, where
+       getsockopt(..., TCP_MAXSEG, ..) reports a TCP maximal segment
+       size that is 1/2 to 1/3 of the MTU. For example, with kernel
+       5.1.16-300.fc30.x86_64 the TCP client and server announce
+       an mss of 65495 in the TCP handshake, but getsockopt()
+       returns 32741 (less than half). As a matter of principle,
+       Postfix won't turn on client-side TCP_NODELAY because that
+       hides application performance bugs, and because that still
+       suffers from server-side delayed ACKs. Instead, Postfix
+       avoids sending "small" writes back-to-back, by choosing a
+       VSTREAM buffer size that is a multiple of the reported MSS.
+       This workaround bumps the multiplier from 2x to 4x. File:
+       util/vstream_tweak.c.
+
+20190825
+
+       Bugfix (introduced: 20051222): the Dovecot client could
+       segfault (null pointer read) or cause an SMTP server assertion
+       to fail when talking to a fake Dovecot server. The client
+       now logs a proper error instead. Problem reported by Tim
+       Düsterhus. File: xsasl/xsasl_dovecot_server.c.
+
+20190914
+
+       Bugfix (introduced: Postfix 3.4): don't whitewash OpenSSL
+       error results after a plaintext output error. The code could
+       loop, and with some OpenSSL error results could flood the
+       log with error messages (see below for a specific case).
+       Problem reported by Andreas Schulze. File: tlsproxy/tlsproxy.c.
+
+       Bitrot: don't invoke SSL_shutdown() when the SSL engine
+       thinks it is processing a TLS handshake. The commit at
+       https://github.com/openssl/openssl/commit/64193c8218540499984cd63cda41f3cd491f3f59
+       changed the error status, incompatibly, from SSL_ERROR_NONE
+       into SSL_ERROR_SSL. File: tlsproxy/tlsproxxy.c.
index bb19360d069494c438cb8c1279d62b473a3f9eaf..1f4c207cbd210ace0c8a3bdf124649f48301a228 100644 (file)
@@ -3333,7 +3333,7 @@ extern char *var_tls_dane_digests;
  /*
   * The default is backwards-incompatible.
   */
-#define VAR_TLS_FAST_SHUTDOWN  "tls_fast_shutdown"
+#define VAR_TLS_FAST_SHUTDOWN  "tls_fast_shutdown_enable"
 #define DEF_TLS_FAST_SHUTDOWN  1
 extern bool var_tls_fast_shutdown;
 
index 2f1bc03a6434afb599751bcc1bb458e7c9467b43..4c98887d28a20b77c1458474a98819b9dfb53dbc 100644 (file)
@@ -20,8 +20,8 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20190629"
-#define MAIL_VERSION_NUMBER    "3.4.6"
+#define MAIL_RELEASE_DATE      "20190921"
+#define MAIL_VERSION_NUMBER    "3.4.7"
 
 #ifdef SNAPSHOT
 #define MAIL_VERSION_DATE      "-" MAIL_RELEASE_DATE
index 9149c5c640f82c02a88e58f9caedebbb5baf962f..50b4154ff8ab78fd6f5a98d158ffe4ba8a33dc77 100644 (file)
@@ -618,11 +618,11 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
     switch (err) {
 
        /*
-        * No error from SSL_read and SSL_write means that the plaintext
-        * output buffer is full and that the plaintext input buffer is
-        * empty. Stop read/write events on the ciphertext stream. Keep the
-        * timer alive as a safety mechanism for the case that the plaintext
-        * pseudothreads get stuck.
+        * No error means a successful SSL_accept/connect/shutdown request or
+        * sequence of SSL_read/write requests. Disable read/write events on
+        * the ciphertext stream. Keep the ciphertext stream timer alive as a
+        * safety mechanism for the case that the plaintext pseudothreads get
+        * stuck.
         */
     case SSL_ERROR_NONE:
        if (state->ssl_last_err != SSL_ERROR_NONE) {
@@ -676,10 +676,23 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
     default:
 
        /*
-        * Allow buffered-up plaintext output to trickle out.
+        * Allow buffered-up plaintext output to trickle out. Permanently
+        * disable read/write activity on the ciphertext stream, so that this
+        * function will no longer be called. Keep the ciphertext stream
+        * timer alive as a safety mechanism for the case that the plaintext
+        * pseudothreads get stuck. Return into tlsp_strategy(), which will
+        * enable plaintext write events.
         */
-       if (state->plaintext_buf && NBBIO_WRITE_PEND(state->plaintext_buf))
+#define TLSP_CAN_TRICKLE_OUT_PLAINTEXT(buf) \
+       ((buf) && !NBBIO_ERROR_FLAGS(buf) && NBBIO_WRITE_PEND(buf))
+
+       if (TLSP_CAN_TRICKLE_OUT_PLAINTEXT(state->plaintext_buf)) {
+           event_disable_readwrite(ciphertext_fd);
+           event_request_timer(tlsp_ciphertext_event, (void *) state,
+                               state->timeout);
+           state->flags |= TLSP_FLAG_NO_MORE_CIPHERTEXT_IO;
            return (TLSP_STAT_OK);
+       }
        tlsp_state_free(state);
        return (TLSP_STAT_ERR);
     }
@@ -749,6 +762,18 @@ static void tlsp_strategy(TLSP_STATE *state)
     int     ssl_write_err;
     int     handshake_err;
 
+    /*
+     * This function is called after every ciphertext or plaintext event, to
+     * schedule new ciphertext or plaintext I/O.
+     */
+
+    /*
+     * Try to make an SSL I/O request. If this fails with SSL_ERROR_WANT_READ
+     * or SSL_ERROR_WANT_WRITE, enable ciphertext read or write events, and
+     * retry the SSL I/O request in a later tlsp_strategy() call.
+     */
+    if ((state->flags & TLSP_FLAG_NO_MORE_CIPHERTEXT_IO) == 0) {
+
     /*
      * Do not enable plain-text I/O before completing the TLS handshake.
      * Otherwise the remote peer can prepend plaintext to the optional
@@ -784,9 +809,8 @@ static void tlsp_strategy(TLSP_STATE *state)
     if (NBBIO_ERROR_FLAGS(plaintext_buf)) {
        if (NBBIO_ACTIVE_FLAGS(plaintext_buf))
            nbbio_disable_readwrite(state->plaintext_buf);
-       ssl_stat = SSL_shutdown(tls_context->con);
-       /* XXX Wait for return value 1 if sessions are to be reused? */
-       if (ssl_stat < 0) {
+       if (!SSL_in_init(tls_context->con)
+           && (ssl_stat = SSL_shutdown(tls_context->con)) < 0) {
            handshake_err = SSL_get_error(tls_context->con, ssl_stat);
            tlsp_eval_tls_error(state, handshake_err);
            /* At this point, state could be a dangling pointer. */
@@ -862,6 +886,19 @@ static void tlsp_strategy(TLSP_STATE *state)
                            ssl_write_err : ssl_read_err) < 0)
        /* At this point, state is a dangling pointer. */
        return;
+    }
+
+    /*
+     * Destroy state when the ciphertext I/O was permanently disbled and we
+     * can no longer trickle out plaintext.
+     */
+    else {
+       plaintext_buf = state->plaintext_buf;
+       if (!TLSP_CAN_TRICKLE_OUT_PLAINTEXT(plaintext_buf)) {
+           tlsp_state_free(state);
+           return;
+       }
+    }
 
     /*
      * Try to enable/disable plaintext read/write events. Basically, if we
index c50681354e453116f9373a6b453b84341e47dadd..eacbb1fabaae8513f17e8eadc1f94b20e3da97a8 100644 (file)
@@ -47,6 +47,7 @@ typedef struct {
 } TLSP_STATE;
 
 #define TLSP_FLAG_DO_HANDSHAKE (1<<0)
+#define TLSP_FLAG_NO_MORE_CIPHERTEXT_IO (1<<1) /* overrides DO_HANDSHAKE */
 
 extern TLSP_STATE *tlsp_state_create(const char *, VSTREAM *);
 extern void tlsp_state_free(TLSP_STATE *);
index 668654d05f1e1701d5a6fd6fe438be5f63256cbc..a2e220c45058eeb14e55545881f9a62e0be0a610 100644 (file)
@@ -124,12 +124,20 @@ int     vstream_tweak_tcp(VSTREAM *fp)
      * stream buffer size to less than VSTREAM_BUFSIZE, when the request is
      * made before the first stream read or write operation. We don't want to
      * reduce the buffer size.
+     * 
+     * As of 20190820 we increase the mss size multipler from 2x to 4x, because
+     * some LINUX loopback TCP stacks report an MSS of 21845 which is 3x
+     * smaller than the MTU of 65536. Even with a VSTREAM buffer 2x the
+     * reported MSS size, performance would suck due to Nagle or delayed ACK
+     * delays.
      */
 #define EFF_BUFFER_SIZE(fp) (vstream_req_bufsize(fp) ? \
                vstream_req_bufsize(fp) : VSTREAM_BUFSIZE)
 
 #ifdef CA_VSTREAM_CTL_BUFSIZE
-    if (mss > EFF_BUFFER_SIZE(fp) / 2) {
+    if (mss > EFF_BUFFER_SIZE(fp) / 4) {
+       if (mss < INT_MAX / 2)
+           mss *= 2;
        if (mss < INT_MAX / 2)
            mss *= 2;
        vstream_control(fp,
index 226cf11a6bed2a4864d2610faff40e57736f26f7..601f7874bc914d2d05438bf5a5c13f2e20360c37 100644 (file)
@@ -584,10 +584,20 @@ static int xsasl_dovecot_handle_reply(XSASL_DOVECOT_SERVER *server,
            if (xsasl_dovecot_parse_reply(server, &line) == 0) {
                /* authentication successful */
                xsasl_dovecot_parse_reply_args(server, line, reply, 1);
+               if (server->username == 0) {
+                   msg_warn("missing Dovecot server %s username field", cmd);
+                   vstring_strcpy(reply, "Authentication backend error");
+                   return XSASL_AUTH_FAIL;
+               }
                return XSASL_AUTH_DONE;
            }
        } else if (strcmp(cmd, "CONT") == 0) {
            if (xsasl_dovecot_parse_reply(server, &line) == 0) {
+               if (line == 0) {
+                   msg_warn("missing Dovecot server %s reply field", cmd);
+                   vstring_strcpy(reply, "Authentication backend error");
+                   return XSASL_AUTH_FAIL;
+               }
                vstring_strcpy(reply, line);
                return XSASL_AUTH_MORE;
            }