From 30398c0651d976f7ca2713ba9441c117eb37ed1e Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Mon, 25 Nov 2019 16:18:15 +0000 Subject: [PATCH] Make smtp_flush() work for TLS channel --- src/src/smtp_in.c | 25 +++++++++++++++---------- src/src/tls-gnu.c | 3 +++ src/src/tls-openssl.c | 17 ++++++++++------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 301f3c52c..b88fde1b5 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -947,16 +947,13 @@ if (fl.rcpt_in_progress) /* Now write the string */ +if ( #ifndef DISABLE_TLS -if (tls_in.active.sock >= 0) - { - if (tls_write(NULL, gs.s, gs.ptr, more) < 0) - smtp_write_error = -1; - } -else + tls_in.active.sock >= 0 ? (tls_write(NULL, gs.s, gs.ptr, more) < 0) : #endif - -if (fprintf(smtp_out, "%s", gs.s) < 0) smtp_write_error = -1; + (fwrite(gs.s, gs.ptr, 1, smtp_out) == 0) + ) + smtp_write_error = -1; } @@ -967,8 +964,7 @@ if (fprintf(smtp_out, "%s", gs.s) < 0) smtp_write_error = -1; /* This function isn't currently used within Exim (it detects errors when it tries to read the next SMTP input), but is available for use in local_scan(). -For non-TLS connections, it flushes the output and checks for errors. For -TLS-connections, it checks for a previously-detected TLS write error. +It flushes the output and checks for errors. Arguments: none Returns: 0 for no error; -1 after an error @@ -978,6 +974,15 @@ int smtp_fflush(void) { if (tls_in.active.sock < 0 && fflush(smtp_out) != 0) smtp_write_error = -1; + +if ( +#ifndef DISABLE_TLS + tls_in.active.sock >= 0 ? (tls_write(NULL, NULL, 0, FALSE) < 0) : +#endif + (fflush(smtp_out) != 0) + ) + smtp_write_error = -1; + return smtp_write_error; } diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index f3c3835fe..7b0f2f6ad 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -3311,6 +3311,9 @@ Arguments: len number of bytes more more data expected soon +Calling with len zero and more unset will flush buffered writes. The buff +argument can be null for that case. + Returns: the number of bytes after a successful write, -1 after a failed write */ diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 5ea4d964e..7e3cc3f78 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -3531,11 +3531,12 @@ Arguments: Returns: the number of bytes after a successful write, -1 after a failed write -Used by both server-side and client-side TLS. +Used by both server-side and client-side TLS. Calling with len zero and more unset +will flush buffered writes; buff can be null for this case. */ int -tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more) +tls_write(void * ct_ctx, const uschar * buff, size_t len, BOOL more) { size_t olen = len; int outbytes, error; @@ -3561,6 +3562,8 @@ a store reset there, so use POOL_PERM. */ if ((more || corked)) { + if (!len) buff = US &error; /* dummy just so that string_catn is ok */ + #ifndef DISABLE_PIPE_CONNECT int save_pool = store_pool; store_pool = POOL_PERM; @@ -3590,16 +3593,16 @@ for (int left = len; left > 0;) DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error); switch (error) { + case SSL_ERROR_NONE: /* the usual case */ + left -= outbytes; + buff += outbytes; + break; + case SSL_ERROR_SSL: ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring); return -1; - case SSL_ERROR_NONE: - left -= outbytes; - buff += outbytes; - break; - case SSL_ERROR_ZERO_RETURN: log_write(0, LOG_MAIN, "SSL channel closed on write"); return -1; -- 2.30.2