]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20110205
authorWietse Venema <wietse@porcupine.org>
Sat, 5 Feb 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:09 +0000 (06:37 +0000)
23 files changed:
postfix/HISTORY
postfix/README_FILES/POSTSCREEN_README
postfix/WISHLIST
postfix/html/POSTSCREEN_README.html
postfix/html/postscreen.8.html
postfix/man/man8/postscreen.8
postfix/proto/POSTSCREEN_README.html
postfix/src/global/mail_version.h
postfix/src/global/smtp_stream.c
postfix/src/global/smtp_stream.h
postfix/src/postscreen/postscreen.c
postfix/src/postscreen/postscreen_smtpd.c
postfix/src/qmqpd/qmqpd_peer.c
postfix/src/smtp/smtp_chat.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_chat.c
postfix/src/smtpd/smtpd_peer.c
postfix/src/smtpd/smtpd_proxy.c
postfix/src/smtpstone/smtp-source.c
postfix/src/util/myaddrinfo.c
postfix/src/util/myaddrinfo.h
postfix/src/util/vstream.c
postfix/src/util/vstream.h

index 28e43204619e8f2f6573a685d4b442ab9289e029..64021a07dbab5107197b3471edadcd436ea68d52 100644 (file)
@@ -16545,3 +16545,29 @@ Apologies for any names omitted.
        disable further network writes. This eliminates the need
        for clumsy code to avoid unwanted I/O while shutting down
        a TLS engine or closing a VSTREAM.  File: util/smtp_stream.c.
+
+20110201
+
+       Cleanup: when verifying that the client_address->client_name
+       lookup result resolves to the client_address, request
+       hostname->address lookup with the same protocol family (IPv4
+       or IPv6) as the client_address.  Files: util/myaddrinfo.[hc],
+       smtpd/smtpd_peer.c, qmqpd/qmqpd_peer.c.
+
+20110205
+
+       Infrastructure: vstream_peek_data() primitive to look ahead
+       at buffered input. Use vstream_peek() to find out how much,
+       and escape() for human presentation.  Files: util/vstream.[hc].
+
+       Cleanup: smtpd(8) and postscreen(8) now log the input that
+       triggers an SMTP command pipelining violation. File:
+       postscreen/postscreen_smtpd.c, smtpd/smtpd.c.
+
+       Infrastructure: smtp_get() option to skip over input in
+       excess of the line length limit. Files: smtp/smtp_stream.[hc].
+
+       Cleanup: handle excessively-long client requests and server
+       responses more gracefully, i.e. without losing synchronization.
+       Files: smtpd/smtpd_chat.c, smtpd/smtpd_proxy.c, smtp/smtp_chat.c,
+       smtpstone/smtp-source.c.
index 789aa379b1d2ce20817ddf6a41c94fdca84eedcb..21d4e24f84a7579dc3950898e9d2bd61d4f489a3 100644 (file)
@@ -57,8 +57,8 @@ that keeps the zombies away, Postfix would be spending most of its resources
 not receiving email.
 
 The main challenge for postscreen(8) is to make an is-it-a-zombie decision
-based on a single measurement. This is necessary because many zombies avoid
-spamming the same site repeatedly, in an attempt to fly under the radar. Once
+based on a single measurement. This is necessary because many zombies try to
+fly under the radar and avoid spamming the same site repeatedly. Once
 postscreen(8) decides that a client is not-a-zombie, it whitelists the client
 temporarily to avoid further delays for legitimate mail.
 
@@ -88,8 +88,8 @@ passes a test, its IP address is whitelisted from 24 hours for simple tests, to
 1 week for complex tests. Whitelisting minimizes the impact of postscreen(8)'s
 tests on legitimate mail clients.
 
-After logging its findings, postscreen(8) by default hands off all connections
-to a Postfix SMTP server process. This mode is useful for non-destructive
+By default, postscreen(8) hands off all connections to a Postfix SMTP server
+process after logging its findings. This mode is useful for non-destructive
 testing.
 
 In a typical production setting, postscreen(8) is configured to reject mail
