From cdb37db5c0ff060de7edfc94e830cab6b7f7c084 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 6 Feb 2021 22:01:23 +0000 Subject: [PATCH] Fix handling of server which follows a RCPT 452 with a 250. Bug 26092 (cherry picked from commit d6870e76cf0b838eab1929e5d5afb486c4e7b448) --- doc/doc-txt/ChangeLog | 5 +++++ src/src/transports/smtp.c | 11 +++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index c9ad2e259..f687f73f5 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -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. + diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index b0dedfa8c..0c87027f5 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -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; -- 2.30.2