Index | Thread | Search

From:
"Omar Polo" <op@omarpolo.com>
Subject:
smtpd: ehlo MUST reset the transaction
To:
tech@openbsd.org
Date:
Sun, 05 Apr 2026 19:26:04 +0200

Download raw body.

Thread
  • Omar Polo:

    smtpd: ehlo MUST reset the transaction

quoting RFC5321 ยง4.1.4:

> An EHLO command MAY be issued by a client later in the session.  If it
> is issued after the session begins and the EHLO command is acceptable to
> the SMTP server, the SMTP server MUST clear all buffers and reset the
> state exactly as if a RSET command had been issued. [...]
		     
This was brought to my attention a few times over the last release
cycle, we even had an issue on the -portable repository, as there are
some clients that actually rely on this behaviour.

I've tested a simpler variation of the diff below for several months
(been procrastinating on cleaning it up) on my mx and at a customer's
site.

To ease the review, take a look at smtp_proceed_rset() in the same file
as well too, it's exactly what i'm adding in smtp_proceed_ehlo.

smtp_tx_free() could feel a bit awkward to use like this, but it will
actually set session->tx back to NULL internally.

okay?

diff /home/op/w/smtpd
path + /home/op/w/smtpd
commit - 90063ccc4246e9d74e7fc619f8817b9f18458a99
blob - 00bac7ede042aa5378e6476b5173d3f6932a7d91
file + smtp_session.c
--- smtp_session.c
+++ smtp_session.c
@@ -1422,13 +1422,6 @@ smtp_check_ehlo(struct smtp_session *s, const char *ar
 		return 0;
 	}
 
-	if (s->helo[0]) {
-		smtp_reply(s, "503 %s %s: Already identified",
-		    esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-		    esc_description(ESC_INVALID_COMMAND));
-		return 0;
-	}
-
 	if (args == NULL) {
 		smtp_reply(s, "501 %s %s: EHLO requires domain name",
 		    esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
@@ -1770,6 +1763,12 @@ smtp_proceed_ehlo(struct smtp_session *s, const char *
 	s->flags |= SF_EHLO;
 	s->flags |= SF_8BITMIME;
 
+	if (s->tx) {
+		if (s->tx->msgid)
+			smtp_tx_rollback(s->tx);
+		smtp_tx_free(s->tx);
+	}
+
 	smtp_report_link_identify(s, "EHLO", s->helo);
 
 	smtp_enter_state(s, STATE_HELO);