index 0f4a67c8d76246fd1c588b52fa2c5174d17b2e81..7224eb7f1c457fe70d16dbdd7f73a1572f38ec3a 100644 (file)
@@ -9,12 +9,14 @@ Wish list:
        Don't forget Apple's code donation for fetching mail from
        IMAP server.
 
-       propagate alias owner from pcre, regexp, etc. databases.
+       postconf command-line option to show the compile-time
+       settings (CCARGS, AUXLIBS) in case binary packages
+       don't install the makedefs.out file.
 
-       vstream_peek_len() and vstream_peek_data() to count the
-       unread data and to access it, respectively. vstream_peek_data()
-       can access the saved read buffer if a double-buffered stream
-       is in write mode.
+       propagate alias owner from pcre, regexp, cidr, texthash,
+       etc. databases, i.e. set the owner property at open time;
+       it can't be looked up at run-time with fstat(dict->stat_fd)
+       because there is no open file. What about *SQL, LDAP, etc.?
 
        events.c: cache the side effects of file descriptor event
        enable/disable operations in user space, and do bulk kernel
@@ -106,14 +108,21 @@ Wish list:
 
        Make postconf aware of local_, smtp_, etc. parameter names
        that have prefixes derived from mail delivery transport
-       names.  Unfortunately, it is wrong to assume that all "unix"
-       master.cf entries are delivery agents (though it may be OK
-       for postconf to peek in master.cf when given a parameter
-       with an unknown prefix). This requires a new main.cf parameter
+       names, LDAP/SQL table names, spawn(8) services, and so on.
+       Clearly, it is wrong to assume that all "unix" master.cf
+       entries are delivery agents (though it may be OK for postconf
+       to peek in master.cf when given a parameter with an unknown
+       prefix). This requires a new main.cf parameter (delivery_prefixes?)
        that lists all known mail delivery transport names. postconf
        can safely ignore names that don't exist in master.cf, and
        qmgr_transport_create() can safely warn about a name that
-       isn't listed in that new main.cf parameter.
+       isn't listed in that new main.cf parameter. A similar
+       parameter would be needed for spawn(8) services (spawn_prefixes?)
+       and for legacy-style database "sources" (database_prefixes?).
+       The spawn(8) daemon could warn if the service name is not
+       listed in main.cf, and the LDAP/SQL/etc.  drivers could
+       warn if a legacy-style database source is not listed in
+       main.cf.
 
        Need a regular expression table to translate address
        verification responses into hard/soft/accept reply codes.
index 3561164b47031245a94af5b1b8451e376c39a085..2850fb8dd349f89ef1e33ed6bf7704613d4bf0f6 100644 (file)
@@ -92,10 +92,10 @@ spending most of its resources not receiving email. </p>
 
 <p> The main challenge for <a href="postscreen.8.html">postscreen(8)</a> is to make an is-it-a-zombie
 decision based on a single measurement. This is necessary because
-many zombies avoid spamming the same site repeatedly, in an attempt
-to fly under the radar.  Once <a href="postscreen.8.html">postscreen(8)</a> decides that a client
-is not-a-zombie, it whitelists the client temporarily to avoid
-further delays for legitimate mail. </p>
+many zombies try to fly under the radar and avoid spamming the same
+site repeatedly.  Once <a href="postscreen.8.html">postscreen(8)</a> decides that a client is
+not-a-zombie, it whitelists the client temporarily to avoid further
+delays for legitimate mail. </p>
 
 <p> Zombies have challenges too: they have only a limited amount
 of time to deliver spam before their IP address becomes blacklisted.
@@ -126,9 +126,9 @@ whitelisted from 24 hours for simple tests, to 1 week for complex
 tests.  Whitelisting minimizes the impact of <a href="postscreen.8.html">postscreen(8)</a>'s tests
 on legitimate mail clients. </p>
 
