From: "Omar Polo" Subject: smtpd: ehlo MUST reset the transaction To: tech@openbsd.org Date: Sun, 05 Apr 2026 19:26:04 +0200 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);