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.
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.
I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
-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:
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
<h2> Introduction </h2>
<p> 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.
<li> <p> The <a href="cleanup.8.html">cleanup(8)</a> server implements the final processing
stage before mail is queued. It adds missing From: and other message
-headers, transforms addresses as described in the <a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a>
+headers, and transforms addresses as described in the
+<a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a>
document. Optionally, the <a href="cleanup.8.html">cleanup(8)</a> server can be configured to
do light-weight content inspection with regular expressions as
described in the <a href="BUILTIN_FILTER_README.html">BUILTIN_FILTER_README</a> document. The <a href="cleanup.8.html">cleanup(8)</a>
<b>x</b> (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 <b>#</b> outside
- a character class and the next newline character
- are ignored. An escaping backslash can be used to
- include a whitespace or <b>#</b> 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 <b>#</b><i>comment</i> after patterns.
<b>A</b> (default: off)
Toggles the PCRE_ANCHORED flag. When this flag is
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
<h2> Introduction </h2>
<p> 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.
<li> <p> 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)
# 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
* 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
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 */
0, 0,
};
SOCKOPT_SIZE optlen;
+ int sndbufsize;
const char *ehlo_words;
int discard_mask;
static const NAME_MASK pix_bug_table[] = {
* 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
/*
int except;
int rec_type;
NOCLOBBER int prev_type = 0;
- NOCLOBBER int sndbuffree;
NOCLOBBER int mail_from_rejected;
NOCLOBBER int downgrading;
int mime_errs;
#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
*/
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) {
/*
}
/*
- * 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.
* 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;
return (state->session = 0);
}
+ /*
+ * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
+ */
+ vstream_tweak_sock(session->stream);
+
/*
* Update the list of used cached addresses.
*/
} else
session->namaddrport = mystrdup(session->namaddr);
- session->sndbufsize = 0;
session->send_proto_helo = 0;
if (flags & SMTP_MISC_FLAG_CONN_STORE)
* 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.
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
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)) {
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.
* TLS initialization status.
*/
static TLS_APPL_STATE *smtpd_tls_ctx;
-static int require_server_cert;
+static int ask_client_cert;
#endif
* 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);
}
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");
}
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.
* 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];
/* const char *format;
/* va_list *ap;
/*
+/* ssize_t vstream_bufstat(stream, command)
+/* VSTREAM *stream;
+/* int command;
+/*
/* ssize_t vstream_peek(stream)
/* VSTREAM *stream;
/*
/* 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()
* 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,
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)
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