-<p> After logging its findings, <a href="postscreen.8.html">postscreen(8)</a> by default hands off
-all connections to a Postfix SMTP server process. This mode is
-useful for non-destructive testing. </p>
+<p> By default, <a href="postscreen.8.html">postscreen(8)</a> hands off all connections to a Postfix
+SMTP server process after logging its findings. This mode is useful
+for non-destructive testing. </p>
 
 <p> In a typical production setting, <a href="postscreen.8.html">postscreen(8)</a> is configured
 to reject mail from clients that fail one or more tests, after
index 7b459f76874c4e654971374bca394a07c1d9ded2..b2b5367bb401f8160f9229c48e461ebed3374100 100644 (file)
@@ -61,7 +61,7 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
        <a href="http://tools.ietf.org/html/rfc1985">RFC 1985</a> (ETRN command)
        <a href="http://tools.ietf.org/html/rfc2034">RFC 2034</a> (SMTP Enhanced Status Codes)
        <a href="http://tools.ietf.org/html/rfc2821">RFC 2821</a> (SMTP protocol)
-       <a href="http://tools.ietf.org/html/rfc2920">RFC 2920</a> (SMTP Pipelining)
+       Not: <a href="http://tools.ietf.org/html/rfc2920">RFC 2920</a> (SMTP Pipelining)
        <a href="http://tools.ietf.org/html/rfc3207">RFC 3207</a> (STARTTLS command)
        <a href="http://tools.ietf.org/html/rfc3461">RFC 3461</a> (SMTP DSN Extension)
        <a href="http://tools.ietf.org/html/rfc3463">RFC 3463</a> (Enhanced Status Codes)
index 84b85c23ac56816dd7a0b41ec55fbe26919197a5..93062d8888ba01ace8f42defe09cca69530eef25 100644 (file)
@@ -64,7 +64,7 @@ RFC 1870 (Message Size Declaration)
 RFC 1985 (ETRN command)
 RFC 2034 (SMTP Enhanced Status Codes)
 RFC 2821 (SMTP protocol)
-RFC 2920 (SMTP Pipelining)
+Not: RFC 2920 (SMTP Pipelining)
 RFC 3207 (STARTTLS command)
 RFC 3461 (SMTP DSN Extension)
 RFC 3463 (Enhanced Status Codes)
index e71ebe1a962bbd64f0daec9a7d07d8b310e6fa42..85e6755591811062ebea0e4d3161aed9663b3c9a 100644 (file)
@@ -92,10 +92,10 @@ spending most of its resources not receiving email. </p>
 
 <p> The main challenge for postscreen(8) is to make an is-it-a-zombie
 decision based on a single measurement. This is necessary because
-many zombies avoid spamming the same site repeatedly, in an attempt
-to fly under the radar.  Once postscreen(8) decides that a client
-is not-a-zombie, it whitelists the client temporarily to avoid
-further delays for legitimate mail. </p>
+many zombies try to fly under the radar and avoid spamming the same
+site repeatedly.  Once postscreen(8) decides that a client is
+not-a-zombie, it whitelists the client temporarily to avoid further
+delays for legitimate mail. </p>
 
 <p> Zombies have challenges too: they have only a limited amount
 of time to deliver spam before their IP address becomes blacklisted.
@@ -126,9 +126,9 @@ whitelisted from 24 hours for simple tests, to 1 week for complex
 tests.  Whitelisting minimizes the impact of postscreen(8)'s tests
 on legitimate mail clients. </p>
 
-<p> After logging its findings, postscreen(8) by default hands off
-all connections to a Postfix SMTP server process. This mode is
-useful for non-destructive testing. </p>
+<p> By default, postscreen(8) hands off all connections to a Postfix
+SMTP server process after logging its findings. This mode is useful
+for non-destructive testing. </p>
 
 <p> In a typical production setting, postscreen(8) is configured
 to reject mail from clients that fail one or more tests, after
