Fix handling of server which follows a RCPT 452 with a 250. Bug 26092
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 6 Feb 2021 22:01:23 +0000 (22:01 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 6 Feb 2021 22:01:23 +0000 (22:01 +0000)
    (cherry picked from commit d6870e76cf0b838eab1929e5d5afb486c4e7b448)

doc/doc-txt/ChangeLog
src/src/transports/smtp.c

index c9ad2e259cee8af2c90e58f1dc3a94c7e80f73c3..f687f73f52847bd4f6c56f234fc63956cb40a103 100644 (file)
@@ -148,6 +148,11 @@ JH/41 Fix daemon SIGHUP on FreeBSD.  Previously, a named socket for IPC was
       This affected any platform not supporting "abstract" Unix-domain
       sockets (i.e. not Linux).
 
+JH/42 Bug 2692: Harden against a peer which reneges on a 452 "too many
+      recipients" response to RCPT in a later response, with a 250.  The
+      previous coding assumed this would not happen, and under PIPELINING
+      would result in both lost and duplicate recipients for a message.
+
 
 
 
index b0dedfa8cacd752b270af92b72e78519f06f2b58..0c87027f5ff9a2a86a0a5a4f568b46de1e1f606d 100644 (file)
@@ -1087,7 +1087,7 @@ if (sx->pending_MAIL)
   {
   DEBUG(D_transport) debug_printf("%s expect mail\n", __FUNCTION__);
   count--;
-  sx->pending_MAIL = FALSE;
+  sx->pending_MAIL = sx->RCPT_452 = FALSE;
   if (!smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
                          '2', ob->command_timeout))
     {
@@ -1227,7 +1227,7 @@ while (count-- > 0)
 
        if (addr->more_errno >> 8 == 52  &&  yield & 3)
          {
-         if (!sx->RCPT_452)
+         if (!sx->RCPT_452)            /* initialised at MAIL-ack above */
            {
            DEBUG(D_transport)
              debug_printf("%s: seen first 452 too-many-rcpts\n", __FUNCTION__);
@@ -1274,6 +1274,8 @@ while (count-- > 0)
        }
       }
     }
+  if (count && !(addr = addr->next))
+    return -2;
   }       /* Loop for next RCPT response */
 
 /* Update where to start at for the next block of responses, unless we
@@ -3922,9 +3924,10 @@ else
       }
 
     /* Process all transported addresses - for LMTP or PRDR, read a status for
-    each one. */
+    each one. We used to drop out at first_addr, until someone returned a 452
+    followed by a 250... and we screwed up the accepted addresses. */
 
-    for (address_item * addr = addrlist; addr != sx->first_addr; addr = addr->next)
+    for (address_item * addr = addrlist; addr; addr = addr->next)
       {
       if (addr->transport_return != PENDING_OK) continue;