]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.7-20091008
authorWietse Venema <wietse@porcupine.org>
Thu, 8 Oct 2009 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:35:40 +0000 (06:35 +0000)
52 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/Makefile.in
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/conf/master.cf
postfix/conf/post-install
postfix/conf/postfix-files
postfix/html/Makefile.in
postfix/html/dnsblog.8.html [new file with mode: 0644]
postfix/html/pipe.8.html
postfix/html/postconf.5.html
postfix/html/postfix-manuals.html
postfix/html/postfix.1.html
postfix/html/postscreen.8.html [new file with mode: 0644]
postfix/man/Makefile.in
postfix/man/man1/postfix.1
postfix/man/man5/postconf.5
postfix/man/man8/dnsblog.8 [new file with mode: 0644]
postfix/man/man8/pipe.8
postfix/man/man8/postscreen.8 [new file with mode: 0644]
postfix/mantools/postlink
postfix/proto/postconf.proto
postfix/src/dns/dns_lookup.c
postfix/src/dnsblog/.indent.pro [new symlink]
postfix/src/dnsblog/Makefile.in [new file with mode: 0644]
postfix/src/dnsblog/dnsblog.c [new file with mode: 0644]
postfix/src/global/Makefile.in
postfix/src/global/addr_match_list.c [new file with mode: 0644]
postfix/src/global/addr_match_list.h [new file with mode: 0644]
postfix/src/global/db_common.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/master/Makefile.in
postfix/src/master/event_server.c [new file with mode: 0644]
postfix/src/master/mail_server.h
postfix/src/master/master_avail.c
postfix/src/master/multi_server.c
postfix/src/master/single_server.c
postfix/src/master/trigger_server.c
postfix/src/milter/milter8.c
postfix/src/pipe/pipe.c
postfix/src/postfix/postfix.c
postfix/src/postscreen/.indent.pro [new symlink]
postfix/src/postscreen/Makefile.in [new file with mode: 0644]
postfix/src/postscreen/postscreen.c [new file with mode: 0644]
postfix/src/smtpd/smtpd_check.c
postfix/src/util/events.c
postfix/src/util/events.h
postfix/src/util/read_wait.c
postfix/src/util/sys_defs.h
postfix/src/util/upass_listen.c

index 6fd89ea4d459a4e8b28a67fe73be2f780e4ca450..32ea76168930a1165c4dd2fbc8193e324f2633fb 100644 (file)
@@ -1,4 +1,5 @@
 -TABOUNCE
+-TADDR_MATCH_LIST
 -TADDR_PATTERN
 -TALIAS_TOKEN
 -TANVIL_CLNT
 -TPOSTMAP_KEY_STATE
 -TPOST_MAIL_STATE
 -TPRIVATE_STR_TABLE
+-TPS_DNSBL_ENTRY
+-TPS_DNS_STREAM
+-TPS_STATE
 -TQMGR_ENTRY
 -TQMGR_FEEDBACK
 -TQMGR_JOB
index 9bb8ec2638bf2b20c8c91cd8395bd6fb40432f2d..bd80ff95a4a5c0af2da3292405ab1ef6efe64b89 100644 (file)
@@ -15309,16 +15309,76 @@ Apologies for any names omitted.
        and Milters make redundant or conflicting decisions. File:
        cleanup_milter.c.
 
+20090614
+
+       Preliminary postscreen triage server for all inbound SMTP
+       connections.  This is not a proxy: it rejects bad clients
+       and forwards the rest of the connections to a real Postfix
+       SMTP server. The initial version does a simple "friend or
+       foe" based on whether the client starts talking too soon.
+       Decisions are cached, so "good" clients have no overhead.
+       File: postscreen/postscreen.c.
+
+       Cleanup: more robust code for receiving file descriptors
+       via the "pass" master service protocol.  File:
+       util/upass_listen.c.
+
+20090617
+
+       Temporary helper daemon that does parallel DNSBL lookups
+       for postscreen(8). It logs successful lookups to the maillog
+       file without blocking the client. postscreen(8) will use
+       the results in a later non-production version. To enable
+       DNSBL lookups, specify "postscreen_dnsbl_sites = name,
+       name, etc". and restart postscreen(8) with "postfix reload".
+       File: src/dnsblog/dnblog.c.
+
+20090618
+
+       postscreen(8) logging and actions are now documented in the
+       postscreen(8) manpage. When a client is listed in DNSBLs
+       specified with postscreen_dnsbl_sites, it is no longer
+       whitelisted. Instead the number of blocklist hits is logged.
+       File: postscreen/postscreen.c.
+
+20090619
+
+       postscreen(8) by default no longer immediately drops
+       connections. Specify "postscreen_greet_action = drop" and
+       "postscreen_hangup_action = drop" for the old behavior.
+       There is also a new postscreen_dnsbl_action parameter, for
+       completeness.  File: postscreen/postscreen.c.
+
+20090708
+
+       Portability: FreeBSD 8 has closefrom(). File: uti/sys_defs.h.
+
 20090710
 
        Bugfix (introduced Postfix 2.3): Postfix got out of sync
        with a Milter application after the application sent a
-       "quarantine" request at end-of-message time. The milter
+       "quarantine" request at end-of-message time. The milter 
        application would still be in the end-of-message state,
        while Postfix would already be working on the next SMTP
        event (typically, QUIT or MAIL FROM).  Problem diagnosed
        with help from Alban Deniz. File: milter/milter8.c.
 
+20090711-2
+
+       New "event_server" Postfix server framework. It is similar
+       to the "multi_server" framework but does not manage client
+       I/O events.  This framework is suitable for servers such
+       as postscreen that have complex event management requirements.
+       File: master/event_server.c.
+
+       New event_fork() primitive to resume event processing in a
+       child process after it is created with fork(). This is
+       needed by postscreen to complete work-in-progress in the
+       background after "postfix reload". File: util/events.c.
+
+       Cleanup: postscreen migrated to the "event_server" framework.
+       File: postscreen/postscreen.c.
+
 20090712
 
        Cleanup: ${multi_instance_name:postfix}${multi_instance_name
@@ -15331,7 +15391,57 @@ Apologies for any names omitted.
        feature can be used meaningfully at any protocol stage.
        File: proto/postconf.proto.
 
+20090717
+
+       Cleanup: postscreen PREGREET detection now uses non-destructive
+       read, so that the real SMTP server can still receive the
+       HELO command (apparently some sites allow pregreeters to
+       talk to their servers).  File: postscreen/postscreen.c.
+
 20090805
 
        Bugfix: don't panic when an unexpected smtpd access map is
        specified. File: smtpd/smtpd_check.c.
+
+20090918
+
+       Bugfix (introduced Postfix 2.3): with Milter RCPT TO replies
+       turned off, there was no automatic flush-before-read on the
+       smtpd-to-milter stream, because the read was done on the
+       cleanup-to-milter stream. Problem reported by Stephen Warren.
+       File: milter/milter8.c.
+
+20091005
+
+       Bugfix: core dump while printing error message for malformed
+       %<letter> sequence in LDAP, MySQL or PostgreSQL configuration.
+       File: global/db_common.c. Fix by Victor Duchovni.
+
+20091006
+
+       Feature: "postscreen_whitelist_networks = $mynetworks" (the
+       default) to avoid problems with buggy SMTP implementations
+       in network appliances.  Note: this feature never uses the
+       remote SMTP client hostname.  Files: global/addr_match_list.[hc],
+       postscreen/postscreen.c.
+
+       Feature: postscreen_blacklist_networks (default: empty) to
+       permanently blacklist hosts or networks. Address syntax is
+       as with mynetworks. Note: this feature never uses the remote
+       SMTP client hostname.  File: postscreen/postscreen.c.
+
+       Feature: postscreen_blacklist_action (default: continue)
+       to control what happens with a permanently blacklisted
+       client.
+
+20091007
+
+       Feature: hostname-based check_client_{mx,ns}_access,
+       check_reverse_client_hostname_{mx,ns}_access (the client
+       IP address is not used). Rob Foehl.  Files: smtpd/smtpd_check.c,
+       global/mail_params.h, proto/postconf.proto, mantools/postlink.
+
+20091008
+
+       Documentation: restructured the postscreen(8) manpage
+       as a sequence of tests. File: postscreen/postscreen.c.
index 87a77d8dafa8a7e5db4a4ec7cd203c4144d40511..c5efb2165bae6be6b137a2b54e27061d47c542f5 100644 (file)
@@ -9,7 +9,7 @@ DIRS    = src/util src/global src/dns src/tls src/xsasl src/milter src/master \
        src/postkick src/postlock src/postlog src/postmap src/postqueue \
        src/postsuper src/qmqpd src/spawn src/flush src/verify \
        src/virtual src/proxymap src/anvil src/scache src/discard src/tlsmgr \
-       src/postmulti
+       src/postmulti src/postscreen src/dnsblog
 MANDIRS        = proto man html
 LIBEXEC        = libexec/post-install libexec/postfix-files libexec/postfix-script \
        libexec/postfix-wrapper libexec/main.cf libexec/master.cf \
index 620a44132a7ec8da5a8ee391c79e90100686d10b..e85a4b0fcd6449082d9184a0f30b6e3fe5c37762 100644 (file)
@@ -14,6 +14,92 @@ specifies the release date of a stable release or snapshot release.
 If you upgrade from Postfix 2.5 or earlier, read RELEASE_NOTES-2.6
 before proceeding.
 
+Incompatibility with snapshot 20091008
+======================================
+
+NOTE: You must stop and start the Postfix master daemon before you
+can use the postscreen(8) daemon.  This is needed because the Postfix
+"pass" master service type did not work reliably on some systems.
+
+Major changes with snapshot 20091008
+====================================
+
+Prototype postscreen(8) server that runs a number of time-consuming
+checks in parallel for all incoming SMTP connections, before clients
+are allowed to talk to a real Postfix SMTP server.  It detects
+clients that start talking too soon, or clients that appear on DNS
+blocklists, or clients that hang up without sending any command.
+
+By doing these checks in a single postscreen(8) process, Postfix
+can avoid wasting one SMTP server process per connection. A side
+benefit of postscreen(8)'s DNSBL lookups is that DNS records are
+already cached before the Postfix SMTP server looks them up later.
+
+postscreen(8) maintains a temporary whitelist of positive decisions.
+Once an SMTP client is whitelisted, it is immediately forwarded
+to a real Postfix SMTP server process without further checking.
+
+By default, the program logs only statistics, and it does not run
+any checks on clients in mynetworks (primarily, to avoid problems
+with buggy SMTP implementations in network appliances).  The logging
+function alone is already useful for research.
+
+postscreen(8) can be configured to drop clients that start talking
+too soon, or clients that appear on DNS blocklists. For details,
+see below.
+
+postscreen(8) has been tested on FreeBSD and Linux systems.  It
+probably needs additional work before it can be used on Solaris.
+
+This snapshot adds three new entries to the master.cf file. 
+
+To enable the postscreen(8) service and log client information
+without blocking mail:
+
+1 - Comment out the "smtp  inet ... smtpd" service in master.cf,
+    including any "-o parameter=value" entries that follow.
+
+2 - Uncomment the new "smtpd pass ... smtpd" service in master.cf.
+
+3 - Uncomment the the new "smtp inet ... postscreen" service in
+    master.cf, and duplicate any "-o parameter=value" entries from
+    the smtpd service that was commented out in step 1.
+
+4 - Uncomment the new "dnsblog  unix ... dnsblog" service in
+    master.cf.  This service does DNSBL lookups for postscreen(8)
+    and logs results.
+
+5 - To enable DNSBL lookups, list some DNS blocklist sites in
+    main.cf, e.g., "postscreen_dnsbl_sites = zen.spamhaus.org".
+    Separate domain names with comma or whitespace.
+
+Note: you must stop and start the master daemon.  This is needed
+because the Postfix "pass" master service type did not work reliably
+on all systems.
+
+To use the postscreen(8) service to block mail, edit main.cf and
+specify one or more of:
+
+- "postscreen_greet_action = drop", to drop clients that talk before
+  their turn. This alone stops about one third of all known-to-be
+  illegitimate connections to Wietse's mail server.
+
+- "postscreen_hangup_action = drop", to waste no time on clients
+  that hang up without sending a command. On Wietse's server, only
+  one percent of illegitimate connections behaves like this.
+
+- "postscreen_dnsbl_action = drop", to drop clients that are on DNS
+  blocklists. Different blocklists cover different client categories.
+
+There is also support for permanent blacklists and whitelists; see
+the postscreen(8) manual page for details.
+
+Note: right now, postscreen(8) "drop" actions disconnect the client
+without reporting sender and recipient information. In a future
+implementation, the connection may instead be passed to a dummy
+SMTP protocol engine that logs sender and recipient information
+before dropping the connection.
+
 Incompatibility with snapshot 20090606
 ======================================
 
index f50e604288cb9bc9e1bb936ebda4fa40e087990b..0ec301189075cf3b83a7fdc64ddebc9aaa25c2b0 100644 (file)
@@ -2,6 +2,44 @@ Wish list:
 
        Remove this file from the stable release.
 
+       SMTP connection caching without storing connections, to
+       improve TLS mail delivery performance.
+
+       Should not milter8_mail_event() unset the "hold" default
+       reply? Better, the default reply should not be used for
+       this purpose.
+
+       Unescape the pregreeter's HELO command argument so that
+       <CR><LF> don't show up as ??.
+
+       Make postscreen logging easier. Always log connect, then log
+       why the connection is or is not forwarded.
+
+       Don't send MASTER_STAT_TAKEN/MASTER_STAT_AVAIL when a server
+       runs with process limit of 1. But this means the master
+       never learns that the process is successful and will always
+       pause $service_throttle_time before restarting a failed service.
+
+       Don't bother maintaining a per-service lockfile when a
+       server runs with process limit of 1. The purpose of the
+       lockfile is to avoid thundering herd problems when the kernel
+       wakes up multiple processes for each new client connection.
+
+       Concurrency/speed-matching: invoke a before-queue (smtpd_proxy)
+       filter after the entire message is received, so that fewer
+       filter processes will be running simultaneously.  In some
+       parts of the world, after-queue filtering is problematic.
+
+       This is different than the MailChannels patented solution
+       to multiplex many slow SMTP connections over a few fast
+       SMTP connections. We simply postpone opening the connection
+       to the filter, and rely on the before-filter SMTP server
+       to reject invalid recipients. MailChannels uses one
+       connection-to-MTA to discover invalid recipients, receives
+       the email message with a potentially reduced bitrate, and
+       then uses another connection-to-MTA to deliver the message
+       quickly.
+
        Implement PREPEND action for milter_header_checks. Save the
        to-be-prepended text to buffer, then emit it along with the
        new header.
index b665952ff4960df74630695fd09808a1317d2ba0..d89a164060c5201351dab390fe1fd0472d8aa4a4 100644 (file)
@@ -102,3 +102,6 @@ scache    unix  -       -       n       -       1       scache
 #mailman   unix  -       n       n       -       -       pipe
 #  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
 #  ${nexthop} ${user}
+#smtp      inet  n       -       n       -       1       postscreen
+#smtpd     pass  -       -       n       -       -       smtpd
+#dnsblog   unix  -       -       n       -       0       dnsblog
index 446c57f90a156e5458a3377bfd1ac33f67ed287f..6e818671a8d82822800abf7852962c7cc1090250 100644 (file)
@@ -737,6 +737,36 @@ q
 EOF
     }
 
+    # Postfix 2.7.
+    # Add missing postscreen service to master.cf.
+
+    grep '^#*smtp.*postscreen' $config_directory/master.cf >/dev/null || {
+       echo Editing $config_directory/master.cf, adding missing entry for postscreen TCP service
+       cat >>$config_directory/master.cf <<EOF || exit 1
+#smtp     inet  n       -       n       -       1       postscreen
+EOF
+    }
+
+    # Postfix 2.7.
+    # Add missing smtpd (unix-domain) service to master.cf.
+
+    grep '^#*smtpd.*smtpd' $config_directory/master.cf >/dev/null || {
+       echo Editing $config_directory/master.cf, adding missing entry for smtpd unix-domain service
+       cat >>$config_directory/master.cf <<EOF || exit 1
+#smtpd     pass  -       -       n       -       -       smtpd
+EOF
+    }
+
+    # Postfix 2.7.
+    # Add temporary dnsblog (unix-domain) service to master.cf.
+
+    grep '^#*dnsblog.*dnsblog' $config_directory/master.cf >/dev/null || {
+       echo Editing $config_directory/master.cf, adding missing entry for dnsblog unix-domain service
+       cat >>$config_directory/master.cf <<EOF || exit 1
+#dnsblog  unix  -       -       n       -       0       dnsblog
+EOF
+    }
+
     # Report (but do not remove) obsolete files.
 
     test -n "$obsolete" && {
index 7ff93eafa2e5a054ae6c1e0d5118357c8141ce0b..3a603bc896c3110946af8b20750afe8870332363 100644 (file)
@@ -67,6 +67,7 @@ $daemon_directory/anvil:f:root:-:755
 $daemon_directory/bounce:f:root:-:755
 $daemon_directory/cleanup:f:root:-:755
 $daemon_directory/discard:f:root:-:755
+$daemon_directory/dnsblog:f:root:-:755
 $daemon_directory/error:f:root:-:755
 $daemon_directory/flush:f:root:-:755
 #$daemon_directory/lmtp:f:root:-:755
@@ -82,6 +83,7 @@ $daemon_directory/postfix-files:f:root:-:644
 $daemon_directory/postfix-script:f:root:-:755
 $daemon_directory/postfix-wrapper:f:root:-:755
 $daemon_directory/postmulti-script:f:root:-:755
+$daemon_directory/postscreen:f:root:-:755
 $daemon_directory/proxymap:f:root:-:755
 $daemon_directory/qmgr:f:root:-:755
 $daemon_directory/qmqpd:f:root:-:755
@@ -179,6 +181,7 @@ $manpage_directory/man8/cleanup.8:f:root:-:644
 $manpage_directory/man8/anvil.8:f:root:-:644
 $manpage_directory/man8/defer.8:f:root:-:644
 $manpage_directory/man8/discard.8:f:root:-:644
+$manpage_directory/man8/dnsblog.8:f:root:-:644
 $manpage_directory/man8/error.8:f:root:-:644
 $manpage_directory/man8/flush.8:f:root:-:644
 $manpage_directory/man8/lmtp.8:f:root:-:644
@@ -188,6 +191,7 @@ $manpage_directory/man8/nqmgr.8:f:root:-:644:o
 $manpage_directory/man8/oqmgr.8:f:root:-:644:
 $manpage_directory/man8/pickup.8:f:root:-:644
 $manpage_directory/man8/pipe.8:f:root:-:644
+$manpage_directory/man8/postscreen.8:f:root:-:644
 $manpage_directory/man8/proxymap.8:f:root:-:644
 $manpage_directory/man8/qmgr.8:f:root:-:644
 $manpage_directory/man8/qmqpd.8:f:root:-:644
@@ -343,6 +347,7 @@ $html_directory/cidr_table.5.html:f:root:-:644
 $html_directory/cleanup.8.html:f:root:-:644
 $html_directory/defer.8.html:h:$html_directory/bounce.8.html:-:644
 $html_directory/discard.8.html:f:root:-:644
+$html_directory/dnsblog.8.html:f:root:-:644
 $html_directory/error.8.html:f:root:-:644
 $html_directory/flush.8.html:f:root:-:644
 $html_directory/generics.5.html:f:root:-:644:o
@@ -378,6 +383,7 @@ $html_directory/postlog.1.html:f:root:-:644
 $html_directory/postmap.1.html:f:root:-:644
 $html_directory/postmulti.1.html:f:root:-:644
 $html_directory/postqueue.1.html:f:root:-:644
+$html_directory/postscreen.8.html:f:root:-:644
 $html_directory/postsuper.1.html:f:root:-:644
 $html_directory/qshape.1.html:f:root:-:644
 $html_directory/proxymap.8.html:f:root:-:644
index 7d20df6bba0dbb5e4fa33edfa61c0ef5da053895..e1d73f93a1d593c7402b7347778cdcbf69d4f9b2 100644 (file)
@@ -7,7 +7,8 @@ DAEMONS =  bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
        showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
        oqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html \
        trace.8.html verify.8.html proxymap.8.html anvil.8.html \
-       scache.8.html discard.8.html tlsmgr.8.html
+       scache.8.html discard.8.html tlsmgr.8.html postscreen.8.html \
+       dnsblog.8.html
 COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
        postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
        postlog.1.html postdrop.1.html postmap.1.html postmulti.1.html \
@@ -47,6 +48,10 @@ discard.8.html: ../src/discard/discard.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
 
+dnsblog.8.html: ../src/dnsblog/dnsblog.c
+       PATH=../mantools:$$PATH; \
+       srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
+
 error.8.html: ../src/error/error.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
@@ -94,6 +99,10 @@ pipe.8.html: ../src/pipe/pipe.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
 
+postscreen.8.html: ../src/postscreen/postscreen.c
+       PATH=../mantools:$$PATH; \
+       srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
+
 proxymap.8.html: ../src/proxymap/proxymap.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
diff --git a/postfix/html/dnsblog.8.html b/postfix/html/dnsblog.8.html
new file mode 100644 (file)
index 0000000..d455de1
--- /dev/null
@@ -0,0 +1,95 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+<html> <head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+<title> Postfix manual - dnsblog(8) </title>
+</head> <body> <pre>
+DNSBLOG(8)                                                          DNSBLOG(8)
+
+<b>NAME</b>
+       dnsblog - Postfix DNS blocklist logger
+
+<b>SYNOPSIS</b>
+       <b>dnsblog</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+       The  <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a>  server implements an ad-hoc DNS blocklist
+       lookup service that will eventually be replaced by an  UDP
+       client  that  is  built  directly  into  the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+       server.
+
+       With each connection, the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> server receives a DNS
+       blocklist domain name and an IP address. If the address is
+       listed under the DNS blocklist, the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> server logs
+       the match and replies with the query arguments plus a non-
+       zero status.  Otherwise it replies with  the  query  argu-
+       ments  plus a zero status.  Finally, The <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> server
+       closes the connection.
+
+<b>DIAGNOSTICS</b>
+       Problems and transactions are logged to <b>syslogd</b>(8).
+
+<b>CONFIGURATION PARAMETERS</b>
+       Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up  automatically,  as  <b>dns-</b>
+       <b>blog</b>(8)  processes  run for only a limited amount of time.
+       Use the command "<b>postfix reload</b>" to speed up a change.
+
+       The text below provides  only  a  parameter  summary.  See
+       <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
+
+       <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
+              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              <a href="master.5.html">master.cf</a> configuration files.
+
+       <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
+              How much time a Postfix daemon process may take  to
+              handle  a  request  before  it  is  terminated by a
+              built-in watchdog timer.
+
+       <b><a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> (empty)</b>
+              Optional list of DNS blocklist domains.
+
+       <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
+              The time limit for sending or receiving information
+              over an internal communication channel.
+
+       <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
+              The  process  ID  of  a  Postfix  command or daemon
+              process.
+
+       <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
+              The process name of a  Postfix  command  or  daemon
+              process.
+
+       <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
+              The  location of the Postfix top-level queue direc-
+              tory.
+
+       <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
+              The syslog facility of Postfix logging.
+
+       <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
+              becomes, for example, "postfix/smtpd".
+
+<b>SEE ALSO</b>
+       <a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
+       <a href="postconf.5.html">postconf(5)</a>, configuration parameters
+       syslogd(5), system logging
+
+<b>LICENSE</b>
+       The Secure Mailer license must be  distributed  with  this
+       software.
+
+<b>HISTORY</b>
+       This service is temporary with Postfix version 2.7.
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
+       IBM T.J. Watson Research
+       P.O. Box 704
+       Yorktown Heights, NY 10598, USA
+
+                                                                    DNSBLOG(8)
+</pre> </body> </html>
index 4ce64ec8b3f613463b730993b67af8ee019d5e0c..94be20a98683fcfb9e272ee20c11f31fd04191f4 100644 (file)
@@ -200,12 +200,12 @@ PIPE(8)                                                                PIPE(8)
        <b>user</b>=<i>username</i> (required)
 
        <b>user</b>=<i>username</i>:<i>groupname</i>
-              Execute the external command with the rights of the
-              specified <i>username</i>.  The software refuses  to  exe-
-              cute  commands  with  root  privileges, or with the
-              privileges of the mail system owner.  If  <i>groupname</i>
-              is  specified,  the  corresponding group ID is used
-              instead of the group ID of <i>username</i>.
+              Execute  the  external command with the user ID and
+              group ID of the specified <i>username</i>.   The  software
+              refuses  to  execute commands with root privileges,
+              or with the privileges of the mail system owner. If
+              <i>groupname</i>  is specified, the corresponding group ID
+              is used instead of the group ID of <i>username</i>.
 
        <b>argv</b>=<i>command</i>... (required)
               The command to be executed. This must be  specified
@@ -381,72 +381,73 @@ PIPE(8)                                                                PIPE(8)
        ventions defined in &lt;<b>sysexits.h</b>&gt;.   Exit  status  0  means
        normal successful completion.
 
-       Postfix  version  2.3  and  later  support  <a href="http://tools.ietf.org/html/rfc3463">RFC 3463</a>-style
-       enhanced status codes.  If a  command  terminates  with  a
-       non-zero  exit  status, and the command output begins with
-       an enhanced status code, this status code takes precedence
-       over the non-zero exit status.
+       In the case of a non-zero exit status, a limited amount of
+       command output is reported in an delivery status notifica-
+       tion.   When  the  output  begins  with  a  4.X.X or 5.X.X
+       enhanced status code, the  status  code  takes  precedence
+       over  the  non-zero  exit  status (Postfix version 2.3 and
+       later).
 
-       Problems  and transactions are logged to <b>syslogd</b>(8).  Cor-
-       rupted message files are marked so that the queue  manager
+       Problems and transactions are logged to <b>syslogd</b>(8).   Cor-
+       rupted  message files are marked so that the queue manager
        can move them to the <b>corrupt</b> queue for further inspection.
 
 <b>SECURITY</b>
-       This program needs a dual personality  1)  to  access  the
-       private  Postfix  queue and IPC mechanisms, and 2) to exe-
+       This  program  needs  a  dual personality 1) to access the
+       private Postfix queue and IPC mechanisms, and 2)  to  exe-
        cute external commands as the specified user. It is there-
        fore security sensitive.
 
 <b>CONFIGURATION PARAMETERS</b>
-       Changes  to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as <a href="pipe.8.html"><b>pipe</b>(8)</a>
-       processes run for only a limited amount of time.  Use  the
+       Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as  <a href="pipe.8.html"><b>pipe</b>(8)</a>
+       processes  run  for only a limited amount of time. Use the
        command "<b>postfix reload</b>" to speed up a change.
 
-       The  text  below  provides  only  a parameter summary. See
+       The text below provides  only  a  parameter  summary.  See
        <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
 
 <b>RESOURCE AND RATE CONTROLS</b>
-       In the text below, <i>transport</i> is the first field in a  <b>mas-</b>
+       In  the text below, <i>transport</i> is the first field in a <b>mas-</b>
        <b>ter.cf</b> entry.
 
        <b><a href="postconf.5.html#transport_destination_concurrency_limit"><i>transport</i>_destination_concurrency_limit</a> ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
               Limit the number of parallel deliveries to the same
-              destination, for delivery via the named  <i>transport</i>.
+              destination,  for delivery via the named <i>transport</i>.
               The limit is enforced by the Postfix queue manager.
 
        <b><a href="postconf.5.html#transport_destination_recipient_limit"><i>transport</i>_destination_recipient_limit</a>   ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
