A message with a single successful recipient but with a failed
rcpt to: command afterward generates an incorrect Received: header.

The following produces the bug:

thief$ nc localhost 25
220 thief.private ESMTP OpenSMTPD
ehlo thief.private^M
250-thief.private Hello thief.private [127.0.0.1], pleased to meet you
250-8BITMIME
250-ENHANCEDSTATUSCODES
250-SIZE 36700160
250-DSN
250 HELP
mail from:<me>^M
250 2.0.0 Ok
rcpt to:<me>^M
250 2.1.5 Destination address valid: Recipient ok
rcpt to:<nonexistant>^M
550 Invalid recipient: <nonexistant@thief.private>
data^M
354 Enter mail, end with "." on a line by itself
From:<me>^M
^M
test^M
.^M
250 2.0.0 8f9363cc Message accepted for delivery
quit^M
221 2.0.0 Bye
thief$

This gives the following message (I have the mask-src option set here):

Date: Sat, 8 Oct 2022 12:08:48 -0600 (MDT)
From: me@thief.private
Return-Path: <me@thief.private>
Delivered-To: me@thief.private
Received: by thief.private (OpenSMTPD) with ESMTP id 8f9363cc for
        <nonexistant@thief.private>; Sat, 8 Oct 2022 12:08:48 -0600 (MDT)
Message-ID: <ba820306321af158@thief.private>

test

The following patch fixes the problem:

Index: smtp_session.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtp_session.c,v
retrieving revision 1.432
diff -u -p -r1.432 smtp_session.c
--- smtp_session.c      1 Jul 2021 07:42:16 -0000       1.432
+++ smtp_session.c      8 Oct 2022 18:04:51 -0000
@@ -2732,6 +2732,7 @@ static void
 smtp_message_begin(struct smtp_tx *tx)
 {
        struct smtp_session *s;
+       struct smtp_rcpt *srfp;
        int     (*m_printf)(struct smtp_tx *, const char *, ...);

        m_printf = smtp_message_printf;
@@ -2780,10 +2781,13 @@ smtp_message_begin(struct smtp_tx *tx)
                }
        }

+       /* If we get failed "RCPT TO" commands that modify tx->evp, then
+        * make sure we use the real recipient for the "for" clause */
        if (tx->rcptcount == 1) {
+               srfp = TAILQ_FIRST(&tx->rcpts);
                m_printf(tx, "\n\tfor <%s@%s>",
-                   tx->evp.rcpt.user,
-                   tx->evp.rcpt.domain);
+                   srfp->maddr.user,
+                   srfp->maddr.domain);
        }

        m_printf(tx, ";\n\t%s\n", time_to_text(time(&tx->time)));

I use OpenSMTPD on OpenBSD for my personal mail, and it's great. Happy
to contribute in any way I can. Thank you for all you do.

Reply via email to