From 5ddc9771fa4d7861d3e5bfd6ea30c054883eaf40 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 6 Nov 2016 23:10:34 +0000 Subject: [PATCH] Ensure socket is nonblocking before draining. Bug 1914 --- doc/doc-txt/ChangeLog | 2 ++ src/src/daemon.c | 5 +++-- src/src/transports/smtp.c | 5 +++-- test/log/0502 | 7 +++++++ test/scripts/0000-Basic/0502 | 18 ++++++++++++++++++ test/src/client.c | 29 +++++++++++++++++++++++------ test/src/server.c | 2 -- test/stderr/0502 | 2 ++ test/stdout/0502 | 20 ++++++++++++++++++++ 9 files changed, 78 insertions(+), 12 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index e9b0705f4..d4d091ed2 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -129,6 +129,8 @@ JH/32 Bug 1909: Fix OCSP proof verification for cases where the proof is signed directly by the cert-signing cert, rather than an intermediate OCSP-signing cert. This is the model used by LetsEncrypt. +JH/33 Bug 1914: Ensure socket is nonblocking before draining after SMTP QUIT. + Exim version 4.87 ----------------- diff --git a/src/src/daemon.c b/src/src/daemon.c index 35e61dbfd..bc33aec45 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -520,12 +520,13 @@ if (pid == 0) { if (smtp_out) { - int i; + int i, fd = fileno(smtp_in); 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--; + if (fcntl(fd, F_SETFL, O_NONBLOCK) == 0) + for(i = 16; read(fd, buf, sizeof(buf)) > 0 && i > 0; ) i--; } search_tidyup(); smtp_log_no_mail(); /* Log no mail if configured */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 6c6a10266..d6ef34eff 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -3168,8 +3168,9 @@ 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 */ + if (fcntl(inblock.sock, F_SETFL, O_NONBLOCK) == 0) + for (rc = 16; read(inblock.sock, inbuffer, sizeof(inbuffer)) > 0 && rc > 0;) + rc--; /* drain socket */ } (void)close(inblock.sock); diff --git a/test/log/0502 b/test/log/0502 index 37d82e43b..93673ff90 100644 --- a/test/log/0502 +++ b/test/log/0502 @@ -13,3 +13,10 @@ 1999-03-02 09:44:33 Messages accepted: 1999-03-02 09:44:33 Recipients: 1999-03-02 09:44:33 Accepted: + +******** SERVER ******** +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 +1999-03-02 09:44:33 Messages received: +1999-03-02 09:44:33 Messages accepted: +1999-03-02 09:44:33 Recipients: +1999-03-02 09:44:33 Accepted: diff --git a/test/scripts/0000-Basic/0502 b/test/scripts/0000-Basic/0502 index d4b8f0fdb..c22205ca7 100644 --- a/test/scripts/0000-Basic/0502 +++ b/test/scripts/0000-Basic/0502 @@ -23,3 +23,21 @@ exim -bs -DLAST='' mail from: quit **** +# +# Check the server closes conn after a quit-response +exim -DSERVER=server -DLAST=accept -bd -oX PORT_D +**** +client 127.0.0.1 PORT_D +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 HELP +QUIT +??? 221 +???*eof +**** +# +killdaemon diff --git a/test/src/client.c b/test/src/client.c index 5e6b6472a..2b73098f5 100644 --- a/test/src/client.c +++ b/test/src/client.c @@ -24,6 +24,7 @@ ripped from the openssl ocsp and s_client utilities. */ #include #include #include +#include #include #include @@ -897,9 +898,13 @@ while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL) /* Expect incoming */ - if (strncmp(CS outbuffer, "??? ", 4) == 0) + if ( strncmp(CS outbuffer, "???", 3) == 0 + && (outbuffer[3] == ' ' || outbuffer[3] == '*') + ) { unsigned char *lineptr; + unsigned exp_eof = outbuffer[3] == '*'; + printf("%s\n", outbuffer); if (*inptr == 0) /* Refill input buffer */ @@ -921,15 +926,27 @@ while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL) } if (rc < 0) - { + { printf("Read error %s\n", strerror(errno)); - exit(81) ; - } + exit(81); + } else if (rc == 0) + if (exp_eof) + { + printf("Expected EOF read\n"); + continue; + } + else + { + printf("Enexpected EOF read\n"); + close(sock); + exit(80); + } + else if (exp_eof) { - printf("Unexpected EOF read\n"); + printf("Expected EOF not read\n"); close(sock); - exit(80); + exit(74); } else { diff --git a/test/src/server.c b/test/src/server.c index 4a48965e2..26fcaf070 100644 --- a/test/src/server.c +++ b/test/src/server.c @@ -397,7 +397,6 @@ else sin4.sin_addr.s_addr = (S_ADDR_TYPE)INADDR_ANY; sin4.sin_port = htons(port); if (bind(listen_socket[i], (struct sockaddr *)&sin4, sizeof(sin4)) < 0) - { if (listen_socket[v6n] < 0 || errno != EADDRINUSE) { printf("IPv4 socket bind() failed: %s\n", strerror(errno)); @@ -408,7 +407,6 @@ else close(listen_socket[i]); listen_socket[i] = -1; } - } } } } diff --git a/test/stderr/0502 b/test/stderr/0502 index 71afc025b..a3b308501 100644 --- a/test/stderr/0502 +++ b/test/stderr/0502 @@ -1 +1,3 @@ 1999-03-02 09:44:33 ACL for QUIT returned ERROR: QUIT or not-QUIT teplevel ACL may not fail ('deny' verb used incorrectly) + +******** SERVER ******** diff --git a/test/stdout/0502 b/test/stdout/0502 index a0fbe6b00..edb6d3156 100644 --- a/test/stdout/0502 +++ b/test/stdout/0502 @@ -19,3 +19,23 @@ 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 250 OK 221 myhost.test.ex closing connection +Connecting to 127.0.0.1 port 1225 ... connected +??? 220 +<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +>>> EHLO test.ex +??? 250- +<<< 250-myhost.test.ex Hello test.ex [127.0.0.1] +??? 250- +<<< 250-SIZE 52428800 +??? 250- +<<< 250-8BITMIME +??? 250- +<<< 250-PIPELINING +??? 250 HELP +<<< 250 HELP +>>> QUIT +??? 221 +<<< 221 myhost.test.ex closing connection +???*eof +Expected EOF read +End of script -- 2.25.1