-              Limit the number of recipients per  message  deliv-
-              ery,  for  delivery  via  the named <i>transport</i>.  The
+              Limit  the  number of recipients per message deliv-
+              ery, for delivery via  the  named  <i>transport</i>.   The
               limit is enforced by the Postfix queue manager.
 
        <b><a href="postconf.5.html#transport_time_limit"><i>transport</i>_time_limit</a> ($<a href="postconf.5.html#command_time_limit">command_time_limit</a>)</b>
-              Limit the time for delivery  to  external  command,
+              Limit  the  time  for delivery to external command,
               for delivery via the named <i>transport</i>.  The limit is
               enforced by the pipe delivery agent.
 
-              Postfix 2.4 and later support a suffix that  speci-
-              fies  the  time  unit:  s (seconds), m (minutes), h
+              Postfix  2.4 and later support a suffix that speci-
+              fies the time unit: s  (seconds),  m  (minutes),  h
               (hours), d (days), w (weeks). The default time unit
               is seconds.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The maximal number  of  digits  after  the  decimal
+              The  maximal  number  of  digits  after the decimal
               point when logging sub-second delay values.
 
        <b><a href="postconf.5.html#export_environment">export_environment</a> (see 'postconf -d' output)</b>
-              The  list  of  environment variables that a Postfix
+              The list of environment variables  that  a  Postfix
               process will export to non-Postfix processes.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -458,25 +459,25 @@ PIPE(8)                                                                PIPE(8)
               and most Postfix daemon processes.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time  that  an  idle  Postfix
-              daemon  process  waits  for  an incoming connection
+              The  maximum  amount  of  time that an idle Postfix
+              daemon process waits  for  an  incoming  connection
               before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The maximal number of incoming connections  that  a
-              Postfix  daemon  process will service before termi-
+              The  maximal  number of incoming connections that a
+              Postfix daemon process will service  before  termi-
               nating voluntarily.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The process ID  of  a  Postfix  command  or  daemon
+              The  process  ID  of  a  Postfix  command or daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The  process  name  of  a Postfix command or daemon
+              The process name of a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
-              The location of the Postfix top-level queue  direc-
+              The  location of the Postfix top-level queue direc-
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
@@ -487,8 +488,8 @@ PIPE(8)                                                                PIPE(8)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              The mail system  name  that  is  prepended  to  the
-              process  name  in  syslog  records, so that "smtpd"
+              The  mail  system  name  that  is  prepended to the
+              process name in syslog  records,  so  that  "smtpd"
               becomes, for example, "postfix/smtpd".
 
 <b>SEE ALSO</b>
@@ -500,7 +501,7 @@ PIPE(8)                                                                PIPE(8)
        syslogd(8), system logging
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 9dced2a3fba35cf7076aab6cf1743ed86943efe2..c73971ea1ff4e048ef9901a9cd55f3881d09a3ed 100644 (file)
@@ -6469,6 +6469,244 @@ and enabled instances are processed in reverse order. </p>
 <p> This feature is available in Postfix 2.6 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="postscreen_blacklist_action">postscreen_blacklist_action</a>
+(default: continue)</b></DT><DD>
+
+<p> The action that <a href="postscreen.8.html">postscreen(8)</a> takes when an SMTP client is
+permanently blacklisted with the <a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a>
+parameter.  Specify one of the following: </p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Continue waiting until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
+elapsed, and report whether the client triggers a PREGREET or HANGUP
+error, or whether the client is listed at the DNSBL sites specified
+with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.  Take the corresponding
+action, or forward the connection to a real SMTP server process.
+</p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection immediately with a 521 SMTP reply, without
+reporting PREGREET, HANGUP or DNSBL results. </dd>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+</dl>
+
+
+</DD>
+
+<DT><b><a name="postscreen_blacklist_networks">postscreen_blacklist_networks</a>
+(default: empty)</b></DT><DD>
+
+<p> Network addresses that are permanently blacklisted; see the
+<a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter for possible actions.  This
+parameter uses the same address syntax as the <a href="postconf.5.html#mynetworks">mynetworks</a> parameter.
+The blacklist has higher precedence than whitelists. This feature
+never uses the remote SMTP client hostname.  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_cache_map">postscreen_cache_map</a>
+(default: btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_whitelist)</b></DT><DD>
+
+<p> Persistent storage for the <a href="postscreen.8.html">postscreen(8)</a> server decisions. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_cache_ttl">postscreen_cache_ttl</a>
+(default: 1d)</b></DT><DD>
+
+<p> The amount of time that <a href="postscreen.8.html">postscreen(8)</a> will cache a decision for
+a specific SMTP client IP address. During this time, the client IP
+address is excluded from tests. If possible, expired decisions are
+renewed silently. Specify a non-zero time value (an integral value
+plus an optional one-letter suffix that specifies the time unit).
+</p>
+
+<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks).  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_dnsbl_action">postscreen_dnsbl_action</a>
+(default: continue)</b></DT><DD>
+
+<p>The action that <a href="postscreen.8.html">postscreen(8)</a> takes when an SMTP client is listed
+at the DNS blocklist domains specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>
+parameter.  Specify one of the following: </p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Forward the connection to a real SMTP server process. </p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection with a 521 SMTP reply. </dd>
+
+</dl>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>
+(default: empty)</b></DT><DD>
+
+<p>Optional list of DNS blocklist domains. When the list is non-enpty,
+the <a href="dnsblog.8.html">dnsblog(8)</a> daemon will query these domains with the IP addresses
+of non-whitelisted <a href="postscreen.8.html">postscreen(8)</a> clients. Specify a list of domain
+names, separated by comma or whitespace. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_greet_action">postscreen_greet_action</a>
+(default: continue)</b></DT><DD>
+
+<p>The action that <a href="postscreen.8.html">postscreen(8)</a> takes when an SMTP client speaks
+before its turn within the time specified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>
+parameter.  Specify one of the following: </p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Continue waiting until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
+elapsed. If the client is listed at the DNS blocklist domains
+specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter, execute the
+action specified with the <a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> parameter, otherwise
+forward the connection to a real SMTP server process. </p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection immediately with a 521 SMTP reply, without
+examining DNSBL lookup results. </dd>
+
+</dl>
+
+<p> In either case, <a href="postscreen.8.html">postscreen(8)</a> will not whitelist the SMTP client
+IP address. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_greet_banner">postscreen_greet_banner</a>
+(default: $<a href="postconf.5.html#smtpd_banner">smtpd_banner</a>)</b></DT><DD>
+
+<p> The text in the optional "220-text..." server response that
+<a href="postscreen.8.html">postscreen(8)</a> sends ahead of the real Postfix SMTP server's "220
+text..." response, in an attempt to confuse bad SMTP clients so
+that they speak before their turn (pre-greet).  Specify an empty
+value to disable this feature.  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_greet_wait">postscreen_greet_wait</a>
+(default: 4s)</b></DT><DD>
+
+<p> The amount of time that <a href="postscreen.8.html">postscreen(8)</a> will wait for an SMTP
+client to send a command before its turn, and for DNS blocklist
+lookup results to arrive. This is done only when the SMTP client
+IP address is not permanently whitelisted, and when it has no cached
+decision.  Specify a non-zero time value (an integral value plus
+an optional one-letter suffix that specifies the time unit).  </p>
+
+<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks).  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_hangup_action">postscreen_hangup_action</a>
+(default: continue)</b></DT><DD>
+
+<p>The action that <a href="postscreen.8.html">postscreen(8)</a> takes when an SMTP client disconnects
+without sending data, within the time specified with the
+<a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter.  Specify one of the following:
+</p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Continue waiting until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
+elapsed, and report whether the client is listed at the DNSBL sites
+specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter. Do not
+forward the broken connection to a real SMTP server process. </p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection immediately, without reporting DNSBL lookup
+results. </dd>
+
+</dl>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_post_queue_limit">postscreen_post_queue_limit</a>
+(default: $<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b></DT><DD>
+
+<p> The number of clients that can be waiting for service from a
+real SMTP server process. When this queue is full, all clients will
+receive a 421 reponse. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_pre_queue_limit">postscreen_pre_queue_limit</a>
+(default: $<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b></DT><DD>
+
+<p> The number of non-whitelisted clients that can be waiting for
+a decision whether they will receive service from a real SMTP server
+process. When this queue is full, all non-whitelisted clients will
+receive a 421 reponse. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_whitelist_networks">postscreen_whitelist_networks</a>
+(default: $<a href="postconf.5.html#mynetworks">mynetworks</a>)</b></DT><DD>
+
+<p> Network addresses that are permanently whitelisted, and that
+will not be subjected to <a href="postscreen.8.html">postscreen(8)</a> checks. This parameter uses
+the same address syntax as the <a href="postconf.5.html#mynetworks">mynetworks</a> parameter. This feature
+never uses the remote SMTP client hostname.  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
 </DD>
 
 <DT><b><a name="prepend_delivered_header">prepend_delivered_header</a>
@@ -8292,8 +8530,9 @@ The default time unit is s (seconds).
 (default: dns)</b></DT><DD>
 
 <p>
-What mechanisms when the Postfix SMTP client uses to look up a host's IP
-address.  This parameter is ignored when DNS lookups are disabled.
+What mechanisms the Postfix SMTP client uses to look up a host's IP
+address.  This parameter is ignored when DNS lookups are disabled
+(see: <a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a>).
 </p>
 
 <p>
@@ -10569,6 +10808,22 @@ Postfix version 2.5).  This feature is available with Postfix version
 parent domains, client IP address, or networks obtained by stripping
 least significant octets. See the <a href="access.5.html">access(5)</a> manual page for details. </dd>
 
+<dt><b><a name="check_client_mx_access">check_client_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for the
+client hostname, and execute the corresponding action.  Note: a result
+of "OK" is not allowed for safety reasons. Instead, use DUNNO in order
+to exclude specific hosts from blacklists.  This feature is available
+in Postfix 2.7 and later.  </dd>
+
+<dt><b><a name="check_client_ns_access">check_client_ns_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified <a href="access.5.html">access(5)</a> database for the DNS servers for
+the client hostname, and execute the corresponding action.  Note: a
+result of "OK" is not allowed for safety reasons. Instead, use DUNNO
+in order to exclude specific hosts from blacklists.  This feature is
+available in Postfix 2.7 and later.  </dd>
+
 <dt><b><a name="check_reverse_client_hostname_access">check_reverse_client_hostname_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
 
 <dd>Search the specified access database for the unverified reverse
@@ -10579,6 +10834,22 @@ safety reasons.  Instead, use DUNNO in order to exclude specific
 hosts from blacklists.  This feature is available in Postfix 2.6
 and later.</dd>
 
+<dt><b><a name="check_reverse_client_hostname_mx_access">check_reverse_client_hostname_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for the
+unverified reverse client hostname, and execute the corresponding
+action.  Note: a result of "OK" is not allowed for safety reasons.
+Instead, use DUNNO in order to exclude specific hosts from blacklists.
+This feature is available in Postfix 2.7 and later.  </dd>
+
+<dt><b><a name="check_reverse_client_hostname_ns_access">check_reverse_client_hostname_ns_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified <a href="access.5.html">access(5)</a> database for the DNS servers for
+the unverified reverse client hostname, and execute the corresponding
+action.  Note: a result of "OK" is not allowed for safety reasons.
+Instead, use DUNNO in order to exclude specific hosts from blacklists.
+This feature is available in Postfix 2.7 and later.  </dd>
+
 <dt><b><a name="permit_inet_interfaces">permit_inet_interfaces</a></b></dt>
 
 <dd>Permit the request when the client IP address matches
@@ -12198,6 +12469,18 @@ Examples:
 </pre>
 
 
+</DD>
+
+<DT><b><a name="smtpd_service">smtpd_service</a>
+(default: smtpd)</b></DT><DD>
+
+<p> The internal service that <a href="postscreen.8.html">postscreen(8)</a> forwards allowed
+connections to. In a future version there may be different
+classes of SMTP service. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+
 </DD>
 
 <DT><b><a name="smtpd_soft_error_limit">smtpd_soft_error_limit</a>
index 92fc12202d669fdc2cb4c3fcd4684eac1d429117..655bc7db6655b0bc82d85a879151cfaef0256160 100644 (file)
@@ -196,6 +196,8 @@ the following convention:  </p>
 
 <li> <a href="pipe.8.html">pipe(8)</a>, deliver mail to non-Postfix command 
 
+<li> <a href="postscreen.8.html">postscreen(8)</a>, Postfix SMTP triage server 
+
 <li> <a href="proxymap.8.html">proxymap(8)</a>, Postfix lookup table proxy server 
 
 <li> <a href="qmgr.8.html">qmgr(8)</a>, Postfix queue manager 
index 2339142f096dce9619774c1636a336826ff50975..8415435d4ab3521f6c978a79f4116686ae1abc61 100644 (file)
@@ -315,6 +315,7 @@ POSTFIX(1)                                                          POSTFIX(1)
        <a href="qmgr.8.html">oqmgr(8)</a>, old Postfix queue manager
        <a href="pickup.8.html">pickup(8)</a>, Postfix local mail pickup
        <a href="pipe.8.html">pipe(8)</a>, deliver mail to non-Postfix command
+       <a href="postscreen.8.html">postscreen(8)</a>, Postfix SMTP triage server
        <a href="proxymap.8.html">proxymap(8)</a>, Postfix lookup table proxy server
        <a href="qmgr.8.html">qmgr(8)</a>, Postfix queue manager
        <a href="qmqpd.8.html">qmqpd(8)</a>, Postfix QMQP server
diff --git a/postfix/html/postscreen.8.html b/postfix/html/postscreen.8.html
new file mode 100644 (file)
index 0000000..73fbc51
--- /dev/null
@@ -0,0 +1,352 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+<html> <head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+<title> Postfix manual - postscreen(8) </title>
+</head> <body> <pre>
+POSTSCREEN(8)                                                    POSTSCREEN(8)
+
+<b>NAME</b>
+       postscreen - Postfix SMTP triage server
+
+<b>SYNOPSIS</b>
+       <b>postscreen</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+       The Postfix <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server performs triage on multi-
+       ple inbound SMTP connections in parallel. The program  can
+       run in two basic modes.
+
+       In  <b>observation  mode</b> the purpose is to collect statistics
+       without actually blocking mail. <a href="postscreen.8.html"><b>postscreen</b>(8)</a> runs a  num-
+       ber  of  tests  before  it forwards a connection to a real
+       SMTP server process.  These tests introduce a delay  of  a
+       few  seconds;  once  a client passes the tests as "clean",
+       its IP address is whitelisted and  subsequent  connections
+       incur no delays until the whitelist entry expires.
+
+       In  <b>enforcement  mode</b> the purpose is to block mail without
+       using up one Postfix SMTP server process for every connec-
+       tion.   Here,  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  terminates  connections from
+       SMTP clients that fail the above tests, and forwards  only
+       the  remaining  connections to a real SMTP server process.
+       By  running  time-consuming  spam  tests  in  parallel  in
+       <a href="postscreen.8.html"><b>postscreen</b>(8)</a>,  more  Postfix SMTP server processes remain
+       available for legitimate clients.
+
+       Note: <a href="postscreen.8.html"><b>postscreen</b>(8)</a> is not an SMTP proxy; this  is  inten-
+       tional.  The  purpose  is to prioritize legitimate clients
+       with as little overhead as possible.
+
+       <a href="postscreen.8.html"><b>postscreen</b>(8)</a> logs its observations and takes  actions  as
+       described in the sections that follow.
+
+<b>PERMANENT BLACKLIST TEST</b>
+       The   <a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a>   parameter  (default:
+       empty) specifies a permanent blacklist for SMTP client  IP
+       addresses.  The address syntax is as with <a href="postconf.5.html#mynetworks">mynetworks</a>. When
+       the SMTP client address matches the  permanent  blacklist,
+       this is logged as:
+
+       <b>BLACKLISTED</b> <i>address</i>
+
+       The  <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a>  parameter  specifies the
+       action that is taken next:
+
+       <b>continue</b> (default, observation mode)
+              Continue with the SMTP GREETING PHASE TESTS  below.
+
+       <b>drop</b> (enforcement mode)
+              Drop  the  connection  immediately  with a 521 SMTP
+              reply.  In a future implementation, the  connection
+              may  instead  be  passed  to  a dummy SMTP protocol
+              engine that logs sender and recipient  information.
+
+<b>PERMANENT WHITELIST TEST</b>
+       The   <a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a>   parameter  (default:
+       $<a href="postconf.5.html#mynetworks">mynetworks</a>) specifies  a  permanent  whitelist  for  SMTP
+       client  IP  addresses.   This  feature  is  not  used  for
+       addresses that appear on the permanent blacklist. When the
+       SMTP  client address matches the permanent whitelist, this
+       is logged as:
+
+       <b>WHITELISTED</b> <i>address</i>
+
+       The action is not configurable:  immediately  forward  the
+       connection to a real SMTP server process.
+
+<b>TEMPORARY WHITELIST TEST</b>
+       The  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  daemon maintains a <i>temporary</i> whitelist
+       for SMTP client IP addresses  that  have  passed  all  the
+       tests  described below. The <a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> parameter
+       specifies the location of the  temporary  whitelist.   The
+       temporary  whitelist is not used for SMTP client addresses
+       that appear on the <i>permanent</i> blacklist or whitelist.
+
+       When the SMTP client  address  appears  on  the  temporary
+       whitelist, this is logged as:
+
+       <b>PASS OLD</b> <i>address</i>
+
+       The  action  is  not configurable: immediately forward the
+       connection to a real SMTP server process.  The  client  is
+       excluded  from further tests until its temporary whitelist
+       entry expires, as controlled with the <a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a>
+       parameter.  Expired entries are silently renewed if possi-
+       ble.
+
+<b>SMTP GREETING PHASE TESTS</b>
+       The  <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>  parameter  specifies  a   time
+       interval during which <a href="postscreen.8.html"><b>postscreen</b>(8)</a> runs a number of tests
+       as described below.  These tests run before the client may
+       see  the real SMTP server's "220 text..." server greeting.
+       When the SMTP client passes all the tests, this is  logged
+       as:
+
+       <b>PASS NEW</b> <i>address</i>
+
+       The  action  is  to  forward the connection to a real SMTP
+       server process and to create a temporary  whitelist  entry
+       that  excludes  the  client  IP address from further tests
+       until the temporary whitelist entry expires, as controlled
+       with the <a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a> parameter.
+
+       In  a  future  implementation, the connection may first be
+       passed to a dummy SMTP  protocol  engine  that  implements
+       more  protocol  tests  including  greylisting,  before the
+       client is allowed to talk to a real SMTP server process.
+
+<b>PREGREET TEST</b>
+       The <a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> parameter specifies  the  text
+       for  a  "220-text..."  teaser banner (default: $<a href="postconf.5.html#smtpd_banner">smtpd_ban</a>-
+       <a href="postconf.5.html#smtpd_banner">ner</a>).  The <a href="postscreen.8.html"><b>postscreen</b>(8)</a>  daemon  sends  this  before  the
+       <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>  timer  is  started.  The purpose of
+       the teaser banner is to confuse SPAM clients so that  they
+       speak  before their turn. It has no effect on SMTP clients
+       that correctly implement the protocol.
+
+       To avoid problems with  broken  SMTP  engines  in  network
+       appliances,  either  exclude  them from all tests with the
+       <a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> feature or else  specify  an
+       empty   <a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a>   value   to  disable  the
+       "220-text..."  teaser banner.
+
+       When    an    SMTP    client     speaks     before     the
+       <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has elapsed, this is logged as:
+
+       <b>PREGREET</b> <i>count</i> <b>after</b> <i>time</i> <b>from</b> <i>address text...</i>
+
+       Translation: the client at <i>address</i> sent <i>count</i> bytes before
+       its  turn  to  speak, and this happened <i>time</i> seconds after
+       the test started. The <i>text</i> is what the client sent  (trun-
+       cated  at  100  bytes,  and  with non-printable characters
+       replaced with "?").
+
+       The <a href="postconf.5.html#postscreen_greet_action">postscreen_greet_action</a> parameter specifies the action
+       that is taken next:
+
+       <b>continue</b> (default, observation mode)
+              Wait   until  the  <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>  time  has
+              elapsed, then report DNSBL lookup results if appli-
+              cable. Either perform DNSBL-related actions or for-
+              ward the connection to a real SMTP server  process.
+
+       <b>drop</b> (enforcement mode)
+              Drop  the  connection  immediately  with a 521 SMTP
+              reply.  In a future implementation, the  connection
+              may  instead  be  passed  to  a dummy SMTP protocol
+              engine that logs sender and recipient  information.
+
+<b>HANGUP TEST</b>
+       When  the  SMTP  client  hangs up without sending any data
+       before the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has elapsed, this is
+       logged as:
+
+       <b>HANGUP after</b> <i>time</i> <b>from</b> <i>address</i>
+
+       The  <a href="postconf.5.html#postscreen_hangup_action">postscreen_hangup_action</a> specifies the action that is
+       taken next:
+
+       <b>continue</b> (default, observation mode)
+              Wait  until  the  <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>  time   has
+              elapsed, then report DNSBL lookup results if appli-
+              cable. Do not forward the broken  connection  to  a
+              real SMTP server process.
+
+       <b>drop</b> (enforcement mode)
+              Drop the connection immediately.
+
+<b>DNS BLOCKLIST TEST</b>
+       The   <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>  parameter  (default:  empty)
+       specifies a  list  of  DNS  blocklist  servers.  When  the
+       <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>  time  has  elapsed,  and  the  SMTP
+       client address is reported by at least one of these block-
+       lists, this is logged as:
+
+       <b>DNSBL rank</b> <i>count</i> <b>for</b> <i>address</i>
+
+       Translation:  the  client  at <i>address</i> is listed with <i>count</i>
+       DNSBL servers. The <i>count</i> does not depend on the number  of
+       DNS records that an individual DNSBL server returns.
+
+       The <a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> parameter specifies the action
+       that is taken next:
+
+       <b>continue</b> (default, observation mode)
+              Forward  the  connection  to  a  real  SMTP  server
+              process.
+
+       <b>drop</b> (enforcement mode)
+              Drop  the  connection  immediately  with a 521 SMTP
+              reply.  In a future implementation, the  connection
+              may  instead  be  passed  to  a dummy SMTP protocol
+              engine that logs sender and recipient  information.
+
+<b>SECURITY</b>
+       The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server is moderately security-sensitive.
+       It talks to untrusted clients on the network. The  process
+       can be run chrooted at fixed low privilege.
+
+<b>STANDARDS</b>
+       <a href="http://tools.ietf.org/html/rfc5321">RFC 5321</a> (SMTP, including multi-line 220 greetings)
+       <a href="http://tools.ietf.org/html/rfc2920">RFC 2920</a> (SMTP Pipelining)
+
+<b>DIAGNOSTICS</b>
+       Problems and transactions are logged to <b>syslogd</b>(8).
+
+<b>CONFIGURATION PARAMETERS</b>
+       Changes  to  <a href="postconf.5.html">main.cf</a>  are  not picked up automatically, as
+       <a href="postscreen.8.html"><b>postscreen</b>(8)</a> processes may run for  several  hours.   Use
+       the command "postfix reload" after a configuration change.
+
+       The text below provides  only  a  parameter  summary.  See
+       <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
+
+<b>TRIAGE PARAMETERS</b>
+       <b><a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> (continue)</b>
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
+              client  is   permanently   blacklisted   with   the
+              <a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> parameter.
+
+       <b><a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> (empty)</b>
+              Network addresses that are permanently blacklisted;
+              see the <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a>  parameter  for
+              possible actions.
+
+       <b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> (btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_whitelist)</b>
+              Persistent  storage  for  the  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
+              decisions.
+
+       <b><a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a> (1d)</b>
+              The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache  a
+              decision for a specific SMTP client IP address.
+
+       <b><a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> (continue)</b>
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
+              client is listed at the DNS blocklist domains spec-
+              ified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
+
+       <b><a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> (empty)</b>
+              Optional list of DNS blocklist domains.
+
+       <b><a href="postconf.5.html#postscreen_greet_action">postscreen_greet_action</a> (continue)</b>
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
+              client speaks before its turn within the time spec-
+              ified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter.
+
+       <b><a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> ($<a href="postconf.5.html#smtpd_banner">smtpd_banner</a>)</b>
+              The  text  in  the  optional  "220-text..."  server
+              response that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> sends ahead of the real
+              Postfix SMTP server's "220 text..." response, in an
+              attempt to confuse bad SMTP clients  so  that  they
+              speak before their turn (pre-greet).
+
+       <b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (4s)</b>
+              The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will wait for
+              an SMTP client to send a command before  its  turn,
+              and for DNS blocklist lookup results to arrive.
+
+       <b><a href="postconf.5.html#postscreen_hangup_action">postscreen_hangup_action</a> (continue)</b>
+              The  action  that  <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
+              client disconnects without sending data, within the
+              time   specified   with  the  <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>
+              parameter.
+
+       <b><a href="postconf.5.html#postscreen_post_queue_limit">postscreen_post_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
+              The number of clients that can be waiting for  ser-
+              vice from a real SMTP server process.
+
+       <b><a href="postconf.5.html#postscreen_pre_queue_limit">postscreen_pre_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
+              The  number  of non-whitelisted clients that can be
+              waiting for a decision whether  they  will  receive
+              service from a real SMTP server process.
+
+       <b><a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
+              Network addresses that are permanently whitelisted,
+              and that will not  be  subjected  to  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+              checks.
+
+       <b><a href="postconf.5.html#smtpd_service">smtpd_service</a> (smtpd)</b>
+              The  internal  service  that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> forwards
+              allowed connections to.
+
+<b>MISCELLANEOUS CONTROLS</b>
+       <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
+              <a href="master.5.html">master.cf</a> configuration files.
+
+       <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
+              built-in watchdog timer.
+
+       <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
+              The  maximal  number  of  digits  after the decimal
+              point when logging sub-second delay values.
+
+       <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
+              The location of  all  postfix  administrative  com-
+              mands.
+
+       <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
+              The time limit for sending or receiving information
+              over an internal communication channel.
+
+       <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
+              The maximum amount of time  that  an  idle  Postfix
+              daemon  process  waits  for  an incoming connection
+              before terminating voluntarily.
+
+       <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
+              The process ID  of  a  Postfix  command  or  daemon
+              process.
+
+       <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
+              The  process  name  of  a Postfix command or daemon
+              process.
+
+       <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
+              The syslog facility of Postfix logging.
+
+       <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
+              becomes, for example, "postfix/smtpd".
+
+<b>SEE ALSO</b>
+       <a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
+       <a href="dnsblog.8.html">dnsblog(8)</a>, temporary DNS helper
+       syslogd(8), system logging
+
+<b>LICENSE</b>
+       The Secure Mailer license must be  distributed  with  this
+       software.
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
+       IBM T.J. Watson Research
+       P.O. Box 704
+       Yorktown Heights, NY 10598, USA
+
+                                                                 POSTSCREEN(8)
+</pre> </body> </html>
index c9753a2860da970f88436e1c9f59942e2daae6a5..1e359ea51b00a69ffe35394665ebfa0ee7f4f3b6 100644 (file)
@@ -7,7 +7,8 @@ DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
        man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
        man8/oqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8 \
        man8/verify.8 man8/trace.8 man8/proxymap.8 man8/anvil.8 \
-       man8/scache.8 man8/discard.8 man8/tlsmgr.8
+       man8/scache.8 man8/discard.8 man8/tlsmgr.8 man8/postscreen.8 \
+       man8/dnsblog.8
 COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
        man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
        man1/postmap.1 man1/postmulti.1 man1/postqueue.1 man1/postsuper.1 \
@@ -59,6 +60,11 @@ man8/discard.8: ../src/discard/discard.c
            (cmp -s junk $? || mv junk $?) && rm -f junk
        ../mantools/srctoman $? >$@
 
+man8/dnsblog.8: ../src/dnsblog/dnsblog.c
+       ../mantools/fixman ../proto/postconf.proto $? >junk && \
+           (cmp -s junk $? || mv junk $?) && rm -f junk
+       ../mantools/srctoman $? >$@
+
 man8/error.8: ../src/error/error.c
        ../mantools/fixman ../proto/postconf.proto $? >junk && \
            (cmp -s junk $? || mv junk $?) && rm -f junk
@@ -100,6 +106,11 @@ man8/pipe.8: ../src/pipe/pipe.c
            (cmp -s junk $? || mv junk $?) && rm -f junk
        ../mantools/srctoman $? >$@
 
+man8/postscreen.8: ../src/postscreen/postscreen.c
+       ../mantools/fixman ../proto/postconf.proto $? >junk && \
+           (cmp -s junk $? || mv junk $?) && rm -f junk
+       ../mantools/srctoman $? >$@
+
 man8/proxymap.8: ../src/proxymap/proxymap.c
        ../mantools/fixman ../proto/postconf.proto $? >junk && \
            (cmp -s junk $? || mv junk $?) && rm -f junk
index f1d59b8c75925debbcc75ed0888b292a7028c28f..c8d60194127140da7e6cbb58f6d33b3127484d1e 100644 (file)
@@ -273,6 +273,7 @@ master(8), Postfix master daemon
 oqmgr(8), old Postfix queue manager
 pickup(8), Postfix local mail pickup
 pipe(8), deliver mail to non-Postfix command
+postscreen(8), Postfix SMTP triage server
 proxymap(8), Postfix lookup table proxy server
 qmgr(8), Postfix queue manager
 qmqpd(8), Postfix QMQP server
index e984d837b89acaf36af8e04887b134fed2908a78..2cf5b495922304ac13dc395ca381ef46b118cf25 100644 (file)
@@ -3627,6 +3627,131 @@ as "stop" commands. For these commands, disabled instances are skipped,
 and enabled instances are processed in reverse order.
 .PP
 This feature is available in Postfix 2.6 and later.
+.SH postscreen_blacklist_action (default: continue)
+The action that \fBpostscreen\fR(8) takes when an SMTP client is
+permanently blacklisted with the postscreen_blacklist_networks
+parameter.  Specify one of the following:
+.IP "continue"
+Continue waiting until the postscreen_greet_wait time has
+elapsed, and report whether the client triggers a PREGREET or HANGUP
+error, or whether the client is listed at the DNSBL sites specified
+with the postscreen_dnsbl_sites parameter.  Take the corresponding
+action, or forward the connection to a real SMTP server process.
+.IP "drop"
+Drop the connection immediately with a 521 SMTP reply, without
+reporting PREGREET, HANGUP or DNSBL results.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_blacklist_networks (default: empty)
+Network addresses that are permanently blacklisted; see the
+postscreen_blacklist_action parameter for possible actions.  This
+parameter uses the same address syntax as the mynetworks parameter.
+The blacklist has higher precedence than whitelists. This feature
+never uses the remote SMTP client hostname.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_cache_map (default: btree:$data_directory/ps_whitelist)
+Persistent storage for the \fBpostscreen\fR(8) server decisions.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_cache_ttl (default: 1d)
+The amount of time that \fBpostscreen\fR(8) will cache a decision for
+a specific SMTP client IP address. During this time, the client IP
+address is excluded from tests. If possible, expired decisions are
+renewed silently. Specify a non-zero time value (an integral value
+plus an optional one-letter suffix that specifies the time unit).
+.PP
+Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks).
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_dnsbl_action (default: continue)
+The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
+at the DNS blocklist domains specified with the postscreen_dnsbl_sites
+parameter.  Specify one of the following:
+.IP "continue"
+Forward the connection to a real SMTP server process.
+.IP "drop"
+Drop the connection with a 521 SMTP reply.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_dnsbl_sites (default: empty)
+Optional list of DNS blocklist domains. When the list is non-enpty,
+the \fBdnsblog\fR(8) daemon will query these domains with the IP addresses
+of non-whitelisted \fBpostscreen\fR(8) clients. Specify a list of domain
+names, separated by comma or whitespace.
+.SH postscreen_greet_action (default: continue)
+The action that \fBpostscreen\fR(8) takes when an SMTP client speaks
+before its turn within the time specified with the postscreen_greet_wait
+parameter.  Specify one of the following:
+.IP "continue"
+Continue waiting until the postscreen_greet_wait time has
+elapsed. If the client is listed at the DNS blocklist domains
+specified with the postscreen_dnsbl_sites parameter, execute the
+action specified with the postscreen_dnsbl_action parameter, otherwise
+forward the connection to a real SMTP server process.
+.IP "drop"
+Drop the connection immediately with a 521 SMTP reply, without
+examining DNSBL lookup results.
+.PP
+In either case, \fBpostscreen\fR(8) will not whitelist the SMTP client
+IP address.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_greet_banner (default: $smtpd_banner)
+The text in the optional "220-text..." server response that
+\fBpostscreen\fR(8) sends ahead of the real Postfix SMTP server's "220
+text..." response, in an attempt to confuse bad SMTP clients so
+that they speak before their turn (pre-greet).  Specify an empty
+value to disable this feature.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_greet_wait (default: 4s)
+The amount of time that \fBpostscreen\fR(8) will wait for an SMTP
+client to send a command before its turn, and for DNS blocklist
+lookup results to arrive. This is done only when the SMTP client
+IP address is not permanently whitelisted, and when it has no cached
+decision.  Specify a non-zero time value (an integral value plus
+an optional one-letter suffix that specifies the time unit).
+.PP
+Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks).
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_hangup_action (default: continue)
+The action that \fBpostscreen\fR(8) takes when an SMTP client disconnects
+without sending data, within the time specified with the
+postscreen_greet_wait parameter.  Specify one of the following:
+.IP "continue"
+Continue waiting until the postscreen_greet_wait time has
+elapsed, and report whether the client is listed at the DNSBL sites
+specified with the postscreen_dnsbl_sites parameter. Do not
+forward the broken connection to a real SMTP server process.
+.IP "drop"
+Drop the connection immediately, without reporting DNSBL lookup
+results.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_post_queue_limit (default: $default_process_limit)
+The number of clients that can be waiting for service from a
+real SMTP server process. When this queue is full, all clients will
+receive a 421 reponse.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_pre_queue_limit (default: $default_process_limit)
+The number of non-whitelisted clients that can be waiting for
+a decision whether they will receive service from a real SMTP server
+process. When this queue is full, all non-whitelisted clients will
+receive a 421 reponse.
+.PP
+This feature is available in Postfix 2.7.
+.SH postscreen_whitelist_networks (default: $mynetworks)
+Network addresses that are permanently whitelisted, and that
+will not be subjected to \fBpostscreen\fR(8) checks. This parameter uses
+the same address syntax as the mynetworks parameter. This feature
+never uses the remote SMTP client hostname.
+.PP
+This feature is available in Postfix 2.7.
 .SH prepend_delivered_header (default: command, file, forward)
 The message delivery contexts where the Postfix \fBlocal\fR(8) delivery
 agent prepends a Delivered-To:  message header with the address
