EAI Future-proofing: don't apply strict_mime_encoding_domain
checks to unknown message subtypes such as message/global*.
File: global/mime_state.c.
+
+20111025
+
+ Bugfix (introduced: Postfix 2.8): postscreen 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. The fix
+ redirects the client to the dummy SMTP engine which sends
+ the 421 reply at the first legitimate opportunity. Problem
+ reported by Ralf Hildebrandt. Files: postscreen/postscreen_send.c,
+ postscreen/postscreen_smtpd.c, postscreen/postscreen.h.
+
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20111024"
+#define MAIL_RELEASE_DATE "20111025"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
(void) rec_fprintf(stream, REC_TYPE_MILT_COUNT, "%d", count);
if (msg_verbose)
- msg_info("send %d milters");
+ msg_info("send %d milters", count);
/*
* XXX Optimization: don't send or receive further information when there
#define PSC_STATE_FLAG_NEW (1<<3) /* some test was never passed */
#define PSC_STATE_FLAG_BLIST_FAIL (1<<4) /* blacklisted */
#define PSC_STATE_FLAG_HANGUP (1<<5) /* NOT a test failure */
-/* unused */
+#define PSC_STATE_FLAG_SMTPD_421 (1<<6) /* hang up after command */
#define PSC_STATE_FLAG_WLIST_FAIL (1<<7) /* do not whitelist */
/*
extern void psc_smtpd_init(void);
extern void psc_smtpd_pre_jail_init(void);
+#define PSC_SMTPD_421(state, reply) do { \
+ (state)->flags |= PSC_STATE_FLAG_SMTPD_421; \
+ (state)->final_reply = (reply); \
+ psc_smtpd_tests(state); \
+ } while (0)
+
/*
* postscreen_misc.c
*/
/* work is finished including postscreen cache updates.
/*
/* In case of an immediate error, psc_send_socket() sends a 421
-/* reply to the remote SMTP client and closes the connection.
+/* reply to the remote SMTP client and closes the connection
+/* if no partial SMTP greeting was sent. Otherwise, it redirects
+/* the SMTP client to the dummy protocol engine which sends
+/* 421 at the first legitimate opportunity and hangs up.
/* LICENSE
/* .ad
/* .fi
* suspicious. Alternatively, we could send attributes along with the
* socket with client reputation information, making everything even more
* Postfix-specific.
+ *
+ * If the operation fails after the partial SMTP handshake was sent,
+ * redirect the client to the dummy SMTP engine, which finishes the
+ * partial SMTP handshake sends the bad news after the first client
+ * command.
*/
if ((server_fd =
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);
+ if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
+ PSC_SMTPD_421(state, "421 4.3.2 No system resources\r\n");
+ } else {
+ 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);
- if (LOCAL_SEND_FD(state->smtp_server_fd,
+ if (LOCAL_SEND_FD(server_fd,
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);
+ (void) close(server_fd);
+ if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
+ PSC_SMTPD_421(state, "421 4.3.2 No system resources\r\n");
+ } else {
+ PSC_SEND_REPLY(state, "421 4.3.2 No system resources\r\n");
+ psc_free_session_state(state);
+ }
return;
} else {
#if 0
PSC_DEL_CLIENT_STATE(state);
#endif
+ PSC_ADD_SERVER_STATE(state, server_fd);
PSC_READ_EVENT_REQUEST(state->smtp_server_fd, psc_send_socket_close_event,
(char *) state, PSC_SEND_SOCK_NOTIFY_TIMEOUT);
return;
/*
/* void psc_smtpd_tests(state)
/* PSC_STATE *state;
+/*
+/* void PSC_SMTPD_421(state, final_reply)
+/* PSC_STATE *state;
+/* const char *final_reply;
/* DESCRIPTION
/* psc_smtpd_pre_jail_init() performs one-time per-process
/* initialization during the "before chroot" execution phase.
/* protocol tests and for collecting helo/sender/recipient
/* information.
/*
+/* PSC_SMTPD_421() redirects the SMTP client to the dummy SMTP
+/* protocol engine, completes the SMTP protocol handshake,
+/* sends the specified final reply after the first non-QUIT
+/* client command, and hangs up without doing any protocol
+/* tests. The final reply must end in <CR><LF>.
+/*
/* Unlike the Postfix SMTP server, this engine does not announce
/* PIPELINING support. This exposes spambots that pipeline
/* their commands anyway. Like the Postfix SMTP server, this
if (strcasecmp(command, cmdp->name) == 0)
break;
+ if ((state->flags & PSC_STATE_FLAG_SMTPD_421)
+ && cmdp->action != psc_quit_cmd) {
+ PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
+ state->final_reply);
+ return;
+ }
/* Non-SMTP command test. */
if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP)
== PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0
*
* XXX Make "opportunistically" configurable for each test.
*/
- state->flags |= (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_NSMTP_TODO | \
- PSC_STATE_FLAG_BARLF_TODO);
+ if ((state->flags & PSC_STATE_FLAG_SMTPD_421) == 0)
+ state->flags |= (PSC_STATE_FLAG_PIPEL_TODO | \
+ PSC_STATE_FLAG_NSMTP_TODO | \
+ PSC_STATE_FLAG_BARLF_TODO);
/*
* Send no SMTP banner to pregreeting clients. This eliminates a lot of