-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
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
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.
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 \
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
======================================
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.
#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
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" && {
$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
$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
$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
$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
$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
$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
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 \
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 >$@
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 >$@
--- /dev/null
+<!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>
<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
ventions defined in <<b>sysexits.h</b>>. 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>
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>
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>
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>
<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>
(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>
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
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
</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>
<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
<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
--- /dev/null
+<!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>
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 \
(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
(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
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
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
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"
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
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.
.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
--- /dev/null
+.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
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
--- /dev/null
+.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
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;
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;
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;
# 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;
# 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;
# 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;
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
%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>
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
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
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
<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>
} 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);
} else if (status == DNS_RETRY) {
soft_err = 1;
}
+ /* XXX Stop after NXDOMAIN error. */
}
return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status);
}
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+/*++
+/* 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);
+}
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 \
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 \
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)
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
--- /dev/null
+/*++
+/* 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
--- /dev/null
+#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
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;
}
#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"
#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
* 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
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)
@$(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
--- /dev/null
+/*++
+/* 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();
+}
#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
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
*/
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\": "
/* 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
/* 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;
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 *) */
} 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 */
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);
}
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 */
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,
/* 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
/* 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
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+/*++
+/* 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);
+}
}
} 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);
+ }
}
/*
/*
/* 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
} 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().
} 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().
} 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().
#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)
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.
/*
/* 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.
#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 */
{
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) {
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);