@@ -4711,8 +4836,9 @@ and for receiving the initial server response.
 Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
 The default time unit is s (seconds).
 .SH smtp_host_lookup (default: dns)
-What mechanisms when the Postfix SMTP client uses to look up a host's IP
-address.  This parameter is ignored when DNS lookups are disabled.
+What mechanisms the Postfix SMTP client uses to look up a host's IP
+address.  This parameter is ignored when DNS lookups are disabled
+(see: disable_dns_lookups).
 .PP
 Specify one of the following:
 .IP "\fBdns\fR"
@@ -6434,6 +6560,18 @@ Postfix version 2.5).  This feature is available with Postfix version
 Search the specified access database for the client hostname,
 parent domains, client IP address, or networks obtained by stripping
 least significant octets. See the \fBaccess\fR(5) manual page for details.
+.IP "\fBcheck_client_mx_access \fItype:table\fR\fR"
+Search the specified \fBaccess\fR(5) database for the MX hosts for the
+client hostname, and execute the corresponding action.  Note: a result
+of "OK" is not allowed for safety reasons. Instead, use DUNNO in order
+to exclude specific hosts from blacklists.  This feature is available
+in Postfix 2.7 and later.
+.IP "\fBcheck_client_ns_access \fItype:table\fR\fR"
+Search the specified \fBaccess\fR(5) database for the DNS servers for
+the client hostname, and execute the corresponding action.  Note: a
+result of "OK" is not allowed for safety reasons. Instead, use DUNNO
+in order to exclude specific hosts from blacklists.  This feature is
+available in Postfix 2.7 and later.
 .IP "\fBcheck_reverse_client_hostname_access \fItype:table\fR\fR"
 Search the specified access database for the unverified reverse
 client hostname, parent domains, client IP address, or networks
@@ -6442,6 +6580,18 @@ manual page for details.  Note: a result of "OK" is not allowed for
 safety reasons.  Instead, use DUNNO in order to exclude specific
 hosts from blacklists.  This feature is available in Postfix 2.6
 and later.
+.IP "\fBcheck_reverse_client_hostname_mx_access \fItype:table\fR\fR"
+Search the specified \fBaccess\fR(5) database for the MX hosts for the
+unverified reverse client hostname, and execute the corresponding
+action.  Note: a result of "OK" is not allowed for safety reasons.
+Instead, use DUNNO in order to exclude specific hosts from blacklists.
+This feature is available in Postfix 2.7 and later.
+.IP "\fBcheck_reverse_client_hostname_ns_access \fItype:table\fR\fR"
+Search the specified \fBaccess\fR(5) database for the DNS servers for
+the unverified reverse client hostname, and execute the corresponding
+action.  Note: a result of "OK" is not allowed for safety reasons.
+Instead, use DUNNO in order to exclude specific hosts from blacklists.
+This feature is available in Postfix 2.7 and later.
 .IP "\fBpermit_inet_interfaces\fR"
 Permit the request when the client IP address matches
 $inet_interfaces.
@@ -7533,6 +7683,12 @@ smtpd_sender_restrictions = reject_unknown_sender_domain,
 .fi
 .ad
 .ft R
+.SH smtpd_service (default: smtpd)
+The internal service that \fBpostscreen\fR(8) forwards allowed
+connections to. In a future version there may be different
+classes of SMTP service.
+.PP
+This feature is available in Postfix 2.7.
 .SH smtpd_soft_error_limit (default: 10)
 The number of errors a remote SMTP client is allowed to make without
 delivering mail before the Postfix SMTP server slows down all its
diff --git a/postfix/man/man8/dnsblog.8 b/postfix/man/man8/dnsblog.8
new file mode 100644 (file)
index 0000000..f18b81c
--- /dev/null
@@ -0,0 +1,89 @@
+.TH DNSBLOG 8 
+.ad
+.fi
+.SH NAME
+dnsblog
+\-
+Postfix DNS blocklist logger
+.SH "SYNOPSIS"
+.na
+.nf
+\fBdnsblog\fR [generic Postfix daemon options]
+.SH DESCRIPTION
+.ad
+.fi
+The \fBdnsblog\fR(8) server implements an ad-hoc DNS blocklist
+lookup service that will eventually be replaced by an UDP
+client that is built directly into the \fBpostscreen\fR(8)
+server.
+
+With each connection, the \fBdnsblog\fR(8) server receives
+a DNS blocklist domain name and an IP address. If the address
+is listed under the DNS blocklist, the \fBdnsblog\fR(8)
+server logs the match and replies with the query arguments
+plus a non-zero status.  Otherwise it replies with the query
+arguments plus a zero status.  Finally, The \fBdnsblog\fR(8)
+server closes the connection.
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to \fBsyslogd\fR(8).
+.SH "CONFIGURATION PARAMETERS"
+.na
+.nf
+.ad
+.fi
+Changes to \fBmain.cf\fR are picked up automatically, as
+\fBdnsblog\fR(8) processes run for only a limited amount
+of time. Use the command "\fBpostfix reload\fR" to speed
+up a change.
+
+The text below provides only a parameter summary. See
+\fBpostconf\fR(5) for more details including examples.
+.IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+The default location of the Postfix main.cf and master.cf
+configuration files.
+.IP "\fBdaemon_timeout (18000s)\fR"
+How much time a Postfix daemon process may take to handle a
+request before it is terminated by a built-in watchdog timer.
+.IP "\fBpostscreen_dnsbl_sites (empty)\fR"
+Optional list of DNS blocklist domains.
+.IP "\fBipc_timeout (3600s)\fR"
+The time limit for sending or receiving information over an internal
+communication channel.
+.IP "\fBprocess_id (read-only)\fR"
+The process ID of a Postfix command or daemon process.
+.IP "\fBprocess_name (read-only)\fR"
+The process name of a Postfix command or daemon process.
+.IP "\fBqueue_directory (see 'postconf -d' output)\fR"
+The location of the Postfix top-level queue directory.
+.IP "\fBsyslog_facility (mail)\fR"
+The syslog facility of Postfix logging.
+.IP "\fBsyslog_name (see 'postconf -d' output)\fR"
+The mail system name that is prepended to the process name in syslog
+records, so that "smtpd" becomes, for example, "postfix/smtpd".
+.SH "SEE ALSO"
+.na
+.nf
+smtpd(8), Postfix SMTP server
+postconf(5), configuration parameters
+syslogd(5), system logging
+.SH "LICENSE"
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH "HISTORY"
+.na
+.nf
+.ad
+.fi
+This service is temporary with Postfix version 2.7.
+.SH "AUTHOR(S)"
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index 47489974569adcbdd46d9edf7e37ebb600a6e50f..ec088ac6b5508606213bd2369e9d136550c1396f 100644 (file)
@@ -187,7 +187,7 @@ Don't deliver messages that exceed this size limit (in
 bytes); return them to the sender instead.
 .IP "\fBuser\fR=\fIusername\fR (required)"
 .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
-Execute the external command with the rights of the
+Execute the external command with the user ID and group ID of the
 specified \fIusername\fR.  The software refuses to execute
 commands with root privileges, or with the privileges of the
 mail system owner. If \fIgroupname\fR is specified, the
@@ -325,11 +325,11 @@ Command exit status codes are expected to
 follow the conventions defined in <\fBsysexits.h\fR>.
 Exit status 0 means normal successful completion.
 
-Postfix version 2.3 and later support RFC 3463-style enhanced
-status codes.  If a command terminates with a non-zero exit
-status, and the command output begins with an enhanced
-status code, this status code takes precedence over the
-non-zero exit status.
+In the case of a non-zero exit status, a limited amount of
+command output is reported in an delivery status notification.
+When the output begins with a 4.X.X or 5.X.X enhanced status
+code, the status code takes precedence over the non-zero
+exit status (Postfix version 2.3 and later).
 
 Problems and transactions are logged to \fBsyslogd\fR(8).
 Corrupted message files are marked so that the queue manager
