Make smtp_flush() work for TLS channel
authorJeremy Harris <jgh146exb@wizmail.org>
Mon, 25 Nov 2019 16:18:15 +0000 (16:18 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 30 Nov 2019 23:16:24 +0000 (23:16 +0000)
src/src/smtp_in.c
src/src/tls-gnu.c
src/src/tls-openssl.c

index 301f3c52cd2487a9b74e3012a96b7f8e283a2230..b88fde1b56cc0174a9132a0ffb755a273de6dd13 100644 (file)
@@ -947,16 +947,13 @@ if (fl.rcpt_in_progress)
 
 /* Now write the string */
 
 
 /* Now write the string */
 
+if (
 #ifndef DISABLE_TLS
 #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
 #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().
 
 /* 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
 
 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;
 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;
 }
 
 return smtp_write_error;
 }
 
index f3c3835fecd6b6a57d773d3933ac717ccf8a67f4..7b0f2f6adb01248dd0b4c273d2c6ba0a2104d459 100644 (file)
@@ -3311,6 +3311,9 @@ Arguments:
   len       number of bytes
   more     more data expected soon
 
   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
 */
 Returns:    the number of bytes after a successful write,
             -1 after a failed write
 */
index 5ea4d964e8b02a39d809c4f65a516d1145d7eb26..7e3cc3f78e053355603716b8f2e57973b2793930 100644 (file)
@@ -3531,11 +3531,12 @@ Arguments:
 Returns:    the number of bytes after a successful write,
             -1 after a failed write
 
 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
 */
 
 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;
 {
 size_t olen = len;
 int outbytes, error;
@@ -3561,6 +3562,8 @@ a store reset there, so use POOL_PERM. */
 
 if ((more || corked))
   {
 
 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;
 #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)
     {
   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_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;
     case SSL_ERROR_ZERO_RETURN:
       log_write(0, LOG_MAIN, "SSL channel closed on write");
       return -1;