diff --git a/postfix/HISTORY b/postfix/HISTORY index 8fbc67cfe..859cb3b75 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -14745,8 +14745,8 @@ Apologies for any names omitted. Feature: smtp_sasl_tls_verified_security_options is no longer #ifdef SNAPSHOT. - Feature: elliptic curve support. This requires OpenSSL version - 0.9.9 or later. Victor Duchovni. Files: TLS_README, + Feature: elliptic curve support. This requires OpenSSL + version 0.9.9 or later. Victor Duchovni. Files: TLS_README, smtpd/smtpd.c, smtp/smtp.c, tls/tls_dh.c, tls/tls_certkey.c, tls/tls_server.c, tls/tls_client.c, tls/tls.h, tls/tls_misc.c. @@ -14757,3 +14757,29 @@ Apologies for any names omitted. 20081109 Cleanup: confusing names of variables. File: smtpd/smtpd.c. + +20081126 + + Bugfix: pcre_table(5) incorrectly claimed that the 'x' flag + supports #comment after text. File: proto/pcre_table. + +20081202 + + Cleanup: vstream_bufstat() provides a more systematic + approach to get information about VSTREAM buffers. The + vstream_peek() function is now a backwards compatibility + wrapper. Files: util/vstream.[hc]. + + Cleanup: the SMTP server should warn about "lost connection + after QUIT" only when the "." reply was pipelined together + with the "QUIT" reply. File: smtpd/smtpd.c. + + Cleanup: the SMTP client's code was duplicating buffer + management that was already done in the VSTREAM module. + File: smtp/smtp_proto.c. + +20081203 + + Cleanup: adjust the VSTREAM buffer strategy when reusing + an SMTP connection with a large TCP MSS value. File: + smtp/smtp_proto.c. diff --git a/postfix/README_FILES/OVERVIEW b/postfix/README_FILES/OVERVIEW index cc6e83222..2cfc28a9d 100644 --- a/postfix/README_FILES/OVERVIEW +++ b/postfix/README_FILES/OVERVIEW @@ -4,10 +4,10 @@ PPoossttffiixx AArrcchhiitteeccttuurree OOvveerrvviiee IInnttrroodduuccttiioonn -This document presents an overview of the Postfix architecture, and is the -place where you find a pointer to every Postfix command or server program. The -text gives the general context in which each command or server program is used, -and provides pointers to documents with specific usage examples and background +This document presents an overview of the Postfix architecture, and provides +pointers to descriptions of every Postfix command or server program. The text +gives the general context in which each command or server program is used, and +provides pointers to documents with specific usage examples and background information. Topics covered by this document: @@ -63,7 +63,7 @@ programs, while unnumbered names inside shaded areas represent Postfix queues. section), and postmaster notifications about problems with Postfix. * The cleanup(8) server implements the final processing stage before mail is - queued. It adds missing From: and other message headers, transforms + queued. It adds missing From: and other message headers, and transforms addresses as described in the ADDRESS_REWRITING_README document. Optionally, the cleanup(8) server can be configured to do light-weight content inspection with regular expressions as described in the diff --git a/postfix/html/OVERVIEW.html b/postfix/html/OVERVIEW.html index 693f082cc..5c8ff198f 100644 --- a/postfix/html/OVERVIEW.html +++ b/postfix/html/OVERVIEW.html @@ -21,7 +21,7 @@ Architecture Overview
This document presents an overview of the Postfix architecture, -and is the place where you find a pointer to every Postfix command +and provides pointers to descriptions of every Postfix command or server program. The text gives the general context in which each command or server program is used, and provides pointers to documents with specific usage examples and background information. @@ -173,7 +173,8 @@ notifications about problems with Postfix.
The cleanup(8) server implements the final processing stage before mail is queued. It adds missing From: and other message -headers, transforms addresses as described in the ADDRESS_REWRITING_README +headers, and transforms addresses as described in the +ADDRESS_REWRITING_README document. Optionally, the cleanup(8) server can be configured to do light-weight content inspection with regular expressions as described in the BUILTIN_FILTER_README document. The cleanup(8) diff --git a/postfix/html/pcre_table.5.html b/postfix/html/pcre_table.5.html index a80d3108e..9db86451e 100644 --- a/postfix/html/pcre_table.5.html +++ b/postfix/html/pcre_table.5.html @@ -110,12 +110,12 @@ PCRE_TABLE(5) PCRE_TABLE(5) x (default: off) Toggles the pcre extended flag. When this flag is - on, whitespace in the pattern (other than in a - character class) and characters between a # outside - a character class and the next newline character - are ignored. An escaping backslash can be used to - include a whitespace or # character as part of the - pattern. + on, whitespace characters in the pattern (other + than in a character class) are ignored. To include + a whitespace character as part of the pattern, + escape it with backslash. + + Note: do not use #comment after patterns. A (default: off) Toggles the PCRE_ANCHORED flag. When this flag is diff --git a/postfix/man/man5/pcre_table.5 b/postfix/man/man5/pcre_table.5 index c3c008fb1..f7b57a187 100644 --- a/postfix/man/man5/pcre_table.5 +++ b/postfix/man/man5/pcre_table.5 @@ -100,11 +100,11 @@ default, which is inconvenient for multi-line message header matching. .IP "\fBx\fR (default: off)" Toggles the pcre extended flag. When this flag is on, whitespace -in the pattern (other than in a character class) and -characters between a \fB#\fR outside a character class and -the next newline character are ignored. An escaping backslash -can be used to include a whitespace or \fB#\fR character -as part of the pattern. +characters in the pattern (other than in a character class) +are ignored. To include a whitespace character as part of +the pattern, escape it with backslash. +.sp +Note: do not use \fB#\fIcomment\fR after patterns. .IP "\fBA\fR (default: off)" Toggles the PCRE_ANCHORED flag. When this flag is on, the pattern is forced to be "anchored", that is, it is diff --git a/postfix/proto/OVERVIEW.html b/postfix/proto/OVERVIEW.html index 924f38695..6e25b064d 100644 --- a/postfix/proto/OVERVIEW.html +++ b/postfix/proto/OVERVIEW.html @@ -21,7 +21,7 @@ Architecture Overview
This document presents an overview of the Postfix architecture, -and is the place where you find a pointer to every Postfix command +and provides pointers to descriptions of every Postfix command or server program. The text gives the general context in which each command or server program is used, and provides pointers to documents with specific usage examples and background information. @@ -173,7 +173,8 @@ notifications about problems with Postfix.
The cleanup(8) server implements the final processing stage before mail is queued. It adds missing From: and other message -headers, transforms addresses as described in the ADDRESS_REWRITING_README +headers, and transforms addresses as described in the +ADDRESS_REWRITING_README document. Optionally, the cleanup(8) server can be configured to do light-weight content inspection with regular expressions as described in the BUILTIN_FILTER_README document. The cleanup(8) diff --git a/postfix/proto/pcre_table b/postfix/proto/pcre_table index 679e67ef7..3c21a4ade 100644 --- a/postfix/proto/pcre_table +++ b/postfix/proto/pcre_table @@ -90,11 +90,11 @@ # matching. # .IP "\fBx\fR (default: off)" # Toggles the pcre extended flag. When this flag is on, whitespace -# in the pattern (other than in a character class) and -# characters between a \fB#\fR outside a character class and -# the next newline character are ignored. An escaping backslash -# can be used to include a whitespace or \fB#\fR character -# as part of the pattern. +# characters in the pattern (other than in a character class) +# are ignored. To include a whitespace character as part of +# the pattern, escape it with backslash. +# .sp +# Note: do not use \fB#\fIcomment\fR after patterns. # .IP "\fBA\fR (default: off)" # Toggles the PCRE_ANCHORED flag. When this flag is on, # the pattern is forced to be "anchored", that is, it is diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 6af2aa16a..f1e7ab2f9 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "20081109" +#define MAIL_RELEASE_DATE "20081203" #define MAIL_VERSION_NUMBER "2.6" #ifdef SNAPSHOT diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index da3f3034b..d1ecf37fe 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -208,7 +208,6 @@ typedef struct SMTP_SESSION { int error_mask; /* error classes */ struct MIME_STATE *mime_state; /* mime state machine */ - int sndbufsize; /* PIPELINING buffer size */ int send_proto_helo; /* XFORWARD support */ time_t expire_time; /* session reuse expiration time */ diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index ab80bcc63..d79828fd8 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -274,6 +274,7 @@ int smtp_helo(SMTP_STATE *state) 0, 0, }; SOCKOPT_SIZE optlen; + int sndbufsize; const char *ehlo_words; int discard_mask; static const NAME_MASK pix_bug_table[] = { @@ -559,27 +560,24 @@ int smtp_helo(SMTP_STATE *state) * if we do. */ if (session->features & SMTP_FEATURE_PIPELINING) { - optlen = sizeof(session->sndbufsize); + optlen = sizeof(sndbufsize); if (getsockopt(vstream_fileno(session->stream), SOL_SOCKET, - SO_SNDBUF, (char *) &session->sndbufsize, &optlen) < 0) + SO_SNDBUF, (char *) &sndbufsize, &optlen) < 0) msg_fatal("%s: getsockopt: %m", myname); - if (session->sndbufsize > VSTREAM_BUFSIZE) - session->sndbufsize = VSTREAM_BUFSIZE; - if (session->sndbufsize == 0) { - session->sndbufsize = VSTREAM_BUFSIZE; + if (sndbufsize > VSTREAM_BUFSIZE) + sndbufsize = VSTREAM_BUFSIZE; + if (sndbufsize < VSTREAM_BUFSIZE) { + sndbufsize = VSTREAM_BUFSIZE; if (setsockopt(vstream_fileno(session->stream), SOL_SOCKET, - SO_SNDBUF, (char *) &session->sndbufsize, optlen) < 0) + SO_SNDBUF, (char *) &sndbufsize, optlen) < 0) msg_fatal("%s: setsockopt: %m", myname); } if (msg_verbose) msg_info("Using %s PIPELINING, TCP send buffer size is %d", (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP", - session->sndbufsize); - } else { - session->sndbufsize = 0; + sndbufsize); } - #ifdef USE_TLS /* @@ -1081,7 +1079,6 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, int except; int rec_type; NOCLOBBER int prev_type = 0; - NOCLOBBER int sndbuffree; NOCLOBBER int mail_from_rejected; NOCLOBBER int downgrading; int mime_errs; @@ -1131,20 +1128,6 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, #define CANT_RSET_THIS_SESSION \ (session->features |= SMTP_FEATURE_RSET_REJECTED) - /* - * Sanity check. We don't want smtp_chat() to inadvertently flush the - * output buffer. That means someone broke pipelining support. - */ - if (session->sndbufsize > VSTREAM_BUFSIZE) - msg_panic("bad sndbufsize %d > VSTREAM_BUFSIZE %d", - session->sndbufsize, VSTREAM_BUFSIZE); - - /* - * Miscellaneous initialization. Some of this might be done in - * smtp_xfer() but that just complicates interfaces and data structures. - */ - sndbuffree = session->sndbufsize; - /* * Pipelining support requires two loops: one loop for sending and one * for receiving. Each loop has its own independent state. Most of the @@ -1432,8 +1415,12 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, */ if (SENDER_IN_WAIT_STATE || (SENDER_IS_AHEAD - && (VSTRING_LEN(next_command) + 2 > sndbuffree - || time((time_t *) 0) - vstream_ftime(session->stream) > 10))) { + && ((session->features & SMTP_FEATURE_PIPELINING) == 0 + || (VSTRING_LEN(next_command) + 2 + + vstream_bufstat(session->stream, VSTREAM_BST_OUT_PEND) + > VSTREAM_BUFSIZE) + || time((time_t *) 0) + - vstream_ftime(session->stream) > 10))) { while (SENDER_IS_AHEAD) { /* @@ -1707,10 +1694,8 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, } /* - * At this point, the sender and receiver are fully synchronized, - * so that the entire TCP send buffer becomes available again. + * At this point, the sender and receiver are fully synchronized. */ - sndbuffree = session->sndbufsize; /* * We know the server response to every command that was sent. @@ -1874,8 +1859,6 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, * Copy the next command to the buffer and update the sender state. */ if (except == 0) { - if (sndbuffree > 0) - sndbuffree -= VSTRING_LEN(next_command) + 2; smtp_chat_cmd(session, "%s", vstring_str(next_command)); } else { DONT_CACHE_THIS_SESSION; diff --git a/postfix/src/smtp/smtp_reuse.c b/postfix/src/smtp/smtp_reuse.c index 1ed72d73b..0eb989f18 100644 --- a/postfix/src/smtp/smtp_reuse.c +++ b/postfix/src/smtp/smtp_reuse.c @@ -213,6 +213,11 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd, return (state->session = 0); } + /* + * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. + */ + vstream_tweak_sock(session->stream); + /* * Update the list of used cached addresses. */ diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index c87fe7535..1a0b15a75 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -585,7 +585,6 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest, } else session->namaddrport = mystrdup(session->namaddr); - session->sndbufsize = 0; session->send_proto_helo = 0; if (flags & SMTP_MISC_FLAG_CONN_STORE) @@ -695,13 +694,12 @@ int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, * XXX Be sure to use unsigned types in the format string. Sign characters * would be rejected by the alldig() test on the reading end. */ - vstring_sprintf(endp_prop, "%u\n%s\n%s\n%s\n%u\n%u\n%lu\n%u", + vstring_sprintf(endp_prop, "%u\n%s\n%s\n%s\n%u\n%u\n%lu", session->reuse_count, session->dest, session->host, session->addr, session->port, session->features & SMTP_FEATURE_ENDPOINT_MASK, - (long) session->expire_time, - session->sndbufsize); + (long) session->expire_time); /* * Append the passivated SASL attributes. @@ -740,7 +738,6 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop, unsigned features; /* server features */ time_t expire_time; /* session re-use expiration time */ unsigned reuse_count; /* # times reused */ - unsigned sndbufsize; /* PIPELINING buffer size */ /* * XXX it would be nice to have a VSTRING to VSTREAM adapter so that we @@ -790,12 +787,6 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop, expire_time = strtoul(prop, 0, 10); #endif - if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) { - msg_warn("%s: bad cached session sndbufsize property", myname); - return (0); - } - sndbufsize = atoi(prop); - if (dest_prop && VSTRING_LEN(dest_prop)) { dest_props = STR(dest_prop); if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) { @@ -815,14 +806,12 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop, session->features = (features | SMTP_FEATURE_FROM_CACHE); CACHE_THIS_SESSION_UNTIL(expire_time); session->reuse_count = ++reuse_count; - session->sndbufsize = sndbufsize; if (msg_verbose) msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, " - "ttl=%ld, reuse=%d, sndbuf=%u", + "ttl=%ld, reuse=%d", myname, dest, host, addr, ntohs(port), features, - (long) (expire_time - time((time_t *) 0)), reuse_count, - sndbufsize); + (long) (expire_time - time((time_t *) 0)), reuse_count); /* * Re-activate the SASL attributes. diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 9b844ae52..204fc838c 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1266,7 +1266,7 @@ MILTERS *smtpd_milters; * TLS initialization status. */ static TLS_APPL_STATE *smtpd_tls_ctx; -static int require_server_cert; +static int ask_client_cert; #endif @@ -3286,7 +3286,8 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg * XXX When this was added in Postfix 2.1 we used vstream_fflush(). As of * Postfix 2.3 we use smtp_flush() for better error reporting. */ - smtp_flush(state->client); + if (vstream_bufstat(state->client, VSTREAM_BST_OUT_PEND) > 0) + smtp_flush(state->client); return (0); } @@ -3857,7 +3858,7 @@ static void smtpd_start_tls(SMTPD_STATE *state) ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_excl_ciph); if (enforce_tls) ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_mand_excl); - if (require_server_cert) + if (ask_client_cert) ADD_EXCLUDE(cipher_exclusions, "aNULL"); } @@ -4645,7 +4646,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) const char *cert_file; int have_server_cert; int no_server_cert_ok; - int ask_client_cert; + int require_server_cert; /* * Can't use anonymous ciphers if we want client certificates. diff --git a/postfix/src/util/myaddrinfo.h b/postfix/src/util/myaddrinfo.h index c567eb7d0..766eed27a 100644 --- a/postfix/src/util/myaddrinfo.h +++ b/postfix/src/util/myaddrinfo.h @@ -130,6 +130,13 @@ extern char *gai_strerror(int); * Routines and data structures to hide some of the complexity of the * addrinfo API. They still don't hide that we may get results for address * families that we aren't interested in. + * + * Note: the getnameinfo() and inet_ntop() system library functions use unsafe + * APIs with separate pointer and length arguments. To avoid buffer overflow + * problems with these functions, Postfix uses pointers to structures + * internally. This way the compiler can enforce that callers provide + * buffers with the appropriate length, instead of having to trust that + * callers will never mess up some length calculation. */ typedef struct { char buf[MAI_HOSTNAME_STRSIZE]; diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index b3b9fce56..299899795 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -101,6 +101,10 @@ /* const char *format; /* va_list *ap; /* +/* ssize_t vstream_bufstat(stream, command) +/* VSTREAM *stream; +/* int command; +/* /* ssize_t vstream_peek(stream) /* VSTREAM *stream; /* @@ -320,8 +324,18 @@ /* vstream_vfprintf() provides an alternate interface /* for formatting an argument list according to a format string. /* +/* vstream_bufstat() provides input and output buffer status +/* information. The command is one of the following: +/* .IP VSTREAM_BST_IN_PEND +/* Return the number of characters that can be read without +/* refilling the read buffer. +/* .IP VSTREAM_BST_OUT_PEND +/* Return the number of characters that are waiting in the +/* write buffer. +/* .PP /* vstream_peek() returns the number of characters that can be /* read from the named stream without refilling the read buffer. +/* This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND). /* /* vstream_setjmp() saves processing context and makes that context /* available for use with vstream_longjmp(). Normally, vstream_setjmp() @@ -703,8 +717,10 @@ static int vstream_buf_get_ready(VBUF *bp) * allocation gives the application a chance to override the default * buffering policy. */ - if (bp->data == 0) - vstream_buf_alloc(bp, VSTREAM_BUFSIZE); + if (stream->req_bufsize == 0) + stream->req_bufsize = VSTREAM_BUFSIZE; + if (bp->len < stream->req_bufsize) + vstream_buf_alloc(bp, stream->req_bufsize); /* * If the stream is double-buffered and the write buffer is not empty, @@ -1306,6 +1322,47 @@ VSTREAM *vstream_vfprintf(VSTREAM *vp, const char *format, va_list ap) return (vp); } +/* vstream_bufstat - get stream buffer status */ + +ssize_t vstream_bufstat(VSTREAM *vp, int command) +{ + VBUF *bp; + + switch (command & VSTREAM_BST_MASK_DIR) { + case VSTREAM_BST_FLAG_IN: + if (vp->buf.flags & VSTREAM_FLAG_READ) { + bp = &vp->buf; + } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) { + bp = &vp->read_buf; + } else { + bp = 0; + } + switch (command & ~VSTREAM_BST_MASK_DIR) { + case VSTREAM_BST_FLAG_PEND: + return (bp ? -bp->cnt : 0); + /* Add other requests below. */ + } + break; + case VSTREAM_BST_FLAG_OUT: + if (vp->buf.flags & VSTREAM_FLAG_WRITE) { + bp = &vp->buf; + } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) { + bp = &vp->write_buf; + } else { + bp = 0; + } + switch (command & ~VSTREAM_BST_MASK_DIR) { + case VSTREAM_BST_FLAG_PEND: + return (bp ? bp->len - bp->cnt : 0); + /* Add other requests below. */ + } + break; + } + msg_panic("vstream_bufstat: unknown command: %d", command); +} + +#undef vstream_peek /* API binary compatibility. */ + /* vstream_peek - peek at a stream */ ssize_t vstream_peek(VSTREAM *vp) diff --git a/postfix/src/util/vstream.h b/postfix/src/util/vstream.h index 845be337f..7695c2302 100644 --- a/postfix/src/util/vstream.h +++ b/postfix/src/util/vstream.h @@ -154,6 +154,17 @@ extern int vstream_pclose(VSTREAM *); extern VSTREAM *vstream_vfprintf(VSTREAM *, const char *, va_list); extern ssize_t vstream_peek(VSTREAM *); +extern ssize_t vstream_bufstat(VSTREAM *, int); + +#define VSTREAM_BST_FLAG_IN (1<<0) +#define VSTREAM_BST_FLAG_OUT (1<<1) +#define VSTREAM_BST_FLAG_PEND (1<<2) + +#define VSTREAM_BST_MASK_DIR (VSTREAM_BST_FLAG_IN | VSTREAM_BST_FLAG_OUT) +#define VSTREAM_BST_IN_PEND (VSTREAM_BST_FLAG_IN | VSTREAM_BST_FLAG_PEND) +#define VSTREAM_BST_OUT_PEND (VSTREAM_BST_FLAG_OUT | VSTREAM_BST_FLAG_PEND) + +#define vstream_peek(vp) vstream_bufstat((vp), VSTREAM_BST_IN_PEND) /* * Exception handling. We use pointer to jmp_buf to avoid a lot of unused