diff --git a/postfix/man/man8/postscreen.8 b/postfix/man/man8/postscreen.8
new file mode 100644 (file)
index 0000000..550f325
--- /dev/null
@@ -0,0 +1,358 @@
+.TH POSTSCREEN 8 
+.ad
+.fi
+.SH NAME
+postscreen
+\-
+Postfix SMTP triage server
+.SH "SYNOPSIS"
+.na
+.nf
+\fBpostscreen\fR [generic Postfix daemon options]
+.SH DESCRIPTION
+.ad
+.fi
+The Postfix \fBpostscreen\fR(8) server performs triage on
+multiple inbound SMTP connections in parallel. The program
+can run in two basic modes.
+
+In \fBobservation mode\fR the purpose is to collect statistics
+without actually blocking mail. \fBpostscreen\fR(8) runs a
+number of tests before it forwards a connection to a real
+SMTP server process.  These tests introduce a delay of a
+few seconds; once a client passes the tests as "clean", its
+IP address is whitelisted and subsequent connections incur
+no delays until the whitelist entry expires.
+
+In \fBenforcement mode\fR the purpose is to block mail
+without using up one Postfix SMTP server process for every
+connection.  Here, \fBpostscreen\fR(8) terminates connections
+from SMTP clients that fail the above tests, and forwards
+only the remaining connections to a real SMTP server process.
+By running time-consuming spam tests in parallel in
+\fBpostscreen\fR(8), more Postfix SMTP server processes
+remain available for legitimate clients.
+.PP
+Note: \fBpostscreen\fR(8) is not an SMTP proxy; this is
+intentional. The purpose is to prioritize legitimate clients
+with as little overhead as possible.
+
+\fBpostscreen\fR(8) logs its observations and takes actions
+as described in the sections that follow.
+.SH "PERMANENT BLACKLIST TEST"
+.na
+.nf
+.ad
+.fi
+The postscreen_blacklist_networks parameter (default: empty)
+specifies a permanent blacklist for SMTP client IP addresses.
+The address syntax is as with mynetworks. When the SMTP
+client address matches the permanent blacklist, this is
+logged as:
+.sp
+.nf
+\fBBLACKLISTED \fIaddress\fR
+.fi
+.sp
+The postscreen_blacklist_action parameter specifies the
+action that is taken next:
+.IP "\fBcontinue\fR (default, observation mode)"
+Continue with the SMTP GREETING PHASE TESTS below.
+.IP "\fBdrop\fR (enforcement mode)"
+Drop the connection immediately with a 521 SMTP reply.  In
+a future implementation, the connection may instead be
+passed to a dummy SMTP protocol engine that logs sender and
+recipient information.
+.SH "PERMANENT WHITELIST TEST"
+.na
+.nf
+.ad
+.fi
+The postscreen_whitelist_networks parameter (default:
+$mynetworks) specifies a permanent whitelist for SMTP client
+IP addresses.  This feature is not used for addresses that
+appear on the permanent blacklist. When the SMTP client
+address matches the permanent whitelist, this is logged as:
+.sp
+.nf
+\fBWHITELISTED \fIaddress\fR
+.fi
+.sp
+The action is not configurable: immediately forward the
+connection to a real SMTP server process.
+.SH "TEMPORARY WHITELIST TEST"
+.na
+.nf
+.ad
+.fi
+The \fBpostscreen\fR(8) daemon maintains a \fItemporary\fR
+whitelist for SMTP client IP addresses that have passed all
+the tests described below. The postscreen_cache_map parameter
+specifies the location of the temporary whitelist.  The
+temporary whitelist is not used for SMTP client addresses
+that appear on the \fIpermanent\fR blacklist or whitelist.
+
+When the SMTP client address appears on the temporary
+whitelist, this is logged as:
+.sp
+.nf
+\fBPASS OLD \fIaddress\fR
+.fi
+.sp
+The action is not configurable: immediately forward the
+connection to a real SMTP server process.  The client is
+excluded from further tests until its temporary whitelist
+entry expires, as controlled with the postscreen_cache_ttl
+parameter.  Expired entries are silently renewed if possible.
+.SH "SMTP GREETING PHASE TESTS"
+.na
+.nf
+.ad
+.fi
+The postscreen_greet_wait parameter specifies a time interval
+during which \fBpostscreen\fR(8) runs a number of tests as
+described below.  These tests run before the client may
+see the real SMTP server's "220 text..." server greeting.
+When the SMTP client passes all the tests, this is logged
+as:
+.sp
+.nf
+\fBPASS NEW \fIaddress\fR
+.fi
+.sp
+The action is to forward the connection to a real SMTP
+server process and to create a temporary whitelist entry
+that excludes the client IP address from further tests until
+the temporary whitelist entry expires, as controlled with
+the postscreen_cache_ttl parameter.
+
+In a future implementation, the connection may first be passed to
+a dummy SMTP protocol engine that implements more protocol
+tests including greylisting, before the client is allowed
+to talk to a real SMTP server process.
+.SH "PREGREET TEST"
+.na
+.nf
+.ad
+.fi
+The postscreen_greet_banner parameter specifies the text
+for a "220-text..." teaser banner (default: $smtpd_banner).
+The \fBpostscreen\fR(8) daemon sends this before the
+postscreen_greet_wait timer is started.  The purpose of the
+teaser banner is to confuse SPAM clients so that they speak
+before their turn. It has no effect on SMTP clients that
+correctly implement the protocol.
+
+To avoid problems with broken SMTP engines in network
+appliances, either exclude them from all tests with the
+postscreen_whitelist_networks feature or else specify an
+empty postscreen_greet_banner value to disable the "220-text..."
+teaser banner.
+
+When an SMTP client speaks before the postscreen_greet_wait
+time has elapsed, this is logged as:
+.sp
+.nf
+\fBPREGREET \fIcount \fBafter \fItime \fBfrom \fIaddress text...\fR
+.fi
+.sp
+Translation: the client at \fIaddress\fR sent \fIcount\fR
+bytes before its turn to speak, and this happened \fItime\fR
+seconds after the test started. The \fItext\fR is what the
+client sent (truncated at 100 bytes, and with non-printable
+characters replaced with "?").
+
+The postscreen_greet_action parameter specifies the action
+that is taken next:
+.IP "\fBcontinue\fR (default, observation mode)"
+Wait until the postscreen_greet_wait time has elapsed, then
+report DNSBL lookup results if applicable. Either perform
+DNSBL-related actions or forward the connection to a real
+SMTP server process.
+.IP "\fBdrop\fR (enforcement mode)"
+Drop the connection immediately with a 521 SMTP reply.
+In a future implementation, the connection may instead be passed
+to a dummy SMTP protocol engine that logs sender and recipient
+information.
+.SH "HANGUP TEST"
+.na
+.nf
+.ad
+.fi
+When the SMTP client hangs up without sending any data
+before the postscreen_greet_wait time has elapsed, this is
+logged as:
+.sp
+.nf
+\fBHANGUP after \fItime \fBfrom \fIaddress\fR
+.fi
+.sp
+The postscreen_hangup_action specifies the action
+that is taken next:
+.IP "\fBcontinue\fR (default, observation mode)"
+Wait until the postscreen_greet_wait time has elapsed, then
+report DNSBL lookup results if applicable. Do not forward
+the broken connection to a real SMTP server process.
+.IP "\fBdrop\fR (enforcement mode)"
+Drop the connection immediately.
+.SH "DNS BLOCKLIST TEST"
+.na
+.nf
+.ad
+.fi
+The postscreen_dnsbl_sites parameter (default: empty)
+specifies a list of DNS blocklist servers. When the
+postscreen_greet_wait time has elapsed, and the SMTP client
+address is reported by at least one of these blocklists,
+this is logged as:
+.sp
+.nf
+\fBDNSBL rank \fIcount \fBfor \fIaddress\fR
+.fi
+.sp
+Translation: the client at \fIaddress\fR is listed with
+\fIcount\fR DNSBL servers. The \fIcount\fR does not
+depend on the number of DNS records that an individual DNSBL
+server returns.
+
+The postscreen_dnsbl_action parameter specifies the action
+that is taken next:
+.IP "\fBcontinue\fR (default, observation mode)"
+Forward the connection to a real SMTP server process.
+.IP "\fBdrop\fR (enforcement mode)"
+Drop the connection immediately with a 521 SMTP reply.
+In a future implementation, the connection may instead be passed
+to a dummy SMTP protocol engine that logs sender and recipient
+information.
+.SH "SECURITY"
+.na
+.nf
+.ad
+.fi
+The \fBpostscreen\fR(8) server is moderately security-sensitive.
+It talks to untrusted clients on the network. The process
+can be run chrooted at fixed low privilege.
+.SH "STANDARDS"
+.na
+.nf
+RFC 5321 (SMTP, including multi-line 220 greetings)
+RFC 2920 (SMTP Pipelining)
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to \fBsyslogd\fR(8).
+.SH "CONFIGURATION PARAMETERS"
+.na
+.nf
+.ad
+.fi
+Changes to main.cf are not picked up automatically, as
+\fBpostscreen\fR(8) processes may run for several hours.
+Use the command "postfix reload" after a configuration
+change.
+
+The text below provides only a parameter summary. See
+\fBpostconf\fR(5) for more details including examples.
+.SH "TRIAGE PARAMETERS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBpostscreen_blacklist_action (continue)\fR"
+The action that \fBpostscreen\fR(8) takes when an SMTP client is
+permanently blacklisted with the postscreen_blacklist_networks
+parameter.
+.IP "\fBpostscreen_blacklist_networks (empty)\fR"
+Network addresses that are permanently blacklisted; see the
+postscreen_blacklist_action parameter for possible actions.
+.IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
+Persistent storage for the \fBpostscreen\fR(8) server decisions.
+.IP "\fBpostscreen_cache_ttl (1d)\fR"
+The amount of time that \fBpostscreen\fR(8) will cache a decision for
+a specific SMTP client IP address.
+.IP "\fBpostscreen_dnsbl_action (continue)\fR"
+The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
+at the DNS blocklist domains specified with the postscreen_dnsbl_sites
+parameter.
+.IP "\fBpostscreen_dnsbl_sites (empty)\fR"
+Optional list of DNS blocklist domains.
+.IP "\fBpostscreen_greet_action (continue)\fR"
+The action that \fBpostscreen\fR(8) takes when an SMTP client speaks
+before its turn within the time specified with the postscreen_greet_wait
+parameter.
+.IP "\fBpostscreen_greet_banner ($smtpd_banner)\fR"
+The text in the optional "220-text..." server response that
+\fBpostscreen\fR(8) sends ahead of the real Postfix SMTP server's "220
+text..." response, in an attempt to confuse bad SMTP clients so
+that they speak before their turn (pre-greet).
+.IP "\fBpostscreen_greet_wait (4s)\fR"
+The amount of time that \fBpostscreen\fR(8) will wait for an SMTP
+client to send a command before its turn, and for DNS blocklist
+lookup results to arrive.
+.IP "\fBpostscreen_hangup_action (continue)\fR"
+The action that \fBpostscreen\fR(8) takes when an SMTP client disconnects
+without sending data, within the time specified with the
+postscreen_greet_wait parameter.
+.IP "\fBpostscreen_post_queue_limit ($default_process_limit)\fR"
+The number of clients that can be waiting for service from a
+real SMTP server process.
+.IP "\fBpostscreen_pre_queue_limit ($default_process_limit)\fR"
+The number of non-whitelisted clients that can be waiting for
+a decision whether they will receive service from a real SMTP server
+process.
+.IP "\fBpostscreen_whitelist_networks ($mynetworks)\fR"
+Network addresses that are permanently whitelisted, and that
+will not be subjected to \fBpostscreen\fR(8) checks.
+.IP "\fBsmtpd_service (smtpd)\fR"
+The internal service that \fBpostscreen\fR(8) forwards allowed
+connections to.
+.SH "MISCELLANEOUS CONTROLS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+The default location of the Postfix main.cf and master.cf
+configuration files.
+.IP "\fBdaemon_timeout (18000s)\fR"
+How much time a Postfix daemon process may take to handle a
+request before it is terminated by a built-in watchdog timer.
+.IP "\fBdelay_logging_resolution_limit (2)\fR"
+The maximal number of digits after the decimal point when logging
+sub-second delay values.
+.IP "\fBcommand_directory (see 'postconf -d' output)\fR"
+The location of all postfix administrative commands.
+.IP "\fBipc_timeout (3600s)\fR"
+The time limit for sending or receiving information over an internal
+communication channel.
+.IP "\fBmax_idle (100s)\fR"
+The maximum amount of time that an idle Postfix daemon process waits
+for an incoming connection before terminating voluntarily.
+.IP "\fBprocess_id (read-only)\fR"
+The process ID of a Postfix command or daemon process.
+.IP "\fBprocess_name (read-only)\fR"
+The process name of a Postfix command or daemon process.
+.IP "\fBsyslog_facility (mail)\fR"
+The syslog facility of Postfix logging.
+.IP "\fBsyslog_name (see 'postconf -d' output)\fR"
+The mail system name that is prepended to the process name in syslog
+records, so that "smtpd" becomes, for example, "postfix/smtpd".
+.SH "SEE ALSO"
+.na
+.nf
+smtpd(8), Postfix SMTP server
+dnsblog(8), temporary DNS helper
+syslogd(8), system logging
+.SH "LICENSE"
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH "AUTHOR(S)"
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index 31fa892cb7876e3ed9dfaa7684e6c167d2063ed0..4e0a3d69f3a1a7b697633350e495d1565c83e798 100755 (executable)
@@ -475,7 +475,7 @@ while (<>) {
     s;\bsmtpd_autho[-</bB>]*\n*[ <bB>]*rized_verp_clients\b;<a href="postconf.5.html#smtpd_authorized_verp_clients">$&</a>;g;
     s;\bsmtpd_autho[-</bB>]*\n*[ <bB>]*rized_xclient_hosts\b;<a href="postconf.5.html#smtpd_authorized_xclient_hosts">$&</a>;g;
     s;\bsmtpd_autho[-</bB>]*\n*[ <bB>]*rized_xforward_hosts\b;<a href="postconf.5.html#smtpd_authorized_xforward_hosts">$&</a>;g;
-    s;\bsmtpd_banner\b;<a href="postconf.5.html#smtpd_banner">$&</a>;g;
+    s;\bsmtpd_ban[-</bB>]*\n*[ <bB>]*ner\b;<a href="postconf.5.html#smtpd_banner">$&</a>;g;
     s;\bsmtpd_client_connection_count_limit\b;<a href="postconf.5.html#smtpd_client_connection_count_limit">$&</a>;g;
     s;\bsmtpd_client_event_limit_exceptions\b;<a href="postconf.5.html#smtpd_client_event_limit_exceptions">$&</a>;g;
     s;\bsmtpd_client_connection_rate_limit\b;<a href="postconf.5.html#smtpd_client_connection_rate_limit">$&</a>;g;
@@ -702,6 +702,7 @@ while (<>) {
     s/[<bB>]*cleanup[<\/bB>]*\(8\)/<a href="cleanup.8.html">$&<\/a>/g;
     s/[<bB>]*defer[<\/bB>]*\(8\)/<a href="defer.8.html">$&<\/a>/g;
     s/[<bB>]*dis[-<\/bB>]*\n* *[<bB>]*card[<\/bB>]*\(8\)/<a href="discard.8.html">$&<\/a>/g;
+    s/[<bB>]*dnsblog[<\/bB>]*\(8\)/<a href="dnsblog.8.html">$&<\/a>/g;
     s/[<bB>]*error[<\/bB>]*\(8\)/<a href="error.8.html">$&<\/a>/g;
     s/[<bB>]*flush[<\/bB>]*\(8\)/<a href="flush.8.html">$&<\/a>/g;
     s/[<bB>]*lmtp[<\/bB>]*\(8\)/<a href="lmtp.8.html">$&<\/a>/g;
@@ -709,6 +710,7 @@ while (<>) {
     s/[<bB>]*mas[-<\/bB>]*\n* *[<bB>]*ter[<\/bB>]*\(8\)/<a href="master.8.html">$&<\/a>/g;
     s/[<bB>]*pickup[<\/bB>]*\(8\)/<a href="pickup.8.html">$&<\/a>/g;
     s/[<bB>]*pipe[<\/bB>]*\(8\)/<a href="pipe.8.html">$&<\/a>/g;
+    s/[<bB>]*postscreen[<\/bB>]*\(8\)/<a href="postscreen.8.html">$&<\/a>/g;
     s/[<bB>]*oqmgr[<\/bB>]*\(8\)/<a href="qmgr.8.html">$&<\/a>/g;
     s/[<bB>]*\bqmgr[<\/bB>]*\(8\)/<a href="qmgr.8.html">$&<\/a>/g;
     s/[<bB>]*qmqpd[<\/bB>]*\(8\)/<a href="qmqpd.8.html">$&<\/a>/g;
@@ -797,7 +799,12 @@ while (<>) {
     # Access restrictions - client
 
     s;\bcheck_client_access\b;<a href="postconf.5.html#check_client_access">$&</a>;g;
+    s;\bcheck_client_mx_access\b;<a href="postconf.5.html#check_client_mx_access">$&</a>;g;
+    s;\bcheck_client_ns_access\b;<a href="postconf.5.html#check_client_ns_access">$&</a>;g;
     s;\bcheck_ccert_access\b;<a href="postconf.5.html#check_ccert_access">$&</a>;g;
+    s;\bcheck_reverse_client_hostname_access\b;<a href="postconf.5.html#check_reverse_client_hostname_access">$&</a>;g;
+    s;\bcheck_reverse_client_hostname_mx_access\b;<a href="postconf.5.html#check_reverse_client_hostname_mx_access">$&</a>;g;
+    s;\bcheck_reverse_client_hostname_ns_access\b;<a href="postconf.5.html#check_reverse_client_hostname_ns_access">$&</a>;g;
     s;\bpermit_inet_interfaces\b;<a href="postconf.5.html#permit_inet_interfaces">$&</a>;g;
     s;\bpermit_mynetworks\b;<a href="postconf.5.html#permit_mynetworks">$&</a>;g;
     s;\bpermit_sasl_authenticated\b;<a href="postconf.5.html#permit_sasl_authenticated">$&</a>;g;
@@ -813,6 +820,8 @@ while (<>) {
     # Access restrictions - helo
 
     s;\bcheck_helo_access\b;<a href="postconf.5.html#check_helo_access">$&</a>;g;
+    s;\bcheck_helo_mx_access\b;<a href="postconf.5.html#check_helo_mx_access">$&</a>;g;
+    s;\bcheck_helo_ns_access\b;<a href="postconf.5.html#check_helo_ns_access">$&</a>;g;
     s;\breject_invalid_helo_hostname\b;<a href="postconf.5.html#reject_invalid_helo_hostname">$&</a>;g;
     s;\breject_invalid_hostname\b;<a href="postconf.5.html#reject_invalid_helo_hostname">$&</a>;g;
     s;\breject_non_fqdn_helo_hostname\b;<a href="postconf.5.html#reject_non_fqdn_helo_hostname">$&</a>;g;
@@ -824,6 +833,8 @@ while (<>) {
     # Access restrictions - sender
 
     s;\bcheck_sender_access\b;<a href="postconf.5.html#check_sender_access">$&</a>;g;
+    s;\bcheck_sender_mx_access\b;<a href="postconf.5.html#check_sender_mx_access">$&</a>;g;
+    s;\bcheck_sender_ns_access\b;<a href="postconf.5.html#check_sender_ns_access">$&</a>;g;
     s;\b(reject_authenti)([-</bB>]*\n*[ <bB>]*)(cated_sender_login_mismatch)\b;<a href="postconf.5.html#reject_authenticated_sender_login_mismatch">$1<\/a>$2<a href="postconf.5.html#reject_authenticated_sender_login_mismatch">$3</a>;g;
     s;\breject_non_fqdn_sender\b;<a href="postconf.5.html#reject_non_fqdn_sender">$&</a>;g;
     s;\breject_rhsbl_sender\b;<a href="postconf.5.html#reject_rhsbl_sender">$&</a>;g;
@@ -877,6 +888,21 @@ while (<>) {
     s;\bmulti_instance_name\b;<a href="postconf.5.html#multi_instance_name">$&</a>;g;
     s;\bmulti_instance_enable\b;<a href="postconf.5.html#multi_instance_enable">$&</a>;g;
 
+    # postscreen
+    s;\bpostscreen_cache_map\b;<a href="postconf.5.html#postscreen_cache_map">$&</a>;g;
+    s;\bpostscreen_cache_ttl\b;<a href="postconf.5.html#postscreen_cache_ttl">$&</a>;g;
+    s;\bsmtpd_service\b;<a href="postconf.5.html#smtpd_service">$&</a>;g;
+    s;\bpostscreen_post_queue_limit\b;<a href="postconf.5.html#postscreen_post_queue_limit">$&</a>;g;
+    s;\bpostscreen_pre_queue_limit\b;<a href="postconf.5.html#postscreen_pre_queue_limit">$&</a>;g;
+    s;\bpostscreen_greet_banner\b;<a href="postconf.5.html#postscreen_greet_banner">$&</a>;g;
+    s;\bpostscreen_greet_wait\b;<a href="postconf.5.html#postscreen_greet_wait">$&</a>;g;
+    s;\bpostscreen_greet_action\b;<a href="postconf.5.html#postscreen_greet_action">$&</a>;g;
+    s;\bpostscreen_dnsbl_sites\b;<a href="postconf.5.html#postscreen_dnsbl_sites">$&</a>;g;
+    s;\bpostscreen_dnsbl_action\b;<a href="postconf.5.html#postscreen_dnsbl_action">$&</a>;g;
+    s;\bpostscreen_hangup_action\b;<a href="postconf.5.html#postscreen_hangup_action">$&</a>;g;
+    s;\bpostscreen_whitelist_networks\b;<a href="postconf.5.html#postscreen_whitelist_networks">$&</a>;g;
+    s;\bpostscreen_black[-</bB>]*\n*[ <bB>]*list_networks\b;<a href="postconf.5.html#postscreen_blacklist_networks">$&</a>;g;
+    s;\bpostscreen_black[-</bB>]*\n*[ <bB>]*list_action\b;<a href="postconf.5.html#postscreen_blacklist_action">$&</a>;g;
 
     # Hyperlink URLs and RFC documents
 
index 1c988ec03d601ed805b753e0e293a597562f125f..335e230b78f8db6c4125faa1dd6bb3b53e7f41b1 100644 (file)
@@ -4046,8 +4046,9 @@ The default time unit is s (seconds).
 %PARAM smtp_host_lookup dns
 
 <p>
-What mechanisms when the Postfix SMTP client uses to look up a host's IP
-address.  This parameter is ignored when DNS lookups are disabled.
+What mechanisms the Postfix SMTP client uses to look up a host's IP
+address.  This parameter is ignored when DNS lookups are disabled
+(see: disable_dns_lookups).
 </p>
 
 <p>
@@ -4759,6 +4760,22 @@ Postfix version 2.5).  This feature is available with Postfix version
 parent domains, client IP address, or networks obtained by stripping
 least significant octets. See the access(5) manual page for details. </dd>
 
+<dt><b><a name="check_client_mx_access">check_client_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified access(5) database for the MX hosts for the
+client hostname, and execute the corresponding action.  Note: a result
+of "OK" is not allowed for safety reasons. Instead, use DUNNO in order
+to exclude specific hosts from blacklists.  This feature is available
+in Postfix 2.7 and later.  </dd>
+
+<dt><b><a name="check_client_ns_access">check_client_ns_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified access(5) database for the DNS servers for
+the client hostname, and execute the corresponding action.  Note: a
+result of "OK" is not allowed for safety reasons. Instead, use DUNNO
+in order to exclude specific hosts from blacklists.  This feature is
+available in Postfix 2.7 and later.  </dd>
+
 <dt><b><a name="check_reverse_client_hostname_access">check_reverse_client_hostname_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
 
 <dd>Search the specified access database for the unverified reverse
@@ -4769,6 +4786,22 @@ safety reasons.  Instead, use DUNNO in order to exclude specific
 hosts from blacklists.  This feature is available in Postfix 2.6
 and later.</dd>
 
+<dt><b><a name="check_reverse_client_hostname_mx_access">check_reverse_client_hostname_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified access(5) database for the MX hosts for the
+unverified reverse client hostname, and execute the corresponding
+action.  Note: a result of "OK" is not allowed for safety reasons.
+Instead, use DUNNO in order to exclude specific hosts from blacklists.
+This feature is available in Postfix 2.7 and later.  </dd>
+
+<dt><b><a name="check_reverse_client_hostname_ns_access">check_reverse_client_hostname_ns_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified access(5) database for the DNS servers for
+the unverified reverse client hostname, and execute the corresponding
+action.  Note: a result of "OK" is not allowed for safety reasons.
+Instead, use DUNNO in order to exclude specific hosts from blacklists.
+This feature is available in Postfix 2.7 and later.  </dd>
+
 <dt><b><a name="permit_inet_interfaces">permit_inet_interfaces</a></b></dt>
 
 <dd>Permit the request when the client IP address matches
@@ -4939,7 +4972,7 @@ of time where it is not allowed, or when the client sends SMTP
 commands ahead of time without knowing that Postfix actually supports
 ESMTP command pipelining. This stops mail from bulk mail software
 that improperly uses ESMTP command pipelining in order to speed up
-deliveries.
+deliveries. 
 <br> With Postfix 2.6 and later, the SMTP server sets a per-session
 flag whenever it detects illegal pipelining, including pipelined
 EHLO or HELO commands. The reject_unauth_pipelining feature simply
@@ -12331,3 +12364,197 @@ inspection for DKIM-signed mail from known friendly domains. </p>
 
 <p> This feature is available in Postfix 2.7, and as an optional
 patch for Postfix 2.6. </p>
+
+%PARAM postscreen_cache_map btree:$data_directory/ps_whitelist
+
+<p> Persistent storage for the postscreen(8) server decisions. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM smtpd_service smtpd
+
+<p> The internal service that postscreen(8) forwards allowed
+connections to. In a future version there may be different
+classes of SMTP service. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_post_queue_limit $default_process_limit
+
+<p> The number of clients that can be waiting for service from a
+real SMTP server process. When this queue is full, all clients will
+receive a 421 reponse. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_pre_queue_limit $default_process_limit
+
+<p> The number of non-whitelisted clients that can be waiting for
+a decision whether they will receive service from a real SMTP server
+process. When this queue is full, all non-whitelisted clients will
+receive a 421 reponse. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_cache_ttl 1d
+
+<p> The amount of time that postscreen(8) will cache a decision for
+a specific SMTP client IP address. During this time, the client IP
+address is excluded from tests. If possible, expired decisions are
+renewed silently. Specify a non-zero time value (an integral value
+plus an optional one-letter suffix that specifies the time unit).
+</p>
+
+<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks).  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_greet_wait 4s
+
+<p> The amount of time that postscreen(8) will wait for an SMTP
+client to send a command before its turn, and for DNS blocklist
+lookup results to arrive. This is done only when the SMTP client
+IP address is not permanently whitelisted, and when it has no cached
+decision.  Specify a non-zero time value (an integral value plus
+an optional one-letter suffix that specifies the time unit).  </p>
+
+<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks).  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_dnsbl_sites
+
+<p>Optional list of DNS blocklist domains. When the list is non-enpty,
+the dnsblog(8) daemon will query these domains with the IP addresses
+of non-whitelisted postscreen(8) clients. Specify a list of domain
+names, separated by comma or whitespace. </p>
+
+%PARAM postscreen_dnsbl_action continue
+
+<p>The action that postscreen(8) takes when an SMTP client is listed
+at the DNS blocklist domains specified with the postscreen_dnsbl_sites
+parameter.  Specify one of the following: </p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Forward the connection to a real SMTP server process. </p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection with a 521 SMTP reply. </dd>
+
+</dl>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_greet_action continue
+
+<p>The action that postscreen(8) takes when an SMTP client speaks
+before its turn within the time specified with the postscreen_greet_wait
+parameter.  Specify one of the following: </p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Continue waiting until the postscreen_greet_wait time has
+elapsed. If the client is listed at the DNS blocklist domains
+specified with the postscreen_dnsbl_sites parameter, execute the
+action specified with the postscreen_dnsbl_action parameter, otherwise
+forward the connection to a real SMTP server process. </p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection immediately with a 521 SMTP reply, without
+examining DNSBL lookup results. </dd>
+
+</dl>
+
+<p> In either case, postscreen(8) will not whitelist the SMTP client
+IP address. </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_hangup_action continue
+
+<p>The action that postscreen(8) takes when an SMTP client disconnects
+without sending data, within the time specified with the
+postscreen_greet_wait parameter.  Specify one of the following:
+</p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Continue waiting until the postscreen_greet_wait time has
+elapsed, and report whether the client is listed at the DNSBL sites
+specified with the postscreen_dnsbl_sites parameter. Do not
+forward the broken connection to a real SMTP server process. </p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection immediately, without reporting DNSBL lookup
+results. </dd>
+
+</dl>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_whitelist_networks $mynetworks
+
+<p> Network addresses that are permanently whitelisted, and that
+will not be subjected to postscreen(8) checks. This parameter uses
+the same address syntax as the mynetworks parameter. This feature
+never uses the remote SMTP client hostname.  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_blacklist_networks 
+
+<p> Network addresses that are permanently blacklisted; see the
+postscreen_blacklist_action parameter for possible actions.  This
+parameter uses the same address syntax as the mynetworks parameter.
+The blacklist has higher precedence than whitelists. This feature
+never uses the remote SMTP client hostname.  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_greet_banner $smtpd_banner
+
+<p> The text in the optional "220-text..." server response that
+postscreen(8) sends ahead of the real Postfix SMTP server's "220
+text..." response, in an attempt to confuse bad SMTP clients so
+that they speak before their turn (pre-greet).  Specify an empty
+value to disable this feature.  </p>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+%PARAM postscreen_blacklist_action continue
+
+<p> The action that postscreen(8) takes when an SMTP client is
+permanently blacklisted with the postscreen_blacklist_networks
+parameter.  Specify one of the following: </p>
+
+<dl>
+
+<dt> continue </dt>
+
+<dd> Continue waiting until the postscreen_greet_wait time has
+elapsed, and report whether the client triggers a PREGREET or HANGUP
+error, or whether the client is listed at the DNSBL sites specified
+with the postscreen_dnsbl_sites parameter.  Take the corresponding
+action, or forward the connection to a real SMTP server process.
+</p>
+
+<dt> drop </dt>
+
+<dd> Drop the connection immediately with a 521 SMTP reply, without
+reporting PREGREET, HANGUP or DNSBL results. </dd>
+
+<p> This feature is available in Postfix 2.7. </p>
+
+</dl>
index 5be1b404d11e37cbc4abe2cefaf10ad9e6eecc2d..4de86edb29f1ac25ee48509391f9375bfcb16846 100644 (file)
@@ -660,6 +660,7 @@ int     dns_lookup_l(const char *name, unsigned flags, DNS_RR **rrlist,
        } else if (status == DNS_RETRY) {
            soft_err = 1;
        }
+       /* XXX Stop after NXDOMAIN error. */
     }
     va_end(ap);
     return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status);
@@ -697,6 +698,7 @@ int     dns_lookup_v(const char *name, unsigned flags, DNS_RR **rrlist,
        } else if (status == DNS_RETRY) {
            soft_err = 1;
        }
+       /* XXX Stop after NXDOMAIN error. */
     }
     return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status);
 }
diff --git a/postfix/src/dnsblog/.indent.pro b/postfix/src/dnsblog/.indent.pro
new file mode 120000 (symlink)
index 0000000..5c837ec
--- /dev/null
@@ -0,0 +1 @@
+../../.indent.pro
\ No newline at end of file
diff --git a/postfix/src/dnsblog/Makefile.in b/postfix/src/dnsblog/Makefile.in
new file mode 100644 (file)
index 0000000..ec53919
--- /dev/null
@@ -0,0 +1,78 @@
+SHELL  = /bin/sh
+SRCS   = dnsblog.c
+OBJS   = dnsblog.o
+HDRS   = 
+TESTSRC        =
+DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+TESTPROG= 
+PROG   = dnsblog
+INC_DIR = ../../include
+LIBS   = ../../lib/libdns.a ../../lib/libmaster.a ../../lib/libglobal.a \
+       ../../lib/libutil.a
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+$(PROG): $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
+
+$(OBJS): ../../conf/makedefs.out
+
+Makefile: Makefile.in
+       cat ../../conf/makedefs.out $? >$@
+
+test:  $(TESTPROG)
+
+tests: test
+
+root_tests:
+
+update: ../../libexec/$(PROG)
+
+../../libexec/$(PROG): $(PROG)
+       cp $(PROG) ../../libexec
+
+printfck: $(OBJS) $(PROG)
+       rm -rf printfck
+       mkdir printfck
+       sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
+       set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
+       cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
+
+lint:
+       lint $(DEFS) $(SRCS) $(LINTFIX)
+
+clean:
+       rm -f *.o *core $(PROG) $(TESTPROG) junk 
+       rm -rf printfck
+
+tidy:  clean
+
+depend: $(MAKES)
+       (sed '1,/^# do not edit/!d' Makefile.in; \
+       set -e; for i in [a-z][a-z0-9]*.c; do \
+           $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+           -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
+           -e 's/o: \.\//o: /' -e p -e '}' ; \
+       done | sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+       @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+dnsblog.o: ../../include/argv.h
+dnsblog.o: ../../include/attr.h
+dnsblog.o: ../../include/dns.h
+dnsblog.o: ../../include/iostuff.h
+dnsblog.o: ../../include/mail_conf.h
+dnsblog.o: ../../include/mail_params.h
+dnsblog.o: ../../include/mail_proto.h
+dnsblog.o: ../../include/mail_server.h
+dnsblog.o: ../../include/mail_version.h
+dnsblog.o: ../../include/msg.h
+dnsblog.o: ../../include/myaddrinfo.h
+dnsblog.o: ../../include/sock_addr.h
+dnsblog.o: ../../include/sys_defs.h
+dnsblog.o: ../../include/valid_hostname.h
+dnsblog.o: ../../include/vbuf.h
+dnsblog.o: ../../include/vstream.h
+dnsblog.o: ../../include/vstring.h
+dnsblog.o: dnsblog.c
diff --git a/postfix/src/dnsblog/dnsblog.c b/postfix/src/dnsblog/dnsblog.c
new file mode 100644 (file)
index 0000000..60a943e
--- /dev/null
@@ -0,0 +1,258 @@
+/*++
+/* NAME
+/*     dnsblog 8
+/* SUMMARY
+/*     Postfix DNS blocklist logger
+/* SYNOPSIS
+/*     \fBdnsblog\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/*     The \fBdnsblog\fR(8) server implements an ad-hoc DNS blocklist
+/*     lookup service that will eventually be replaced by an UDP
+/*     client that is built directly into the \fBpostscreen\fR(8)
+/*     server.
+/*
+/*     With each connection, the \fBdnsblog\fR(8) server receives
+/*     a DNS blocklist domain name and an IP address. If the address
+/*     is listed under the DNS blocklist, the \fBdnsblog\fR(8)
+/*     server logs the match and replies with the query arguments
+/*     plus a non-zero status.  Otherwise it replies with the query
+/*     arguments plus a zero status.  Finally, The \fBdnsblog\fR(8)
+/*     server closes the connection.
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/*     Changes to \fBmain.cf\fR are picked up automatically, as
+/*     \fBdnsblog\fR(8) processes run for only a limited amount
+/*     of time. Use the command "\fBpostfix reload\fR" to speed
+/*     up a change.
+/*
+/*     The text below provides only a parameter summary. See
+/*     \fBpostconf\fR(5) for more details including examples.
+/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+/*     The default location of the Postfix main.cf and master.cf
+/*     configuration files.
+/* .IP "\fBdaemon_timeout (18000s)\fR"
+/*     How much time a Postfix daemon process may take to handle a
+/*     request before it is terminated by a built-in watchdog timer.
+/* .IP "\fBpostscreen_dnsbl_sites (empty)\fR"
+/*     Optional list of DNS blocklist domains.
+/* .IP "\fBipc_timeout (3600s)\fR"
+/*     The time limit for sending or receiving information over an internal
+/*     communication channel.
+/* .IP "\fBprocess_id (read-only)\fR"
+/*     The process ID of a Postfix command or daemon process.
+/* .IP "\fBprocess_name (read-only)\fR"
+/*     The process name of a Postfix command or daemon process.
+/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
+/*     The location of the Postfix top-level queue directory.
+/* .IP "\fBsyslog_facility (mail)\fR"
+/*     The syslog facility of Postfix logging.
+/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
+/*     The mail system name that is prepended to the process name in syslog
+/*     records, so that "smtpd" becomes, for example, "postfix/smtpd".
+/* SEE ALSO
+/*     smtpd(8), Postfix SMTP server
+/*     postconf(5), configuration parameters
+/*     syslogd(5), system logging
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* HISTORY
+/* .ad
+/* .fi
+/*     This service is temporary with Postfix version 2.7.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <argv.h>
+#include <myaddrinfo.h>
+#include <valid_hostname.h>
+#include <sock_addr.h>
+
+/* Global library. */
+
+#include <mail_conf.h>
+#include <mail_version.h>
+#include <mail_proto.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* Server skeleton. */
+
+#include <mail_server.h>
+
+/* Application-specific. */
+
+ /*
+  * Static so we don't allocate and free on every request.
+  */
+static VSTRING *rbl_domain;
+static VSTRING *addr;
+static VSTRING *query;
+static VSTRING *why;
+
+ /*
+  * Silly little macros.
+  */
+#define STR(x)                 vstring_str(x)
+
+/* static void dnsblog_query - query DNSBL for client address */
+
+static int dnsblog_query(const char *dnsbl_domain, const char *addr)
+{
+    const char *myname = "dnsblog_query";
+    ARGV   *octets;
+    int     i;
+    struct addrinfo *res;
+    unsigned char *ipv6_addr;
+    int     dns_status;
+    DNS_RR *addr_list;
+    DNS_RR *rr;
+    MAI_HOSTADDR_STR hostaddr;
+    int     found = 0;
+
+    if (msg_verbose)
+       msg_info("%s: addr %s dnsbl_domain %s",
+                myname, addr, dnsbl_domain);
+
+    VSTRING_RESET(query);
+
+    /*
+     * 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 HAS_IPV6
+    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);
+    }
+
+    /*
+     * Tack on the RBL domain name and query the DNS for an A record. Don't
+     * do this for AAAA records. Yet.
+     */
+    vstring_strcat(query, dnsbl_domain);
+    dns_status = dns_lookup(STR(query), T_A, 0, &addr_list, (VSTRING *) 0, why);
+    if (dns_status == DNS_OK) {
+       for (rr = addr_list; rr != 0; rr = rr->next) {
+           if (dns_rr_to_pa(rr, &hostaddr) == 0) {
+               msg_warn("%s: skipping reply record type %s for query %s: %m",
+                        myname, dns_strtype(rr->type), STR(query));
+           } else {
+               msg_info("addr %s blocked by domain %s as %s",
+                        addr, dnsbl_domain, hostaddr.buf);
+               found = 1;
+           }
+       }
+       dns_rr_free(addr_list);
+    } else if (dns_status == DNS_NOTFOUND) {
+       if (msg_verbose)
+           msg_info("%s: addr %s not listed under domain %s",
+                    myname, addr, dnsbl_domain);
+    } else {
+       msg_warn("%s: lookup error for DNS query %s: %s",
+                myname, STR(query), STR(why));
+    }
+    return (found);
+}
+
+/* dnsblog_service - perform service for client */
+
+static void dnsblog_service(VSTREAM *client_stream, char *unused_service,
+                                   char **argv)
+{
+    int     found;
+
+    /*
+     * Sanity check. This service takes no command-line arguments.
+     */
+    if (argv[0])
+       msg_fatal("unexpected command-line argument: %s", argv[0]);
+
+    /*
+     * This routine runs whenever a client connects to the socket dedicated
+     * to the dnsblog service. All connection-management stuff is handled by
+     * the common code in single_server.c.
+     */
+    if (attr_scan(client_stream,
+                 ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+                 ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, rbl_domain,
+                 ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+                 ATTR_TYPE_END) == 2) {
+       found = dnsblog_query(STR(rbl_domain), STR(addr));
+       attr_print(client_stream, ATTR_FLAG_NONE,
+                  ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, STR(rbl_domain),
+                  ATTR_TYPE_STR, MAIL_ATTR_ADDR, STR(addr),
+                  ATTR_TYPE_INT, MAIL_ATTR_STATUS, found,
+                  ATTR_TYPE_END);
+       vstream_fflush(client_stream);
+    }
+}
+
+/* post_jail_init - post-jail initialization */
+
+static void post_jail_init(char *unused_name, char **unused_argv)
+{
+    rbl_domain = vstring_alloc(100);
+    addr = vstring_alloc(100);
+    query = vstring_alloc(100);
+    why = vstring_alloc(100);
+}
+
+MAIL_VERSION_STAMP_DECLARE;
+
+/* main - pass control to the multi-threaded skeleton */
+
+int     main(int argc, char **argv)
+{
+
+    /*
+     * Fingerprint executables and core dumps.
+     */
+    MAIL_VERSION_STAMP_ALLOCATE;
+
+    multi_server_main(argc, argv, dnsblog_service,
+                     MAIL_SERVER_POST_INIT, post_jail_init,
+                     MAIL_SERVER_UNLIMITED,
+                     0);
+}
index 6f62dc9d334530d7fe7c5bab9d3a02150e604bcf..56c9b6cedf1c82513df9d669724b7a7b7b3b11b3 100644 (file)
@@ -29,7 +29,7 @@ SRCS  = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
        user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \
        verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c \
        fold_addr.c header_body_checks.c mkmap_proxy.c data_redirect.c \
-       match_service.c mail_conf_nint.c
+       match_service.c mail_conf_nint.c addr_match_list.c
 OBJS   = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
        clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
@@ -60,7 +60,7 @@ OBJS  = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \
        verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o \
        fold_addr.o header_body_checks.o mkmap_proxy.o data_redirect.o \
-       match_service.o mail_conf_nint.o
+       match_service.o mail_conf_nint.o addr_match_list.o
 HDRS   = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
        canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
        conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
@@ -84,7 +84,8 @@ HDRS  = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
        string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \
        trace.h user_acl.h valid_mailhost_addr.h verify.h verify_clnt.h \
        verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h \
-       fold_addr.h header_body_checks.h data_redirect.h match_service.h
+       fold_addr.h header_body_checks.h data_redirect.h match_service.h \
+       addr_match_list.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@@ -525,6 +526,11 @@ abounce.o: mail_params.h
 abounce.o: mail_proto.h
 abounce.o: msg_stats.h
 abounce.o: recipient_list.h
+addr_match_list.o: ../../include/match_list.h
+addr_match_list.o: ../../include/match_ops.h
+addr_match_list.o: ../../include/sys_defs.h
+addr_match_list.o: addr_match_list.c
+addr_match_list.o: addr_match_list.h
 anvil_clnt.o: ../../include/attr.h
 anvil_clnt.o: ../../include/attr_clnt.h
 anvil_clnt.o: ../../include/iostuff.h
diff --git a/postfix/src/global/addr_match_list.c b/postfix/src/global/addr_match_list.c
new file mode 100644 (file)
index 0000000..a066c10
--- /dev/null
@@ -0,0 +1,119 @@
+/*++
+/* NAME
+/*     addr_match_list 3
+/* SUMMARY
+/*     address list membership
+/* SYNOPSIS
+/*     #include <addr_match_list.h>
+/*
+/*     ADDR_MATCH_LIST *addr_match_list_init(flags, pattern_list)
+/*     int     flags;
+/*     const char *pattern_list;
+/*
+/*     int     addr_match_list_match(list, addr)
+/*     ADDR_MATCH_LIST *list;
+/*     const char *addr;
+/*
+/*     void    addr_match_list_free(list)
+/*     ADDR_MATCH_LIST *list;
+/* DESCRIPTION
+/*     This is a convenience wrapper around the match_list module.
+/*
+/*     This module implements tests for list membership of a
+/*     network address.
+/*
+/*     A list pattern specifies an internet address, or a network/mask
+/*     pattern, where the mask specifies the number of bits in the
+/*     network part.  When a pattern specifies a file name, its
+/*     contents are substituted for the file name; when a pattern
+/*     is a type:name table specification, table lookup is used
+/*     instead.  Patterns are separated by whitespace and/or commas.
+/*     In order to reverse the result, precede a pattern with an
+/*     exclamation point (!).
+/*
+/*     A host matches a list when its address matches a pattern.
+/*     The matching process is case insensitive.
+/*
+/*     addr_match_list_init() performs initializations. The first
+/*     argument is MATCH_FLAG_NONE for future extension.
+/*     The second argument is a list of patterns, or the absolute
+/*     pathname of a file with patterns.
+/*
+/*     addr_match_list_match() matches the specified host address
+/*     against the specified list of patterns.
+/*
+/*     addr_match_list_free() releases storage allocated by
+/*     addr_match_list_init().
+/* DIAGNOSTICS
+/*     Fatal errors: unable to open or read a pattern file; invalid
+/*     pattern. Panic: interface violations.
+/* SEE ALSO
+/*     match_list(3) generic list matching
+/*     match_ops(3) match host by name or by address
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <match_list.h>
+
+/* Global library. */
+
+#include "addr_match_list.h"
+
+#ifdef TEST
+
+#include <msg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vstream.h>
+#include <msg_vstream.h>
+
+static void usage(char *progname)
+{
+    msg_fatal("usage: %s [-v] pattern_list address", progname);
+}
+
+int     main(int argc, char **argv)
+{
+    ADDR_MATCH_LIST *list;
+    char   *host;
+    char   *addr;
+    int     ch;
+
+    msg_vstream_init(argv[0], VSTREAM_ERR);
+
+    while ((ch = GETOPT(argc, argv, "v")) > 0) {
+       switch (ch) {
+       case 'v':
+           msg_verbose++;
+           break;
+       default:
+           usage(argv[0]);
+       }
+    }
+    if (argc != optind + 2)
+       usage(argv[0]);
+    list = addr_match_list_init(MATCH_FLAG_PARENT, argv[optind]);
+    addr = argv[optind + 1];
+    vstream_printf("%s: %s\n", addr,
+                  addr_match_list_match(list, addr) ?
+                  "YES" : "NO");
+    vstream_fflush(VSTREAM_OUT);
+    addr_match_list_free(list);
+    return (0);
+}
+
+#endif
diff --git a/postfix/src/global/addr_match_list.h b/postfix/src/global/addr_match_list.h
new file mode 100644 (file)
index 0000000..d27c672
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _ADDR_MATCH_LIST_H_INCLUDED_
+#define _ADDR_MATCH_LIST_H_INCLUDED_
+
+/*++
+/* NAME
+/*     addr 3h
+/* SUMMARY
+/*     address list membership
+/* SYNOPSIS
+/*     #include <addr_match_list.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <match_list.h>
+#include <match_ops.h>
+
+ /*
+  * External interface.
+  */
+#define ADDR_MATCH_LIST MATCH_LIST
+
+#define addr_match_list_init(f, p) \
+       match_list_init((f), (p), 1, match_hostaddr)
+#define addr_match_list_match(l, a) \
+       match_list_match((l), (a))
+#define addr_match_list_free   match_list_free
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index 92223b056f5aa410cdf9e88da9c6be40704cbc8b..887ceacd427501e63bb9bd1c86458372c764d7e2 100644 (file)
@@ -228,7 +228,7 @@ int     db_common_parse(DICT *dict, void **ctxPtr, const char *format, int query
                break;
            default:
                msg_fatal("db_common_parse: %s: Invalid %s template: %s",
-                         dict->name, query ? "query" : "result", format);
+                      ctx->dict->name, query ? "query" : "result", format);
            }
     return dynamic;
 }
