Bugfix: when <unistd.h> is included, read is a reserved
identifier. File: smtpstone/smtp-source.c.
+20050317
+
+ Cleanup: change wording of error message when an IPv6 address
+ is mistaken for maptype:mapname. File: util/dict_open.c.
+
+20050321
+
+ Robustness: don't look for SMTP status code when there was
+ none. File: smtp/smtp_chat.c, lmtp/lmtp_chat.c.
+
+ Portability: missing netinet/in.h include, so that ntohs()
+ was not defined on HP-UX. File: smtp/smtp_proto.c.
+
+20050327
+
+ Bugfix: the SMTP and LMTP clients did not ask the queue
+ manager to reduce destination concurrency when "lost
+ connection" or "connection timed out" happened AFTER Postfix
+ received the server greeting. Files: smtp/smtp_trouble.c,
+ lmtp/lmtp-trouble.c.
+
+20050328
+
+ Cleanup: the REPLACE action is no longer implemented as
+ PREPEND+IGNORE. The result remains in the input stream, and
+ is subject to address rewriting and other processing where
+ applicable. File: cleanup/cleanup_message.c.
-# HEADER_CHECKS(5) HEADER_CHECKS(5)
+# HEADER_CHECKS(5) HEADER_CHECKS(5)
#
# NAME
# header_checks - Postfix built-in header/body inspection
# line, immediately before the input that
# triggered the PREPEND action.
#
+# o The prepended text is not considered part of
+# the input stream: it is not subject to
+# header/body checks or address rewriting, and
+# it does not affect the way that Postfix adds
+# missing message headers.
+#
# o When prepending text before a message header
# line, the prepended text must begin with a
# valid message header label.
# Replace the current line with the specified text
# and inspect the next input line.
#
-# Note: when replacing a message header line, the
-# replacement text must begin with a valid header
-# label.
-#
# This feature is available in Postfix 2.2 and later.
+# The description below applies to Postfix 2.2.2 and
+# later.
+#
+# Notes:
+#
+# o When replacing a message header line, the
+# replacement text must begin with a valid
+# header label.
+#
+# o The replaced text remains part of the input
+# stream. Unlike the result from the PREPEND
+# action, a replaced message header may be
+# subject to address rewriting and may affect
+# the way that Postfix adds missing message
+# headers.
#
# REJECT optional text...
# Reject the entire message. Reply with optional
# P.O. Box 704
# Yorktown Heights, NY 10598, USA
#
-# HEADER_CHECKS(5)
+# HEADER_CHECKS(5)
-# VIRTUAL(5) VIRTUAL(5)
+# VIRTUAL(5) VIRTUAL(5)
#
# NAME
# virtual - Postfix virtual alias table format
# postmap -q - /etc/postfix/virtual <inputfile
#
# DESCRIPTION
-# The optional virtual(5) alias table specifies address
-# aliasing for arbitrary local or non-local recipient
-# addresses. Virtual aliasing is recursive, and is done by
-# the Postfix cleanup(8) daemon.
+# The optional virtual(5) alias table rewrites recipient
+# addresses for all local, virtual and remote mail destina-
+# tions. This is unlike the aliases(5) table which is used
+# only for local(8) delivery. Virtual aliasing is recur-
+# sive, and is implemented by the Postfix cleanup(8) daemon
+# before mail is queued.
#
# The main applications of virtual aliasing are:
#
# virtual_alias_maps = hash:/etc/postfix/virtual
#
# Note: some systems use dbm databases instead of hash.
-# See the output from "postconf -m" for available
-# database types.
+# See the output from "postconf -m" for available data-
+# base types.
#
# /etc/postfix/virtual:
# virtual-alias.domain anything (right-hand content does not matter)
# constituent parts, nor is user+foo broken up into user and
# foo.
#
-# Patterns are applied in the order as specified in the
-# table, until a pattern is found that matches the search
+# Patterns are applied in the order as specified in the ta-
+# ble, until a pattern is found that matches the search
# string.
#
# Results are the same as with indexed file lookups, with
# TCP-BASED TABLES
# This section describes how the table lookups change when
# lookups are directed to a TCP-based server. For a descrip-
-# tion of the TCP client/server lookup protocol, see
-# tcp_table(5). This feature is not available up to and
-# including Postfix version 2.2.
+# tion of the TCP client/server lookup protocol, see tcp_ta-
+# ble(5). This feature is not available up to and including
+# Postfix version 2.2.
#
# Each lookup operation uses the entire address once. Thus,
# user@domain mail addresses are not broken up into their
# P.O. Box 704
# Yorktown Heights, NY 10598, USA
#
-# VIRTUAL(5)
+# VIRTUAL(5)
line, immediately before the input that
triggered the <b>PREPEND</b> action.
+ <b>o</b> The prepended text is not considered part of
+ the input stream: it is not subject to
+ header/body checks or address rewriting, and
+ it does not affect the way that Postfix adds
+ missing message headers.
+
<b>o</b> When prepending text before a message header
line, the prepended text must begin with a
valid message header label.
Replace the current line with the specified text
and inspect the next input line.
- Note: when replacing a message header line, the
- replacement text must begin with a valid header
- label.
-
This feature is available in Postfix 2.2 and later.
+ The description below applies to Postfix 2.2.2 and
+ later.
+
+ Notes:
+
+ <b>o</b> When replacing a message header line, the
+ replacement text must begin with a valid
+ header label.
+
+ <b>o</b> The replaced text remains part of the input
+ stream. Unlike the result from the <b>PREPEND</b>
+ action, a replaced message header may be
+ subject to address rewriting and may affect
+ the way that Postfix adds missing message
+ headers.
<b>REJECT</b> <i>optional text...</i>
Reject the entire message. Reply with <i>optional</i>
<b>postmap -q - /etc/postfix/virtual</b> <<i>inputfile</i>
<b>DESCRIPTION</b>
- The optional <a href="virtual.5.html"><b>virtual</b>(5)</a> alias table specifies address
- aliasing for arbitrary local or non-local recipient
- addresses. Virtual aliasing is recursive, and is done by
- the Postfix <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon.
+ The optional <a href="virtual.5.html"><b>virtual</b>(5)</a> alias table rewrites recipient
+ addresses for all local, virtual and remote mail destina-
+ tions. This is unlike the <a href="aliases.5.html"><b>aliases</b>(5)</a> table which is used
+ only for <a href="local.8.html"><b>local</b>(8)</a> delivery. Virtual aliasing is recur-
+ sive, and is implemented by the Postfix <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon
+ before mail is queued.
The main applications of virtual aliasing are:
The prepended text is output on a separate line, immediately
before the input that triggered the \fBPREPEND\fR action.
.IP \(bu
+The prepended text is not considered part of the input
+stream: it is not subject to header/body checks or address
+rewriting, and it does not affect the way that Postfix adds
+missing message headers.
+.IP \(bu
When prepending text before a message header line, the prepended
text must begin with a valid message header label.
.IP \(bu
Replace the current line with the specified text and inspect the next
input line.
.sp
-Note: when replacing a message header line, the replacement text
-must begin with a valid header label.
+This feature is available in Postfix 2.2 and later. The
+description below applies to Postfix 2.2.2 and later.
.sp
-This feature is available in Postfix 2.2 and later.
+Notes:
+.RS
+.IP \(bu
+When replacing a message header line, the replacement text
+must begin with a valid header label.
+.IP \(bu
+The replaced text remains part of the input stream. Unlike
+the result from the \fBPREPEND\fR action, a replaced message
+header may be subject to address rewriting and may affect
+the way that Postfix adds missing message headers.
+.RE
.IP "\fBREJECT \fIoptional text...\fR
Reject the entire message. Reply with \fIoptional text...\fR when
the optional text is specified, otherwise reply with a generic error
.SH DESCRIPTION
.ad
.fi
-The optional \fBvirtual\fR(5) alias table specifies address aliasing
-for arbitrary local or non-local recipient addresses. Virtual aliasing
-is recursive, and is done by the Postfix \fBcleanup\fR(8) daemon.
+The optional \fBvirtual\fR(5) alias table rewrites recipient
+addresses for all local, virtual and remote mail destinations.
+This is unlike the \fBaliases\fR(5) table which is used
+only for \fBlocal\fR(8) delivery. Virtual aliasing is
+recursive, and is implemented by the Postfix \fBcleanup\fR(8)
+daemon before mail is queued.
The main applications of virtual aliasing are:
.IP \(bu
# The prepended text is output on a separate line, immediately
# before the input that triggered the \fBPREPEND\fR action.
# .IP \(bu
+# The prepended text is not considered part of the input
+# stream: it is not subject to header/body checks or address
+# rewriting, and it does not affect the way that Postfix adds
+# missing message headers.
+# .IP \(bu
# When prepending text before a message header line, the prepended
# text must begin with a valid message header label.
# .IP \(bu
# Replace the current line with the specified text and inspect the next
# input line.
# .sp
-# Note: when replacing a message header line, the replacement text
-# must begin with a valid header label.
+# This feature is available in Postfix 2.2 and later. The
+# description below applies to Postfix 2.2.2 and later.
# .sp
-# This feature is available in Postfix 2.2 and later.
+# Notes:
+# .RS
+# .IP \(bu
+# When replacing a message header line, the replacement text
+# must begin with a valid header label.
+# .IP \(bu
+# The replaced text remains part of the input stream. Unlike
+# the result from the \fBPREPEND\fR action, a replaced message
+# header may be subject to address rewriting and may affect
+# the way that Postfix adds missing message headers.
+# .RE
# .IP "\fBREJECT \fIoptional text...\fR
# Reject the entire message. Reply with \fIoptional text...\fR when
# the optional text is specified, otherwise reply with a generic error
#
# \fBpostmap -q - /etc/postfix/virtual <\fIinputfile\fR
# DESCRIPTION
-# The optional \fBvirtual\fR(5) alias table specifies address aliasing
-# for arbitrary local or non-local recipient addresses. Virtual aliasing
-# is recursive, and is done by the Postfix \fBcleanup\fR(8) daemon.
+# The optional \fBvirtual\fR(5) alias table rewrites recipient
+# addresses for all local, virtual and remote mail destinations.
+# This is unlike the \fBaliases\fR(5) table which is used
+# only for \fBlocal\fR(8) delivery. Virtual aliasing is
+# recursive, and is implemented by the Postfix \fBcleanup\fR(8)
+# daemon before mail is queued.
#
# The main applications of virtual aliasing are:
# .IP \(bu
/* cleanup_act - act upon a header/body match */
-static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf,
- const char *value, const char *map_class)
+static const char *cleanup_act(CLEANUP_STATE *state, char *context,
+ const char *buf, const char *value,
+ const char *map_class)
{
const char *optional_text = value + strcspn(value, " \t");
int command_len = optional_text - value;
- VSTRING *bp;
while (*optional_text && ISSPACE(*optional_text))
optional_text++;
#define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
-#define CLEANUP_ACT_KEEP 1
#define CLEANUP_ACT_DROP 0
if (STREQUAL(value, "REJECT", command_len)) {
state->errs |= CLEANUP_STAT_CONT;
state->flags &= ~CLEANUP_FLAG_FILTER;
cleanup_act_log(state, "reject", context, buf, state->reason);
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
if (STREQUAL(value, "WARN", command_len)) {
cleanup_act_log(state, "warning", context, buf, optional_text);
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
if (STREQUAL(value, "FILTER", command_len)) {
if (*optional_text == 0) {
msg_warn("missing FILTER command argument in %s map", map_class);
} else if (strchr(optional_text, ':') == 0) {
- msg_warn("bad FILTER command %s in %s, need transport:destination",
+ msg_warn("bad FILTER command %s in %s -- "
+ "need transport:destination",
optional_text, map_class);
} else {
if (state->filter)
state->filter = mystrdup(optional_text);
cleanup_act_log(state, "filter", context, buf, optional_text);
}
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
if (STREQUAL(value, "DISCARD", command_len)) {
cleanup_act_log(state, "discard", context, buf, optional_text);
state->flags |= CLEANUP_FLAG_DISCARD;
state->flags &= ~CLEANUP_FLAG_FILTER;
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
if (STREQUAL(value, "HOLD", command_len)) {
cleanup_act_log(state, "hold", context, buf, optional_text);
state->flags |= CLEANUP_FLAG_HOLD;
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
if (STREQUAL(value, "PREPEND", command_len)) {
if (*optional_text == 0) {
msg_warn("PREPEND action without text in %s map", map_class);
} else if (strcmp(context, CLEANUP_ACT_CTXT_HEADER) == 0
&& !is_header(optional_text)) {
- msg_warn("bad PREPEND header text \"%s\" in %s map, "
+ msg_warn("bad PREPEND header text \"%s\" in %s map -- "
"need \"headername: headervalue\"",
optional_text, map_class);
} else {
cleanup_act_log(state, "prepend", context, buf, optional_text);
cleanup_out_string(state, REC_TYPE_NORM, optional_text);
}
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
if (STREQUAL(value, "REPLACE", command_len)) {
if (*optional_text == 0) {
msg_warn("REPLACE action without text in %s map", map_class);
- return (CLEANUP_ACT_KEEP);
- } else if (strcmp(context, CLEANUP_ACT_CTXT_HEADER) == 0) {
- if (!is_header(optional_text)) {
- msg_warn("bad REPLACE header text \"%s\" in %s map, "
- "need \"headername: headervalue\"",
- optional_text, map_class);
- return (CLEANUP_ACT_KEEP);
- }
- /* XXX Impedance mismatch. */
- bp = vstring_strcpy(vstring_alloc(100), optional_text);
- cleanup_out_header(state, bp);
- vstring_free(bp);
+ return (buf);
+ } else if (strcmp(context, CLEANUP_ACT_CTXT_HEADER) == 0
+ && !is_header(optional_text)) {
+ msg_warn("bad REPLACE header text \"%s\" in %s map -- "
+ "need \"headername: headervalue\"",
+ optional_text, map_class);
+ return (buf);
} else {
- cleanup_out_string(state, REC_TYPE_NORM, optional_text);
+ cleanup_act_log(state, "replace", context, buf, optional_text);
+ return (mystrdup(optional_text));
}
- cleanup_act_log(state, "replace", context, buf, optional_text);
- return (CLEANUP_ACT_DROP);
}
if (STREQUAL(value, "REDIRECT", command_len)) {
if (strchr(optional_text, '@') == 0) {
- msg_warn("bad REDIRECT target \"%s\" in %s map, need user@domain",
+ msg_warn("bad REDIRECT target \"%s\" in %s map -- "
+ "need user@domain",
optional_text, map_class);
} else {
if (state->redirect)
cleanup_act_log(state, "redirect", context, buf, optional_text);
state->flags &= ~CLEANUP_FLAG_FILTER;
}
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
/* Allow and ignore optional text after the action. */
return (CLEANUP_ACT_DROP);
if (STREQUAL(value, "DUNNO", command_len)) /* preferred */
- return (CLEANUP_ACT_KEEP);
+ return (buf);
if (STREQUAL(value, "OK", command_len)) /* compat */
- return (CLEANUP_ACT_KEEP);
+ return (buf);
msg_warn("unknown command in %s map: %s", map_class, value);
- return (CLEANUP_ACT_KEEP);
+ return (buf);
}
/* cleanup_header_callback - process one complete header line */
const char *value;
if ((value = maps_find(checks, header, 0)) != 0) {
- if (cleanup_act(state, CLEANUP_ACT_CTXT_HEADER,
- header, value, map_class)
- == CLEANUP_ACT_DROP)
+ const char *result;
+
+ if ((result = cleanup_act(state, CLEANUP_ACT_CTXT_HEADER,
+ header, value, map_class))
+ == CLEANUP_ACT_DROP) {
return;
+ } else if (result != header) {
+ vstring_strcpy(header_buf, result);
+ hdr_opts = header_opts_find(result);
+ myfree((char *) result);
+ }
}
}
const char *value;
if ((value = maps_find(cleanup_body_checks, buf, 0)) != 0) {
- if (cleanup_act(state, CLEANUP_ACT_CTXT_BODY,
- buf, value, VAR_BODY_CHECKS)
- == CLEANUP_ACT_DROP)
+ const char *result;
+
+ if ((result = cleanup_act(state, CLEANUP_ACT_CTXT_BODY,
+ buf, value, VAR_BODY_CHECKS))
+ == CLEANUP_ACT_DROP) {
return;
+ } else if (result != buf) {
+ cleanup_out(state, type, result, strlen(result));
+ myfree((char *) result);
+ return;
+ }
}
}
cleanup_out(state, type, buf, len);
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
-#define MAIL_RELEASE_DATE "20050315"
-#define MAIL_VERSION_NUMBER "2.2.1"
+#define MAIL_RELEASE_DATE "20050401"
+#define MAIL_VERSION_NUMBER "2.2.2"
#define VAR_MAIL_VERSION "mail_version"
#ifdef SNAPSHOT
static LMTP_RESP rdata;
char *cp;
int last_char;
+ int three_digs = 0;
/*
* Initialize the response data buffer.
*/
for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++)
/* void */ ;
- if (cp - STR(state->buffer) == 3) {
+ if ((three_digs = (cp - STR(state->buffer) == 3)) != 0) {
if (*cp == '-')
continue;
if (*cp == ' ' || *cp == 0)
}
state->error_mask |= MAIL_ERROR_PROTOCOL;
}
- rdata.code = atoi(STR(state->buffer));
+ if (three_digs != 0)
+ rdata.code = atoi(STR(state->buffer));
+ else
+ rdata.code = 0;
VSTRING_TERMINATE(rdata.buf);
rdata.str = STR(rdata.buf);
return (&rdata);
request->arrival_time,
"%s", vstring_str(why));
}
+ if (request->hop_status == 0)
+ request->hop_status = mystrdup(vstring_str(why));
/*
* Cleanup.
freeaddrinfo(res0);
if (found == 0) {
vstring_sprintf(why, "%s: host not found", host);
- smtp_errno = SMTP_ERR_FAIL;
+ if (smtp_errno != SMTP_ERR_RETRY)
+ smtp_errno = SMTP_ERR_FAIL;
}
return (addr_list);
}
static SMTP_RESP rdata;
char *cp;
int last_char;
+ int three_digs = 0;
/*
* Initialize the response data buffer.
*/
for (cp = STR(session->buffer); *cp && ISDIGIT(*cp); cp++)
/* void */ ;
- if (cp - STR(session->buffer) == 3) {
+ if ((three_digs = (cp - STR(session->buffer) == 3)) != 0) {
if (*cp == '-')
continue;
if (*cp == ' ' || *cp == 0)
}
session->error_mask |= MAIL_ERROR_PROTOCOL;
}
- rdata.code = atoi(STR(session->buffer));
+ if (three_digs != 0)
+ rdata.code = atoi(STR(session->buffer));
+ else
+ rdata.code = 0;
VSTRING_TERMINATE(rdata.buf);
rdata.str = STR(rdata.buf);
return (&rdata);
#include <sys_defs.h>
#include <sys/stat.h>
#include <sys/socket.h> /* shutdown(2) */
+#include <netinet/in.h> /* ntohs() */
#include <string.h>
#include <unistd.h>
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
/*
* Per-site policies can override main.cf settings.
- *
- * XXX 200412 This does not work as some people may expect. A policy that
- * specifies "use TLS" in a policy file while TLS is turned off in main.cf
- * cannot work, because there is no OpenSSL context for creating sessions
- * (that context exists only if TLS is enabled via main.cf settings; the
- * OpenSSL context is created at process initialization time and cannot be
- * created on the fly).
*/
typedef struct {
int dont_use; /* don't use TLS */
"%s", vstring_str(why));
SMTP_RCPT_DROP(state, rcpt);
}
+ /* XXX This assumes no fall-back relay. */
+ if (request->hop_status == 0)
+ request->hop_status = mystrdup(vstring_str(why));
}
/*
DICT *dict;
if ((dict_name = split_at(saved_dict_spec, ':')) == 0)
- msg_fatal("open dictionary: need \"type:name\" form instead of: \"%s\"",
+ msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s\"",
dict_spec);
dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags);
DICT_OPEN_INFO *dp;
DICT *dict;
+ if (*dict_type == 0 || *dict_name == 0)
+ msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s:%s\"",
+ dict_type, dict_name);
if (dict_open_hash == 0)
dict_open_init();
if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0)