legitimate configurations that deliver mail to a symbolic
link in a directory with less restrictive permissions.
+20080815
+
+ Feature: the milter_default_action parameter now accepts
+ the "quarantine" action. This works like "accept" but also
+ freezes the mail in the "hold" queue. File: milter/milter8.c.
+
+ Robustness: transition from setjmp()/longjmp() to the signal
+ mask saving/restoring versions sigsetjmp()/siglongjmp().
+ These functions have been around for 15 years, but they
+ have had bugs on supported platforms, so makedefs tests for
+ them. Files: makedefs, util/sys_defs.h, util/vstream.h.
+
+20080822
+
+ Cleanup: the proxymap_service_name and proxywrite_service_name
+ parameters make the proxymap service names configurable.
+ This paves the way for a future option where the proxymap
+ services are accessible via TCP so that they can be shared
+ among multiple Postfix hosts. File: global/dict_proxy.c.
+
+ Feature: MacOS X support for kqueue style event handling,
+ with workaround for broken MacOS X versions. Files:
+ util/sys_defs.h, makedefs.
+
+ Cleanup: the makedefs script now keeps its test programs
+ in a directory makedefs.d, instead of inlining them as
+ fragile "here documents". Files: makedefs, makedefs.d/*.
+
+20080823
+
+ Feature: IPv6 dns blocklist lookup. File: smtpd/smtpd_check.c.
+
+20080824
+
+ Cleanup: untangled the MacOS X version dependent sections
+ in the makedefs script, to make future updates easier. File:
+ makedefs.
+
+ Cleanup: don't log multiple Milter "hold" actions for
+ the same message. File: cleanup/cleanup_milter.c.
application errors. The default action is to respond with a temporary error
status, so that the client will try again later. Specify "accept" if you want
to receive mail as if the filter does not exist, and "reject" to reject mail
-with a permanent status.
+with a permanent status. The "quarantine" action is like "accept" but freezes
+the message in the "hold" queue, and is available with Postfix 2.6 or later.
/etc/postfix/main.cf:
- # What to do in case of errors? Specify accept, reject, or tempfail.
+ # What to do in case of errors? Specify accept, reject, tempfail,
+ # or quarantine (Postfix 2.6 or later).
milter_default_action = tempfail
M\bMi\bil\blt\bte\ber\br p\bpr\bro\bot\bto\boc\bco\bol\bl v\bve\ber\brs\bsi\bio\bon\bn
Postfix 2.1), and tell users to connect to this instead of the public SMTP
service.
+ o NOTE: Broken DNS configurations also cause lengthy delays before
+ Postfix sends "220 hostname.example.com ...". In this case the delay
+ happens even when Postfix is not busy.
+
* The Postfix SMTP server logs an increased number of "lost connection after
CONNECT" events. This happens because remote SMTP clients disconnect before
Postfix answers the connection.
+ o NOTE: A portscan for open SMTP ports also results in "lost connection
+ ..." logfile messages.
+
* Postfix 2.3 and later logs a warning that all server ports are busy:
Oct 3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
condition, increase the process count in master.cf or reduce the
service time per client
-NOTE: The first two symptoms may also happen without overload, for example:
-
- * Broken DNS also causes lengthy delays before "220 hostname.example.com ..."
- while the Postfix SMTP server tries to look up the client's hostname.
-
- * A portscan for open SMTP ports also results in "lost connection ..."
- logfile messages.
-
Legitimate mail that doesn't get through during an episode of overload is not
necessarily lost. It should still arrive once the situation returns to normal,
as long as the overload condition is temporary.
Linux epoll(4), or Solaris /dev/poll).
* You can reduce the Postfix memory footprint by using cdb: lookup tables
- instead of Berkeley DB.
+ instead of Berkeley DB's hash: or btree: tables.
1 /etc/postfix/main.cf:
2 # Raise the global process limit, 100 since Postfix 2.0.
the SMTP server's "maxproc" field in master.cf, SMTP server processes will
report problems when connecting to policy server processes, because there
aren't enough of them. Examples of errors are "connection refused" or
- "operation timed out". To fix, edit master.cf and specify a zero "maxproc"
- field in all policy server entries; see line 6 in the example below. Issue
- a "postfix reload" command to make the change effective.
+ "operation timed out".
+
+ To fix, edit master.cf and specify a zero "maxproc" field in all policy
+ server entries; see line 6 in the example below. Issue a "postfix reload"
+ command to make the change effective.
1 /etc/postfix/master.cf:
2 # =============================================================
When increasing the number of SMTP server processes is not practical, you can
improve Postfix server responsiveness by eliminating unnecessary work. When
Postfix spends less time per SMTP session, the same number of SMTP server
-processes can service more clients in the same amount of time.
+processes can service more clients.
* Eliminate non-functional RBL lookups (blocklists that are no longer in
operation). These lookups can degrade performance. Postfix logs a warning
The mail_release_date configuration parameter (format: yyyymmdd)
specifies the release date of a stable release or snapshot release.
+Incompatibility with snapshot 20080814
+======================================
+
+When a mailbox file is not owned by its recipient, the local and
+virtual delivery agents now log a warning and defer delivery.
+Specify "strict_mailbox_ownership = no" to ignore such ownership
+discrepancies.
+
Incompatibility with snapshot 20080629
======================================
Wish list:
-
+
Force a panic when the VDA patch reduces the file size limit
under the message size. They break the code that marks a
recipient as "done", when that recipient was added late
that it makes smtpd_mumble_restrictions available for local
and remote mail; the disadvantage is that it makes local
submissions more dependent on networking. One possibility
- is to use "pickup -o content_filter=smtp:127.0.0.1". Another
- is to have the pickup or cleanup server drive an SMTP client
- directly; this would require extension of the mail_stream()
- interface, plus a way to handle bounced/deferred recipients
- intelligently.
+ is to use "pickup -o content_filter=smtp:127.0.0.1:10025";
+ we could also to suppress "mail loop" detection for loopback
+ connections. Another is to have the pickup or cleanup
+ server drive an SMTP client directly; this would require
+ extension of the mail_stream() interface, plus a way to
+ handle bounced/deferred recipients intelligently.
Consolidate duplicated code in *_server_accept_{pass,inet}().
temporary error status, so that the client will try again later.
Specify "accept" if you want to receive mail as if the filter does
not exist, and "reject" to reject mail with a permanent status.
+The "quarantine" action is like "accept" but freezes the message
+in the "<a href="QSHAPE_README.html#hold_queue">hold" queue</a>, and is available with Postfix 2.6 or later.
</p>
<blockquote>
<pre>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
- # What to do in case of errors? Specify accept, reject, or tempfail.
+ # What to do in case of errors? Specify accept, reject, tempfail,
+ # or quarantine (Postfix 2.6 or later).
<a href="postconf.5.html#milter_default_action">milter_default_action</a> = tempfail
</pre>
</blockquote>
entry in <a href="master.5.html">master.cf</a> (present since Postfix 2.1), and tell users to
connect to this instead of the public SMTP service. </p>
+<ul>
+
+<li> <p> NOTE: Broken DNS configurations also cause lengthy delays
+before Postfix sends "220 hostname.example.com ...". In this case
+the delay happens even when Postfix is not busy. </p>
+
+</ul>
+
<li> <p> The Postfix SMTP server logs an increased number of "lost
connection after CONNECT" events. This happens because remote SMTP
clients disconnect before Postfix answers the connection. </p>
+<ul>
+
+<li> <p> NOTE: A portscan for open SMTP ports also results in "lost
+connection ..." logfile messages. </p>
+
+</ul>
+
<li> <p> Postfix 2.3 and later logs a warning that all server ports
are busy: </p>
</ul>
-<p> NOTE: The first two symptoms may also happen without overload,
-for example: </p>
-
-<ul>
-
-<li> <p> Broken DNS also causes lengthy delays before "220
-hostname.example.com
-..." while the Postfix SMTP server tries to look up the client's
-hostname. </p>
-
-<li> <p> A portscan for open SMTP ports also results in "lost
-connection ..." logfile messages. </p>
-
-</ul>
-
<p> Legitimate mail that doesn't get through during an episode of
overload is not necessarily lost. It should still arrive once the
situation returns to normal, as long as the overload condition is
</p>
<li> <p> You can reduce the Postfix memory footprint by using <a href="CDB_README.html">cdb</a>:
-lookup tables instead of Berkeley DB. </p>
+lookup tables instead of Berkeley DB's hash: or btree: tables. </p>
<pre>
1 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="master.5.html">master.cf</a>, SMTP server processes will report problems when connecting
to policy server processes, because there aren't enough of them.
Examples of errors are "connection refused" or "operation timed
-out". To fix, edit <a href="master.5.html">master.cf</a> and specify a zero "maxproc" field
+out". </p>
+
+<p> To fix, edit <a href="master.5.html">master.cf</a> and specify a zero "maxproc" field
in all policy server entries; see line 6 in the example below.
Issue a "postfix reload" command to make the change effective. </p>
<p> When increasing the number of SMTP server processes is not
practical, you can improve Postfix server responsiveness by eliminating
unnecessary work. When Postfix spends less time per SMTP session, the
-same number of SMTP server processes can service more clients in
-the same amount of time. </p>
+same number of SMTP server processes can service more clients. </p>
<ul>
<p> The name of the <a href="scache.8.html">scache(8)</a> connection cache service. This service
maintains a limited pool of cached sessions. </p>
+<p> This feature is available in Postfix 2.2 and later. </p>
+
</DD>
<dt>tempfail</dt> <dd>Reject all further commands in this session
with a temporary status code. </dd>
+<dt>quarantine</dt> <dd>Like "accept", but freeze the message in
+the "<a href="QSHAPE_README.html#hold_queue">hold" queue</a>. Available with Postfix 2.6 and later. </dd>
+
</dl>
<p> This feature is available in Postfix 2.3 and later. </p>
</p>
+</DD>
+
+<DT><b><a name="proxymap_service_name">proxymap_service_name</a>
+(default: proxymap)</b></DT><DD>
+
+<p> The name of the proxymap read-only table lookup service. This
+service is normally implemented by the <a href="proxymap.8.html">proxymap(8)</a> daemon. </p>
+
+<p> This feature is available in Postfix 2.6 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="proxywrite_service_name">proxywrite_service_name</a>
+(default: proxywrite)</b></DT><DD>
+
+<p> The name of the proxywrite read-write table lookup service.
+This service is normally implemented by the <a href="proxymap.8.html">proxymap(8)</a> daemon.
+</p>
+
+<p> This feature is available in Postfix 2.6 and later. </p>
+
+
</DD>
<DT><b><a name="qmgr_clog_warn_time">qmgr_clog_warn_time</a>
# Do not build with Linux EPOLL support.
# By default, EPOLL support is compiled in on platforms that
# are known to support it.
-# .IP \fB-DNO_KQUEUE\fR
-# Do not build with FreeBSD/NetBSD/OpenBSD KQUEUE support.
-# By default, KQUEUE support is compiled in on platforms that
-# are known to support it.
# .IP \fB-DNO_IPV6\fR
# Do not build with IPv6 support.
# By default, IPv6 support is compiled in on platforms that
# are known to have IPv6 support.
+# .IP \fB-DNO_KQUEUE\fR
+# Do not build with FreeBSD/NetBSD/OpenBSD/MacOSX KQUEUE support.
+# By default, KQUEUE support is compiled in on platforms that
+# are known to support it.
# .IP \fB-DNO_PCRE\fR
# Do not build with PCRE support.
# By default, PCRE support is compiled in when the \fBpcre-config\fR
# utility is installed.
+# .IP \fB-DNO_SIGSETJMP\fR
+# Use setjmp()/longjmp() instead of sigsetjmp()/siglongjmp().
+# By default, Postfix uses sigsetjmp()/siglongjmp() when they
+# appear to work.
# .RE
# .IP \fBDEBUG=\fIdebug_level\fR
# Specifies a non-default debugging level. The default is \fB-g\fR.
SunOS.5*) SYSTYPE=SUNOS5
RANLIB=echo
SYSLIBS="-lresolv -lsocket -lnsl"
- # Solaris 5 added usleep() and POSIX regular expressions
+ # Solaris 2.5 added usleep() and POSIX regular expressions
case $RELEASE in
5.[0-4]) CCARGS="$CCARGS -DMISSING_USLEEP -DNO_POSIX_REGEXP";;
esac
# Kernel 2.6 added EPOLL
case "$RELEASE" in
2.[0-5].*) CCARGS="$CCARGS -DNO_EPOLL";;
- esac
- # Workaround for retarded libc
- case "$RELEASE" in
- 2.6.*)
- trap 'rm -f makedefs.test makedefs.test.o makedefs.test.c' 1 2 3 15
- cat >makedefs.test.c <<EOF
-#include <sys/types.h>
-#include <sys/epoll.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv)
-{
- int epoll_handle;
-
- if ((epoll_handle = epoll_create(1)) < 0) {
- perror("epoll_create");
- exit(1);
- }
- exit(0);
-}
-EOF
- ${CC-gcc} -o makedefs.test makedefs.test.c || exit 1
- ./makedefs.test 2>/dev/null || CCARGS="$CCARGS -DNO_EPOLL"
- rm -f makedefs.test makedefs.test.o makedefs.test.c;;
+ # Workaround for retarded libc
+ 2.6.*) trap 'rm -f linux_epoll linux_epoll.o' 1 2 3 15
+ ${CC-gcc} -o linux_epoll makedefs.d/linux_epoll.c || exit 1
+ ./linux_epoll 2>/dev/null ||
+ CCARGS="$CCARGS -DNO_EPOLL"
+ rm -f linux_epoll linux_epoll.o;;
esac
;;
GNU.0*|GNU/kFreeBSD.[567]*)
RANLIB=echo
SYSLIBS="-lresolv -lsocket -lnsl"
;;
-Rhapsody.5*|Darwin.*)
- SYSTYPE=MACOSX
+ Darwin.*) SYSTYPE=MACOSX
# Use the native compiler by default
: ${CC=cc}
+ # Darwin > 1.3 uses awk and flat_namespace
case $RELEASE in
1.[0-3]) AWK=gawk
- CCARGS="$CCARGS -DNO_IPV6"
- ;;
- [2-6].*) AWK=awk
- CCARGS="$CCARGS -DNO_IPV6"
- SYSLIBS=-flat_namespace
;;
*) AWK=awk
SYSLIBS=-flat_namespace
- CCARGS="$CCARGS -DBIND_8_COMPAT -DNO_NETINFO"
+ ;;
+ esac
+ # Darwin 7 adds IPv6 support, BIND_8_COMPAT, NO_NETINFO
+ case $RELEASE in
+ [1-6].*) CCARGS="$CCARGS -DNO_IPV6"
+ ;;
+ *) CCARGS="$CCARGS -DBIND_8_COMPAT -DNO_NETINFO"
+ ;;
+ esac
+ # Darwin 8.11.1 has kqueue support, but let's play safe
+ case $RELEASE in
+ [1-8].*) CCARGS="$CCARGS -DNO_KQUEUE"
+ ;;
+ *) trap 'rm -f macosx_kqueue macosx_kqueue.o' 1 2 3 15
+ ${CC-gcc} -o macosx_kqueue makedefs.d/macosx_kqueue.c || exit 1
+ ./macosx_kqueue 2>/dev/null ||
+ CCARGS="$CCARGS -DNO_KQUEUE"
+ rm -f macosx_kqueue macosx_kqueue.o
;;
esac
;;
-"Mac OS".10*) SYSTYPE=MACOSX
+Rhapsody.5*|"Mac OS".10*)
+ SYSTYPE=MACOSX
# Use the native compiler by default
: ${CC=cc}
AWK=gawk
*) error "Unknown system type: $SYSTEM $RELEASE";;
esac
+#
+# sigsetjmp()/siglongjmp() can be "better" than setjmp()/longjmp()
+# if used wisely (that is: almost never, just like signals).
+# Unfortunately some implementations have been buggy in the past.
+#
+case "$CCARGS" in
+ *-DNO_SIGSETJMP*) ;;
+ *) trap 'rm -f sigsetjmp sigsetjmp.o' 1 2 3 15
+ ${CC-gcc} -o sigsetjmp makedefs.d/sigsetjmp.c || exit 1
+ ./sigsetjmp 2>/dev/null || CCARGS="$CCARGS -DNO_SIGSETJMP"
+ rm -f sigsetjmp sigsetjmp.o;;
+esac
+
#
# OpenSSL has no configuration query utility, but we don't try to
# guess. We assume includes in /usr/include/openssl and libraries in
--- /dev/null
+#include <sys/types.h>
+#include <sys/epoll.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ int epoll_handle;
+
+ if ((epoll_handle = epoll_create(1)) < 0) {
+ perror("epoll_create");
+ exit(1);
+ }
+ exit(0);
+}
--- /dev/null
+/* Adapted from libevent. */
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef EV_SET
+#define EV_SET(kp, id, fi, fl, ffl, da, ud) do { \
+ struct kevent *__kp = (kp); \
+ __kp->ident = (id); \
+ __kp->filter = (fi); \
+ __kp->flags = (fl); \
+ __kp->fflags = (ffl); \
+ __kp->data = (da); \
+ __kp->udata = (ud); \
+ } while(0)
+#endif
+
+int main(int argc, char **argv)
+{
+ int kq;
+ struct kevent test_change;
+ struct kevent test_result;
+
+ if ((kq = kqueue()) < 0) {
+ perror("kqueue");
+ exit(1);
+ }
+#define TEST_FD (-1)
+
+ EV_SET(&test_change, TEST_FD, EVFILT_READ, EV_ADD, 0, 0, 0);
+ if (kevent(kq,
+ &test_change, sizeof(test_change) / sizeof(struct kevent),
+ &test_result, sizeof(test_result) / sizeof(struct kevent),
+ (struct timespec *) 0) != 1 ||
+ test_result.ident != TEST_FD ||
+ test_result.flags != EV_ERROR) {
+ fprintf(stderr, "kqueue is broken\n");
+ exit(1);
+ }
+ exit(0);
+}
--- /dev/null
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int count = 0;
+
+int main(int argc, char **argv)
+{
+ sigjmp_buf env;
+ int retval;
+
+ switch (retval = sigsetjmp(env, 1)) {
+ case 0:
+ siglongjmp(env, 12345);
+ case 12345:
+ break;
+ default:
+ fprintf(stderr, "Error: siglongjmp ignores second argument\n");
+ exit(1);
+ }
+
+ switch (retval = sigsetjmp(env, 1)) {
+ case 0:
+ if (count++ > 0) {
+ fprintf(stderr, "Error: not overriding siglongjmp(env, 0)\n");
+ exit(1);
+ }
+ siglongjmp(env, 0);
+ case 1:
+ break;
+ default:
+ fprintf(stderr, "Error: overriding siglongjmp(env, 0) with %d\n",
+ retval);
+ exit(1);
+ }
+ exit(0);
+}
.SH connection_cache_service_name (default: scache)
The name of the \fBscache\fR(8) connection cache service. This service
maintains a limited pool of cached sessions.
+.PP
+This feature is available in Postfix 2.2 and later.
.SH connection_cache_status_update_time (default: 600s)
How frequently the \fBscache\fR(8) server logs usage statistics with
connection cache hit and miss rates for logical destinations and for
.IP "tempfail"
Reject all further commands in this session
with a temporary status code.
+.IP "quarantine"
+Like "accept", but freeze the message in
+the "hold" queue. Available with Postfix 2.6 and later.
.PP
This feature is available in Postfix 2.3 and later.
.SH milter_end_of_data_macros (default: see postconf -n output)
Table references that don't begin with proxy: are ignored.
.PP
This feature is available in Postfix 2.5 and later.
+.SH proxymap_service_name (default: proxymap)
+The name of the proxymap read-only table lookup service. This
+service is normally implemented by the \fBproxymap\fR(8) daemon.
+.PP
+This feature is available in Postfix 2.6 and later.
+.SH proxywrite_service_name (default: proxywrite)
+The name of the proxywrite read-write table lookup service.
+This service is normally implemented by the \fBproxymap\fR(8) daemon.
+.PP
+This feature is available in Postfix 2.6 and later.
.SH qmgr_clog_warn_time (default: 300s)
The minimal delay between warnings that a specific destination is
clogging up the Postfix active queue. Specify 0 to disable.
s;\bprocess_name\b;<a href="postconf.5.html#process_name">$&</a>;g;
s;\bpropagate_unmatched_extensions\b;<a href="postconf.5.html#propagate_unmatched_extensions">$&</a>;g;
s;\bproxy_inter[-</bB>]*\n* *[<bB>]*faces\b;<a href="postconf.5.html#proxy_interfaces">$&</a>;g;
+ s;\bproxymap_service_name\b;<a href="postconf.5.html#proxymap_service_name">$&</a>;g;
+ s;\bproxywrite_service_name\b;<a href="postconf.5.html#proxywrite_service_name">$&</a>;g;
s;\bproxy_read_maps\b;<a href="postconf.5.html#proxy_read_maps">$&</a>;g;
s;\bproxy_write_maps\b;<a href="postconf.5.html#proxy_write_maps">$&</a>;g;
s;\bqmgr_clog_warn_time\b;<a href="postconf.5.html#qmgr_clog_warn_time">$&</a>;g;
temporary error status, so that the client will try again later.
Specify "accept" if you want to receive mail as if the filter does
not exist, and "reject" to reject mail with a permanent status.
+The "quarantine" action is like "accept" but freezes the message
+in the "hold" queue, and is available with Postfix 2.6 or later.
</p>
<blockquote>
<pre>
/etc/postfix/main.cf:
- # What to do in case of errors? Specify accept, reject, or tempfail.
+ # What to do in case of errors? Specify accept, reject, tempfail,
+ # or quarantine (Postfix 2.6 or later).
milter_default_action = tempfail
</pre>
</blockquote>
entry in master.cf (present since Postfix 2.1), and tell users to
connect to this instead of the public SMTP service. </p>
+<ul>
+
+<li> <p> NOTE: Broken DNS configurations also cause lengthy delays
+before Postfix sends "220 hostname.example.com ...". In this case
+the delay happens even when Postfix is not busy. </p>
+
+</ul>
+
<li> <p> The Postfix SMTP server logs an increased number of "lost
connection after CONNECT" events. This happens because remote SMTP
clients disconnect before Postfix answers the connection. </p>
+<ul>
+
+<li> <p> NOTE: A portscan for open SMTP ports also results in "lost
+connection ..." logfile messages. </p>
+
+</ul>
+
<li> <p> Postfix 2.3 and later logs a warning that all server ports
are busy: </p>
</ul>
-<p> NOTE: The first two symptoms may also happen without overload,
-for example: </p>
-
-<ul>
-
-<li> <p> Broken DNS also causes lengthy delays before "220
-hostname.example.com
-..." while the Postfix SMTP server tries to look up the client's
-hostname. </p>
-
-<li> <p> A portscan for open SMTP ports also results in "lost
-connection ..." logfile messages. </p>
-
-</ul>
-
<p> Legitimate mail that doesn't get through during an episode of
overload is not necessarily lost. It should still arrive once the
situation returns to normal, as long as the overload condition is
</p>
<li> <p> You can reduce the Postfix memory footprint by using cdb:
-lookup tables instead of Berkeley DB. </p>
+lookup tables instead of Berkeley DB's hash: or btree: tables. </p>
<pre>
1 /etc/postfix/main.cf:
master.cf, SMTP server processes will report problems when connecting
to policy server processes, because there aren't enough of them.
Examples of errors are "connection refused" or "operation timed
-out". To fix, edit master.cf and specify a zero "maxproc" field
+out". </p>
+
+<p> To fix, edit master.cf and specify a zero "maxproc" field
in all policy server entries; see line 6 in the example below.
Issue a "postfix reload" command to make the change effective. </p>
<p> When increasing the number of SMTP server processes is not
practical, you can improve Postfix server responsiveness by eliminating
unnecessary work. When Postfix spends less time per SMTP session, the
-same number of SMTP server processes can service more clients in
-the same amount of time. </p>
+same number of SMTP server processes can service more clients. </p>
<ul>
<p> The name of the scache(8) connection cache service. This service
maintains a limited pool of cached sessions. </p>
+<p> This feature is available in Postfix 2.2 and later. </p>
+
%PARAM connection_cache_ttl_limit 2s
<p> The maximal time-to-live value that the scache(8) connection
<dt>tempfail</dt> <dd>Reject all further commands in this session
with a temporary status code. </dd>
+<dt>quarantine</dt> <dd>Like "accept", but freeze the message in
+the "hold" queue. Available with Postfix 2.6 and later. </dd>
+
</dl>
<p> This feature is available in Postfix 2.3 and later. </p>
The default setting is not backwards compatible. </p>
<p> This feature is available in Postfix 2.5.3 and later. </p>
+
+%PARAM proxymap_service_name proxymap
+
+<p> The name of the proxymap read-only table lookup service. This
+service is normally implemented by the proxymap(8) daemon. </p>
+
+<p> This feature is available in Postfix 2.6 and later. </p>
+
+%PARAM proxywrite_service_name proxywrite
+
+<p> The name of the proxywrite read-write table lookup service.
+This service is normally implemented by the proxymap(8) daemon.
+</p>
+
+<p> This feature is available in Postfix 2.6 and later. </p>
+
/*
* XXX Workaround: truncate a long message header so that we don't exceed
- * the Milter request size limit of 65535.
+ * the default Sendmail libmilter request size limit of 65535.
*/
#define KLUDGE_HEADER_LIMIT 60000
if ((cleanup_milters || state->milters)
switch (resp[0]) {
case 'H':
/* XXX Should log the reason here. */
+ if (state->flags & CLEANUP_FLAG_HOLD)
+ return (0);
state->flags |= CLEANUP_FLAG_HOLD;
action = "milter-hold";
text = "milter triggers HOLD action";
int server_flags;
int status;
const char *service;
- const char *relative_path;
+ char *relative_path;
char *kludge = 0;
char *prefix;
CLNT_STREAM **pstream;
/*
- * Sanity checks.
+ * If this map can't be proxied then we silently do a direct open. This
+ * allows sites to benefit from proxying the virtual mailbox maps without
+ * unnecessary pain.
+ */
+ if (dict_flags & DICT_FLAG_NO_PROXY)
+ return (dict_open(map, open_flags, dict_flags));
+
+ /*
+ * Use a shared stream for proxied table lookups of the same type.
*
* XXX A complete implementation would also allow O_RDWR without O_CREAT.
* But we must not pass on every possible set of flags to the proxy
* server; only sets that make sense. For now, the flags are passed
* implicitly by choosing between the proxymap or proxywrite service.
+ *
+ * XXX Use absolute pathname to make this work from non-daemon processes.
*/
if (open_flags == O_RDONLY) {
pstream = &proxymap_stream;
- service = MAIL_SERVICE_PROXYMAP;
- relative_path = MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYMAP;
+ service = var_proxymap_service;
} else if (open_flags == (O_RDWR | O_CREAT)) {
pstream = &proxywrite_stream;
- service = MAIL_SERVICE_PROXYWRITE;
- relative_path = MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYWRITE;
+ service = var_proxywrite_service;
} else
msg_fatal("%s: %s map open requires O_RDONLY or O_RDWR|O_CREAT mode",
map, DICT_TYPE_PROXY);
- /*
- * OK. If this map can't be proxied then we silently do a direct open.
- * This allows sites to benefit from proxying the virtual mailbox maps
- * without unnecessary pain.
- */
- if (dict_flags & DICT_FLAG_NO_PROXY)
- return (dict_open(map, open_flags, dict_flags));
+ if (*pstream == 0) {
+ relative_path = concatenate(MAIL_CLASS_PRIVATE "/",
+ service, (char *) 0);
+ if (access(relative_path, F_OK) == 0)
+ prefix = MAIL_CLASS_PRIVATE;
+ else
+ prefix = kludge = concatenate(var_queue_dir, "/",
+ MAIL_CLASS_PRIVATE, (char *) 0);
+ *pstream = clnt_stream_create(prefix, service, var_ipc_idle_limit,
+ var_ipc_ttl_limit);
+ if (kludge)
+ myfree(kludge);
+ myfree(relative_path);
+ }
/*
* Local initialization.
dict_proxy->dict.close = dict_proxy_close;
dict_proxy->in_flags = dict_flags;
dict_proxy->result = vstring_alloc(10);
-
- /*
- * Use a shared stream for proxied table lookups of the same type.
- *
- * XXX Use absolute pathname to make this work from non-daemon processes.
- */
- if (*pstream == 0) {
- if (access(relative_path, F_OK) == 0)
- prefix = MAIL_CLASS_PRIVATE;
- else
- prefix = kludge = concatenate(var_queue_dir, "/",
- MAIL_CLASS_PRIVATE, (char *) 0);
- *pstream = clnt_stream_create(prefix, service, var_ipc_idle_limit,
- var_ipc_ttl_limit);
- if (kludge)
- myfree(kludge);
- }
dict_proxy->clnt = *pstream;
dict_proxy->service = service;
/* char *var_flush_service;
/* char *var_verify_service;
/* char *var_trace_service;
+/* char *var_proxymap_service;
+/* char *var_proxywrite_service;
/* int var_db_create_buf;
/* int var_db_read_buf;
/* int var_mime_maxdepth;
char *var_flush_service;
char *var_verify_service;
char *var_trace_service;
+char *var_proxymap_service;
+char *var_proxywrite_service;
int var_db_create_buf;
int var_db_read_buf;
int var_mime_maxdepth;
VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0,
VAR_VERIFY_SERVICE, DEF_VERIFY_SERVICE, &var_verify_service, 1, 0,
VAR_TRACE_SERVICE, DEF_TRACE_SERVICE, &var_trace_service, 1, 0,
+ VAR_PROXYMAP_SERVICE, DEF_PROXYMAP_SERVICE, &var_proxymap_service, 1, 0,
+ VAR_PROXYWRITE_SERVICE, DEF_PROXYWRITE_SERVICE, &var_proxywrite_service, 1, 0,
VAR_INT_FILT_CLASSES, DEF_INT_FILT_CLASSES, &var_int_filt_classes, 0, 0,
0,
};
#define DEF_TRACE_SERVICE MAIL_SERVICE_TRACE
extern char *var_trace_service;
+ /*
+ * Proxymappers.
+ */
+#define VAR_PROXYMAP_SERVICE "proxymap_service_name"
+#define DEF_PROXYMAP_SERVICE MAIL_SERVICE_PROXYMAP
+extern char *var_proxymap_service;
+
+#define VAR_PROXYWRITE_SERVICE "proxywrite_service_name"
+#define DEF_PROXYWRITE_SERVICE MAIL_SERVICE_PROXYWRITE
+extern char *var_proxywrite_service;
+
/*
* Mailbox/maildir delivery errors that cause delivery to be tried again.
*/
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20080814"
+#define MAIL_RELEASE_DATE "20080824"
#define MAIL_VERSION_NUMBER "2.6"
#ifdef SNAPSHOT
}
if (strcasecmp(milter->def_action, "accept") == 0) {
reply = 0;
+ } else if (strcasecmp(milter->def_action, "quarantine") == 0) {
+ reply = "H";
} else {
reply = "451 4.3.5 Server configuration problem - try again later";
}
reply = "550 5.5.0 Service unavailable";
} else if (strcasecmp(milter->def_action, "tempfail") == 0) {
reply = "451 4.7.1 Service unavailable - try again later";
+ } else if (strcasecmp(milter->def_action, "quarantine") == 0) {
+ reply = "H";
} else {
msg_warn("milter %s: unrecognized default action: %s",
milter->m.name, milter->def_action);
/* .IP "\fB-a accept|tempfail|reject|discard|skip|\fIddd x.y.z text\fR"
/* Specifies a non-default reply for the MTA command specified
/* with \fB-c\fR. The default is \fBtempfail\fR.
+/* .IP "\fB-A address\fR"
+/* Add the specified recipient address. Multiple -A options
+/* are supported.
/* .IP "\fB-d\fI level\fR"
/* Enable libmilter debugging at the specified level.
/* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR"
#endif
+#define MAX_RCPT 10
+int rcpt_count = 0;
+char *rcpt_addr[MAX_RCPT];
+
static int test_reply(SMFICTX *ctx, int code)
{
(void) fflush(stdout); /* In case output redirected. */
#endif
#ifdef SMFIR_INSHEADER
if (ins_hdr && smfi_insheader(ctx, ins_idx, ins_hdr, ins_val) == MI_FAILURE)
- fprintf(stderr, "smfi_insheader failed");
+ fprintf(stderr, "smfi_insheader failed\n");
#endif
#ifdef SMFIR_CHGHEADER
if (chg_hdr && smfi_chgheader(ctx, chg_hdr, chg_idx, chg_val) == MI_FAILURE)
- fprintf(stderr, "smfi_chgheader failed");
+ fprintf(stderr, "smfi_chgheader failed\n");
#endif
+ {
+ int count;
+
+ for (count = 0; count < rcpt_count; count++)
+ if (smfi_addrcpt(ctx, rcpt_addr[count]) == MI_FAILURE)
+ fprintf(stderr, "smfi_addrcpt `%s' failed\n", rcpt_addr[count]);
+ }
return (test_reply(ctx, test_eom_reply));
}
char *noreply = 0;
const struct noproto_map *np;
- while ((ch = getopt(argc, argv, "a:c:C:d:i:lm:M:n:N:p:r:R:v")) > 0) {
+ while ((ch = getopt(argc, argv, "a:A:c:C:d:i:lm:M:n:N:p:r:R:v")) > 0) {
switch (ch) {
case 'a':
action = optarg;
break;
+ case 'A':
+ if (rcpt_count >= MAX_RCPT) {
+ fprintf(stderr, "too many -A options\n");
+ exit(1);
+ }
+ rcpt_addr[rcpt_count++] = optarg;
+ break;
case 'c':
command = optarg;
break;
int i;
SMTPD_RBL_STATE *rbl;
const char *reply_addr;
+ struct addrinfo *res;
+ unsigned char *ipv6_addr;
if (msg_verbose)
msg_info("%s: %s %s", myname, reply_class, addr);
+ query = vstring_alloc(100);
+
/*
- * IPv4 / IPv6-mapped IPv4 (if supported) only for now
- */
- if (valid_ipv6_hostaddr(addr, DONT_GRIPE))
- return SMTPD_CHECK_DUNNO;
+ * Reverse the client IPV6 address, represented as 32 hexadecimal
+ * nibbles. We use the binary address to avoid tricky code. Asking for an
+ * AAAA record makes no sense here. Just like with IPv4 we use the lookup
+ * result as a bit mask, not as an IP address.
+ */
+#ifdef PF_INET6
+ if (valid_ipv6_hostaddr(addr, DONT_GRIPE)) {
+ if (hostaddr_to_sockaddr(addr, (char *) 0, 0, &res) != 0
+ || res->ai_family != PF_INET6)
+ msg_fatal("%s: unable to convert address %s", myname, addr);
+ ipv6_addr = (unsigned char *) &SOCK_ADDR_IN6_ADDR(res->ai_addr);
+ for (i = sizeof(SOCK_ADDR_IN6_ADDR(res->ai_addr)) - 1; i >= 0; i--)
+ vstring_sprintf_append(query, "%x.%x.",
+ ipv6_addr[i] & 0xf, ipv6_addr[i] >> 4);
+ freeaddrinfo(res);
+ } else
+#endif
+
+ /*
+ * Reverse the client IPV4 address, represented as four decimal octet
+ * values. We use the textual address for convenience.
+ */
+ {
+ octets = argv_split(addr, ".");
+ for (i = octets->argc - 1; i >= 0; i--) {
+ vstring_strcat(query, octets->argv[i]);
+ vstring_strcat(query, ".");
+ }
+ argv_free(octets);
+ }
/*
- * Reverse the client IPV4 address, tack on the RBL domain name and query
- * the DNS for an A record.
+ * Tack on the RBL domain name and query the DNS for an A record.
*/
- query = vstring_alloc(100);
- octets = argv_split(addr, ".");
- for (i = octets->argc - 1; i >= 0; i--) {
- vstring_strcat(query, octets->argv[i]);
- vstring_strcat(query, ".");
- }
- argv_free(octets);
vstring_strcat(query, rbl_domain);
reply_addr = split_at(STR(query), '=');
rbl = (SMTPD_RBL_STATE *) ctable_locate(smtpd_rbl_cache, STR(query));
/* transport is currently limited to one of the following:
/* .RS
/* .IP inet
-/* servername has the form "host:port".
+/* servername has the form "inet:host:port".
+/* .IP local
+/* servername has the form "local:private/servicename" or
+/* "local:public/servicename". This is the preferred way to
+/* specify Postfix daemons that are configured as "unix" in
+/* master.cf.
/* .IP unix
-/* servername has the form "private/servicename" or
-/* "public/servicename".
+/* servername has the form "unix:private/servicename" or
+/* "unix:public/servicename". This does not work on Solaris,
+/* where Postfix uses STREAMS instead of UNIX-domain sockets.
/* .RE
/* .IP timeout
/* The time limit for sending, receiving, or for connecting
int stream_send_fd(int fd, int sendfd)
{
+#ifdef STREAM_CONNECTIONS
const char *myname = "stream_send_fd";
-#ifdef STREAM_CONNECTIONS
if (ioctl(fd, I_SENDFD, sendfd) < 0)
msg_fatal("%s: send file descriptor %d: %m", myname, sendfd);
return (0);
#else
- msg_fatal("stream connections are not implemented");
+ msg_fatal("stream connections are not implemented");
#endif
}
#define NATIVE_DAEMON_DIR "/usr/libexec/postfix"
#define SOCKADDR_SIZE socklen_t
#define SOCKOPT_SIZE socklen_t
+#ifndef NO_KQUEUE
+# define EVENTS_STYLE EVENTS_STYLE_KQUEUE
+# define USE_SYSV_POLL
+#endif
+
#endif
/*
#define EVENTS_STYLE_DEVPOLL 3 /* Solaris /dev/poll */
#define EVENTS_STYLE_EPOLL 4 /* Linux epoll */
+#if !defined(USE_SYSV_POLL) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
+#error "need USE_SYSV_POLL with EVENTS_STYLE != EVENTS_STYLE_SELECT"
+#endif
+
/*
* Defaults for all systems.
*/
break;
case VSTREAM_CTL_EXCEPT:
if (stream->jbuf == 0)
- stream->jbuf = (jmp_buf *) mymalloc(sizeof(jmp_buf));
+ stream->jbuf =
+ (VSTREAM_JMP_BUF *) mymalloc(sizeof(VSTREAM_JMP_BUF));
break;
#ifdef VSTREAM_CTL_DUPFD
typedef ssize_t (*VSTREAM_FN) (int, void *, size_t, int, void *);
typedef int (*VSTREAM_WAITPID_FN) (pid_t, WAIT_STATUS_T *, int);
+#ifdef NO_SIGSETJMP
+#define VSTREAM_JMP_BUF jmp_buf
+#else
+#define VSTREAM_JMP_BUF sigjmp_buf
+#endif
+
typedef struct VSTREAM {
VBUF buf; /* generic intelligent buffer */
int fd; /* file handle, no 256 limit */
pid_t pid; /* vstream_popen/close() */
VSTREAM_WAITPID_FN waitpid_fn; /* vstream_popen/close() */
int timeout; /* read/write timout */
- jmp_buf *jbuf; /* exception handling */
+ VSTREAM_JMP_BUF *jbuf; /* exception handling */
struct timeval iotime; /* time of last fill/flush */
/* At bottom for Postfix 2.4 binary compatibility. */
ssize_t req_bufsize; /* write buffer size */
/*
* Exception handling. We use pointer to jmp_buf to avoid a lot of unused
* baggage for streams that don't need this functionality.
+ *
+ * XXX sigsetjmp()/siglongjmp() save and restore the signal mask which can
+ * avoid surprises in code that manipulates signals, but unfortunately some
+ * systems have bugs in their implementation.
*/
+#ifdef NO_SIGSETJMP
#define vstream_setjmp(stream) setjmp((stream)->jbuf[0])
#define vstream_longjmp(stream, val) longjmp((stream)->jbuf[0], (val))
+#else
+#define vstream_setjmp(stream) sigsetjmp((stream)->jbuf[0], 1)
+#define vstream_longjmp(stream, val) siglongjmp((stream)->jbuf[0], (val))
+#endif
/*
* Tweaks and workarounds.