index d67a2a6bcbffe00a9080df6c168869d65d4321a1..cdb691078dac45a0e5225021da9b16d7e3ba1d15 100644 (file)
@@ -2084,9 +2084,13 @@ extern int var_map_defer_code;
 #define CHECK_RECIP_ACL                "check_recipient_access"
 #define CHECK_ETRN_ACL         "check_etrn_access"
 
+#define CHECK_CLIENT_MX_ACL    "check_client_mx_access"
+#define CHECK_REVERSE_CLIENT_MX_ACL "check_reverse_client_hostname_mx_access"
 #define CHECK_HELO_MX_ACL      "check_helo_mx_access"
 #define CHECK_SENDER_MX_ACL    "check_sender_mx_access"
 #define CHECK_RECIP_MX_ACL     "check_recipient_mx_access"
+#define CHECK_CLIENT_NS_ACL    "check_client_ns_access"
+#define CHECK_REVERSE_CLIENT_NS_ACL "check_reverse_client_hostname_ns_access"
 #define CHECK_HELO_NS_ACL      "check_helo_ns_access"
 #define CHECK_SENDER_NS_ACL    "check_sender_ns_access"
 #define CHECK_RECIP_NS_ACL     "check_recipient_ns_access"
@@ -3127,6 +3131,65 @@ extern char *var_multi_stop_cmds;
 #define DEF_MULTI_CNTRL_CMDS   "reload flush"
 extern char *var_multi_cntrl_cmds;
 
+ /*
+  * postscreen(8)
+  */
+#define VAR_PS_CACHE_MAP       "postscreen_cache_map"
+#define DEF_PS_CACHE_MAP       "btree:$data_directory/ps_cache"
+extern char *var_ps_cache_map;
+
+#define VAR_SMTPD_SERVICE      "smtpd_service"
+#define DEF_SMTPD_SERVICE      "smtpd"
+extern char *var_smtpd_service;
+
+#define VAR_PS_POST_QLIMIT     "postscreen_post_queue_limit"
+#define DEF_PS_POST_QLIMIT     "$" VAR_PROC_LIMIT
+extern int var_ps_post_queue_limit;
+
+#define VAR_PS_PRE_QLIMIT      "postscreen_pre_queue_limit"
+#define DEF_PS_PRE_QLIMIT      "$" VAR_PROC_LIMIT
+extern int var_ps_pre_queue_limit;
+
+#define VAR_PS_CACHE_TTL       "postscreen_cache_ttl"
+#define DEF_PS_CACHE_TTL       "1d"
+extern int var_ps_cache_ttl;
+
+#define VAR_PS_GREET_WAIT      "postscreen_greet_wait"
+#define DEF_PS_GREET_WAIT      "4s"
+extern int var_ps_greet_wait;
+
+#define VAR_PS_GREET_ACTION    "postscreen_greet_action"
+#define DEF_PS_GREET_ACTION    "continue"
+extern char *var_ps_greet_action;
+
+#define VAR_PS_DNSBL_SITES     "postscreen_dnsbl_sites"
+#define DEF_PS_DNSBL_SITES     ""
+extern char *var_ps_dnsbl_sites;
+
+#define VAR_PS_DNSBL_ACTION    "postscreen_dnsbl_action"
+#define DEF_PS_DNSBL_ACTION    "continue"
+extern char *var_ps_dnsbl_action;
+
+#define VAR_PS_HUP_ACTION      "postscreen_hangup_action"
+#define DEF_PS_HUP_ACTION      "continue"
+extern char *var_ps_hangup_action;
+
+#define VAR_PS_WLIST_NETS      "postscreen_whitelist_networks"
+#define DEF_PS_WLIST_NETS      "$" VAR_MYNETWORKS
+extern char *var_ps_wlist_nets;
+
+#define VAR_PS_BLIST_NETS      "postscreen_blacklist_networks"
+#define DEF_PS_BLIST_NETS      ""
+extern char *var_ps_blist_nets;
+
+#define VAR_PS_BLIST_ACTION    "postscreen_blacklist_action"
+#define DEF_PS_BLIST_ACTION    "continue"
+extern char *var_ps_blist_nets;
+
+#define VAR_PS_GREET_BANNER    "postscreen_greet_banner"
+#define DEF_PS_GREET_BANNER    "$" VAR_SMTPD_BANNER
+extern char *var_ps_banner;
+
 /* LICENSE
 /* .ad
 /* .fi
index 27aab4fb87e1537860f286caf96fdedc16a7c510..29735886b2d44ccdeadb7e455309c3c860a7371a 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20090828"
+#define MAIL_RELEASE_DATE      "20091008"
 #define MAIL_VERSION_NUMBER    "2.7"
 
 #ifdef SNAPSHOT
index 00cee038eb966c2821546107c2ba8cf110460544..53f65bd9eeaaf431d05f8027987c907ab65b067e 100644 (file)
@@ -7,7 +7,7 @@ OBJS    = master.o master_conf.o master_ent.o master_sig.o master_avail.o \
        master_spawn.o master_service.o master_status.o master_listen.o \
        master_vars.o master_wakeup.o master_watch.o master_flow.o
 LIB_OBJ        = single_server.o multi_server.o trigger_server.o master_proto.o \
-       mail_flow.o
+       mail_flow.o event_server.o
 HDRS   = mail_server.h master_proto.h mail_flow.h
 INT_HDR        = master.h
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
@@ -83,6 +83,35 @@ depend: $(MAKES)
        @$(EXPORT) make -f Makefile.in Makefile 1>&2
 
 # do not edit below this line - it is generated by 'make depend'
+event_server.o: ../../include/chroot_uid.h
+event_server.o: ../../include/debug_process.h
+event_server.o: ../../include/events.h
+event_server.o: ../../include/iostuff.h
+event_server.o: ../../include/listen.h
+event_server.o: ../../include/mail_conf.h
+event_server.o: ../../include/mail_dict.h
+event_server.o: ../../include/mail_params.h
+event_server.o: ../../include/mail_task.h
+event_server.o: ../../include/msg.h
+event_server.o: ../../include/msg_syslog.h
+event_server.o: ../../include/msg_vstream.h
+event_server.o: ../../include/myflock.h
+event_server.o: ../../include/mymalloc.h
+event_server.o: ../../include/resolve_local.h
+event_server.o: ../../include/safe_open.h
+event_server.o: ../../include/sane_accept.h
+event_server.o: ../../include/split_at.h
+event_server.o: ../../include/stringops.h
+event_server.o: ../../include/sys_defs.h
+event_server.o: ../../include/timed_ipc.h
+event_server.o: ../../include/vbuf.h
+event_server.o: ../../include/vstream.h
+event_server.o: ../../include/vstring.h
+event_server.o: ../../include/watchdog.h
+event_server.o: event_server.c
+event_server.o: mail_flow.h
+event_server.o: mail_server.h
+event_server.o: master_proto.h
 mail_flow.o: ../../include/iostuff.h
 mail_flow.o: ../../include/msg.h
 mail_flow.o: ../../include/sys_defs.h
diff --git a/postfix/src/master/event_server.c b/postfix/src/master/event_server.c
new file mode 100644 (file)
index 0000000..42c2ad9
--- /dev/null
@@ -0,0 +1,859 @@
+/*++
+/* NAME
+/*     event_server 3
+/* SUMMARY
+/*     skeleton multi-threaded mail subsystem
+/* SYNOPSIS
+/*     #include <mail_server.h>
+/*
+/*     NORETURN event_server_main(argc, argv, service, key, value, ...)
+/*     int     argc;
+/*     char    **argv;
+/*     void    (*service)(VSTREAM *stream, char *service_name, char **argv);
+/*     int     key;
+/*
+/*     void    event_server_disconnect(fd)
+/*     VSTREAM *stream;
+/*
+/*     void    event_server_drain()
+/* DESCRIPTION
+/*     This module implements a skeleton for multi-threaded
+/*     mail subsystems: mail subsystem programs that service multiple
+/*     clients at the same time. The resulting program expects to be run
+/*     from the \fBmaster\fR process.
+/*
+/*     event_server_main() is the skeleton entry point. It should be
+/*     called from the application main program.  The skeleton does all
+/*     the generic command-line processing, initialization of
+/*     configurable parameters, and connection management.
+/*     Unlike multi_server, this skeleton does not attempt to manage
+/*     all the events on a client connection.
+/*     The skeleton never returns.
+/*
+/*     Arguments:
+/* .IP "void (*service)(VSTREAM *stream, char *service_name, char **argv)"
+/*     A pointer to a function that is called by the skeleton each
+/*     time a client connects to the program's service port. The
+/*     function is run after the program has optionally dropped
+/*     its privileges. The application is responsible for managing
+/*     subsequent I/O events on the stream, and is responsible for
+/*     calling event_server_disconnect() when the stream is closed.
+/*     The stream initial state is non-blocking mode.  The service
+/*     name argument corresponds to the service name in the master.cf
+/*     file.  The argv argument specifies command-line arguments
+/*     left over after options processing.
+/* .PP
+/*     Optional arguments are specified as a null-terminated (key, value)
+/*     list. Keys and expected values are:
+/* .IP "MAIL_SERVER_INT_TABLE (CONFIG_INT_TABLE *)"
+/*     A table with configurable parameters, to be loaded from the
+/*     global Postfix configuration file. Tables are loaded in the
+/*     order as specified, and multiple instances of the same type
+/*     are allowed.
+/* .IP "MAIL_SERVER_STR_TABLE (CONFIG_STR_TABLE *)"
+/*     A table with configurable parameters, to be loaded from the
+/*     global Postfix configuration file. Tables are loaded in the
+/*     order as specified, and multiple instances of the same type
+/*     are allowed.
+/* .IP "MAIL_SERVER_BOOL_TABLE (CONFIG_BOOL_TABLE *)"
+/*     A table with configurable parameters, to be loaded from the
+/*     global Postfix configuration file. Tables are loaded in the
+/*     order as specified, and multiple instances of the same type
+/*     are allowed.
+/* .IP "MAIL_SERVER_TIME_TABLE (CONFIG_TIME_TABLE *)"
+/*     A table with configurable parameters, to be loaded from the
+/*     global Postfix configuration file. Tables are loaded in the
+/*     order as specified, and multiple instances of the same type
+/*     are allowed.
+/* .IP "MAIL_SERVER_RAW_TABLE (CONFIG_RAW_TABLE *)"
+/*     A table with configurable parameters, to be loaded from the
+/*     global Postfix configuration file. Tables are loaded in the
+/*     order as specified, and multiple instances of the same type
+/*     are allowed. Raw parameters are not subjected to $name
+/*     evaluation.
+/* .IP "MAIL_SERVER_NINT_TABLE (CONFIG_NINT_TABLE *)"
+/*     A table with configurable parameters, to be loaded from the
+/*     global Postfix configuration file. Tables are loaded in the
+/*     order as specified, and multiple instances of the same type
+/*     are allowed.
+/* .IP "MAIL_SERVER_PRE_INIT (void *(char *service_name, char **argv))"
+/*     A pointer to a function that is called once
+/*     by the skeleton after it has read the global configuration file
+/*     and after it has processed command-line arguments, but before
+/*     the skeleton has optionally relinquished the process privileges.
+/* .sp
+/*     Only the last instance of this parameter type is remembered.
+/* .IP "MAIL_SERVER_POST_INIT (void *(char *service_name, char **argv))"
+/*     A pointer to a function that is called once
+/*     by the skeleton after it has optionally relinquished the process
+/*     privileges, but before servicing client connection requests.
+/* .sp
+/*     Only the last instance of this parameter type is remembered.
+/* .IP "MAIL_SERVER_LOOP (int *(char *service_name, char **argv))"
+/*     A pointer to function that is executed from
+/*     within the event loop, whenever an I/O or timer event has happened,
+/*     or whenever nothing has happened for a specified amount of time.
+/*     The result value of the function specifies how long to wait until
+/*     the next event. Specify -1 to wait for "as long as it takes".
+/* .sp
+/*     Only the last instance of this parameter type is remembered.
+/* .IP "MAIL_SERVER_EXIT (void *(char *service_name, char **argv))"
+/*     A pointer to function that is executed immediately before normal
+/*     process termination.
+/* .IP "MAIL_SERVER_PRE_ACCEPT (void *(char *service_name, char **argv))"
+/*     Function to be executed prior to accepting a new connection.
+/* .sp
+/*     Only the last instance of this parameter type is remembered.
+/* .IP "MAIL_SERVER_PRE_DISCONN (VSTREAM *, char *service_name, char **argv)"
+/*     A pointer to a function that is called
+/*     by the event_server_disconnect() function (see below).
+/* .sp
+/*     Only the last instance of this parameter type is remembered.
+/* .IP "MAIL_SERVER_IN_FLOW_DELAY (none)"
+/*     Pause $in_flow_delay seconds when no "mail flow control token"
+/*     is available. A token is consumed for each connection request.
+/* .IP MAIL_SERVER_SOLITARY
+/*     This service must be configured with process limit of 1.
+/* .IP MAIL_SERVER_UNLIMITED
+/*     This service must be configured with process limit of 0.
+/* .IP MAIL_SERVER_PRIVILEGED
+/*     This service must be configured as privileged.
+/* .IP "MAIL_SERVER_SLOW_EXIT (void *(char *service_name, char **argv))"
+/*     A pointer to a function that is called after "postfix reload"
+/*     or "master exit".  The application can call event_server_drain()
+/*     (see below) to finish ongoing activities in the background.
+/* .PP
+/*     event_server_disconnect() should be called by the application
+/*     to close a client connection.
+/*
+/*     event_server_drain() should be called when the application
+/*     no longer wishes to accept new client connections. Existing
+/*     clients are handled in a background process, and the process
+/*     terminates when the last client is disconnected. A non-zero
+/*     result means this call should be tried again later.
+/*
+/*     The var_use_limit variable limits the number of clients
+/*     that a server can service before it commits suicide.  This
+/*     value is taken from the global \fBmain.cf\fR configuration
+/*     file. Setting \fBvar_use_limit\fR to zero disables the
+/*     client limit.
+/*
+/*     The var_idle_limit variable limits the time that a service
+/*     receives no client connection requests before it commits
+/*     suicide.  This value is taken from the global \fBmain.cf\fR
+/*     configuration file. Setting \fBvar_idle_limit\fR to zero
+/*     disables the idle limit.
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/* SEE ALSO
+/*     master(8), master process
+/*     syslogd(8) system logging
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <sys/time.h>                  /* select() */
+#include <unistd.h>
+#include <signal.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+#include <time.h>
+
+#ifdef USE_SYS_SELECT_H
+#include <sys/select.h>                        /* select() */
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <msg_syslog.h>
+#include <msg_vstream.h>
+#include <chroot_uid.h>
+#include <listen.h>
+#include <events.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <msg_vstream.h>
+#include <mymalloc.h>
+#include <iostuff.h>
+#include <stringops.h>
+#include <sane_accept.h>
+#include <myflock.h>
+#include <safe_open.h>
+#include <listen.h>
+#include <watchdog.h>
+#include <split_at.h>
+
+/* Global library. */
+
+#include <mail_task.h>
+#include <debug_process.h>
+#include <mail_params.h>
+#include <mail_conf.h>
+#include <mail_dict.h>
+#include <timed_ipc.h>
+#include <resolve_local.h>
+#include <mail_flow.h>
+
+/* Process manager. */
+
+#include "master_proto.h"
+
+/* Application-specific */
+
+#include "mail_server.h"
+
+ /*
+  * Global state.
+  */
+static int client_count;
+static int use_count;
+static int socket_count = 1;
+
+static void (*event_server_service) (VSTREAM *, char *, char **);
+static char *event_server_name;
+static char **event_server_argv;
+static void (*event_server_accept) (int, char *);
+static void (*event_server_onexit) (char *, char **);
+static void (*event_server_pre_accept) (char *, char **);
+static VSTREAM *event_server_lock;
+static int event_server_in_flow_delay;
+static unsigned event_server_generation;
+static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
+static void (*event_server_slow_exit) (char *, char **);
+
+/* event_server_exit - normal termination */
+
+static NORETURN event_server_exit(void)
+{
+    if (event_server_onexit)
+       event_server_onexit(event_server_name, event_server_argv);
+    exit(0);
+}
+
+/* event_server_abort - terminate after abnormal master exit */
+
+static void event_server_abort(int unused_event, char *unused_context)
+{
+    if (msg_verbose)
+       msg_info("master disconnect -- exiting");
+    if (event_server_slow_exit)
+       event_server_slow_exit(event_server_name, event_server_argv);
+    else
+       event_server_exit();
+}
+
+/* event_server_timeout - idle time exceeded */
+
+static void event_server_timeout(int unused_event, char *unused_context)
+{
+    if (msg_verbose)
+       msg_info("idle timeout -- exiting");
+    event_server_exit();
+}
+
+/*  event_server_drain - stop accepting new clients */
+
+int     event_server_drain(void)
+{
+    int     fd;
+
+    switch (fork()) {
+       /* Try again later. */
+    case -1:
+       return (-1);
+       /* Finish existing clients in the background, then terminate. */
+    case 0:
+       (void) msg_cleanup((MSG_CLEANUP_FN) 0);
+       event_fork();
+       for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++)
+           event_disable_readwrite(fd);
+       var_use_limit = 1;
+       return (0);
+       /* Let the master start a new process. */
+    default:
+       exit(0);
+    }
+}
+
+/* event_server_disconnect - terminate client session */
+
+void    event_server_disconnect(VSTREAM *stream)
+{
+    if (msg_verbose)
+       msg_info("connection closed fd %d", vstream_fileno(stream));
+    if (event_server_pre_disconn)
+       event_server_pre_disconn(stream, event_server_name, event_server_argv);
+    (void) vstream_fclose(stream);
+    client_count--;
+    /* Avoid integer wrap-around in a persistent process.  */
+    if (use_count < INT_MAX)
+       use_count++;
+    if (client_count == 0 && var_idle_limit > 0)
+       event_request_timer(event_server_timeout, (char *) 0, var_idle_limit);
+}
+
+/* event_server_execute - in case (char *) != (struct *) */
+
+static void event_server_execute(int unused_event, char *context)
+{
+    VSTREAM *stream = (VSTREAM *) context;
+
+    if (event_server_lock != 0
+       && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
+                  MYFLOCK_OP_NONE) < 0)
+       msg_fatal("select unlock: %m");
+
+    /*
+     * Do bother the application when the client disconnected. Don't drop the
+     * already accepted client request after "postfix reload"; that would be
+     * rude.
+     */
+    if (master_notify(var_pid, event_server_generation, MASTER_STAT_TAKEN) < 0)
+        /* void */ ;
+    event_server_service(stream, event_server_name, event_server_argv);
+    if (master_notify(var_pid, event_server_generation, MASTER_STAT_AVAIL) < 0)
+       event_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
+}
+
+/* event_server_wakeup - wake up application */
+
+static void event_server_wakeup(int fd)
+{
+    VSTREAM *stream;
+    char   *tmp;
+
+#if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
+#ifndef THRESHOLD_FD_WORKAROUND
+#define THRESHOLD_FD_WORKAROUND 128
+#endif
+    int     new_fd;
+
+    /*
+     * Leave some handles < FD_SETSIZE for DBMS libraries, in the unlikely
+     * case of a multi-server with a thousand clients.
+     */
+    if (fd < THRESHOLD_FD_WORKAROUND) {
+       if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
+           msg_fatal("fcntl F_DUPFD: %m");
+       (void) close(fd);
+       fd = new_fd;
+    }
+#endif
+    if (msg_verbose)
+       msg_info("connection established fd %d", fd);
+    non_blocking(fd, BLOCKING);
+    close_on_exec(fd, CLOSE_ON_EXEC);
+    client_count++;
+    stream = vstream_fdopen(fd, O_RDWR);
+    tmp = concatenate(event_server_name, " socket", (char *) 0);
+    vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
+    myfree(tmp);
+    timed_ipc_setup(stream);
+    if (event_server_in_flow_delay && mail_flow_get(1) < 0)
+       event_request_timer(event_server_execute, (char *) stream,
+                           var_in_flow_delay);
+    else
+       event_server_execute(0, (char *) stream);
+}
+
+/* event_server_accept_local - accept client connection request */
+
+static void event_server_accept_local(int unused_event, char *context)
+{
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
+    int     time_left = -1;
+    int     fd;
+
+    /*
+     * Be prepared for accept() to fail because some other process already
+     * got the connection (the number of processes competing for clients is
+     * kept small, so this is not a "thundering herd" problem). If the
+     * accept() succeeds, be sure to disable non-blocking I/O, in order to
+     * minimize confusion.
+     */
+    if (client_count == 0 && var_idle_limit > 0)
+       time_left = event_cancel_timer(event_server_timeout, (char *) 0);
+
+    if (event_server_pre_accept)
+       event_server_pre_accept(event_server_name, event_server_argv);
+    fd = LOCAL_ACCEPT(listen_fd);
+    if (event_server_lock != 0
+       && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
+                  MYFLOCK_OP_NONE) < 0)
+       msg_fatal("select unlock: %m");
+    if (fd < 0) {
+       if (errno != EAGAIN)
+           msg_error("accept connection: %m");
+       if (time_left >= 0)
+           event_request_timer(event_server_timeout, (char *) 0, time_left);
+       return;
+    }
+    event_server_wakeup(fd);
+}
+
+#ifdef MASTER_XPORT_NAME_PASS
+
+/* event_server_accept_pass - accept descriptor */
+
+static void event_server_accept_pass(int unused_event, char *context)
+{
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
+    int     time_left = -1;
+    int     fd;
+
+    /*
+     * Be prepared for accept() to fail because some other process already
+     * got the connection (the number of processes competing for clients is
+     * kept small, so this is not a "thundering herd" problem). If the
+     * accept() succeeds, be sure to disable non-blocking I/O, in order to
+     * minimize confusion.
+     */
+    if (client_count == 0 && var_idle_limit > 0)
+       time_left = event_cancel_timer(event_server_timeout, (char *) 0);
+
+    if (event_server_pre_accept)
+       event_server_pre_accept(event_server_name, event_server_argv);
+    fd = PASS_ACCEPT(listen_fd);
+    if (event_server_lock != 0
+       && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
+                  MYFLOCK_OP_NONE) < 0)
+       msg_fatal("select unlock: %m");
+    if (fd < 0) {
+       if (errno != EAGAIN)
+           msg_error("accept connection: %m");
+       if (time_left >= 0)
+           event_request_timer(event_server_timeout, (char *) 0, time_left);
+       return;
+    }
+    event_server_wakeup(fd);
+}
+
+#endif
+
+/* event_server_accept_inet - accept client connection request */
+
+static void event_server_accept_inet(int unused_event, char *context)
+{
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
+    int     time_left = -1;
+    int     fd;
+
+    /*
+     * Be prepared for accept() to fail because some other process already
+     * got the connection (the number of processes competing for clients is
+     * kept small, so this is not a "thundering herd" problem). If the
+     * accept() succeeds, be sure to disable non-blocking I/O, in order to
+     * minimize confusion.
+     */
+    if (client_count == 0 && var_idle_limit > 0)
+       time_left = event_cancel_timer(event_server_timeout, (char *) 0);
+
+    if (event_server_pre_accept)
+       event_server_pre_accept(event_server_name, event_server_argv);
+    fd = inet_accept(listen_fd);
+    if (event_server_lock != 0
+       && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
+                  MYFLOCK_OP_NONE) < 0)
+       msg_fatal("select unlock: %m");
+    if (fd < 0) {
+       if (errno != EAGAIN)
+           msg_error("accept connection: %m");
+       if (time_left >= 0)
+           event_request_timer(event_server_timeout, (char *) 0, time_left);
+       return;
+    }
+    event_server_wakeup(fd);
+}
+
+/* event_server_main - the real main program */
+
+NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
+{
+    const char *myname = "event_server_main";
+    VSTREAM *stream = 0;
+    char   *root_dir = 0;
+    char   *user_name = 0;
+    int     debug_me = 0;
+    int     daemon_mode = 1;
+    char   *service_name = basename(argv[0]);
+    int     delay;
+    int     c;
+    int     fd;
+    va_list ap;
+    MAIL_SERVER_INIT_FN pre_init = 0;
+    MAIL_SERVER_INIT_FN post_init = 0;
+    MAIL_SERVER_LOOP_FN loop = 0;
+    int     key;
+    char   *transport = 0;
+
+#if 0
+    char   *lock_path;
+    VSTRING *why;
+
+#endif
+    int     alone = 0;
+    int     zerolimit = 0;
+    WATCHDOG *watchdog;
+    char   *oname;
+    char   *oval;
+    const char *err;
+    char   *generation;
+    int     msg_vstream_needed = 0;
+    int     redo_syslog_init = 0;
+
+    /*
+     * Process environment options as early as we can.
+     */
+    if (getenv(CONF_ENV_VERB))
+       msg_verbose = 1;
+    if (getenv(CONF_ENV_DEBUG))
+       debug_me = 1;
+
+    /*
+     * Don't die when a process goes away unexpectedly.
+     */
+    signal(SIGPIPE, SIG_IGN);
+
+    /*
+     * Don't die for frivolous reasons.
+     */
+#ifdef SIGXFSZ
+    signal(SIGXFSZ, SIG_IGN);
+#endif
+
+    /*
+     * May need this every now and then.
+     */
+    var_procname = mystrdup(basename(argv[0]));
+    set_mail_conf_str(VAR_PROCNAME, var_procname);
+
+    /*
+     * Initialize logging and exit handler. Do the syslog first, so that its
+     * initialization completes before we enter the optional chroot jail.
+     */
+    msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
+    if (msg_verbose)
+       msg_info("daemon started");
+
+    /*
+     * Initialize from the configuration file. Allow command-line options to
+     * override compiled-in defaults or configured parameter values.
+     */
+    mail_conf_suck();
+
+    /*
+     * Register dictionaries that use higher-level interfaces and protocols.
+     */
+    mail_dict_init();
+
+    /*
+     * Pick up policy settings from master process. Shut up error messages to
+     * stderr, because no-one is going to see them.
+     */
+    opterr = 0;
+    while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
+       switch (c) {
+       case 'c':
+           root_dir = "setme";
+           break;
+       case 'd':
+           daemon_mode = 0;
+           break;
+       case 'D':
+           debug_me = 1;
+           break;
+       case 'i':
+           mail_conf_update(VAR_MAX_IDLE, optarg);
+           break;
+       case 'l':
+           alone = 1;
+           break;
+       case 'm':
+           mail_conf_update(VAR_MAX_USE, optarg);
+           break;
+       case 'n':
+           service_name = optarg;
+           break;
+       case 'o':
+           if ((err = split_nameval(mystrdup(optarg), &oname, &oval)) != 0)
+               msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
+           mail_conf_update(oname, oval);
+           if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
+               redo_syslog_init = 1;
+           break;
+       case 's':
+           if ((socket_count = atoi(optarg)) <= 0)
+               msg_fatal("invalid socket_count: %s", optarg);
+           break;
+       case 'S':
+           stream = VSTREAM_IN;
+           break;
+       case 'u':
+           user_name = "setme";
+           break;
+       case 't':
+           transport = optarg;
+           break;
+       case 'v':
+           msg_verbose++;
+           break;
+       case 'V':
+           if (++msg_vstream_needed == 1)
+               msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
+           break;
+       case 'z':
+           zerolimit = 1;
+           break;
+       default:
+           msg_fatal("invalid option: %c", c);
+           break;
+       }
+    }
+
+    /*
+     * Initialize generic parameters.
+     */
+    mail_params_init();
+    if (redo_syslog_init)
+       msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
+
+    /*
+     * If not connected to stdin, stdin must not be a terminal.
+     */
+    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
+       msg_vstream_init(var_procname, VSTREAM_ERR);
+       msg_fatal("do not run this command by hand");
+    }
+
+    /*
+     * Application-specific initialization.
+     */
+    va_start(ap, service);
+    while ((key = va_arg(ap, int)) != 0) {
+       switch (key) {
+       case MAIL_SERVER_INT_TABLE:
+           get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
+           break;
+       case MAIL_SERVER_STR_TABLE:
+           get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
+           break;
+       case MAIL_SERVER_BOOL_TABLE:
+           get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
+           break;
+       case MAIL_SERVER_TIME_TABLE:
+           get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
+           break;
+       case MAIL_SERVER_RAW_TABLE:
+           get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
+           break;
+       case MAIL_SERVER_NINT_TABLE:
+           get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
+           break;
+       case MAIL_SERVER_PRE_INIT:
+           pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
+           break;
+       case MAIL_SERVER_POST_INIT:
+           post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
+           break;
+       case MAIL_SERVER_LOOP:
+           loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
+           break;
+       case MAIL_SERVER_EXIT:
+           event_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
+           break;
+       case MAIL_SERVER_PRE_ACCEPT:
+           event_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
+           break;
+       case MAIL_SERVER_PRE_DISCONN:
+           event_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN);
+           break;
+       case MAIL_SERVER_IN_FLOW_DELAY:
+           event_server_in_flow_delay = 1;
+           break;
+       case MAIL_SERVER_SOLITARY:
+           if (stream == 0 && !alone)
+               msg_fatal("service %s requires a process limit of 1",
+                         service_name);
+           break;
+       case MAIL_SERVER_UNLIMITED:
+           if (stream == 0 && !zerolimit)
+               msg_fatal("service %s requires a process limit of 0",
+                         service_name);
+           break;
+       case MAIL_SERVER_PRIVILEGED:
+           if (user_name)
+               msg_fatal("service %s requires privileged operation",
+                         service_name);
+           break;
+       case MAIL_SERVER_SLOW_EXIT:
+           event_server_slow_exit = va_arg(ap, MAIL_SERVER_SLOW_EXIT_FN);
+           break;
+       default:
+           msg_panic("%s: unknown argument type: %d", myname, key);
+       }
+    }
+    va_end(ap);
+
+    if (root_dir)
+       root_dir = var_queue_dir;
+    if (user_name)
+       user_name = var_mail_owner;
+
+    /*
+     * Can options be required?
+     */
+    if (stream == 0) {
+       if (transport == 0)
+           msg_fatal("no transport type specified");
+       if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
+           event_server_accept = event_server_accept_inet;
+       else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
+           event_server_accept = event_server_accept_local;
+#ifdef MASTER_XPORT_NAME_PASS
+       else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
+           event_server_accept = event_server_accept_pass;
+#endif
+       else
+           msg_fatal("unsupported transport type: %s", transport);
+    }
+
+    /*
+     * Retrieve process generation from environment.
+     */
+    if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
+       if (!alldig(generation))
+           msg_fatal("bad generation: %s", generation);
+       OCTAL_TO_UNSIGNED(event_server_generation, generation);
+       if (msg_verbose)
+           msg_info("process generation: %s (%o)",
+                    generation, event_server_generation);
+    }
+
+    /*
+     * Optionally start the debugger on ourself.
+     */
+    if (debug_me)
+       debug_process();
+
+    /*
+     * Traditionally, BSD select() can't handle multiple processes selecting
+     * on the same socket, and wakes up every process in select(). See TCP/IP
+     * Illustrated volume 2 page 532. We avoid select() collisions with an
+     * external lock file.
+     */
+
+    /*
+     * XXX Can't compete for exclusive access to the listen socket because we
+     * also have to monitor existing client connections for service requests.
+     */
+#if 0
+    if (stream == 0 && !alone) {
+       lock_path = concatenate(DEF_PID_DIR, "/", transport,
+                               ".", service_name, (char *) 0);
+       why = vstring_alloc(1);
+       if ((event_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
+                                     (struct stat *) 0, -1, -1, why)) == 0)
+           msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
+       close_on_exec(vstream_fileno(event_server_lock), CLOSE_ON_EXEC);
+       myfree(lock_path);
+       vstring_free(why);
+    }
+#endif
+
+    /*
+     * Set up call-back info.
+     */
+    event_server_service = service;
+    event_server_name = service_name;
+    event_server_argv = argv + optind;
+
+    /*
+     * Run pre-jail initialization.
+     */
+    if (chdir(var_queue_dir) < 0)
+       msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
+    if (pre_init)
+       pre_init(event_server_name, event_server_argv);
+
+    /*
+     * Optionally, restrict the damage that this process can do.
+     */
+    resolve_local_init();
+    tzset();
+    chroot_uid(root_dir, user_name);
+
+    /*
+     * Run post-jail initialization.
+     */
+    if (post_init)
+       post_init(event_server_name, event_server_argv);
+
+    /*
+     * Are we running as a one-shot server with the client connection on
+     * standard input? If so, make sure the output is written to stdout so as
+     * to satisfy common expectation.
+     */
+    if (stream != 0) {
+       vstream_control(stream,
+                       VSTREAM_CTL_DOUBLE,
+                       VSTREAM_CTL_WRITE_FD, STDOUT_FILENO,
+                       VSTREAM_CTL_END);
+       service(stream, event_server_name, event_server_argv);
+       vstream_fflush(stream);
+       event_server_exit();
+    }
+
+    /*
+     * Running as a semi-resident server. Service connection requests.
+     * Terminate when we have serviced a sufficient number of clients, when
+     * no-one has been talking to us for a configurable amount of time, or
+     * when the master process terminated abnormally.
+     */
+    if (var_idle_limit > 0)
+       event_request_timer(event_server_timeout, (char *) 0, var_idle_limit);
+    for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
+       event_enable_read(fd, event_server_accept, CAST_INT_TO_CHAR_PTR(fd));
+       close_on_exec(fd, CLOSE_ON_EXEC);
+    }
+    event_enable_read(MASTER_STATUS_FD, event_server_abort, (char *) 0);
+    close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
+    close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
+    close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
+    watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0);
+
+    /*
+     * The event loop, at last.
+     */
+    while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
+       if (event_server_lock != 0) {
+           watchdog_stop(watchdog);
+           if (myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
+                       MYFLOCK_OP_EXCLUSIVE) < 0)
+               msg_fatal("select lock: %m");
+       }
+       watchdog_start(watchdog);
+       delay = loop ? loop(event_server_name, event_server_argv) : -1;
+       event_loop(delay);
+    }
+    event_server_exit();
+}
index 57e0389cef634b2b0315551ab62056e662fcfafd..5a88b2ff800d77f5b0c6d3e7b5bd953759ff2985 100644 (file)
 #define MAIL_SERVER_WATCHDOG   19
 
 #define MAIL_SERVER_IN_FLOW_DELAY      20
