diff --git a/postfix/HISTORY b/postfix/HISTORY index cb2b0805e..f210ba68d 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -8384,6 +8384,19 @@ Apologies for any names omitted. "check_smtpd_policy_service" in smtpd_mumble_restrictions. See SMTPD_POLICY_SERVICE_README for details. +20030716 + + Bugfix: in the sample policy server, changed "ok" into + "dunno" so the server can be used in the middle of a + restriction list. + + Cleanup: when an RBL reply has multiple TXT records, + concatenate them up to some reasonable limit, instead of + selecting one randomly. File: smtpd/smtpd_check.c. + + Safety: always truncate SMTP server error replies to 512 + bytes. File: smtpd/smtpd_check.c. + Open problems: Low: smtp-source may block when sending large test messages. diff --git a/postfix/README_FILES/SMTPD_POLICY_README b/postfix/README_FILES/SMTPD_POLICY_README index b5eee81c1..5469ef45f 100644 --- a/postfix/README_FILES/SMTPD_POLICY_README +++ b/postfix/README_FILES/SMTPD_POLICY_README @@ -47,8 +47,8 @@ server sends in a delegated SMTPD access policy request: 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 +- Protocol states are CONNECT, EHLO, HELO, MAIL, RCPT, DATA or + ETRN; these are the SMTP protocol states where the Postfix SMTP server makes an OK/REJECT/HOLD/etc. decision. The policy server replies with any action that is allowed in a @@ -259,9 +259,11 @@ sub smtpd_access_policy { update_database($key, $time_stamp); } + # Specify DUNNO instead of OK so that the check_policy_service restriction + # can be used in the middle of a restriction list. syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose; if ($now - $time_stamp > $greylist_delay) { - return "ok"; + return "dunno"; } else { return "450 Service is unavailable"; } diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index 2fa27b6f0..a03938158 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -148,6 +148,8 @@ smtpd_banner = $myhostname ESMTP $mail_name # 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. +# check_policy_service transport:endpoint: delegate the decision to +# an external policy server. See SMTPD_POLICY_README for details. # 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. @@ -326,6 +328,8 @@ mynetworks_style = subnet # 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. +# check_policy_service transport:endpoint: delegate the decision to +# an external policy server. See SMTPD_POLICY_README for details. # 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. @@ -370,6 +374,8 @@ smtpd_helo_required = no # Filter the message if the result is FILTER transport:nexthop. # Redirect the message if the result is REDIRECT user@domain. # Permit the HELO command if the result is OK or all numerical. +# check_policy_service transport:endpoint: delegate the decision to +# an external policy server. See SMTPD_POLICY_README for details. # 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. @@ -415,6 +421,8 @@ smtpd_helo_restrictions = # the client login name doesn't own the MAIL FROM address according to # $smtpd_sender_login_maps (see above). # reject_non_fqdn_sender: reject sender address that is not in FQDN form +# check_policy_service transport:endpoint: delegate the decision to +# an external policy server. See SMTPD_POLICY_README for details. # 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. @@ -486,6 +494,8 @@ smtpd_sender_restrictions = # Redirect the message if the result is REDIRECT user@domain. # Permit the recipient if the result is OK or all numerical. # reject_non_fqdn_recipient: reject recipient address that is not in FQDN form +# check_policy_service transport:endpoint: delegate the decision to +# an external policy server. See SMTPD_POLICY_README for details. # 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 b9f60efbb..f3f9c7a64 100755 --- a/postfix/examples/smtpd-policy/smtpd-policy.pl +++ b/postfix/examples/smtpd-policy/smtpd-policy.pl @@ -26,7 +26,7 @@ use Sys::Syslog qw(:DEFAULT setlogsock); # To use this from Postfix SMTPD, use in /etc/postfix/main.cf: # # smtpd_recipient_restrictions = -# ... reject_unauth_destination +# ... reject_unauth_destination # check_policy_service unix:private/policy ... # # NOTE: specify check_policy_service AFTER reject_unauth_destination @@ -53,7 +53,7 @@ use Sys::Syslog qw(:DEFAULT setlogsock); # The policy server script will answer in the same style, with an # attribute list followed by a empty line: # -# action=ok +# action=dunno # [empty line] # @@ -67,7 +67,7 @@ $database_name="/var/mta/smtpd-policy.db"; $greylist_delay=3600; # -# Syslogging options for verbose mode and for fatal errors. +# Syslogging options for verbose mode and for fatal errors. # NOTE: comment out the $syslog_socktype line if syslogging does not # work on your system. # @@ -92,15 +92,17 @@ sub smtpd_access_policy { $time_stamp = read_database($key); $now = time(); - # If new request, add this client/sender/recipient to the database. + # If this is a new request add this client/sender/recipient to the database. if ($time_stamp == 0) { $time_stamp = $now; update_database($key, $time_stamp); } + # Specify DUNNO instead of OK so that the check_policy_service restriction + # can be followed by other restrictions. syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose; if ($now - $time_stamp > $greylist_delay) { - return "ok"; + return "dunno"; } else { return "450 Service is unavailable"; } @@ -130,7 +132,7 @@ 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, + $database_obj = tie(%db_hash, 'DB_File', $database_name, O_CREAT|O_RDWR, 0644) || fatal_exit "Cannot open database %s: $!", $database_name; $database_fd = $database_obj->fd; @@ -187,7 +189,7 @@ while ($option = shift(@ARGV)) { if ($option eq "-v") { $verbose = 1; } else { - syslog $syslog_priority, "Invalid option: %s. Usage: %s [-v]", + syslog $syslog_priority, "Invalid option: %s. Usage: %s [-v]", $option, $0; exit 1; } diff --git a/postfix/html/uce.html b/postfix/html/uce.html index fb7f8207d..ec9d020cf 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -441,6 +441,8 @@ significant octets.
reject_unauth_pipelining +
check_policy_service +
See generic restrictions. @@ -593,6 +595,8 @@ or parent domains.
reject_unauth_pipelining +
check_policy_service +
See generic restrictions. @@ -776,6 +780,8 @@ client login name doesn't own the MAIL FROM address according to
reject_unauth_pipelining +
check_policy_service +
See generic restrictions. @@ -1058,6 +1064,8 @@ response code to rejected requests (default: 504).
reject_unauth_pipelining +
check_policy_service +
See generic restrictions. @@ -1139,6 +1147,8 @@ the result code for rejected requests (default: 554).
reject_unauth_pipelining +
check_policy_service +
See generic restrictions. @@ -1206,6 +1216,33 @@ Postfix actually supports SMTP command pipelining. This stops mail from bulk mail software that improperly uses SMTP command pipelining to speed up deliveries. +

