summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2016-09-27 23:23:52 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2016-09-28 00:13:52 +0100
commit60d10ce7e68a5f2cf771a5c079521c8e4f18d157 (patch)
tree79b04a74b51ebe063ed50f83d09ba739e1cc3add
parentc0b9d3e87264ae274b37116103ecc9e1d1b0c647 (diff)
Drain socket to get clean TCP FINs
-rw-r--r--src/src/daemon.c8
-rw-r--r--src/src/smtp_in.c98
-rw-r--r--src/src/tls-gnu.c38
-rw-r--r--src/src/tls-openssl.c2
-rw-r--r--src/src/transports/smtp.c6
-rw-r--r--test/log/20134
-rw-r--r--test/log/20272
-rw-r--r--test/mail/2013.userx18
-rw-r--r--test/mail/2013.usery18
-rw-r--r--test/scripts/2000-GnuTLS/20132
-rw-r--r--test/src/client.c2
-rw-r--r--test/stderr/20134
-rw-r--r--test/stdout/05741
-rw-r--r--test/stdout/20021
-rw-r--r--test/stdout/20141
15 files changed, 117 insertions, 88 deletions
diff --git a/src/src/daemon.c b/src/src/daemon.c
index 64412c97d..a22ac8d68 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -523,9 +523,17 @@ if (pid == 0)
}
else
{
+ int i;
+ uschar * buf[128];
mac_smtp_fflush();
+ /* drain socket, for clean TCP FINs */
+ for(i = 16; read(fileno(smtp_in), buf, sizeof(buf)) > 0 && i > 0; ) i--;
search_tidyup();
smtp_log_no_mail(); /* Log no mail if configured */
+
+ /*XXX should we pause briefly, hoping that the client will be the
+ active TCP closer hence get the TCP_WAIT endpoint? */
+ DEBUG(D_receive) debug_printf("SMTP>>(close on process exit)\n");
_exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 3b631ea10..9484105d6 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -325,6 +325,7 @@ smtp_getc(void)
if (smtp_inptr >= smtp_inend)
{
int rc, save_errno;
+ if (!smtp_out) return EOF;
fflush(smtp_out);
if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
rc = read(fileno(smtp_in), smtp_inbuffer, in_buffer_size);
@@ -1343,26 +1344,23 @@ if (smtp_in == NULL || smtp_batched_input) return;
receive_swallow_smtp();
smtp_printf("421 %s\r\n", message);
-for (;;)
+for (;;) switch(smtp_read_command(FALSE))
{
- switch(smtp_read_command(FALSE))
- {
- case EOF_CMD:
- return;
+ case EOF_CMD:
+ return;
- case QUIT_CMD:
- smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
- mac_smtp_fflush();
- return;
+ case QUIT_CMD:
+ smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+ mac_smtp_fflush();
+ return;
- case RSET_CMD:
- smtp_printf("250 Reset OK\r\n");
- break;
+ case RSET_CMD:
+ smtp_printf("250 Reset OK\r\n");
+ break;
- default:
- smtp_printf("421 %s\r\n", message);
- break;
- }
+ default:
+ smtp_printf("421 %s\r\n", message);
+ break;
}
}
@@ -3403,7 +3401,7 @@ smtp_quit_handler(uschar ** user_msgp, uschar ** log_msgp)
{
HAD(SCH_QUIT);
incomplete_transaction_log(US"QUIT");
-if (acl_smtp_quit != NULL)
+if (acl_smtp_quit)
{
int rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp);
if (rc == ERROR)
@@ -5026,45 +5024,39 @@ while (done <= 0)
set, but we must still reject all incoming commands. */
DEBUG(D_tls) debug_printf("TLS failed to start\n");
- while (done <= 0)
+ while (done <= 0) switch(smtp_read_command(FALSE))
{
- switch(smtp_read_command(FALSE))
- {
- case EOF_CMD:
- log_write(L_smtp_connection, LOG_MAIN, "%s closed by EOF",
- smtp_get_connection_info());
- smtp_notquit_exit(US"tls-failed", NULL, NULL);
- done = 2;
- break;
-
- /* It is perhaps arguable as to which exit ACL should be called here,
- but as it is probably a situation that almost never arises, it
- probably doesn't matter. We choose to call the real QUIT ACL, which in
- some sense is perhaps "right". */
+ case EOF_CMD:
+ log_write(L_smtp_connection, LOG_MAIN, "%s closed by EOF",
+ smtp_get_connection_info());
+ smtp_notquit_exit(US"tls-failed", NULL, NULL);
+ done = 2;
+ break;
- case QUIT_CMD:
- user_msg = NULL;
- if (acl_smtp_quit != NULL)
- {
- rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg,
- &log_msg);
- if (rc == ERROR)
- log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
- log_msg);
- }
- if (user_msg == NULL)
- smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
- else
- smtp_respond(US"221", 3, TRUE, user_msg);
- log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
- smtp_get_connection_info());
- done = 2;
- break;
+ /* It is perhaps arguable as to which exit ACL should be called here,
+ but as it is probably a situation that almost never arises, it
+ probably doesn't matter. We choose to call the real QUIT ACL, which in
+ some sense is perhaps "right". */
+
+ case QUIT_CMD:
+ user_msg = NULL;
+ if ( acl_smtp_quit
+ && ((rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg,
+ &log_msg)) == ERROR))
+ log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
+ log_msg);
+ if (user_msg)
+ smtp_respond(US"221", 3, TRUE, user_msg);
+ else
+ smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+ log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
+ smtp_get_connection_info());
+ done = 2;
+ break;
- default:
- smtp_printf("554 Security failure\r\n");
- break;
- }
+ default:
+ smtp_printf("554 Security failure\r\n");
+ break;
}
tls_close(TRUE, TRUE);
break;
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index a5a680fd2..383a00f4e 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -1829,16 +1829,22 @@ alarm(0);
if (rc != GNUTLS_E_SUCCESS)
{
- tls_error(US"gnutls_handshake",
- sigalrm_seen ? "timed out" : gnutls_strerror(rc), NULL);
/* It seems that, except in the case of a timeout, we have to close the
connection right here; otherwise if the other end is running OpenSSL it hangs
until the server times out. */
- if (!sigalrm_seen)
+ if (sigalrm_seen)
+ tls_error(US"gnutls_handshake", "timed out", NULL);
+ else
{
+ tls_error(US"gnutls_handshake", gnutls_strerror(rc), NULL);
+ gnutls_alert_send_appropriate(state->session, rc);
+ millisleep(500);
+ shutdown(fileno(smtp_out), SHUT_WR);
+ for (rc = 1024; fgetc(smtp_in) != EOF && rc > 0; ) rc--; /* drain skt */
(void)fclose(smtp_out);
(void)fclose(smtp_in);
+ smtp_out = smtp_in = NULL;
}
return FAIL;
@@ -1863,8 +1869,7 @@ if ( state->verify_requirement != VERIFY_NONE
/* Figure out peer DN, and if authenticated, etc. */
-rc = peer_status(state);
-if (rc != OK) return rc;
+if ((rc = peer_status(state)) != OK) return rc;
/* Sets various Exim expansion variables; always safe within server */
@@ -2040,8 +2045,13 @@ do
alarm(0);
if (rc != GNUTLS_E_SUCCESS)
- return tls_error(US"gnutls_handshake",
- sigalrm_seen ? "timed out" : gnutls_strerror(rc), state->host);
+ if (sigalrm_seen)
+ {
+ gnutls_alert_send(state->session, GNUTLS_AL_FATAL, GNUTLS_A_USER_CANCELED);
+ return tls_error(US"gnutls_handshake", "timed out", state->host);
+ }
+ else
+ return tls_error(US"gnutls_handshake", gnutls_strerror(rc), state->host);
DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");
@@ -2118,7 +2128,7 @@ if (!state->tlsp || state->tlsp->active < 0) return; /* TLS was not active */
if (shutdown)
{
- DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS\n");
+ DEBUG(D_tls) debug_printf("tls_close() from '%s': shutting down TLS\n");
gnutls_bye(state->session, GNUTLS_SHUT_WR);
}
@@ -2168,11 +2178,19 @@ if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm)
ssl_xfer_buffer_size);
alarm(0);
- /* A zero-byte return appears to mean that the TLS session has been
+ /* Timeouts do not get this far; see command_timeout_handler().
+ A zero-byte return appears to mean that the TLS session has been
closed down, not that the socket itself has been closed down. Revert to
non-TLS handling. */
- if (inbytes == 0)
+ if (sigalrm_seen)
+ {
+ DEBUG(D_tls) debug_printf("Got tls read timeout\n");
+ state->xfer_error = 1;
+ return EOF;
+ }
+
+ else if (inbytes == 0)
{
DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 64dcab600..d9db7243f 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -2504,7 +2504,7 @@ if (*fdp < 0) return; /* TLS was not active */
if (shutdown)
{
- DEBUG(D_tls) debug_printf("tls_close(): shutting down SSL\n");
+ DEBUG(D_tls) debug_printf("tls_close() from '%s': shutting down SSL\n");
SSL_shutdown(*sslp);
}
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 21c57209c..ecdb8bf26 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -3162,6 +3162,12 @@ specified in the transports, and therefore not visible at top level, in which
case continue_more won't get set. */
HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP(close)>>\n");
+if (lflags.send_quit)
+ {
+ shutdown(outblock.sock, SHUT_WR);
+ for (rc = 16; read(inblock.sock, inbuffer, sizeof(inbuffer)) > 0 && rc > 0;)
+ rc--; /* drain socket */
+ }
(void)close(inblock.sock);
#ifndef DISABLE_EVENT
diff --git a/test/log/2013 b/test/log/2013
index d9ff4a344..21fad4866 100644
--- a/test/log/2013
+++ b/test/log/2013
@@ -3,7 +3,7 @@
1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmaZ-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaY-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qqf
@@ -16,6 +16,6 @@
1999-03-02 09:44:33 Start queue run: pid=pppp -qf
1999-03-02 09:44:33 10HmaZ-0005vi-00 => userx <userx@test.ex> R=server T=local_delivery
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbA-0005vi-00 => userx <userx@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbA-0005vi-00 => usery <usery@test.ex> R=server T=local_delivery
1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2027 b/test/log/2027
index 25155c96a..18b020a62 100644
--- a/test/log/2027
+++ b/test/log/2027
@@ -3,7 +3,7 @@
1999-03-02 09:44:33 Start queue run: pid=pppp -qf
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmaZ-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaY-0005vi-00 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] a TLS session is required but an attempt to start TLS failed
+1999-03-02 09:44:33 10HmaY-0005vi-00 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] TLS error on connection (gnutls_handshake): A TLS fatal alert has been received.
1999-03-02 09:44:33 10HmaY-0005vi-00 TLS session failure: delivering unencrypted to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (not in hosts_require_tls)
1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/mail/2013.userx b/test/mail/2013.userx
index def44beae..a0615146b 100644
--- a/test/mail/2013.userx
+++ b/test/mail/2013.userx
@@ -16,21 +16,3 @@ TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
Test message 1
-From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
-Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
- by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
- (Exim x.yz)
- (envelope-from <CALLER@myhost.test.ex>)
- id 10HmbA-0005vi-00
- for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
-Received: from CALLER by myhost.test.ex with local (Exim x.yz)
- (envelope-from <CALLER@myhost.test.ex>)
- id 10HmaY-0005vi-00
- for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
-Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
-From: CALLER_NAME <CALLER@myhost.test.ex>
-Date: Tue, 2 Mar 1999 09:44:33 +0000
-TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
-
-Test message 2
-
diff --git a/test/mail/2013.usery b/test/mail/2013.usery
new file mode 100644
index 000000000..a93a63d14
--- /dev/null
+++ b/test/mail/2013.usery
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbA-0005vi-00
+ for usery@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaY-0005vi-00
+ for usery@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 2
+
diff --git a/test/scripts/2000-GnuTLS/2013 b/test/scripts/2000-GnuTLS/2013
index f3d5719f0..24c2c58fc 100644
--- a/test/scripts/2000-GnuTLS/2013
+++ b/test/scripts/2000-GnuTLS/2013
@@ -5,7 +5,7 @@ exim -DSERVER=server -bd -oX PORT_D
exim userx@test.ex
Test message 1
****
-exim userx@test.ex
+exim usery@test.ex
Test message 2
****
exim -qqf -d-all+acl
diff --git a/test/src/client.c b/test/src/client.c
index 2bd640205..fe646d64f 100644
--- a/test/src/client.c
+++ b/test/src/client.c
@@ -1117,6 +1117,8 @@ int rc;
}
printf("End of script\n");
+shutdown(sock, SHUT_WR);
+while ((rc = read(sock, inbuffer, sizeof(inbuffer))) > 0) ;
close(sock);
exit(0);
diff --git a/test/stderr/2013 b/test/stderr/2013
index 9ddfc2f66..be80161c2 100644
--- a/test/stderr/2013
+++ b/test/stderr/2013
@@ -59,7 +59,7 @@ cmd buf flush ddd bytes
250-PIPELINING
250 HELP
SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
- SMTP>> RCPT TO:<userx@test.ex>
+ SMTP>> RCPT TO:<usery@test.ex>
SMTP>> DATA
cmd buf flush ddd bytes
SMTP<< 250 OK
@@ -70,7 +70,7 @@ cmd buf flush ddd bytes
cmd buf flush ddd bytes
SMTP(close)>>
LOG: MAIN
- => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
+ => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
LOG: MAIN
Completed
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stdout/0574 b/test/stdout/0574
index aea0754b7..08aacb17c 100644
--- a/test/stdout/0574
+++ b/test/stdout/0574
@@ -59,3 +59,4 @@ SMTP>> 221 myhost.test.ex closing connection
LOG: smtp_connection MAIN
SMTP connection from (test.ex) [127.0.0.1] closed by QUIT
search_tidyup called
+SMTP>>(close on process exit)
diff --git a/test/stdout/2002 b/test/stdout/2002
index ec3c1f954..7fd17f029 100644
--- a/test/stdout/2002
+++ b/test/stdout/2002
@@ -94,6 +94,7 @@ Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected
??? 220
<<< 220 TLS go ahead
Attempting to start TLS
+A TLS fatal alert has been received.
Failed to start TLS
End of script
Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected
diff --git a/test/stdout/2014 b/test/stdout/2014
index 56c959f20..c7aab62f1 100644
--- a/test/stdout/2014
+++ b/test/stdout/2014
@@ -18,6 +18,7 @@ Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected
??? 220
<<< 220 TLS go ahead
Attempting to start TLS
+A TLS fatal alert has been received.
Failed to start TLS
End of script
Connecting to 127.0.0.1 port 1225 ... connected