+#define MAIL_SERVER_SLOW_EXIT  21
 
 typedef void (*MAIL_SERVER_INIT_FN) (char *, char **);
 typedef int (*MAIL_SERVER_LOOP_FN) (char *, char **);
 typedef void (*MAIL_SERVER_EXIT_FN) (char *, char **);
 typedef void (*MAIL_SERVER_ACCEPT_FN) (char *, char **);
 typedef void (*MAIL_SERVER_DISCONN_FN) (VSTREAM *, char *, char **);
+typedef void (*MAIL_SERVER_SLOW_EXIT_FN) (char *, char **);
 
  /*
   * single_server.c
@@ -56,6 +58,14 @@ extern NORETURN multi_server_main(int, char **, MULTI_SERVER_FN,...);
 extern void multi_server_disconnect(VSTREAM *);
 extern int multi_server_drain(void);
 
+ /*
+  * event_server.c
+  */
+typedef void (*EVENT_SERVER_FN) (VSTREAM *, char *, char **);
+extern NORETURN event_server_main(int, char **, EVENT_SERVER_FN,...);
+extern void event_server_disconnect(VSTREAM *);
+extern int event_server_drain(void);
+
  /*
   * trigger_server.c
   */
index 6008ca19f3f395050ae23362a1cefad20158fd40..09baead1fd649849810ed5d7628ba2918092f9bf 100644 (file)
@@ -142,6 +142,7 @@ void    master_avail_listen(MASTER_SERV *serv)
                event_enable_read(serv->listen_fd[n], master_avail_event,
                                  (char *) serv);
        } else if ((serv->flags & MASTER_FLAG_LOCAL_ONLY) == 0
+                  && serv->max_proc != 1/* XXX postscreen(8) */
                   && (now = event_time()) - serv->busy_warn_time > 1000) {
            serv->busy_warn_time = now;
            msg_warn("service \"%s\" (%s) has reached its process limit \"%d\": "
index cd8159023aa3404ab6a5227382e33cebf6e41232..671aa65bfe1bcd65cc02006ef6db45b26b671f08 100644 (file)
 /*     This service must be configured as privileged.
 /* .PP
 /*     multi_server_disconnect() should be called by the application
-/*     when a client disconnects.
+/*     to close a client connection.
 /*
 /*     multi_server_drain() should be called when the application
 /*     no longer wishes to accept new client connections. Existing
-/*     clients are handled in a background process. A non-zero
+/*     clients are handled in a background process, and the process
+/*     terminates when the last client is disconnected. A non-zero
 /*     result means this call should be tried again later.
 /*
 /*     The var_use_limit variable limits the number of clients that
@@ -270,6 +271,7 @@ int     multi_server_drain(void)
        /* Finish existing clients in the background, then terminate. */
     case 0:
        (void) msg_cleanup((MSG_CLEANUP_FN) 0);
+       event_fork();
        for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++)
            event_disable_readwrite(fd);
        var_use_limit = 1;
@@ -291,7 +293,11 @@ void    multi_server_disconnect(VSTREAM *stream)
     event_disable_readwrite(vstream_fileno(stream));
     (void) vstream_fclose(stream);
     client_count--;
-    use_count++;
+    /* Avoid integer wrap-around in a persistent process.  */
+    if (use_count < INT_MAX)
+       use_count++;
+    if (client_count == 0 && var_idle_limit > 0)
+       event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit);
 }
 
 /* multi_server_execute - in case (char *) != (struct *) */
@@ -319,8 +325,6 @@ static void multi_server_execute(int unused_event, char *context)
     } else {
        multi_server_disconnect(stream);
     }
-    if (client_count == 0 && var_idle_limit > 0)
-       event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit);
 }
 
 /* multi_server_enable_read - enable read events */
index a984ac47978a557b9870e42ae1897e2005fc66d8..f6923344bd148b310674958ec0ad96f60d6e0bf2 100644 (file)
@@ -265,7 +265,9 @@ static void single_server_wakeup(int fd)
        single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
     if (msg_verbose)
        msg_info("connection closed");
-    use_count++;
+    /* Avoid integer wrap-around in a persistent process.  */
+    if (use_count < INT_MAX)
+       use_count++;
     if (var_idle_limit > 0)
        event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
 }
index 62330f0389fca835f8c8f6b5d75251c512e95c6d..a5d0ade28fcdf48c6eee47145d8bf3938b2cf219 100644 (file)
@@ -266,7 +266,9 @@ static void trigger_server_wakeup(int fd)
        trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
     if (var_idle_limit > 0)
        event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
-    use_count++;
+    /* Avoid integer wrap-around in a persistent process.  */
+    if (use_count < INT_MAX)
+       use_count++;
 }
 
 /* trigger_server_accept_fifo - accept fifo client request */
index e839532f6a87a30473dd47421d5ad4d7d25af240..6fea0f06a18d03cea3d932f2f29bec34cd93e5d5 100644 (file)
@@ -2584,6 +2584,13 @@ static int milter8_send(MILTER *m, VSTREAM *stream)
     if (msg_verbose)
        msg_info("%s: milter %s", myname, milter->m.name);
 
