Ensure socket is nonblocking before draining. Bug 1914
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 6 Nov 2016 23:10:34 +0000 (23:10 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 8 Nov 2016 15:35:34 +0000 (15:35 +0000)
doc/doc-txt/ChangeLog
src/src/daemon.c
src/src/transports/smtp.c
test/log/0502
test/scripts/0000-Basic/0502
test/src/client.c
test/src/server.c
test/stderr/0502
test/stdout/0502

index e9b0705f4d5a5111ad4ebe6439f0ef2b0eadaae9..d4d091ed2855acd71f83e32f2e68800e0a4f08cc 100644 (file)
@@ -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
 -----------------
index 35e61dbfde9e9086946914e5bd44dc4feed93670..bc33aec45619dc9a13acb9393c74c0d041225928 100644 (file)
@@ -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 */
index 6c6a102661f705ec37512e73f521b6af3acbcb35..d6ef34eff09d875678c5efcf26d54f0ac97485cb 100644 (file)
@@ -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);
 
index 37d82e43bb5dd2511e2748d9dd123ebde1e1daef..93673ff90450ebb669ceaa423d42c32db6cdd38a 100644 (file)
 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:          
index d4b8f0fdb9f623b90c11322fc7775a48317cf75b..c22205ca70d70f196c1f8a4e22a223a36b0449ed 100644 (file)
@@ -23,3 +23,21 @@ exim -bs -DLAST=''
 mail from:<a@b>
 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
index 5e6b6472ac082565926394d61ee8e805d6dafd98..2b73098f56c571fa50f16a24644a8a3e4af7fe18 100644 (file)
@@ -24,6 +24,7 @@ ripped from the openssl ocsp and s_client utilities. */
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/tcp.h>
 
 #include <netdb.h>
 #include <arpa/inet.h>
@@ -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
         {
index 4a48965e27142e5f2df0c353a0999045a9ad72ec..26fcaf070e1c79f461aa14c62f7db813bb7ddc5b 100644 (file)
@@ -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;
           }
-        }
       }
     }
   }
index 71afc025badd10ef96766e652aaaee7c04d6afcc..a3b3085013634ecd6af5c535ca75c88cdc4167c4 100644 (file)
@@ -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 ********
index a0fbe6b0000e8cc2d8d25d625cf637a04ebdc3a6..edb6d3156060c2b2bdc244f61376e01a8db603af 100644 (file)
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
 221 myhost.test.ex closing connection\r
+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