]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20111025
authorWietse Venema <wietse@porcupine.org>
Tue, 25 Oct 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:33 +0000 (06:37 +0000)
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/milter/milter.c
postfix/src/postscreen/postscreen.h
postfix/src/postscreen/postscreen_send.c
postfix/src/postscreen/postscreen_smtpd.c

index 6e0561a754d9db5c44de41a572411854f627410f..71df8695f4fd5efc6a916e6dc7b3b1bbdbcb0f5b 100644 (file)
@@ -17020,3 +17020,15 @@ Apologies for any names omitted.
        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.
+
index ab6759329ddb4adf1dea5af4e7a127ffe93308c9..75dfe5cb191b85742b25fb249226de4964b14d1b 100644 (file)
@@ -20,7 +20,7 @@
   * 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
index f4c64aff7cfc46162f606e67a783c410d60b12b9..f912add48cc8c872081dd1b1083a90a7136b0ade 100644 (file)
@@ -635,7 +635,7 @@ int     milter_send(MILTERS *milters, VSTREAM *stream)
     (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
index b378aaad4026bbec27fcc63514fb93a2fa483d1e..3a190f7c354fbbcc5ca81d5e94ed8ae613d95637 100644 (file)
@@ -81,7 +81,7 @@ typedef struct {
 #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 */
 
  /*
@@ -435,6 +435,12 @@ extern void psc_smtpd_tests(PSC_STATE *);
 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
   */
index f68a255d7154f613fca90a3ba2456b9f8677d0ae..bb111965e0881dc3f32c70958186941df7a64bb0 100644 (file)
 /*     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
@@ -182,22 +185,35 @@ void    psc_send_socket(PSC_STATE *state)
      * 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 {
 
@@ -209,6 +225,7 @@ void    psc_send_socket(PSC_STATE *state)
 #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;
index 062d19bff39e7db042b723a9c7c7b4aee7e4e578..67db377f570637592c9fee0c1ddb6f4c16045f2f 100644 (file)
 /*
 /*     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
@@ -904,6 +914,12 @@ static void psc_smtpd_read_event(int event, char *context)
            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
@@ -1088,8 +1104,10 @@ void    psc_smtpd_tests(PSC_STATE *state)
      * 
      * 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