+    /*
+     * The next read on this Milter socket happens in a different process. It
+     * will not automatically flush the output buffer in this process.
+     */
+    if (milter->fp)
+       vstream_fflush(milter->fp);
+
     if (attr_print(stream, ATTR_FLAG_MORE,
                   ATTR_TYPE_STR, MAIL_ATTR_MILT_NAME, milter->m.name,
                   ATTR_TYPE_INT, MAIL_ATTR_MILT_VERS, milter->version,
index e9def71da808ad34de7eef97c2b01cb8cfd20bc8..951222bbcd9e9901bb48d26f9ee06dc4a2754612 100644 (file)
 /*     bytes); return them to the sender instead.
 /* .IP "\fBuser\fR=\fIusername\fR (required)"
 /* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
-/*     Execute the external command with the rights of the
+/*     Execute the external command with the user ID and group ID of the
 /*     specified \fIusername\fR.  The software refuses to execute
 /*     commands with root privileges, or with the privileges of the
 /*     mail system owner. If \fIgroupname\fR is specified, the
 /*     follow the conventions defined in <\fBsysexits.h\fR>.
 /*     Exit status 0 means normal successful completion.
 /*
-/*     Postfix version 2.3 and later support RFC 3463-style enhanced
-/*     status codes.  If a command terminates with a non-zero exit
-/*     status, and the command output begins with an enhanced
-/*     status code, this status code takes precedence over the
-/*     non-zero exit status.
+/*     In the case of a non-zero exit status, a limited amount of
+/*     command output is reported in an delivery status notification.
+/*     When the output begins with a 4.X.X or 5.X.X enhanced status
+/*     code, the status code takes precedence over the non-zero
+/*     exit status (Postfix version 2.3 and later).
 /*
 /*     Problems and transactions are logged to \fBsyslogd\fR(8).
 /*     Corrupted message files are marked so that the queue manager
index 2cdccebe3f2d9fb5b21386154e37eb68488e72f5..c49a9479c9a1daa9da7d3f83d20229f9b785a2c1 100644 (file)
 /*     oqmgr(8), old Postfix queue manager
 /*     pickup(8), Postfix local mail pickup
 /*     pipe(8), deliver mail to non-Postfix command
+/*     postscreen(8), Postfix SMTP triage server
 /*     proxymap(8), Postfix lookup table proxy server
 /*     qmgr(8), Postfix queue manager
 /*     qmqpd(8), Postfix QMQP server
diff --git a/postfix/src/postscreen/.indent.pro b/postfix/src/postscreen/.indent.pro
new file mode 120000 (symlink)
index 0000000..5c837ec
--- /dev/null
@@ -0,0 +1 @@
+../../.indent.pro
\ No newline at end of file
diff --git a/postfix/src/postscreen/Makefile.in b/postfix/src/postscreen/Makefile.in
new file mode 100644 (file)
index 0000000..3ea518a
--- /dev/null
@@ -0,0 +1,87 @@
+SHELL  = /bin/sh
+SRCS   = postscreen.c
+OBJS   = postscreen.o
+HDRS   = 
+TESTSRC        =
+DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+TESTPROG= 
+PROG   = postscreen
+INC_DIR = ../../include
+LIBS   = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+$(PROG): $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
+
+$(OBJS): ../../conf/makedefs.out
+
+Makefile: Makefile.in
+       cat ../../conf/makedefs.out $? >$@
+
+test:  $(TESTPROG)
+
+tests: test
+
+root_tests:
+
+update: ../../libexec/$(PROG)
+
+../../libexec/$(PROG): $(PROG)
+       cp $(PROG) ../../libexec
+
+printfck: $(OBJS) $(PROG)
+       rm -rf printfck
+       mkdir printfck
+       sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
+       set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
+       cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
+
+lint:
+       lint $(DEFS) $(SRCS) $(LINTFIX)
+
+clean:
+       rm -f *.o *core $(PROG) $(TESTPROG) junk 
+       rm -rf printfck
+
+tidy:  clean
+
+depend: $(MAKES)
+       (sed '1,/^# do not edit/!d' Makefile.in; \
+       set -e; for i in [a-z][a-z0-9]*.c; do \
+           $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+           -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
+           -e 's/o: \.\//o: /' -e p -e '}' ; \
+       done | sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+       @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+postscreen.o: ../../include/addr_match_list.h
+postscreen.o: ../../include/argv.h
+postscreen.o: ../../include/attr.h
+postscreen.o: ../../include/connect.h
+postscreen.o: ../../include/dict.h
+postscreen.o: ../../include/events.h
+postscreen.o: ../../include/format_tv.h
+postscreen.o: ../../include/htable.h
+postscreen.o: ../../include/iostuff.h
+postscreen.o: ../../include/mail_conf.h
+postscreen.o: ../../include/mail_params.h
+postscreen.o: ../../include/mail_proto.h
+postscreen.o: ../../include/mail_server.h
+postscreen.o: ../../include/mail_version.h
+postscreen.o: ../../include/match_list.h
+postscreen.o: ../../include/match_ops.h
+postscreen.o: ../../include/msg.h
+postscreen.o: ../../include/myaddrinfo.h
+postscreen.o: ../../include/mymalloc.h
+postscreen.o: ../../include/name_code.h
+postscreen.o: ../../include/sane_accept.h
+postscreen.o: ../../include/set_eugid.h
+postscreen.o: ../../include/stringops.h
+postscreen.o: ../../include/sys_defs.h
+postscreen.o: ../../include/vbuf.h
+postscreen.o: ../../include/vstream.h
+postscreen.o: ../../include/vstring.h
+postscreen.o: postscreen.c
diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c
new file mode 100644 (file)
index 0000000..76595bf
--- /dev/null
@@ -0,0 +1,1269 @@
+/*++
+/* NAME
+/*     postscreen 8
+/* SUMMARY
+/*     Postfix SMTP triage server
+/* SYNOPSIS
+/*     \fBpostscreen\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/*     The Postfix \fBpostscreen\fR(8) server performs triage on
+/*     multiple inbound SMTP connections in parallel. The program
+/*     can run in two basic modes.
+/*
+/*     In \fBobservation mode\fR the purpose is to collect statistics
+/*     without actually blocking mail. \fBpostscreen\fR(8) runs a
+/*     number of tests before it forwards a connection to a real
+/*     SMTP server process.  These tests introduce a delay of a
+/*     few seconds; once a client passes the tests as "clean", its
+/*     IP address is whitelisted and subsequent connections incur
+/*     no delays until the whitelist entry expires.
+/*
+/*     In \fBenforcement mode\fR the purpose is to block mail
+/*     without using up one Postfix SMTP server process for every
+/*     connection.  Here, \fBpostscreen\fR(8) terminates connections
+/*     from SMTP clients that fail the above tests, and forwards
+/*     only the remaining connections to a real SMTP server process.
+/*     By running time-consuming spam tests in parallel in
+/*     \fBpostscreen\fR(8), more Postfix SMTP server processes
+/*     remain available for legitimate clients.
+/* .PP
+/*     Note: \fBpostscreen\fR(8) is not an SMTP proxy; this is
+/*     intentional. The purpose is to prioritize legitimate clients
+/*     with as little overhead as possible.
+/*
+/*     \fBpostscreen\fR(8) logs its observations and takes actions
+/*     as described in the sections that follow.
+/* PERMANENT BLACKLIST TEST
+/* .ad
+/* .fi
+/*     The postscreen_blacklist_networks parameter (default: empty)
+/*     specifies a permanent blacklist for SMTP client IP addresses.
+/*     The address syntax is as with mynetworks. When the SMTP
+/*     client address matches the permanent blacklist, this is
+/*     logged as:
+/* .sp
+/* .nf
+/*     \fBBLACKLISTED \fIaddress\fR
+/* .fi
+/* .sp
+/*     The postscreen_blacklist_action parameter specifies the
+/*     action that is taken next:
+/* .IP "\fBcontinue\fR (default, observation mode)"
+/*     Continue with the SMTP GREETING PHASE TESTS below.
+/* .IP "\fBdrop\fR (enforcement mode)"
+/*     Drop the connection immediately with a 521 SMTP reply.  In
+/*     a future implementation, the connection may instead be
+/*     passed to a dummy SMTP protocol engine that logs sender and
+/*     recipient information.
+/* PERMANENT WHITELIST TEST
+/* .ad
+/* .fi
+/*     The postscreen_whitelist_networks parameter (default:
+/*     $mynetworks) specifies a permanent whitelist for SMTP client
+/*     IP addresses.  This feature is not used for addresses that
+/*     appear on the permanent blacklist. When the SMTP client
+/*     address matches the permanent whitelist, this is logged as:
+/* .sp
+/* .nf
+/*     \fBWHITELISTED \fIaddress\fR
+/* .fi
+/* .sp
+/*     The action is not configurable: immediately forward the
+/*     connection to a real SMTP server process.
+/* TEMPORARY WHITELIST TEST
+/* .ad    
+/* .fi
+/*     The \fBpostscreen\fR(8) daemon maintains a \fItemporary\fR
+/*     whitelist for SMTP client IP addresses that have passed all
+/*     the tests described below. The postscreen_cache_map parameter
+/*     specifies the location of the temporary whitelist.  The
+/*     temporary whitelist is not used for SMTP client addresses
+/*     that appear on the \fIpermanent\fR blacklist or whitelist.
+/*
+/*     When the SMTP client address appears on the temporary
+/*     whitelist, this is logged as:
+/* .sp
+/* .nf
+/*     \fBPASS OLD \fIaddress\fR
+/* .fi
+/* .sp
+/*     The action is not configurable: immediately forward the
+/*     connection to a real SMTP server process.  The client is
+/*     excluded from further tests until its temporary whitelist
+/*     entry expires, as controlled with the postscreen_cache_ttl
+/*     parameter.  Expired entries are silently renewed if possible.
+/* SMTP GREETING PHASE TESTS
+/* .ad
+/* .fi
+/*     The postscreen_greet_wait parameter specifies a time interval
+/*     during which \fBpostscreen\fR(8) runs a number of tests as
+/*     described below.  These tests run before the client may
+/*     see the real SMTP server's "220 text..." server greeting.
+/*     When the SMTP client passes all the tests, this is logged
+/*     as:
+/* .sp
+/* .nf
+/*     \fBPASS NEW \fIaddress\fR
+/* .fi
+/* .sp
+/*     The action is to forward the connection to a real SMTP
+/*     server process and to create a temporary whitelist entry
+/*     that excludes the client IP address from further tests until
+/*     the temporary whitelist entry expires, as controlled with
+/*     the postscreen_cache_ttl parameter.
+/*
+/*     In a future implementation, the connection may first be passed to
+/*     a dummy SMTP protocol engine that implements more protocol
+/*     tests including greylisting, before the client is allowed
+/*     to talk to a real SMTP server process.
+/* PREGREET TEST
+/* .ad
+/* .fi
+/*     The postscreen_greet_banner parameter specifies the text
+/*     for a "220-text..." teaser banner (default: $smtpd_banner).
+/*     The \fBpostscreen\fR(8) daemon sends this before the
+/*     postscreen_greet_wait timer is started.  The purpose of the
+/*     teaser banner is to confuse SPAM clients so that they speak
+/*     before their turn. It has no effect on SMTP clients that
+/*     correctly implement the protocol.
+/*
+/*     To avoid problems with broken SMTP engines in network
+/*     appliances, either exclude them from all tests with the
+/*     postscreen_whitelist_networks feature or else specify an
+/*     empty postscreen_greet_banner value to disable the "220-text..."
+/*     teaser banner.
+/*
+/*     When an SMTP client speaks before the postscreen_greet_wait
+/*     time has elapsed, this is logged as:
+/* .sp
+/* .nf
+/*     \fBPREGREET \fIcount \fBafter \fItime \fBfrom \fIaddress text...\fR
+/* .fi
+/* .sp
+/*     Translation: the client at \fIaddress\fR sent \fIcount\fR
+/*     bytes before its turn to speak, and this happened \fItime\fR
+/*     seconds after the test started. The \fItext\fR is what the
+/*     client sent (truncated at 100 bytes, and with non-printable
+/*     characters replaced with "?").
+/*
+/*     The postscreen_greet_action parameter specifies the action
+/*     that is taken next:
+/* .IP "\fBcontinue\fR (default, observation mode)"
+/*     Wait until the postscreen_greet_wait time has elapsed, then
+/*     report DNSBL lookup results if applicable. Either perform
+/*     DNSBL-related actions or forward the connection to a real
+/*     SMTP server process.
+/* .IP "\fBdrop\fR (enforcement mode)"
+/*     Drop the connection immediately with a 521 SMTP reply.
+/*     In a future implementation, the connection may instead be passed
+/*     to a dummy SMTP protocol engine that logs sender and recipient
+/*     information.
+/* HANGUP TEST
+/* .ad
+/* .fi
+/*     When the SMTP client hangs up without sending any data
+/*     before the postscreen_greet_wait time has elapsed, this is
+/*     logged as:
+/* .sp
+/* .nf
+/*     \fBHANGUP after \fItime \fBfrom \fIaddress\fR
+/* .fi
+/* .sp
+/*     The postscreen_hangup_action specifies the action
+/*     that is taken next:
+/* .IP "\fBcontinue\fR (default, observation mode)"
+/*     Wait until the postscreen_greet_wait time has elapsed, then
+/*     report DNSBL lookup results if applicable. Do not forward
+/*     the broken connection to a real SMTP server process.
+/* .IP "\fBdrop\fR (enforcement mode)"
+/*     Drop the connection immediately.
+/* DNS BLOCKLIST TEST
+/* .ad
+/* .fi
+/*     The postscreen_dnsbl_sites parameter (default: empty)
+/*     specifies a list of DNS blocklist servers. When the
+/*     postscreen_greet_wait time has elapsed, and the SMTP client
+/*     address is reported by at least one of these blocklists,
+/*     this is logged as:
+/* .sp
+/* .nf
+/*     \fBDNSBL rank \fIcount \fBfor \fIaddress\fR
+/* .fi
+/* .sp
+/*     Translation: the client at \fIaddress\fR is listed with
+/*     \fIcount\fR DNSBL servers. The \fIcount\fR does not
+/*     depend on the number of DNS records that an individual DNSBL
+/*     server returns.
+/*
+/*     The postscreen_dnsbl_action parameter specifies the action
+/*     that is taken next:
+/* .IP "\fBcontinue\fR (default, observation mode)"
+/*     Forward the connection to a real SMTP server process.
+/* .IP "\fBdrop\fR (enforcement mode)"
+/*     Drop the connection immediately with a 521 SMTP reply.
+/*     In a future implementation, the connection may instead be passed
+/*     to a dummy SMTP protocol engine that logs sender and recipient
+/*     information.
+/* SECURITY
+/* .ad
+/* .fi
+/*     The \fBpostscreen\fR(8) server is moderately security-sensitive.
+/*     It talks to untrusted clients on the network. The process
+/*     can be run chrooted at fixed low privilege.
+/* STANDARDS
+/*     RFC 5321 (SMTP, including multi-line 220 greetings)
+/*     RFC 2920 (SMTP Pipelining)
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/*     Changes to main.cf are not picked up automatically, as
+/*     \fBpostscreen\fR(8) processes may run for several hours.
+/*     Use the command "postfix reload" after a configuration
+/*     change.
+/*
+/*     The text below provides only a parameter summary. See
+/*     \fBpostconf\fR(5) for more details including examples.
+/* TRIAGE PARAMETERS
+/* .ad
+/* .fi
+/* .IP "\fBpostscreen_blacklist_action (continue)\fR"
+/*     The action that \fBpostscreen\fR(8) takes when an SMTP client is
+/*     permanently blacklisted with the postscreen_blacklist_networks
+/*     parameter.
+/* .IP "\fBpostscreen_blacklist_networks (empty)\fR"
+/*     Network addresses that are permanently blacklisted; see the
+/*     postscreen_blacklist_action parameter for possible actions.
+/* .IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
+/*     Persistent storage for the \fBpostscreen\fR(8) server decisions.
+/* .IP "\fBpostscreen_cache_ttl (1d)\fR"
+/*     The amount of time that \fBpostscreen\fR(8) will cache a decision for
+/*     a specific SMTP client IP address.
+/* .IP "\fBpostscreen_dnsbl_action (continue)\fR"
+/*     The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
+/*     at the DNS blocklist domains specified with the postscreen_dnsbl_sites
+/*     parameter.
+/* .IP "\fBpostscreen_dnsbl_sites (empty)\fR"
+/*     Optional list of DNS blocklist domains.
+/* .IP "\fBpostscreen_greet_action (continue)\fR"
+/*     The action that \fBpostscreen\fR(8) takes when an SMTP client speaks
+/*     before its turn within the time specified with the postscreen_greet_wait
+/*     parameter.
+/* .IP "\fBpostscreen_greet_banner ($smtpd_banner)\fR"
+/*     The text in the optional "220-text..." server response that
+/*     \fBpostscreen\fR(8) sends ahead of the real Postfix SMTP server's "220
+/*     text..." response, in an attempt to confuse bad SMTP clients so
+/*     that they speak before their turn (pre-greet).
+/* .IP "\fBpostscreen_greet_wait (4s)\fR"
+/*     The amount of time that \fBpostscreen\fR(8) will wait for an SMTP
+/*     client to send a command before its turn, and for DNS blocklist
+/*     lookup results to arrive.
+/* .IP "\fBpostscreen_hangup_action (continue)\fR"
+/*     The action that \fBpostscreen\fR(8) takes when an SMTP client disconnects
+/*     without sending data, within the time specified with the
+/*     postscreen_greet_wait parameter.
+/* .IP "\fBpostscreen_post_queue_limit ($default_process_limit)\fR"
+/*     The number of clients that can be waiting for service from a
+/*     real SMTP server process.
+/* .IP "\fBpostscreen_pre_queue_limit ($default_process_limit)\fR"
+/*     The number of non-whitelisted clients that can be waiting for
+/*     a decision whether they will receive service from a real SMTP server
+/*     process.
+/* .IP "\fBpostscreen_whitelist_networks ($mynetworks)\fR"
+/*     Network addresses that are permanently whitelisted, and that
+/*     will not be subjected to \fBpostscreen\fR(8) checks.
+/* .IP "\fBsmtpd_service (smtpd)\fR"
+/*     The internal service that \fBpostscreen\fR(8) forwards allowed
+/*     connections to.
+/* MISCELLANEOUS CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+/*     The default location of the Postfix main.cf and master.cf
+/*     configuration files.
+/* .IP "\fBdaemon_timeout (18000s)\fR"
+/*     How much time a Postfix daemon process may take to handle a
+/*     request before it is terminated by a built-in watchdog timer.
+/* .IP "\fBdelay_logging_resolution_limit (2)\fR"
+/*     The maximal number of digits after the decimal point when logging
+/*     sub-second delay values.
+/* .IP "\fBcommand_directory (see 'postconf -d' output)\fR"
+/*     The location of all postfix administrative commands.
+/* .IP "\fBipc_timeout (3600s)\fR"
+/*     The time limit for sending or receiving information over an internal
+/*     communication channel.
+/* .IP "\fBmax_idle (100s)\fR"
+/*     The maximum amount of time that an idle Postfix daemon process waits
+/*     for an incoming connection before terminating voluntarily.
+/* .IP "\fBprocess_id (read-only)\fR"
+/*     The process ID of a Postfix command or daemon process.
+/* .IP "\fBprocess_name (read-only)\fR"
+/*     The process name of a Postfix command or daemon process.
+/* .IP "\fBsyslog_facility (mail)\fR"
+/*     The syslog facility of Postfix logging.
+/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
+/*     The mail system name that is prepended to the process name in syslog
+/*     records, so that "smtpd" becomes, for example, "postfix/smtpd".
+/* SEE ALSO
+/*     smtpd(8), Postfix SMTP server
+/*     dnsblog(8), temporary DNS helper
+/*     syslogd(8), system logging
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef MISSING_STRTOUL
+#define strtoul strtol
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <connect.h>
+#include <iostuff.h>
+#include <events.h>
+#include <mymalloc.h>
+#include <myaddrinfo.h>
+#include <dict.h>
+#include <sane_accept.h>
+#include <stringops.h>
+#include <set_eugid.h>
+#include <vstream.h>
+#include <format_tv.h>
+#include <htable.h>
+#include <name_code.h>
+
+/* Global library. */
+
+#include <mail_conf.h>
+#include <mail_params.h>
+#include <mail_version.h>
+#include <mail_proto.h>
+#include <addr_match_list.h>
+
+/* Master server protocols. */
+
+#include <mail_server.h>
+
+ /*
+  * Configuration parameters.
+  */
+char   *var_smtpd_service;
+char   *var_smtpd_banner;
+char   *var_ps_cache_map;
+int     var_ps_post_queue_limit;
+int     var_ps_pre_queue_limit;
+int     var_proc_limit;
+int     var_ps_cache_ttl;
+int     var_ps_greet_wait;
+char   *var_ps_dnsbl_sites;
+char   *var_ps_dnsbl_action;
+char   *var_ps_greet_action;
+char   *var_ps_hangup_action;
+char   *var_ps_wlist_nets;
+char   *var_ps_blist_nets;
+char   *var_ps_greet_banner;
+char   *var_ps_blist_action;
+
+ /*
+  * Per-session state. See also: new_session_state() and free_event_state()
+  * below.
+  */
+typedef struct {
+    int     flags;                     /* see below */
+    VSTREAM *smtp_client_stream;       /* remote SMTP client */
+    int     smtp_server_fd;            /* real SMTP server */
+    char   *smtp_client_addr;          /* client address */
+    char   *smtp_client_port;          /* client port */
+    struct timeval creation_time;      /* as the name says */
+} PS_STATE;
+
+#define PS_FLAG_NOCACHE                (1<<0)  /* don't store this client */
+#define PS_FLAG_NOFORWARD      (1<<1)  /* don't forward this session */
+#define PS_FLAG_EXPIRED                (1<<2)  /* whitelist expired */
+#define PS_FLAG_WHITELISTED    (1<<3)  /* whitelisted (temp or perm) */
+
+ /*
+  * This program screens all inbound SMTP connections, so it better not waste
+  * time.
+  */
+#define PS_GREET_TIMEOUT               5
+#define PS_SMTP_WRITE_TIMEOUT          1
+#define PS_SEND_SOCK_CONNECT_TIMEOUT   1
+#define PS_SEND_SOCK_NOTIFY_TIMEOUT    100
+
+#define PS_READ_BUF_SIZE               1024
+
+#define DNSBL_SERVICE                  "dnsblog"
+#define DNSBLOG_TIMEOUT                        10
+
+#define PS_ACT_DROP                    1
+#define PS_ACT_CONT                    2
+
+static int check_queue_length;         /* connections being checked */
+static int post_queue_length;          /* being sent to real SMTPD */
+static DICT *cache_map;                        /* cache table handle */
+static VSTRING *temp;                  /* scratchpad */
+static char *smtp_service_name;                /* path to real SMTPD */
+static char *teaser_greeting;          /* spamware teaser banner */
+static ARGV *dnsbl_sites;              /* dns blocklist domains */
+static VSTRING *reply_addr;            /* address in DNSBL reply */
+static VSTRING *reply_domain;          /* domain in DNSBL reply */
+static HTABLE *dnsbl_cache;            /* entries being queried */
+static int dnsbl_action;               /* PS_ACT_DROP or PS_ACT_CONT */
+static int greet_action;               /* PS_ACT_DROP or PS_ACT_CONT */
+static int hangup_action;              /* PS_ACT_DROP or PS_ACT_CONT */
+static ADDR_MATCH_LIST *wlist_nets;    /* permanently whitelisted networks */
+static ADDR_MATCH_LIST *blist_nets;    /* permanently blacklisted networks */
+static int blist_action;               /* PS_ACT_DROP or PS_ACT_CONT */
+
+ /*
+  * See log_adhoc.c for discussion.
+  */
+typedef struct {
+    int     dt_sec;                    /* make sure it's signed */
+    int     dt_usec;                   /* make sure it's signed */
+} DELTA_TIME;
+
+#define DELTA(x, y, z) \
+    do { \
+       (x).dt_sec = (y).tv_sec - (z).tv_sec; \
+       (x).dt_usec = (y).tv_usec - (z).tv_usec; \
+       while ((x).dt_usec < 0) { \
+           (x).dt_usec += 1000000; \
+           (x).dt_sec -= 1; \
+       } \
+       while ((x).dt_usec >= 1000000) { \
+           (x).dt_usec -= 1000000; \
+           (x).dt_sec += 1; \
+       } \
+       if ((x).dt_sec < 0) \
+           (x).dt_sec = (x).dt_usec = 0; \
+    } while (0)
+
+#define SIG_DIGS        2
+
+/* READ_EVENT_REQUEST - prepare for transition to next state */
+
+#define READ_EVENT_REQUEST(fd, action, context, timeout) do { \
+    if (msg_verbose) msg_info("%s: read-request fd=%d", myname, (fd)); \
+    event_enable_read((fd), (action), (context)); \
+    event_request_timer((action), (context), (timeout)); \
+} while (0)
+
+/* CLEAR_EVENT_REQUEST - complete state transition */
+
+#define CLEAR_EVENT_REQUEST(fd, action, context) do { \
+    if (msg_verbose) msg_info("%s: clear-request fd=%d", myname, (fd)); \
+    event_disable_readwrite(fd); \
+    event_cancel_timer((action), (context)); \
+} while (0)
+
+/* SLMs. */
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+ /*
+  * DNSBL lookup status per client IP address.
+  */
+typedef struct {
+    int     dnsbl_count;               /* is this address listed */
+    int     refcount;                  /* query reference count */
+} PS_DNSBL_ENTRY;
+
+/* postscreen_dnsbl_entry_create - create blocklist cache entry */
+
+static PS_DNSBL_ENTRY *postscreen_dnsbl_entry_create(void)
+{
+    PS_DNSBL_ENTRY *entry;
+
+    entry = (PS_DNSBL_ENTRY *) mymalloc(sizeof(*entry));
+    entry->dnsbl_count = 0;
+    entry->refcount = 0;
+    return (entry);
+}
+
+/* postscreen_dnsbl_done - get blocklist cache entry, decrement refcount */
+
+static int postscreen_dnsbl_done(const char *addr)
+{
+    const char *myname = "postscreen_dnsbl_done";
+    PS_DNSBL_ENTRY *entry;
+    int     dnsbl_count;
+
+    /*
+     * Sanity check.
+     */
+    if ((entry = (PS_DNSBL_ENTRY *) htable_find(dnsbl_cache, addr)) == 0)
+       msg_panic("%s: no blocklist cache entry for %s", myname, addr);
+
+    /*
+     * Yes, cache reads are destructive.
+     */
+    dnsbl_count = entry->dnsbl_count;
+    entry->refcount -= 1;
+    if (entry->refcount < 1) {
+       if (msg_verbose)
+           msg_info("%s: delete cache entry for %s", myname, addr);
+       htable_delete(dnsbl_cache, addr, myfree);
+    }
+    return (dnsbl_count);
+}
+
+/* postscreen_dnsbl_reply - receive dnsbl reply, update blocklist cache entry */
+
+static void postscreen_dnsbl_reply(int event, char *context)
+{
+    const char *myname = "postscreen_dnsbl_reply";
+    VSTREAM *stream = (VSTREAM *) context;
+    PS_DNSBL_ENTRY *entry;
+    int     dnsbl_count;
+
+    CLEAR_EVENT_REQUEST(vstream_fileno(stream), postscreen_dnsbl_reply, context);
+
+    /*
+     * Later, this will become an UDP-based DNS client that is built directly
+     * into the postscreen daemon.
+     * 
+     * Don't panic when no blocklist cache entry exists. It may be gone when the
+     * client triggered a "drop" action after pregreet, DNSBL lookup, or
+     * hangup.
+     */
+    if (event == EVENT_READ
+       && attr_scan(stream,
+                    ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+                    ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, reply_domain,
+                    ATTR_TYPE_STR, MAIL_ATTR_ADDR, reply_addr,
+                    ATTR_TYPE_INT, MAIL_ATTR_STATUS, &dnsbl_count,
+                    ATTR_TYPE_END) == 3) {
+       if ((entry = (PS_DNSBL_ENTRY *)
+            htable_find(dnsbl_cache, STR(reply_addr))) != 0)
+           entry->dnsbl_count += dnsbl_count;
+    }
+    vstream_fclose(stream);
+}
+
+/* postscreen_dnsbl_query  - send dnsbl query */
+
+static void postscreen_dnsbl_query(const char *addr)
+{
+    const char *myname = "postscreen_dnsbl_query";
+    int     fd;
+    VSTREAM *stream;
+    char  **cpp;
+    PS_DNSBL_ENTRY *entry;
+
+    /*
+     * Avoid duplicate effort when this lookup is already in progress. Now,
+     * we destroy the entry when the client replies. Later, we increment
+     * refcounts with queries sent, and decrement refcounts with replies
+     * received, so we can maintain state even after a client talks early,
+     * and update the external cache asynchronously.
+     */
+    if ((entry = (PS_DNSBL_ENTRY *) htable_find(dnsbl_cache, addr)) != 0) {
+       entry->refcount += 1;
+       return;
+    }
+    if (msg_verbose)
+       msg_info("%s: create cache entry for %s", myname, addr);
+    entry = postscreen_dnsbl_entry_create();
+    (void) htable_enter(dnsbl_cache, addr, (char *) entry);
+    entry->refcount = 1;
+
+    /*
+     * Later, this will become an UDP-based DNS client that is built directly
+     * into the postscreen daemon.
+     */
+    for (cpp = dnsbl_sites->argv; *cpp; cpp++) {
+       if ((fd = LOCAL_CONNECT("private/" DNSBL_SERVICE, NON_BLOCKING, 1)) < 0) {
+           msg_warn("%s: connect to " DNSBL_SERVICE " service: %m", myname);
+           return;
+       }
+       stream = vstream_fdopen(fd, O_RDWR);
+       attr_print(stream, ATTR_FLAG_NONE,
+                  ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, *cpp,
+                  ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+                  ATTR_TYPE_END);
+       if (vstream_fflush(stream) != 0) {
+           msg_warn("%s: error sending to " DNSBL_SERVICE " service: %m", myname);
+           vstream_fclose(stream);
+           return;
+       }
+       READ_EVENT_REQUEST(vstream_fileno(stream), postscreen_dnsbl_reply,
+                          (char *) stream, DNSBLOG_TIMEOUT);
+    }
+}
+
+/* new_session_state - fill in connection state for event processing */
+
+static PS_STATE *new_session_state(VSTREAM *stream, const char *addr,
+                                          const char *port)
+{
+    PS_STATE *state;
+
+    state = (PS_STATE *) mymalloc(sizeof(*state));
+    state->flags = 0;
+    if ((state->smtp_client_stream = stream) != 0)
+       check_queue_length++;
+    state->smtp_server_fd = (-1);
+    state->smtp_client_addr = mystrdup(addr);
+    state->smtp_client_port = mystrdup(port);
+    GETTIMEOFDAY(&state->creation_time);
+    return (state);
+}
+
+/* free_session_state - destroy connection state including connections */
+
+static void free_session_state(PS_STATE *state)
+{
+    if (state->smtp_client_stream != 0) {
+       event_server_disconnect(state->smtp_client_stream);
+       check_queue_length--;
+    }
+    if (state->smtp_server_fd >= 0) {
+       close(state->smtp_server_fd);
+       post_queue_length--;
+    }
+    myfree(state->smtp_client_addr);
+    myfree(state->smtp_client_port);
+    myfree((char *) state);
+
+    if (check_queue_length < 0 || post_queue_length < 0)
+       msg_panic("bad queue length: check_queue=%d, post_queue=%d",
+                 check_queue_length, post_queue_length);
+}
+
+/* mydelta_time - pretty-formatted delta time */
+
+static char *mydelta_time(VSTRING *buf, struct timeval tv, int *delta)
+{
+    DELTA_TIME pdelay;
+    struct timeval now;
+
+    GETTIMEOFDAY(&now);
+    DELTA(pdelay, now, tv);
+    VSTRING_RESET(buf);
+    format_tv(buf, pdelay.dt_sec, pdelay.dt_usec, SIG_DIGS, var_delay_max_res);
+    *delta = pdelay.dt_sec;
+    return (STR(buf));
+}
+
+/* smtp_reply - reply to the client */
+
+static int smtp_reply(int smtp_client_fd, const char *smtp_client_addr,
+                             const char *smtp_client_port, const char *text)
+{
+    int     ret;
+
+    /*
+     * XXX Need to make sure that the TCP send buffer is large enough for any
+     * response, so that a nasty client can't cause this process to block.
+     */
+    ret = (write_buf(smtp_client_fd, text, strlen(text), 1) < 0);
+    if (ret != 0 && errno != EPIPE)
+       msg_warn("write %s:%s: %m", smtp_client_addr, smtp_client_port);
+    return (ret);
+}
+
+/* send_socket_close_event - file descriptor has arrived or timeout */
+
+static void send_socket_close_event(int event, char *context)
+{
+    const char *myname = "send_socket_close_event";
+    PS_STATE *state = (PS_STATE *) context;
+
+    if (msg_verbose)
+       msg_info("%s: sq=%d cq=%d event %d on send socket %d from %s:%s",
+                myname, post_queue_length, check_queue_length,
+                event, state->smtp_server_fd, state->smtp_client_addr,
+                state->smtp_client_port);
+
+    /*
+     * The real SMTP server has closed the local IPC channel, or we have
+     * reached the limit of our patience. In the latter case it is still
+     * possible that the real SMTP server will receive the socket so we
+     * should not interfere.
+     */
+    CLEAR_EVENT_REQUEST(state->smtp_server_fd, send_socket_close_event, context);
+
+    switch (event) {
+    case EVENT_TIME:
+       msg_warn("timeout sending connection to service %s", smtp_service_name);
+       break;
+    default:
+       break;
+    }
+    free_session_state(state);
+}
+
+/* send_socket - send socket to real smtpd */
+
+static void send_socket(PS_STATE *state)
+{
+    const char *myname = "send_socket";
+    int     window_size;
+
+    if (msg_verbose)
+       msg_info("%s: sq=%d cq=%d send socket %d from %s:%s",
+                myname, post_queue_length, check_queue_length,
+        vstream_fileno(state->smtp_client_stream), state->smtp_client_addr,
+                state->smtp_client_port);
+
+    /*
+     * This is where we would adjust the window size to a value that is
+     * appropriate for this client class.
+     */
+#if 0
+    window_size = 65535;
+    if (setsockopt(vstream_fileno(state->smtp_client_stream), SOL_SOCKET, SO_RCVBUF,
+                  (char *) &window_size, sizeof(window_size)) < 0)
+       msg_warn("setsockopt SO_RCVBUF %d: %m", window_size);
+#endif
+
+    /*
+     * Connect to the real SMTP service over a local IPC channel, send the
+     * file descriptor, and close the file descriptor to save resources.
+     * Experience has shown that some systems will discard information when
+     * we close a channel immediately after writing. Thus, we waste resources
+     * waiting for the remote side to close the local IPC channel first. The
+     * good side of waiting is that we learn when the real SMTP server is
+     * falling behind.
+     * 
+     * This is where we would forward the connection to an SMTP server that
+     * provides an appropriate level of service for this client class. For
+     * example, a server that is more forgiving, or one that is more
+     * suspicious. Alternatively, we could send attributes along with the
+     * socket with client reputation information, making everything even more
+     * Postfix-specific.
+     */
+    if ((state->smtp_server_fd = LOCAL_CONNECT(smtp_service_name, NON_BLOCKING,
+                                      PS_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
+       msg_warn("cannot connect to service %s: %m", smtp_service_name);
+       smtp_reply(vstream_fileno(state->smtp_client_stream),
+                  state->smtp_client_addr, state->smtp_client_port,
+                  "421 4.3.2 All server ports are busy\r\n");
+       free_session_state(state);
+       return;
+    }
+    post_queue_length++;
+    if (LOCAL_SEND_FD(state->smtp_server_fd,
+                     vstream_fileno(state->smtp_client_stream)) < 0) {
+       msg_warn("cannot pass connection to service %s: %m", smtp_service_name);
+       smtp_reply(vstream_fileno(state->smtp_client_stream), state->smtp_client_addr,
+             state->smtp_client_port, "421 4.3.2 No system resources\r\n");
+       free_session_state(state);
+       return;
+    } else {
+
+       /*
+        * Closing the smtp_client_fd here triggers a FreeBSD 7.1 kernel bug
+        * where smtp-source sometimes sees the connection being closed after
+        * it has already received the real SMTP server's 220 greeting!
+        */
+#if 0
+       event_server_disconnect(state->smtp_client_stream);
+       state->smtp_client_stream = 0;
+       check_queue_length--;
+#endif
+       READ_EVENT_REQUEST(state->smtp_server_fd, send_socket_close_event,
+                          (char *) state, PS_SEND_SOCK_NOTIFY_TIMEOUT);
+       return;
+    }
+}
+
+/* smtp_read_event - handle pre-greet, EOF or timeout. */
+
+static void smtp_read_event(int event, char *context)
+{
+    const char *myname = "smtp_read_event";
+    PS_STATE *state = (PS_STATE *) context;
+    char    read_buf[PS_READ_BUF_SIZE];
+    int     read_count;
+    int     dnsbl_count;
+    int     elapsed;
+    int     action;
+
+    if (msg_verbose)
+       msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from %s:%s",
+                myname, post_queue_length, check_queue_length,
+                event, vstream_fileno(state->smtp_client_stream),
+                state->smtp_client_addr, state->smtp_client_port);
+
+    /*
+     * Either the remote SMTP client spoke before its turn, the connection
+     * was closed, or we reached the limit of our patience.
+     */
+    CLEAR_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
+                       smtp_read_event, context);
+
+    /*
+     * If this session ends here, we MUST read the blocklist cache otherwise
+     * we have a memory leak.
+     */
+    switch (event) {
+
+       /*
+        * The SMTP client did not speak before its turn. If it is DNS
+        * blocklisted, drop the connection, or continue and forward the
+        * connection to the real SMTP server.
+        * 
+        * This is where we would use a dummy SMTP protocol engine to further
+        * investigate whether the client cuts corners in the protocol,
+        * before allowing it to talk to a real SMTP server process.
+        */
+    case EVENT_TIME:
+       if (*var_ps_dnsbl_sites)
+           dnsbl_count = postscreen_dnsbl_done(state->smtp_client_addr);
+       else
+           dnsbl_count = 0;
+       if (dnsbl_count > 0) {
+           msg_info("DNSBL rank %d for %s",
+                    dnsbl_count, state->smtp_client_addr);
+           if (dnsbl_action == PS_ACT_DROP) {
+               smtp_reply(vstream_fileno(state->smtp_client_stream),
+                          state->smtp_client_addr, state->smtp_client_port,
+                          "521 5.7.1 Blocked by DNSBL\r\n");
+               state->flags |= PS_FLAG_NOFORWARD;
+           }
+           state->flags |= PS_FLAG_NOCACHE;
+       }
+       if (state->flags & PS_FLAG_NOFORWARD) {
+           free_session_state(state);
+       } else {
+           if ((state->flags & PS_FLAG_NOCACHE) == 0) {
+               msg_info("PASS %s %s", (state->flags & PS_FLAG_EXPIRED) ?
+                        "OLD" : "NEW", state->smtp_client_addr);
+               if (cache_map != 0) {
+                   vstring_sprintf(temp, "%ld", (long) event_time());
+                   dict_put(cache_map, state->smtp_client_addr, STR(temp));
+               }
+           }
+           send_socket(state);
+       }
+       break;
+
+       /*
+        * EOF or the client spoke before its turn. We simply drop the
+        * connection, or we continue waiting and allow DNS replies to
+        * trickle in.
+        * 
+        * This is where we would use a dummy SMTP protocol engine to obtain the
+        * sender and recipient information before dropping a pregreeter's
+        * connection.
+        */
+    default:
+       if ((read_count = recv(vstream_fileno(state->smtp_client_stream),
+                          read_buf, sizeof(read_buf) - 1, MSG_PEEK)) > 0) {
+           read_buf[read_count] = 0;
+           msg_info("PREGREET %d after %s from %s: %.100s", read_count,
+                    mydelta_time(temp, state->creation_time, &elapsed),
+                    state->smtp_client_addr, printable(read_buf, '?'));
+           action = greet_action;
+           if (action == PS_ACT_DROP)
+               smtp_reply(vstream_fileno(state->smtp_client_stream),
+                          state->smtp_client_addr, state->smtp_client_port,
+                          "521 5.5.1 Protocol error\r\n");
+       } else {
+           msg_info("HANGUP after %s from %s",
+                    mydelta_time(temp, state->creation_time, &elapsed),
+                    state->smtp_client_addr);
+           action = hangup_action;
+           state->flags |= PS_FLAG_NOFORWARD;
+       }
+       if (action == PS_ACT_DROP) {
+           if (*var_ps_dnsbl_sites)
+               (void) postscreen_dnsbl_done(state->smtp_client_addr);
+           free_session_state(state);
+       } else {
+           state->flags |= PS_FLAG_NOCACHE;
+           /* not: postscreen_dnsbl_done */
+           if (elapsed > var_ps_greet_wait)
+               elapsed = var_ps_greet_wait;
+           event_request_timer(smtp_read_event, context,
+                               var_ps_greet_wait - elapsed);
+       }
+       break;
+    }
+}
+
+/* postscreen_drain - delayed exit after "postfix reload" */
+
+static void postscreen_drain(char *unused_service, char **unused_argv)
+{
+    int     count;
+
+    /*
+     * After "postfix reload", complete work-in-progress in the background,
+     * instead of dropping already-accepted connections on the floor.
+     * 
+     * Unfortunately we must close all writable tables, so we can't store or
+     * look up reputation information. The reason is that don't have any
+     * multi-writer safety guarantees. We also can't use the single-writer
+     * proxywrite service, because its latency guarantees are too weak.
+     * 
+     * All error retry counts shall be limited. Instead of blocking here, we
+     * could retry failed fork() operations in the event call-back routines,
+     * but we don't need perfection. The host system is severely overloaded
+     * and service levels are already way down.
+     */
+    for (count = 0; /* see below */ ; count++) {
+       if (count >= 5) {
+           msg_fatal("fork: %m");
+       } else if (event_server_drain() != 0) {
+           msg_warn("fork: %m");
+           sleep(1);
+           continue;
+       } else {
+           if (cache_map != 0) {
+               dict_close(cache_map);
+               cache_map = 0;
+           }
+           return;
+       }
+    }
+}
+
+/* postscreen_service - handle new client connection */
+
+static void postscreen_service(VSTREAM *smtp_client_stream,
+                                      char *unused_service,
+                                      char **unused_argv)
+{
+    const char *myname = "postscreen_service";
+    PS_STATE *state;
+    struct sockaddr_storage addr_storage;
+    SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
+    MAI_HOSTADDR_STR smtp_client_addr;
+    MAI_SERVPORT_STR smtp_client_port;
+    int     aierr;
+    const char *stamp_str;
+    time_t  stamp_time;
+    int     window_size;
+    int     state_flags = 0;
+
+    /*
+     * This program handles all incoming connections, so it must not block.
+     * We use event-driven code for all operations that introduce latency.
+     * 
+     * We use the event_server framework. This means we get already-accepted
+     * connections wrapped into a VSTREAM so we have to invoke getpeername()
+     * to find out the remote address and port.
+     */
+
+#define PS_SERVICE_GIVEUP_AND_RETURN(stream) do { \
+       event_server_disconnect(stream); \
+       return; \
+    } while (0);
+
+    /*
+     * Look up the remote SMTP client address and port.
+     */
+    if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
+                   & addr_storage, &addr_storage_len) < 0) {
+       msg_warn("getpeername: %m");
+       smtp_reply(vstream_fileno(smtp_client_stream),
+                  "unknown_address", "unknown_port",
+                  "421 4.3.2 No system resources\r\n");
+       PS_SERVICE_GIVEUP_AND_RETURN(smtp_client_stream);
+    }
+
+    /*
+     * Convert the remote SMTP client address and port to printable form for
+     * logging and access control.
+     */
+    if ((aierr = sockaddr_to_hostaddr((struct sockaddr *) & addr_storage,
+                                     addr_storage_len, &smtp_client_addr,
+                                     &smtp_client_port, 0)) != 0) {
+       msg_warn("cannot convert client address/port to string: %s",
+                MAI_STRERROR(aierr));
+       smtp_reply(vstream_fileno(smtp_client_stream),
+                  "unknown_address", "unknown_port",
+                  "421 4.3.2 No system resources\r\n");
+       PS_SERVICE_GIVEUP_AND_RETURN(smtp_client_stream);
+    }
+    if (strncasecmp("::ffff:", smtp_client_addr.buf, 7) == 0)
+       memmove(smtp_client_addr.buf, smtp_client_addr.buf + 7,
+               sizeof(smtp_client_addr.buf) - 7);
+    if (msg_verbose)
+       msg_info("%s: sq=%d cq=%d connect from %s:%s",
+                myname, post_queue_length, check_queue_length,
+                smtp_client_addr.buf, smtp_client_port.buf);
+
+    /*
+     * Reply with 421 when we can't forward more connections.
+     */
+    if (var_ps_post_queue_limit > 0
+       && post_queue_length >= var_ps_post_queue_limit) {
+       msg_info("reject: connect from %s:%s: all server ports busy",
+                smtp_client_addr.buf, smtp_client_port.buf);
+       smtp_reply(vstream_fileno(smtp_client_stream),
+                  smtp_client_addr.buf, smtp_client_port.buf,
+                  "421 4.3.2 All server ports are busy\r\n");
+       PS_SERVICE_GIVEUP_AND_RETURN(smtp_client_stream);
+    }
+
+    /*
+     * The permanent blacklist has first precedence. If the client is
+     * permanently blacklisted, send some generic reply and hang up
+     * immediately, or torture them a little longer.
+     */
+    if (blist_nets != 0
+       && addr_match_list_match(blist_nets, smtp_client_addr.buf) != 0) {
+       msg_info("BLACKLISTED %s", smtp_client_addr.buf);
+       if (blist_action == PS_ACT_DROP) {
+           smtp_reply(vstream_fileno(smtp_client_stream),
+                      smtp_client_addr.buf, smtp_client_port.buf,
+                      "521 5.3.2 Service currently not available\r\n");
+           PS_SERVICE_GIVEUP_AND_RETURN(smtp_client_stream);
+       }
+    }
+
+    /*
+     * The permanent whitelist has second precedence.
+     */
+    else if (wlist_nets != 0
+         && addr_match_list_match(wlist_nets, smtp_client_addr.buf) != 0) {
+       msg_info("WHITELISTED %s", smtp_client_addr.buf);
+       state_flags |= PS_FLAG_WHITELISTED;
+    }
+
+    /*
+     * Finally, the temporary whitelist (i.e. the postscreen cache) has the
+     * lowest precedence.
+     */
+    else if (cache_map != 0
+         && (stamp_str = dict_get(cache_map, smtp_client_addr.buf)) != 0) {
+       stamp_time = strtoul(stamp_str, 0, 10);
+       if (stamp_time > event_time() - var_ps_cache_ttl) {
+           msg_info("PASS OLD %s", smtp_client_addr.buf);
+           state_flags |= PS_FLAG_WHITELISTED;
+       } else
+           state_flags |= PS_FLAG_EXPIRED;
+    }
+
+    /*
+     * If the client is permanently or temporarily whitelisted, send the
+     * socket to the real SMTP service and get out of the way.
+     */
+    if (state_flags & PS_FLAG_WHITELISTED) {
+       state = new_session_state(smtp_client_stream, smtp_client_addr.buf,
+                                 smtp_client_port.buf);
+       send_socket(state);
+       return;
+    }
+
+    /*
+     * Reply with 421 when we can't analyze more connections.
+     */
+    if (var_ps_pre_queue_limit > 0
+      && check_queue_length - post_queue_length >= var_ps_pre_queue_limit) {
+       msg_info("reject: connect from %s:%s: all screening ports busy",
+                smtp_client_addr.buf, smtp_client_port.buf);
+       smtp_reply(vstream_fileno(smtp_client_stream),
+                  smtp_client_addr.buf, smtp_client_port.buf,
+                  "421 4.3.2 All screening ports are busy\r\n");
+       PS_SERVICE_GIVEUP_AND_RETURN(smtp_client_stream);
+    }
+
+    /*
+     * If the client has no cached decision, send half the greeting banner,
+     * by way of teaser, then wait briefly to see if the client speaks before
+     * its turn.
+     * 
+     * This is where we would do DNS blocklist lookup in the background, and
+     * cancel the lookup when the client takes action first.
+     * 
+     * Before sending the banner we could set the TCP window to the smallest
+     * possible value to save some network bandwidth, at least with spamware
+     * that waits until the server starts speaking.
+     */
+#if 0
+    window_size = 1;
+    if (setsockopt(vstream_fileno(smtp_client_stream), SOL_SOCKET, SO_RCVBUF,
+                  (char *) &window_size, sizeof(window_size)) < 0)
+       msg_warn("setsockopt SO_RCVBUF %d: %m", window_size);
+#endif
+    if (teaser_greeting != 0
+     && smtp_reply(vstream_fileno(smtp_client_stream), smtp_client_addr.buf,
+                  smtp_client_port.buf, teaser_greeting) != 0)
+       PS_SERVICE_GIVEUP_AND_RETURN(smtp_client_stream);
+
+    state = new_session_state(smtp_client_stream, smtp_client_addr.buf,
+                             smtp_client_port.buf);
+    state->flags |= state_flags;
+    READ_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
+                      smtp_read_event, (char *) state, var_ps_greet_wait);
+
+    /*
+     * Run a DNS blocklist query while we wait for the client to respond.
+     */
+    if (*var_ps_dnsbl_sites)
+       postscreen_dnsbl_query(smtp_client_addr.buf);
+}
+
+/* pre_jail_init - pre-jail initialization */
+
+static void pre_jail_init(char *unused_name, char **unused_argv)
+{
+
+    /*
+     * Open read-only maps as before dropping privilege, for consistency with
+     * other Postfix daemons.
+     */
+    if (*var_ps_wlist_nets)
+       wlist_nets =
+       addr_match_list_init(MATCH_FLAG_NONE, var_ps_wlist_nets);
+
+    if (*var_ps_blist_nets)
+       blist_nets =
+           addr_match_list_init(MATCH_FLAG_NONE, var_ps_blist_nets);
+
+    /*
+     * Never, ever, get killed by a master signal, as that would corrupt the
+     * database when we're in the middle of an update.
+     */
+    if (setsid() < 0)
+       msg_warn("setsid: %m");
+
+    /*
+     * Security: don't create root-owned files that contain untrusted data.
+     * And don't create Postfix-owned files in root-owned directories,
+     * either. We want a correct relationship between (file or directory)
+     * ownership and (file or directory) content. To open files before going
+     * to jail, temporarily drop root privileges.
+     */
+    SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid);
+
+    /*
+     * Keep state in persistent external map. As a safety measure we sync the
+     * database on each update. This hurts on LINUX systems that sync all
+     * their dirty disk blocks whenever any application invokes fsync().
+     */
+#define PS_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
+
+    if (*var_ps_cache_map)
+       cache_map = dict_open(var_ps_cache_map,
+                             O_CREAT | O_RDWR,
+                             PS_DICT_OPEN_FLAGS);
+
+    /*
+     * Clean up and restore privilege.
+     */
+    RESTORE_SAVED_EUGID();
+}
+
+/* post_jail_init - post-jail initialization */
+
+static void post_jail_init(char *unused_name, char **unused_argv)
+{
+    const NAME_CODE actions[] = {
+       "drop", PS_ACT_DROP,
+       "continue", PS_ACT_CONT,
+       0, -1,
+    };
+
+    /*
+     * This routine runs after the skeleton code has entered the chroot jail.
+     * Prevent automatic process suicide after a limited number of client
+     * requests. It is OK to terminate after a limited amount of idle time.
+     */
+    var_use_limit = 0;
+
+    /*
+     * Other one-time initialization.
+     */
+    temp = vstring_alloc(10);
+    vstring_sprintf(temp, "%s/%s", MAIL_CLASS_PRIVATE, var_smtpd_service);
+    smtp_service_name = mystrdup(STR(temp));
+    if (*var_ps_greet_banner) {
+       vstring_sprintf(temp, "220-%s\r\n", var_ps_greet_banner);
+       teaser_greeting = mystrdup(STR(temp));
+    }
+    dnsbl_sites = argv_split(var_ps_dnsbl_sites, ", \t\r\n");
+    dnsbl_cache = htable_create(13);
+    reply_addr = vstring_alloc(100);
+    reply_domain = vstring_alloc(100);
+    if ((blist_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                 var_ps_blist_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PS_BLIST_ACTION, var_ps_blist_action);
+    if ((dnsbl_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                 var_ps_dnsbl_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PS_DNSBL_ACTION, var_ps_dnsbl_action);
+    if ((greet_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                 var_ps_greet_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PS_GREET_ACTION, var_ps_greet_action);
+    if ((hangup_action = name_code(actions, NAME_CODE_FLAG_NONE,
+                                  var_ps_hangup_action)) < 0)
+       msg_fatal("bad %s value: %s", VAR_PS_HUP_ACTION, var_ps_hangup_action);
+}
+
+MAIL_VERSION_STAMP_DECLARE;
+
+/* main - pass control to the multi-threaded skeleton */
+
+int     main(int argc, char **argv)
+{
+    static const CONFIG_STR_TABLE str_table[] = {
+       VAR_SMTPD_SERVICE, DEF_SMTPD_SERVICE, &var_smtpd_service, 1, 0,
+       VAR_PS_CACHE_MAP, DEF_PS_CACHE_MAP, &var_ps_cache_map, 0, 0,
+       VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0,
+       VAR_PS_DNSBL_SITES, DEF_PS_DNSBL_SITES, &var_ps_dnsbl_sites, 0, 0,
+       VAR_PS_GREET_ACTION, DEF_PS_GREET_ACTION, &var_ps_greet_action, 1, 0,
+       VAR_PS_DNSBL_ACTION, DEF_PS_DNSBL_ACTION, &var_ps_dnsbl_action, 1, 0,
+       VAR_PS_HUP_ACTION, DEF_PS_HUP_ACTION, &var_ps_hangup_action, 1, 0,
+       VAR_PS_WLIST_NETS, DEF_PS_WLIST_NETS, &var_ps_wlist_nets, 0, 0,
+       VAR_PS_BLIST_NETS, DEF_PS_BLIST_NETS, &var_ps_blist_nets, 0, 0,
+       VAR_PS_GREET_BANNER, DEF_PS_GREET_BANNER, &var_ps_greet_banner, 0, 0,
+       VAR_PS_BLIST_ACTION, DEF_PS_BLIST_ACTION, &var_ps_blist_action, 1, 0,
+       0,
+    };
+    static const CONFIG_INT_TABLE int_table[] = {
+       VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
+       0,
+    };
+    static const CONFIG_NINT_TABLE nint_table[] = {
+       VAR_PS_POST_QLIMIT, DEF_PS_POST_QLIMIT, &var_ps_post_queue_limit, 1, 0,
+       VAR_PS_PRE_QLIMIT, DEF_PS_PRE_QLIMIT, &var_ps_pre_queue_limit, 1, 0,
+       0,
+    };
+    static const CONFIG_TIME_TABLE time_table[] = {
+       VAR_PS_CACHE_TTL, DEF_PS_CACHE_TTL, &var_ps_cache_ttl, 1, 0,
+       VAR_PS_GREET_WAIT, DEF_PS_GREET_WAIT, &var_ps_greet_wait, 1, 0,
+       0,
+    };
+
+    /*
+     * Fingerprint executables and core dumps.
+     */
+    MAIL_VERSION_STAMP_ALLOCATE;
+
+    event_server_main(argc, argv, postscreen_service,
+                     MAIL_SERVER_STR_TABLE, str_table,
+                     MAIL_SERVER_INT_TABLE, int_table,
+                     MAIL_SERVER_NINT_TABLE, nint_table,
+                     MAIL_SERVER_TIME_TABLE, time_table,
+                     MAIL_SERVER_PRE_INIT, pre_jail_init,
+                     MAIL_SERVER_POST_INIT, post_jail_init,
+                     MAIL_SERVER_SOLITARY,
+                     MAIL_SERVER_SLOW_EXIT, postscreen_drain,
+                     0);
+}
index 9b5e522fcfe6d8706f3428e37173b6993dff4d2c..0eb305b035015f954d4f01ae1a144e7d22c0541a 100644 (file)
@@ -3686,6 +3686,34 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
            }
        } else if (is_map_command(state, name, CHECK_CCERT_ACL, &cpp)) {
            status = check_ccert_access(state, *cpp, def_acl);
+       } else if (is_map_command(state, name, CHECK_CLIENT_NS_ACL, &cpp)) {
+           if (strcasecmp(state->name, "unknown") != 0) {
+               status = check_server_access(state, *cpp, state->name,
+                                            T_NS, state->namaddr,
+                                            SMTPD_NAME_CLIENT, def_acl);
+               forbid_whitelist(state, name, status, state->name);
+           }
+       } else if (is_map_command(state, name, CHECK_CLIENT_MX_ACL, &cpp)) {
+           if (strcasecmp(state->name, "unknown") != 0) {
+               status = check_server_access(state, *cpp, state->name,
+                                            T_MX, state->namaddr,
+                                            SMTPD_NAME_CLIENT, def_acl);
+               forbid_whitelist(state, name, status, state->name);
+           }
+       } else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_NS_ACL, &cpp)) {
+           if (strcasecmp(state->reverse_name, "unknown") != 0) {
+               status = check_server_access(state, *cpp, state->reverse_name,
+                                            T_NS, state->namaddr,
+                                            SMTPD_NAME_REV_CLIENT, def_acl);
+               forbid_whitelist(state, name, status, state->reverse_name);
+           }
+       } else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_MX_ACL, &cpp)) {
+           if (strcasecmp(state->reverse_name, "unknown") != 0) {
+               status = check_server_access(state, *cpp, state->reverse_name,
+                                            T_MX, state->namaddr,
+                                            SMTPD_NAME_REV_CLIENT, def_acl);
+               forbid_whitelist(state, name, status, state->reverse_name);
+           }
        }
 
        /*
index bb59b8f7539cfb07dd3c2e89c359d2f626f07b34..a293d5c659d583f98d78a48ab6ddd86cd40e5490 100644 (file)
@@ -35,6 +35,8 @@
 /*
 /*     void    event_drain(time_limit)
 /*     int     time_limit;
+/*
+/*     void    event_fork(void)
 /* DESCRIPTION
 /*     This module delivers I/O and timer events.
 /*     Multiple I/O streams and timers can be monitored simultaneously.
 /*     This routine must not be called from an event_whatever() callback
 /*     routine. Note: this function ignores pending timer events, and
 /*     assumes that no new I/O events will be registered.
+/*
+/*     event_fork() must be called by a child process after it is
+/*     created with fork(), to re-initialize event processing.
 /* DIAGNOSTICS
 /*     Panics: interface violations. Fatal errors: out of memory,
 /*     system call failure. Warnings: the number of available
@@ -282,6 +287,11 @@ static int event_kq;                       /* handle to event filter */
     } while (0)
 #define EVENT_REG_INIT_TEXT    "kqueue"
 