index a4f7c72300b288a6d997b66a671c1f0be355eac6..9a12c01a52d0c7bcd24772eff686be45e218af08 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      "20110130"
+#define MAIL_RELEASE_DATE      "20110205"
 #define MAIL_VERSION_NUMBER    "2.9"
 
 #ifdef SNAPSHOT
index 7c5d19ad9d24abc02afec7f742923ba74409192d..84de8348c09e7d073c155f9c09a1911399de600f 100644 (file)
 /*     int     smtp_fgetc(stream)
 /*     VSTREAM *stream;
 /*
-/*     int     smtp_get(vp, stream, maxlen)
+/*     int     smtp_get(vp, stream, maxlen, flags)
 /*     VSTRING *vp;
 /*     VSTREAM *stream;
 /*     ssize_t maxlen;
+/*     int     flags;
 /*
 /*     void    smtp_fputs(str, len, stream)
 /*     const char *str;
 /*     and protects the program against running out of memory.
 /*     Specify a zero bound to turn off bounds checking.
 /*     The result is the last character read, or VSTREAM_EOF.
+/*     The \fIflags\fR argument is either SMTP_GET_FLAG_NONE (no
+/*     special processing) or SMTP_GET_FLAG_SKIP (skip over input
+/*     in excess of \fImaxlen\fR). Either way, a result value of
+/*     '\n' means that the input did not exceed \fImaxlen\fR.
 /*
 /*     smtp_fputs() writes its string argument to the named stream.
 /*     Long strings are not broken. Each string is followed by a
@@ -275,7 +280,7 @@ int     smtp_fgetc(VSTREAM *stream)
 
 /* smtp_get - read one line from SMTP peer */
 
-int     smtp_get(VSTRING *vp, VSTREAM *stream, ssize_t bound)
+int     smtp_get(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags)
 {
     int     last_char;
     int     next_char;
@@ -330,6 +335,15 @@ int     smtp_get(VSTRING *vp, VSTREAM *stream, ssize_t bound)
        break;
     }
 
+    /*
+     * Optionally, skip over excess input, protected by the same time limit.
+     */
+    if (last_char != '\n' && (flags & SMTP_GET_FLAG_SKIP)
+       && vstream_feof(stream) == 0 && vstream_ferror(stream) == 0)
+       while ((next_char = VSTREAM_GETC(stream)) != VSTREAM_EOF
+              && next_char != '\n')
+            /* void */ ;
+
     /*
      * EOF is bad, whether or not it happens in the middle of a record. Don't
      * allow data that was truncated because of EOF.
index 5593922164404cf73475565576c3e36b842788c3..3bf33c912b1dd6bda7c23e56de917f331d01e1c0 100644 (file)
@@ -36,13 +36,16 @@ extern void smtp_timeout_setup(VSTREAM *, int);
 extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);
 extern void smtp_flush(VSTREAM *);
 extern int smtp_fgetc(VSTREAM *);
-extern int smtp_get(VSTRING *, VSTREAM *, ssize_t);
+extern int smtp_get(VSTRING *, VSTREAM *, ssize_t, int);
 extern void smtp_fputs(const char *, ssize_t len, VSTREAM *);
 extern void smtp_fwrite(const char *, ssize_t len, VSTREAM *);
 extern void smtp_fputc(int, VSTREAM *);
 
 extern void smtp_vprintf(VSTREAM *, const char *, va_list);
 
+#define SMTP_GET_FLAG_NONE     0
+#define SMTP_GET_FLAG_SKIP     (1<<0)  /* skip over excess input */
+
 /* LICENSE
 /* .ad
 /* .fi
index 67bfe3caaf647bb55b90490524583f24912d8192..de7661549b17b0fdc504e0718d97c23594bb9785 100644 (file)
@@ -54,7 +54,7 @@
 /*     RFC 1985 (ETRN command)
 /*     RFC 2034 (SMTP Enhanced Status Codes)
 /*     RFC 2821 (SMTP protocol)
-/*     RFC 2920 (SMTP Pipelining)
+/*     Not: RFC 2920 (SMTP Pipelining)
 /*     RFC 3207 (STARTTLS command)
 /*     RFC 3461 (SMTP DSN Extension)
 /*     RFC 3463 (Enhanced Status Codes)
index f42855c537f03624319dc56808b095f603f834d1..062d19bff39e7db042b723a9c7c7b4aee7e4e578 100644 (file)
 
 #define PSC_SMTPD_BUFFER_EMPTY(state) \
        (!PSC_SMTPD_HAVE_PUSH_BACK(state) \
-       && vstream_peek(state->smtp_client_stream) <= 0)
+       && vstream_peek((state)->smtp_client_stream) <= 0)
+
+#define PSC_SMTPD_PEEK_DATA(state) \
+       vstream_peek_data((state)->smtp_client_stream)
+#define PSC_SMTPD_PEEK_LEN(state) \
+       vstream_peek((state)->smtp_client_stream)
 
  /*
   * Dynamic reply strings. To minimize overhead we format these once.
@@ -941,8 +946,11 @@ static void psc_smtpd_read_event(int event, char *context)
        if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP)
            == PSC_STATE_FLAG_PIPEL_TODO && !PSC_SMTPD_BUFFER_EMPTY(state)) {
            printable(command, '?');
-           msg_info("COMMAND PIPELINING from [%s]:%s after %.100s",
-                    PSC_CLIENT_ADDR_PORT(state), command);
+           escape(psc_temp, PSC_SMTPD_PEEK_DATA(state),
+                  PSC_SMTPD_PEEK_LEN(state) < 100 ?
+                  PSC_SMTPD_PEEK_LEN(state) : 100);
+           msg_info("COMMAND PIPELINING from [%s]:%s after %.100s: %s",
+                    PSC_CLIENT_ADDR_PORT(state), command, STR(psc_temp));
            PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_FAIL);
            PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_PASS);
            state->pipel_stamp = PSC_TIME_STAMP_DISABLED;       /* XXX */
