From: Wietse Venema Date: Tue, 15 Jul 2003 05:00:00 +0000 (-0500) Subject: postfix-2.0.14-20030715 X-Git-Tag: v2.1-RC1-20040331~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=57acae70515d53df4a9a96a4c73ad2d99b36f25a;p=thirdparty%2Fpostfix.git postfix-2.0.14-20030715 --- diff --git a/postfix/README_FILES/ADDRESS_VERIFICATION_README b/postfix/README_FILES/ADDRESS_VERIFICATION_README index d2cc1129c..4abd3bba5 100644 --- a/postfix/README_FILES/ADDRESS_VERIFICATION_README +++ b/postfix/README_FILES/ADDRESS_VERIFICATION_README @@ -143,7 +143,7 @@ the address verification cache quickly, and generate unnecessary sender verification probes. /etc/postfix/sender_access - securityfocus.com + securityfocus.com OK ... The "reject_unknown_sender_domain" restriction blocks mail from diff --git a/postfix/README_FILES/SMTPD_POLICY_README b/postfix/README_FILES/SMTPD_POLICY_README index 9951633d8..b5eee81c1 100644 --- a/postfix/README_FILES/SMTPD_POLICY_README +++ b/postfix/README_FILES/SMTPD_POLICY_README @@ -1,25 +1,30 @@ -SMTPD POLICY DELEGATION PROTOCOL -================================ +POLICY DELEGATION PROTOCOL +========================== The Postfix SMTP server has a number of built-in mechanisms to -block or accept mail at the SMTP protocol stage. Optionally, it -can delegate policy decisions to an external server. +block or accept mail at specific SMTP protocol stages. Optionally, +it can be configured to delegate policy decisions to an external +server that runs outside Postfix. A simple greylist policy can be +implemented with only a dozen lines of PERL. This document describes the following: -- The SMTPD policy delegation protocol. +- The Postfix policy delegation protocol. - Using the example greylist policy server. PROTOCOL DESCRIPTION ==================== -The SMTPD policy delegation protocol is really simple. The client +The Postfix policy delegation protocol is really simple. The client request is a sequence of name=value attributes separated by newline, -and is terminated by an empty line. Here is an example of all the -attributes that the Postfix SMTP server sends in a delegated policy -request: +and is terminated by an empty line. The server reply is one name=value +attribute and it, too, is terminated by an empty line. +Here is an example of all the attributes that the Postfix SMTP +server sends in a delegated SMTPD access policy request: + + request=smtpd_access_policy protocol_state=RCPT protocol_name=SMTP helo_name=some.domain.tld @@ -30,25 +35,36 @@ request: client_name=another.domain.tld [empty line] -The order of the attributes does not matter, and the server ignores -any attributes that it does not recognize. Protocol names are ESMTP -or SMTP; protocol states are CONNECT, EHLO, HELO, MAIL, RCPT, or -DATA. Other attributes speak for themselves. When the same attribute -name is sent more than once, the server may keep the first or the -last attribute value. An attribute name does not contain "=", null -or newline, and an attribute value does not contain null or newline. +- The "request" attribute is required. In this example the request + type is "smtpd_access_policy". +- The order of the attributes does not matter. The policy server + should ignore any attributes that it does not care about. +- When the same attribute name is sent more than once, the server + may keep the first value or the last attribute value. +- An attribute name must not contain "=", null or newline, and an + attribute value must not contain null or newline. + +The following is specific to SMTPD delegated policy requests: + +- Protocol names are ESMTP or SMTP. +- Protocol states are CONNECT, EHLO, HELO, MAIL, RCPT, or DATA; + these are all the SMTP protocol states where the Postfix SMTP + server makes an OK/REJECT/HOLD/etc. decision. -The policy server replies in the same style, with any action that -is allowed in a Postfix SMTPD access table. Example: +The policy server replies with any action that is allowed in a +Postfix SMTPD access table. Example: - action=450 You are greylisted + action=450 Service temporarily unavailable [empty line] +In case of trouble the server must log a warning and disconnect. +Postfix will retry the request at some later time. + CLIENT SIDE CONFIGURATION ========================= -The SMTPD delegated policy client can connect to a TCP socket or -to a UNIX-domain socket. Examples: +The delegated policy client can connect to a TCP socket or to a +UNIX-domain socket. Examples: inet:localhost:9998 unix:/some/where/policy @@ -60,54 +76,147 @@ pathname of a UNIX-domain socket. The third example specifies a pathname relative to the Postfix queue directory; use this for policy servers that are spawned by the Postfix master daemon. -To use the delegated policy service, specify "check_policy_service" -anywhere in the list of smtpd_recipient_restrictions: +To use the delegated policy service for SMTPD access control, +specify "check_policy_service" anywhere in the list of +smtpd_recipient_restrictions: /etc/postfix/main.cf: smtpd_recipient_restrictions = - ... - reject_unauth_destination - check_policy_service unix:private/policy - ... + ... + reject_unauth_destination + check_policy_service unix:private/policy + ... NOTE: specify "check_policy_service" AFTER "reject_unauth_destination" or else your system could become an open relay. +NOTE: Solaris UNIX-domain sockets do not work very well. Use TCP +sockets instead: + +/etc/postfix/main.cf: + smtpd_recipient_restrictions = + ... + reject_unauth_destination + check_policy_service inet:localhost:9998 + ... + +Other client-side configuration parmeters: + +- smtpd_policy_service_max_idle (default: 300s): the amount of time + before Postfix closes an unused policy connection. The socket is + closed while the SMTP server waits for new a SMTP client. + +- smtpd_policy_service_max_ttl (default: 1000s): the amount of time + before Postfix closes an active policy connection. The socket + is closed while the SMTP server waits for new a SMTP client. + +- smtpd_policy_service_timeout (default: 100s): the time limit to + connect to, send to or receive from a policy service. + EXAMPLE: GREYLIST POLICY SERVER =============================== The file examples/smtpd-policy/smtpd-policy.pl in the Postfix source tree implements an example greylist policy server. This server stores a time stamp for every (client, sender, recipient) triple. -Mail is not accepted until a triple's time stamp is more than 3600 -seconds old. This stops junk mail with random sender addresses, -and mail from randomly selected open proxies. It also stops junk -mail from spammers that change IP address frequently. +By default, mail is not accepted until a triple's time stamp is +more than 3600 seconds old. This stops junk mail with randomly +selected sender addresses, and mail that is sent through randomly +selected open proxies. It also stops junk mail from spammers that +change their IP address frequently. + +Copy examples/smtpd-policy/smtpd-policy.pl to /usr/libexec/postfix +or whatever location is appropriate for your system. + +In the smtpd-policy.pl PERL script you need to specify the location +of the greylist database file. The default location is: + + $database_name="/var/mta/smtpd-policy.db"; + +The /var/mta directory (or whatever you choose) should be writable +by "nobody", or by whatever username you configure below in master.cf +for the policy service. + +Example: -The example greylist policy server is a PERL script that runs under -control by the Postfix master daemon: + # mkdir /var/mta + # chown nobody /var/mta + +Note: DO NOT create the greylist database in a world-writable +directory such as /tmp or /var/tmp, and DO NOT create the greylist +database in a file system that can run out of space easily. If the +file becomes corrupted you will not be able to receive mail until +you delete the file by hand. + +The smtpd-policy.pl PERL script can be run under control by the +Postfix master daemon. For example, to run the script as user +"nobody", using a UNIX-domain socket that is accessible by Postfix +processes only: /etc/postfix/master.cf: policy unix - n n - - spawn user=nobody argv=/usr/bin/perl /usr/libexec/postfix/smtpd-policy.pl +Specify "...postfix/smtpd-policy.pl -v" for verbose logging of each +request and reply. + +Greylisting mail from frequently forged domains +----------------------------------------------- + +It is relatively safe to turn on greylisting for specific domains +that often appear in forged email. + /etc/postfix/main.cf: smtpd_recipient_restrictions = - permit_mynetworks + ... reject_unauth_destination - check_policy_service unix:private/policy unix:private/policy + check_sender_access hash:/etc/postfix/sender_access ... + restriction_classes = greylist + greylist = check_policy_service unix:private/policy -There are other delegated policy client configuration parameters -that control timeouts etc. but you should never have to change -those. +/etc/postfix/sender_access: + aol.com greylist + hotmail.com greylist + bigfoot.com greylist + ... etcetera ... -In the smtpd-policy.pl PERL script you need to specify the location -of the greylist database file. DO NOT create the greylist database -in a world-writable directory such as /tmp or /var/tmp, and DO NOT -create the greylist database in a file system that can run out of -space easily. If the file becomes corrupted you will not be able -to receive mail until you delete the file by hand. +Be sure to specify check_sender_access AFTER reject_unauth_destination +or else your system could become an open mail relay. + +A list of frequently forged MAIL FROM domains can be found at +http://www.monkeys.com/anti-spam/filtering/sender-domain-validate.in + +Greylisting all your mail +------------------------- + +If you turn on greylisting for all mail you will almost certainly +want to make exceptions for mailing lists that use one-time sender +addresses, because such mailing lists can pollute your greylist +database relatively quickly. + +/etc/postfix/main.cf: + smtpd_recipient_restrictions = + ... + reject_unauth_destination + check_sender_access hash:/etc/postfix/sender_access + check_policy_service unix:private/policy + ... + +/etc/postfix/sender_access: + securityfocus.com OK + ... + +Be sure to specify check_sender_access and check_policy_service +AFTER reject_unauth_destination or else your system could become +an open mail relay. + +ROUTINE MAINTENANCE +=================== + +The greylist database grows over time, because the greylist server +never removes database entries. If left unattended, the greylist +database will eventually run your file system out of space. When the status file exceeds some reasonable size you can simply delete the file without adverse effects. In the worst case, new @@ -129,20 +238,19 @@ $database_name="/var/mta/smtpd-policy.db"; $greylist_delay=3600; # -# Demo policy routine. The result is an action just like it would -# be specified on the right-hand side of a Postfix access table. -# Request attributes are passed in via the %attr hash. +# Demo SMTPD access policy routine. The result is an action just like +# it would be specified on the right-hand side of a Postfix access +# table. Request attributes are available via the %attr hash. # -sub policy { - local(*attr) = @_; +sub smtpd_access_policy { my($key, $time_stamp, $now); # Open the database on the fly. open_database() unless $database_obj; - + # Lookup the time stamp for this client/sender/recipient. $key = $attr{"client_address"}."/".$attr{"sender"}."/".$attr{"recipient"}; - $time_stamp = read_database($key); + $time_stamp = read_database($key); $now = time(); # If new request, add this client/sender/recipient to the database. @@ -152,9 +260,9 @@ sub policy { } syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose; - if ($time_stamp + $greylist_delay < $now) { + if ($now - $time_stamp > $greylist_delay) { return "ok"; } else { - return "450 request is greylisted"; + return "450 Service is unavailable"; } } diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 9c816160c..217c2de86 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -22,6 +22,17 @@ snapshot release). Patches change the patchlevel and the release date. Snapshots change only the release date, unless they include the same bugfixes as a patch release. +Major changes with Postfix snapshot 2.0.13-20030715 +=================================================== + +Support for SMTP access policy delegation to an external server. +Greylisting is used as an example. See the SMTPD_POLICY_README +file for further information. + +Support for multi-valued RBL lookup results. For example, specify +"reject_rbl_client foo.bar.tld=127.0.0.3" to reject clients that +are listed with a "127.0.0.3" address record. + Major changes with Postfix snapshot 2.0.13-20030706 =================================================== diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index d3ff079dd..2fa27b6f0 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -142,8 +142,12 @@ smtpd_banner = $myhostname ESMTP $mail_name # Permit the ETRN command if the result is OK or all numerical. # reject_rbl_client domain.tld: reject if the reverse client network # address is listed in an A record under domain.tld. +# Append e.g., "=127.0.0.2" to the RBL domain name to select a specific +# address record when an RBL server provides multi-valued results. # reject_rhsbl_client domain.tld: reject if the client hostname is listed # in an A record under domain.tld. +# Append e.g., "=127.0.0.2" to the RBL domain name to select a specific +# address record when an RBL server provides multi-valued results. # reject: reject the request. Place this at the end of a restriction. # permit: permit the request. Place this at the end of a restriction. # warn_if_reject: next restriction logs a warning instead of rejecting. @@ -316,8 +320,12 @@ mynetworks_style = subnet # Permit the SMTP client if the result is OK or all numerical. # reject_rbl_client domain.tld: reject if the reversed client IP address # is listed in an A record under domain.tld. +# Append e.g., "=127.0.0.2" to the RBL domain name to select a specific +# address record when an RBL server provides multi-valued results. # reject_rhsbl_client domain.tld: reject if the client hostname is listed # in an A record under domain.tld. +# Append e.g., "=127.0.0.2" to the RBL domain name to select a specific +# address record when an RBL server provides multi-valued results. # reject: reject the request. Place this at the end of a restriction. # permit: permit the request. Place this at the end of a restriction. # warn_if_reject: next restriction logs a warning instead of rejecting. diff --git a/postfix/examples/smtpd-policy/smtpd-policy.pl b/postfix/examples/smtpd-policy/smtpd-policy.pl index 0d374aaa6..b9f60efbb 100755 --- a/postfix/examples/smtpd-policy/smtpd-policy.pl +++ b/postfix/examples/smtpd-policy/smtpd-policy.pl @@ -39,6 +39,7 @@ use Sys::Syslog qw(:DEFAULT setlogsock); # Each query is a bunch of attributes. Order does not matter, and # the demo script uses only a few of all the attributes shown below: # +# request=smtpd_access_policy # protocol_state=RCPT # protocol_name=SMTP # helo_name=some.domain.tld @@ -76,12 +77,11 @@ $syslog_options="pid"; $syslog_priority="info"; # -# Demo policy routine. The result is an action just like it would -# be specified on the right-hand side of a Postfix access table. -# Request attributes are passed in via the %attr hash. +# Demo SMTPD access policy routine. The result is an action just like +# it would be specified on the right-hand side of a Postfix access +# table. Request attributes are available via the %attr hash. # -sub policy { - local(*attr) = @_; +sub smtpd_access_policy { my($key, $time_stamp, $now); # Open the database on the fly. @@ -99,10 +99,10 @@ sub policy { } syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose; - if ($time_stamp + $greylist_delay < $now) { + if ($now - $time_stamp > $greylist_delay) { return "ok"; } else { - return "450 request is greylisted"; + return "450 Service is unavailable"; } } @@ -118,7 +118,8 @@ sub LOCK_UN { 8 }; # Release lock. # Log an error and abort. # sub fatal_exit { - syslog "err", @_; + my($first) = shift(@_); + syslog "err", "fatal: $first", @_; exit 1; } @@ -128,6 +129,7 @@ sub fatal_exit { sub open_database { my($database_fd); + # Use tied database to make complex manipulations easier to express. $database_obj = tie(%db_hash, 'DB_File', $database_name, O_CREAT|O_RDWR, 0644) || fatal_exit "Cannot open database %s: $!", $database_name; @@ -201,16 +203,21 @@ select((select(STDOUT), $| = 1)[0]); # while () { if (/([^=]+)=(.*)\n/) { - $attr{$1} = $2; - } else { + $attr{substr($1, 0, 512)} = substr($2, 0, 512); + } elsif ($_ eq "\n") { if ($verbose) { for (keys %attr) { syslog $syslog_priority, "Attribute: %s=%s", $_, $attr{$_}; } } - $action = &policy(*attr); + fatal_exit "unrecognized request type: '%s'", $attr{request} + unless $attr{"request"} eq "smtpd_access_policy"; + $action = smtpd_access_policy(); syslog $syslog_priority, "Action: %s", $action if $verbose; print STDOUT "action=$action\n\n"; %attr = (); + } else { + chop; + syslog $syslog_priority, "warning: ignoring garbage: %.100s", $_; } } diff --git a/postfix/html/uce.html b/postfix/html/uce.html index 6d0a25c79..fb7f8207d 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -388,9 +388,14 @@ href="basic.html#mynetworks"> $mynetworks. +
reject_rbl_client domain.tld=127.0.0.2 +
reject_rbl_client domain.tld
Reject the request when the reversed client network address is listed with an -A record under domain.tld. +A record under domain.tld. + +Append the address to the RBL server's domain name to select a +specific address from a multi-valued result. The maps_rbl_reject_code parameter specifies the response code for rejected requests (default: 554), the +
reject_rhsbl_client domain.tld=127.0.0.2 +
reject_rhsbl_client domain.tld
Reject the request when the client hostname is listed with an A record under domain.tld. See above for additional RBL related configuration parameters. +Append the address to the RBL server's domain name to select a +specific address from a multi-valued result. +

diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index bf39f9746..bf6cfd56f 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change the patchlevel and the release date. Snapshots change the * release date only, unless they include the same bugfix as a patch release. */ -#define MAIL_RELEASE_DATE "20030714" +#define MAIL_RELEASE_DATE "20030715" #define VAR_MAIL_VERSION "mail_version" #define DEF_MAIL_VERSION "2.0.14-" MAIL_RELEASE_DATE diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 102ddbbc8..b23c5f170 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -2741,8 +2741,10 @@ static int check_policy_service(SMTPD_STATE *state, const char *server, */ if (action == 0) action = vstring_alloc(10); + if (attr_clnt_request(policy_clnt, ATTR_FLAG_NONE, /* Query attributes. */ + ATTR_TYPE_STR, MAIL_ATTR_REQ, "smtpd_access_policy", ATTR_TYPE_STR, MAIL_ATTR_PROTO_STATE, state->where, ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, state->protocol, ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, state->addr, diff --git a/postfix/src/util/attr_clnt.c b/postfix/src/util/attr_clnt.c index e12644a1e..5b5eea328 100644 --- a/postfix/src/util/attr_clnt.c +++ b/postfix/src/util/attr_clnt.c @@ -39,9 +39,8 @@ /* /* attr_clnt_request() sends the specified request attributes and /* receives a reply. The reply argument specifies a name-value table. -/* The other arguments are as described in attr_print0(3) and in -/* attr_print64(3). The result is the number of attributes received -/* or -1 in case of trouble. +/* The other arguments are as described in attr_print_plain(3). The +/* result is the number of attributes received or -1 in case of trouble. /* /* attr_clnt_free() destroys a client handle and closes its connection. /* DIAGNOSTICS @@ -136,8 +135,7 @@ ATTR_CLNT *attr_clnt_create(const char *service, int timeout, if ((endpoint = split_at(transport, ':')) == 0 || *endpoint == 0 || *transport == 0) - msg_fatal("service \"%s\" should be specified as transport:endpoint", - service); + msg_fatal("need service transport:endpoint instead of \"%s\"", service); if (msg_verbose) msg_info("%s: transport=%s endpoint=%s", myname, transport, endpoint); diff --git a/postfix/src/util/attr_print_plain b/postfix/src/util/attr_print_plain deleted file mode 100755 index b94f004b1..000000000 Binary files a/postfix/src/util/attr_print_plain and /dev/null differ diff --git a/postfix/src/util/attr_scan_plain b/postfix/src/util/attr_scan_plain deleted file mode 100755 index 8293c4c27..000000000 Binary files a/postfix/src/util/attr_scan_plain and /dev/null differ diff --git a/postfix/src/util/auto_clnt.c b/postfix/src/util/auto_clnt.c index 1a487aad1..093d0a95e 100644 --- a/postfix/src/util/auto_clnt.c +++ b/postfix/src/util/auto_clnt.c @@ -21,13 +21,10 @@ /* void auto_clnt_free(auto_clnt) /* AUTO_CLNT *auto_clnt; /* DESCRIPTION -/* This module maintains local IPC client endpoints that automatically +/* This module maintains IPC client endpoints that automatically /* disconnect after a being idle for a configurable amount of time, /* that disconnect after a configurable time to live, /* and that transparently handle most server-initiated disconnects. -/* Server disconnect is detected by read-selecting the client endpoint. -/* The code assumes that the server has disconnected when the endpoint -/* becomes readable. /* /* auto_clnt_create() instantiates a client endpoint. /*