+ + + +

check_policy_service inet:host:port + +
check_policy_service unix:pathname + +
Query the specified server with a list of attributes that +specify (where available) the mail protocol (SMTP or ESMTP), the +queue file name, the protocol state (CONNECT, HELO, EHLO, MAIL, +RCPT, ETRN), the client network address, the hostname given in the +HELO or EHLO command, the sender email address, the recipient email +address. The server is expected to reply with an action just like +the actions found in a Postfix access +table. + +

+ +Example: + +

check_policy_service inet:localhost:9998 + +
check_policy_service unix:private/policy + +
check_policy_service unix:/some/where + diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index bf6cfd56f..0fdb03384 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 "20030715" +#define MAIL_RELEASE_DATE "20030716" #define VAR_MAIL_VERSION "mail_version" #define DEF_MAIL_VERSION "2.0.14-" MAIL_RELEASE_DATE diff --git a/postfix/src/qmqpd/Makefile.in b/postfix/src/qmqpd/Makefile.in index b7b9b8e96..2ccd7d449 100644 --- a/postfix/src/qmqpd/Makefile.in +++ b/postfix/src/qmqpd/Makefile.in @@ -96,6 +96,7 @@ qmqpd.o: ../../include/quote_flags.h qmqpd.o: ../../include/match_parent_style.h qmqpd.o: ../../include/lex_822.h qmqpd.o: ../../include/verp_sender.h +qmqpd.o: ../../include/input_transp.h qmqpd.o: ../../include/mail_server.h qmqpd.o: qmqpd.h qmqpd_peer.o: qmqpd_peer.c diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 30e443680..b098fceb1 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -198,6 +198,8 @@ smtpd_check.o: ../../include/htable.h smtpd_check.o: ../../include/ctable.h smtpd_check.o: ../../include/mac_expand.h smtpd_check.o: ../../include/mac_parse.h +smtpd_check.o: ../../include/attr_clnt.h +smtpd_check.o: ../../include/attr.h smtpd_check.o: ../../include/dns.h smtpd_check.o: ../../include/string_list.h smtpd_check.o: ../../include/match_list.h @@ -222,7 +224,6 @@ smtpd_check.o: ../../include/record.h smtpd_check.o: ../../include/rec_type.h smtpd_check.o: ../../include/mail_proto.h smtpd_check.o: ../../include/iostuff.h -smtpd_check.o: ../../include/attr.h smtpd_check.o: ../../include/mail_addr.h smtpd_check.o: ../../include/verify_clnt.h smtpd_check.o: ../../include/deliver_request.h diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index b23c5f170..5857d5865 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -297,7 +297,6 @@ #include #include #include -#include #include /* DNS library. */ @@ -487,7 +486,7 @@ static void PRINTFLIKE(3, 4) defer_if(SMTPD_DEFER *, int, const char *,...); * Cached RBL lookup state. */ typedef struct { - ARGV *txt; /* TXT records or NULL */ + char *txt; /* TXT content or NULL */ ARGV *a; /* A records */ } SMTPD_RBL_STATE; @@ -834,6 +833,13 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class, vstring_vsprintf(error_text, format, ap); va_end(ap); + /* + * Ensure RFC compliance. We could do this inside smtpd_chat_reply() and + * switch to multi-line for long replies. + */ + vstring_truncate(error_text, 510); + VSTRING_TERMINATE(error_text); + /* * Validate the response, that is, the response must begin with a * three-digit status code, and the first digit must be 4 or 5. If the @@ -2390,6 +2396,9 @@ static void *rbl_pagein(const char *query, void *unused_context) DNS_RR *addr_list; struct in_addr addr; DNS_RR *rr; + DNS_RR *next; + VSTRING *buf; + int space_left; /* * Do the query. If the DNS lookup produces no definitive reply, give the @@ -2406,17 +2415,26 @@ static void *rbl_pagein(const char *query, void *unused_context) /* * Save the result. Yes, we cache negative results as well as positive - * results. + * results. Concatenate multiple TXT records, up to some limit. */ -#define RBL_TXT_LIMIT 256 +#define RBL_TXT_LIMIT 500 rbl = (SMTPD_RBL_STATE *) mymalloc(sizeof(*rbl)); if (dns_lookup(query, T_TXT, 0, &txt_list, (VSTRING *) 0, (VSTRING *) 0) == DNS_OK) { - rbl->txt = argv_alloc(1); - for (rr = txt_list; rr != 0; rr = rr->next) - argv_addn(rbl->txt, rr->data, rr->data_len > RBL_TXT_LIMIT ? - RBL_TXT_LIMIT : rr->data_len, ARGV_END); + buf = vstring_alloc(1); + space_left = RBL_TXT_LIMIT; + for (rr = txt_list; rr != 0 && space_left > 0; rr = next) { + vstring_strncat(buf, rr->data, (int) rr->data_len > space_left ? + space_left : rr->data_len); + space_left = RBL_TXT_LIMIT - VSTRING_LEN(buf); + next = rr->next; + if (next && space_left > 3) { + vstring_strcat(buf, " / "); + space_left -= 3; + } + } + rbl->txt = vstring_export(buf); dns_rr_free(txt_list); } else rbl->txt = 0; @@ -2437,7 +2455,7 @@ static void rbl_pageout(void *data, void *unused_context) if (rbl != 0) { if (rbl->txt) - argv_free(rbl->txt); + myfree(rbl->txt); if (rbl->a) argv_free(rbl->a); myfree((char *) rbl); @@ -2506,16 +2524,7 @@ static int rbl_reject_reply(SMTPD_STATE *state, SMTPD_RBL_STATE *rbl, rbl_exp.domain = rbl_domain; rbl_exp.what = what; rbl_exp.class = reply_class; - - /* - * XXX When presented with multiple txt records pick a random one! There - * is no way to pair up the A records with associated TXT records. If a - * client connects multiple times, it will learn the right reject reason - * at least some of the time. - */ - rbl_exp.txt = mystrdup(rbl->txt == 0 ? "" : - rbl->txt->argc == 1 ? rbl->txt->argv[0] : - rbl->txt->argv[myrand() % rbl->txt->argc]); + rbl_exp.txt = (rbl->txt == 0 ? "" : rbl->txt); for (;;) { if (template == 0) @@ -2537,7 +2546,6 @@ static int rbl_reject_reply(SMTPD_STATE *state, SMTPD_RBL_STATE *rbl, * Clean up. */ vstring_free(why); - myfree((char *) rbl_exp.txt); return (result); } diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 5dbf530db..2ef76b329 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -459,6 +459,7 @@ attr_clnt.o: vstream.h attr_clnt.o: vbuf.h attr_clnt.o: connect.h attr_clnt.o: iostuff.h +attr_clnt.o: htable.h attr_clnt.o: attr.h attr_clnt.o: auto_clnt.h attr_clnt.o: attr_clnt.h