index a4bfe5fe734692f2c574c263518c0699514f66af..ba297117a3e6364c8ffba66b52e04b4740c906e3 100644 (file)
@@ -243,7 +243,8 @@ void    qmqpd_peer_init(QMQPD_STATE *state)
            /*
             * Reject the hostname if it does not list the peer address.
             */
-           aierr = hostname_to_sockaddr(state->name, (char *) 0, 0, &res0);
+           aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
+                                           (char *) 0, 0, &res0);
            if (aierr) {
                msg_warn("%s: hostname %s verification failed: %s",
                         state->addr, state->name, MAI_STRERROR(aierr));
index 31aa0c61b848768fda663fee547a08efa49a6754..7cb1e11f38e80f9e02be90226fbc42feadd64fcc 100644 (file)
@@ -255,10 +255,15 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session)
      * Censor out non-printable characters in server responses. Concatenate
      * multi-line server responses. Separate the status code from the text.
      * Leave further parsing up to the application.
+     * 
+     * We can't parse or store input that exceeds var_line_limit, so we just
+     * skip over it to simplify the remainder of the code below.
      */
     VSTRING_RESET(rdata.str_buf);
     for (;;) {
-       last_char = smtp_get(session->buffer, session->stream, var_line_limit);
+       last_char = smtp_get(session->buffer, session->stream, var_line_limit,
+                            SMTP_GET_FLAG_SKIP);
+       /* XXX Update the per-line time limit. */
        printable(STR(session->buffer), '?');
        if (last_char != '\n')
            msg_warn("%s: response longer than %d: %.30s...",
index 3dd9367b928b855a8f88d111c0af7bcb159efab8..2c569f2540cffd26d90411b520bfbe252de23f98 100644 (file)
@@ -2942,7 +2942,8 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
      * because sendmail permits it.
      */
     for (prev_rec_type = 0; /* void */ ; prev_rec_type = curr_rec_type) {
-       if (smtp_get(state->buffer, state->client, var_line_limit) == '\n')
+       if (smtp_get(state->buffer, state->client, var_line_limit,
+                    SMTP_GET_FLAG_NONE) == '\n')
            curr_rec_type = REC_TYPE_NORM;
        else
            curr_rec_type = REC_TYPE_CONT;
@@ -4653,8 +4654,13 @@ static void smtpd_proto(SMTPD_STATE *state)
                && (state->flags & SMTPD_FLAG_ILL_PIPELINING) == 0
                && (vstream_peek(state->client) > 0
                    || peekfd(vstream_fileno(state->client)) > 0)) {
-               msg_info("improper command pipelining after %s from %s",
-                        cmdp->name, state->namaddr);
+               if (state->expand_buf == 0)
+                   state->expand_buf = vstring_alloc(100);
+               escape(state->expand_buf, vstream_peek_data(state->client),
+                      vstream_peek(state->client) < 100 ?
+                      vstream_peek(state->client) : 100);
+               msg_info("improper command pipelining after %s from %s: %s",
+                        cmdp->name, state->namaddr, STR(state->expand_buf));
                state->flags |= SMTPD_FLAG_ILL_PIPELINING;
            }
            if (cmdp->action(state, argc, argv) != 0)
index da6e80ce657713896a50bab7d777fef83dbfc310..9cc30385e338b58dfc9ae25676d6e020bde95636 100644 (file)
@@ -127,7 +127,12 @@ void    smtpd_chat_query(SMTPD_STATE *state)
 {
     int     last_char;
 
-    last_char = smtp_get(state->buffer, state->client, var_line_limit);
+    /*
+     * We can't parse or store input that exceeds var_line_limit, so we skip
+     * over it to avoid loss of synchronization.
+     */
+    last_char = smtp_get(state->buffer, state->client, var_line_limit,
+                        SMTP_GET_FLAG_SKIP);
     smtp_chat_append(state, "In:  ", STR(state->buffer));
     if (last_char != '\n')
        msg_warn("%s: request longer than %d: %.30s...",
index 2aa9217748eeb01426068f16394357e70de0bacd..af678b6806ca991e0ea66c921347ae536b12e558 100644 (file)
@@ -337,7 +337,8 @@ void    smtpd_peer_init(SMTPD_STATE *state)
             * must not be allowed to enter the audit trail, as people would
             * draw false conclusions.
             */
-           aierr = hostname_to_sockaddr(state->name, (char *) 0, 0, &res0);
+           aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
+                                           (char *) 0, 0, &res0);
            if (aierr) {
                msg_warn("%s: hostname %s verification failed: %s",
                         state->addr, state->name, MAI_STRERROR(aierr));
index a31cd83b561a5fd1437aec3a45d8b728a0727c00..9952c1e9d5ca9fc03bcb6c75309aa3304dc7a9d9 100644 (file)
@@ -434,7 +434,7 @@ static int smtpd_proxy_connect(SMTPD_STATE *state)
                                              FORWARD_HELO(state)))
             || ((server_xforward_features & SMTPD_PROXY_XFORWARD_IDENT)
                 && smtpd_proxy_xforward_send(state, buf, XFORWARD_IDENT,
-                                 IS_AVAIL_CLIENT_IDENT(FORWARD_IDENT(state)),
+                               IS_AVAIL_CLIENT_IDENT(FORWARD_IDENT(state)),
                                              FORWARD_IDENT(state)))
             || ((server_xforward_features & SMTPD_PROXY_XFORWARD_PROTO)
                 && smtpd_proxy_xforward_send(state, buf, XFORWARD_PROTO,
@@ -764,12 +764,16 @@ static int smtpd_proxy_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
     /*
      * Censor out non-printable characters in server responses and save
      * complete multi-line responses if possible.
+     * 
+     * We can't parse or store input that exceeds var_line_limit, so we just
+     * skip over it to simplify the remainder of the code below.
      */
     VSTRING_RESET(proxy->buffer);
     if (buffer == 0)
        buffer = vstring_alloc(10);
     for (;;) {
-       last_char = smtp_get(buffer, proxy->service_stream, var_line_limit);
+       last_char = smtp_get(buffer, proxy->service_stream, var_line_limit,
+                            SMTP_GET_FLAG_SKIP);
        printable(STR(buffer), '?');
        if (last_char != '\n')
            msg_warn("%s: response longer than %d: %.30s...",
index d9d8826bd7e887f810dc5cdb40359e902301451d..4bc531aaa9d6adfbf8e9f01a86f4a109a5bad4d2 100644 (file)
@@ -316,7 +316,7 @@ static RESPONSE *response(VSTREAM *stream, VSTRING *buf)
 #define BUF ((char *) vstring_str(buf))
     VSTRING_RESET(rdata.buf);
     for (;;) {
-       smtp_get(buf, stream, var_line_limit);
+       smtp_get(buf, stream, var_line_limit, SMTP_GET_FLAG_SKIP);
        for (cp = BUF; *cp != 0; cp++)
            if (!ISPRINT(*cp) && !ISSPACE(*cp))
                *cp = '?';
index 171528c22939be23e278110ffc2455f84f18cc5f..d4a6938c715461ca2a0eb9f09399000a6768e8a3 100644 (file)
 /*     int     socktype;
 /*     struct addrinfo **result;
 /*
+/*     int     hostname_to_sockaddr_pf(hostname, pf, service, socktype, result)
+/*     const char *hostname;
+/*     int     pf;
+/*     const char *service;
+/*     int     socktype;
+/*     struct addrinfo **result;
+/*
 /*     int     hostaddr_to_sockaddr(hostaddr, service, socktype, result)
 /*     const char *hostaddr;
 /*     const char *service;
@@ -59,6 +66,9 @@
 /*     result should be destroyed with freeaddrinfo(). A null host
 /*     pointer converts to the null host address.
 /*
+/*     hostname_to_sockaddr_pf() is an extended interface that
+/*     provides a protocol family override.
+/*
 /*     hostaddr_to_sockaddr() converts a printable network address
 /*     into the corresponding binary form.  The result should be
 /*     destroyed with freeaddrinfo(). A null host pointer converts
 /*     hostname, or a null pointer (meaning the wild-card listen
 /*     address).  On output from sockaddr_to_hostname(), storage
 /*     for the result hostname, or a null pointer.
+/* .IP pf
+/*     Protocol type: PF_UNSPEC (meaning: use any protocol that is
+/*     available), PF_INET, or PF_INET6.  This argument is ignored
+/*     in EMULATE_IPV4_ADDRINFO mode.
 /* .IP hostaddr
 /*     On input to hostaddr_to_sockaddr(), a numeric hostname,
 /*     or a null pointer (meaning the wild-card listen address).
@@ -274,10 +288,11 @@ static int find_service(const char *service, int socktype)
 
 #endif
 
-/* hostname_to_sockaddr - hostname to binary address form */
+/* hostname_to_sockaddr_pf - hostname to binary address form */
 
-int     hostname_to_sockaddr(const char *hostname, const char *service,
-                                    int socktype, struct addrinfo ** res)
+int     hostname_to_sockaddr_pf(const char *hostname, int pf,
+                                    const char *service, int socktype,
+                                    struct addrinfo ** res)
 {
 #ifdef EMULATE_IPV4_ADDRINFO
 
@@ -408,7 +423,7 @@ int     hostname_to_sockaddr(const char *hostname, const char *service,
     int     err;
 
     memset((char *) &hints, 0, sizeof(hints));
-    hints.ai_family = inet_proto_info()->ai_family;
+    hints.ai_family = (pf != PF_UNSPEC) ? pf : inet_proto_info()->ai_family;
     hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
     if (!hostname) {
        hints.ai_flags = AI_PASSIVE;
index 766eed27aafd821029766ced61ca69c17bc1812d..95d5ee9ee61f186d809ce69b9bd0705586f43fd0 100644 (file)
@@ -154,8 +154,8 @@ typedef struct {
     char    buf[MAI_SERVPORT_STRSIZE];
 } MAI_SERVPORT_STR;
 
-extern int hostname_to_sockaddr(const char *, const char *, int,
-                                       struct addrinfo **);
+extern int hostname_to_sockaddr_pf(const char *, int, const char *, int,
+                                          struct addrinfo **);
 extern int hostaddr_to_sockaddr(const char *, const char *, int,
                                        struct addrinfo **);
 extern int sockaddr_to_hostaddr(const struct sockaddr *, SOCKADDR_SIZE,
@@ -168,18 +168,24 @@ extern void myaddrinfo_control(int,...);
 
 #define MAI_STRERROR(e) ((e) == EAI_SYSTEM ? strerror(errno) : gai_strerror(e))
 
+#define hostname_to_sockaddr(host, serv, sock, res) \
+       hostname_to_sockaddr_pf((host), PF_UNSPEC, (serv), (sock), (res))
+
  /*
   * Macros for the case where we really don't want to be bothered with things
   * that may fail.
   */
-#define HOSTNAME_TO_SOCKADDR(host, serv, sock, res) \
+#define HOSTNAME_TO_SOCKADDR_PF(host, pf, serv, sock, res) \
     do { \
        int _aierr; \
-       _aierr = hostname_to_sockaddr((host), (serv), (sock), (res)); \
+       _aierr = hostname_to_sockaddr_pf((host), (pf), (serv), (sock), (res)); \
        if (_aierr) \
-           msg_fatal("hostname_to_sockaddr: %s", MAI_STRERROR(_aierr)); \
+           msg_fatal("hostname_to_sockaddr_pf: %s", MAI_STRERROR(_aierr)); \
     } while (0)
 
+#define HOSTNAME_TO_SOCKADDR(host, serv, sock, res) \
+       HOSTNAME_TO_SOCKADDR_PF((host), PF_UNSPEC, (serv), (sock), (res))
+
 #define HOSTADDR_TO_SOCKADDR(host, serv, sock, res) \
     do { \
        int _aierr; \
index 2e1f0a0682cd77125ba417947be128c7023c0fc1..67ebca6d6de62275faa8deb5518d353cdeec09ac 100644 (file)
 /*     ssize_t vstream_peek(stream)
 /*     VSTREAM *stream;
 /*
+/*     const char *vstream_peek_data(stream)
+/*     VSTREAM *stream;
+/*
 /*     int     vstream_setjmp(stream)
 /*     VSTREAM *stream;
 /*
 /*     read from the named stream without refilling the read buffer.
 /*     This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND).
 /*
+/*     vstream_peek_data() returns a pointer to the unread bytes
+/*     that exist according to vstream_peek().
+/*
 /*     vstream_setjmp() saves processing context and makes that context
 /*     available for use with vstream_longjmp().  Normally, vstream_setjmp()
 /*     returns zero.  A non-zero result means that vstream_setjmp() returned
@@ -1502,3 +1508,16 @@ ssize_t vstream_peek(VSTREAM *vp)
        return (0);
     }
 }
+
+/* vstream_peek_data - peek at unread data */
+
+const char *vstream_peek_data(VSTREAM *vp)
+{
+    if (vp->buf.flags & VSTREAM_FLAG_READ) {
+       return (vp->buf.ptr);
+    } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
+       return (vp->read_buf.ptr);
+    } else {
+       return (0);
+    }
+}
index 20b983e633ea365bcc3a7f4263776b19cd91ad9f..448d2f5bab8fe43614a8df1a1f1767903f32f2c8 100644 (file)
@@ -179,6 +179,8 @@ extern ssize_t vstream_bufstat(VSTREAM *, int);
 
 #define vstream_peek(vp) vstream_bufstat((vp), VSTREAM_BST_IN_PEND)
 
+extern const char *vstream_peek_data(VSTREAM *);
+
  /*
   * Exception handling. We use pointer to jmp_buf to avoid a lot of unused
   * baggage for streams that don't need this functionality.