Wietse Venema: > There are two sides to this story. One side is that in Postfix > 2.3..2.6 the SMTP client's error handling had a bug that was exposed > by postscreen's peculiar manner of blocking clients. But that is > not the real problem. > > The other side of the story is that postscreen's error handling is > questionable. When postscreen is unable to hand off a connection > to an smtpd process after sending the "220-" partial greeting, > postscreen sends a 421 response and hangs up. Now, sending 220- > followed by 421 violates SMTP. And that is the real problem.
This patch addresses the protocol problem on the postscreen side. With this, postscreen completes the 220 greeting and then it replies 4xx to all RCPT TO commands. This is safe, but it allows the client to send more commands than is strictly necessary. I'll optimize the fix later to reply with 421 (and hang up) to the first client command, so that postscreen can handle more traffic. Wietse [20111025-postscreen-220-421-patch] 20111025 Workaround (introduced: Postfix 2.8): postcreen sent non-compliant SMTP responses (220- followed by 421) when it could not hand off a connection to a real smtpd process, causing undefined behavior in the remote SMTP client. This workaround simply redirects the client to the after-greeting tests, replying with 4XX to all RCPT TO commands. A final fix will reply with 421 (and hang up) to the first client command. File: postscreen/spostscreen-send.c. diff -cr /var/tmp/postfix-2.9-20111024/src/postscreen/postscreen_send.c ./src/postscreen/postscreen_send.c *** /var/tmp/postfix-2.9-20111024/src/postscreen/postscreen_send.c Wed Feb 16 08:40:32 2011 --- ./src/postscreen/postscreen_send.c Tue Oct 25 10:26:24 2011 *************** *** 187,194 **** PASS_CONNECT(psc_smtpd_service_name, NON_BLOCKING, PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) { msg_warn("cannot connect to service %s: %m", psc_smtpd_service_name); ! PSC_SEND_REPLY(state, "421 4.3.2 All server ports are busy\r\n"); ! psc_free_session_state(state); return; } PSC_ADD_SERVER_STATE(state, server_fd); --- 187,194 ---- PASS_CONNECT(psc_smtpd_service_name, NON_BLOCKING, PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) { msg_warn("cannot connect to service %s: %m", psc_smtpd_service_name); ! /* XXX This assumes no connection hand-off with after-220 tests. */ ! psc_smtpd_tests(state); return; } PSC_ADD_SERVER_STATE(state, server_fd); *************** *** 196,203 **** vstream_fileno(state->smtp_client_stream)) < 0) { msg_warn("cannot pass connection to service %s: %m", psc_smtpd_service_name); ! PSC_SEND_REPLY(state, "421 4.3.2 No system resources\r\n"); ! psc_free_session_state(state); return; } else { --- 196,203 ---- vstream_fileno(state->smtp_client_stream)) < 0) { msg_warn("cannot pass connection to service %s: %m", psc_smtpd_service_name); ! /* XXX This assumes no connection hand-off with after-220 tests. */ ! psc_smtpd_tests(state); return; } else {