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.
/*
* 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;
* 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
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) {
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);
}
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
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. */
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
} 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 *);
* 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,
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;
}