+#define EVENT_REG_FORK_HANDLE(er, n) do { \
+       (void) close(event_kq); \
+       EVENT_REG_INIT_HANDLE(er, (n)); \
+    } while (0)
+
  /*
   * Macros to update the kernel-based filter; see event_enable_read(),
   * event_enable_write() and event_disable_readwrite().
@@ -359,6 +369,11 @@ static int event_pollfd;           /* handle to file descriptor set */
     } while (0)
 #define EVENT_REG_INIT_TEXT    "open /dev/poll"
 
+#define EVENT_REG_FORK_HANDLE(er, n) do { \
+       (void) close(event_pollfd); \
+       EVENT_REG_INIT_HANDLE(er, (n)); \
+    } while (0)
+
  /*
   * Macros to update the kernel-based filter; see event_enable_read(),
   * event_enable_write() and event_disable_readwrite().
@@ -431,6 +446,11 @@ static int event_epollfd;          /* epoll handle */
     } while (0)
 #define EVENT_REG_INIT_TEXT    "epoll_create"
 
+#define EVENT_REG_FORK_HANDLE(er, n) do { \
+       (void) close(event_epollfd); \
+       EVENT_REG_INIT_HANDLE(er, (n)); \
+    } while (0)
+
  /*
   * Macros to update the kernel-based filter; see event_enable_read(),
   * event_enable_write() and event_disable_readwrite().
@@ -649,6 +669,46 @@ void    event_drain(int time_limit)
 #endif
 }
 
+/* event_fork - resume event processing after fork() */
+
+void    event_fork(void)
+{
+#if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
+    EVENT_FDTABLE *fdp;
+    int     err;
+    int     fd;
+
+    /*
+     * No event was ever registered, so there's nothing to be done.
+     */
+    if (EVENT_INIT_NEEDED())
+       return;
+
+    /*
+     * Close the existing filter handle and open a new kernel-based filter.
+     */
+    EVENT_REG_FORK_HANDLE(err, event_fdslots);
+    if (err < 0)
+       msg_fatal("%s: %m", EVENT_REG_INIT_TEXT);
+
+    /*
+     * Populate the new kernel-based filter with events that were registered
+     * in the parent process.
+     */
+    for (fd = 0; fd <= event_max_fd; fd++) {
+       if (EVENT_MASK_ISSET(fd, &event_wmask)) {
+           EVENT_MASK_CLR(fd, &event_wmask);
+           fdp = event_fdtable + fd;
+           event_enable_write(fd, fdp->callback, fdp->context);
+       } else if (EVENT_MASK_ISSET(fd, &event_rmask)) {
+           EVENT_MASK_CLR(fd, &event_rmask);
+           fdp = event_fdtable + fd;
+           event_enable_read(fd, fdp->callback, fdp->context);
+       }
+    }
+#endif
+}
+
 /* event_enable_read - enable read events */
 
 void    event_enable_read(int fd, EVENT_NOTIFY_RDWR callback, char *context)
index 7837a91da63b280438cb3d7e970c39d62b25a1ab..200f7594b0d7fe9e6ec2b0a3b1a7c5cdbb895b2b 100644 (file)
@@ -30,6 +30,7 @@ extern time_t event_request_timer(EVENT_NOTIFY_TIME, char *, int);
 extern int event_cancel_timer(EVENT_NOTIFY_TIME, char *);
 extern void event_loop(int);
 extern void event_drain(int);
+extern void event_fork(void);
 
  /*
   * Event codes.
index c94c1a06fd3e8e222ae54946eb2be8947b4b45cd..ff2102f98d3317fc51283fe151f57f24dfb1652f 100644 (file)
@@ -15,7 +15,8 @@
 /*
 /*     Arguments:
 /* .IP fd
-/*     File descriptor in the range 0..FD_SETSIZE.
+/*     File descriptor in the range 0..FD_SETSIZE (on systems that
+/*     need to use select(2)).
 /* .IP timeout
 /*     If positive, deadline in seconds. A zero value effects a poll.
 /*     A negative value means wait until something happens.
index 92c7927ec6eeaa75a17097b34f7701c53c638e6e..5e5368bc36e3b8edcc7d5e667d33023aa9007511 100644 (file)
 #define HAS_DUPLEX_PIPE                        /* 4.1 breaks with kqueue(2) */
 #endif
 
+#if __FreeBSD_version >= 800098                /* commit: r194262 */
+#define HAS_CLOSEFROM
+#endif
+
 /* OpenBSD version is year+month */
 
 #if OpenBSD >= 199805                  /* XXX */
index 5eab759cbc87c2278f23e94c1e55c488e6df0ea5..3696409bae476deb09410367d98542677faec2fd 100644 (file)
@@ -66,7 +66,7 @@ int     upass_accept(int listen_fd)
 {
     const char *myname = "upass_accept";
     int     accept_fd;
-    int     recv_fd;
+    int     recv_fd = -1;
 
     accept_fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0);
     if (accept_fd < 0) {
@@ -74,7 +74,9 @@ int     upass_accept(int listen_fd)
            msg_warn("%s: accept connection: %m", myname);
        return (-1);
     } else {
-       if ((recv_fd = unix_recv_fd(accept_fd)) < 0)
+       if (read_wait(accept_fd, 100) < 0)
+           msg_warn("%s: timeout receiving file descriptor: %m", myname);
+       else if ((recv_fd = unix_recv_fd(accept_fd)) < 0)
            msg_warn("%s: cannot receive file descriptor: %m", myname);
        if (close(accept_fd) < 0)
            msg_warn("%s: close: %m", myname);