20020919
- Feature: reject_rbl <domainname> by LaMont Jones.
+ Feature: reject_rbl <domain> for client address blacklisting
+ by LaMont Jones, including $name expansion for per-domain
+ customized response messages. The obsolete reject_maps_rbl
+ is now a wrapper that uses the new code.
20020921
- Internal: generic caching and reject reporting that can be
- used for both RBL and RHSBL.
+ Internal: added caching and reject reporting that can be
+ used for both reject_rbl and for the upcoming reject_rhsbl.
+
+20020922
+
+ Feature: reject_rhsbl <domain> for sender domain blacklisting.
+ Provides the same per-domain customized response message
+ mechanisms with $name expansion as reject_rbl.
+
+ Safety: the smtpd_expansion_filter parameter controls what
+ characters are allowed in the expansion of $name macros in
+ template RBL responses.
+
+ Cleanup. In order to make sensible warnings possible when
+ expanding a non-existent $name in RBL reply templates,
+ mac_expand() had to be changed so that an empty string
+ result (i.e. the name does exist) will no longer cause
+ ${name?text} to succeed. File: util/mac_expand.c.
Open problems:
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
+Incompatible changes with Postfix snapshot 1.1.11-20020922
+==========================================================
+
+Subtle change in ${name:result} macro expansions: the expansion
+no longer happens when $name is an empty string.
+
+Major changes with Postfix snapshot 1.1.11-20020922
+===================================================
+
+Complete rewrite of RBL internals to avoid unnecessary code
+duplication and to implement caching of results.
+
+Feature: "reject_rbl rbl.domain.tld" for client IP address
+blacklisting. The old "reject_maps_rbl" is now implemented as a
+wrapper around the reject_rbl code. Based on code by LaMont Jones.
+
+Feature: "reject_rhsbl rbl.domain.tld" for sender domain based
+blacklisting.
+
+"rbl_reply_maps" configuration parameter for lookup tables with
+template responses per RBL server. The template responses support
+$name expansion of client, helo, sender, recipient and RBL server
+attributes. See sample-smtpd.cf for details. Based on code by LaMont
+Jones.
+
+"smtpd_expansion_filter" configuration parameter to control what
+characters are allowed in the expansion of $name macros.
+
Incompatible changes with Postfix snapshot 1.1.11-20020917
==========================================================
Text that follows the <b>220</b> status code in the SMTP
greeting banner.
+ <b>smtpd</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
+ Controls what characters are allowed in $name
+ expansion of rbl template responses and other text.
+
<b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
Restrict the number of recipients that the SMTP
server accepts per message delivery.
instead of the null sender address. A null sender
address cannot be looked up.
- <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b>
+ <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> (deprecated)
List of DNS domains that publish the addresses of
- blacklisted hosts.
+ blacklisted hosts. This is used with the deprecated
+ <b>reject</b><i>_</i><b>maps</b><i>_</i><b>rbl</b> restriction.
<b>permit</b><i>_</i><b>mx</b><i>_</i><b>backup</b><i>_</i><b>networks</b>
- Only domains whose primary MX hosts match the
- listed networks are eligible for the <b>per-</b>
+ Only domains whose primary MX hosts match the
+ listed networks are eligible for the <b>per-</b>
<b>mit</b><i>_</i><b>mx</b><i>_</i><b>backup</b> feature.
<b>relay</b><i>_</i><b>domains</b>
- Restrict what domains or networks this mail system
+ Restrict what domains or networks this mail system
will relay mail from or to.
<b>UCE</b> <b>control</b> <b>responses</b>
<b>access</b><i>_</i><b>map</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates an access
+ Server response when a client violates an access
database restriction.
<b>defer</b><i>_</i><b>code</b>
- Server response when a client request is rejected
+ Server response when a client request is rejected
by the <b>defer</b> restriction.
<b>invalid</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates the
+ Server response when a client violates the
<b>reject</b><i>_</i><b>invalid</b><i>_</i><b>hostname</b> restriction.
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates the
+ Server response when a client violates the
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> restriction.
+ <b>rbl</b><i>_</i><b>reply</b><i>_</i><b>maps</b>
+ Table with template responses, indexed by RBL
+ domain name. These templates are used by the
+ <b>reject</b><i>_</i><b>rbl</b> and <b>reject</b><i>_</i><b>rhsbl</b> restrictions. See also:
+ <b>smtpd</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>.
+
<b>reject</b><i>_</i><b>code</b>
Response code when the client matches a <b>reject</b>
restriction.
.RE
.IP \fBsmtpd_banner\fR
Text that follows the \fB220\fR status code in the SMTP greeting banner.
+.IP \fBsmtpd_expansion_filter\fR
+Controls what characters are allowed in $name expansion of
+rbl template responses and other text.
.IP \fBsmtpd_recipient_limit\fR
Restrict the number of recipients that the SMTP server accepts
per message delivery.
.IP \fBsmtpd_null_access_lookup_key\fR
The lookup key to be used in SMTPD access tables instead of the
null sender address. A null sender address cannot be looked up.
-.IP \fBmaps_rbl_domains\fR
+.IP "\fBmaps_rbl_domains\fR (deprecated)"
List of DNS domains that publish the addresses of blacklisted
-hosts.
+hosts. This is used with the deprecated \fBreject_maps_rbl\fR
+restriction.
.IP \fBpermit_mx_backup_networks\fR
Only domains whose primary MX hosts match the listed networks
are eligible for the \fBpermit_mx_backup\fR feature.
.IP \fBmaps_rbl_reject_code\fR
Server response when a client violates the \fBmaps_rbl_domains\fR
restriction.
+.IP \fBrbl_reply_maps\fR
+Table with template responses, indexed by RBL domain name. These
+templates are used by the \fBreject_rbl\fR and \fBreject_rhsbl\fR
+restrictions. See also: \fBsmtpd_expansion_filter\fR.
.IP \fBreject_code\fR
Response code when the client matches a \fBreject\fR restriction.
.IP \fBrelay_domains_reject_code\fR
#define WARN_IF_REJECT "warn_if_reject"
#define REJECT_RBL "reject_rbl"
+#define REJECT_RHSBL "reject_rhsbl"
#define VAR_RBL_REPLY_MAPS "rbl_reply_maps"
#define DEF_RBL_REPLY_MAPS ""
extern char *var_rbl_reply_maps;
#define DEF_SMTPD_NULL_KEY "<>"
extern char *var_smtpd_null_key;
+#define VAR_SMTPD_EXP_FILTER "smtpd_expansion_filter"
+#define DEF_SMTPD_EXP_FILTER "\\t\\40!\"#$%&'()*+,-./0123456789:;<=>?@\
+ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`\
+abcdefghijklmnopqrstuvwxyz{|}~"
+extern char *var_smtpd_exp_filter;
+
/*
* Heuristic to reject most unknown recipients at the SMTP port.
*/
* 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 "20020921"
+#define MAIL_RELEASE_DATE "20020922"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE
smtpd_token: smtpd_token.c $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS)
-smtpd_check: smtpd_check.c $(SMTPD_CHECK_OBJ) $(LIBS)
+smtpd_check: smtpd_check.o smtpd_check.c $(SMTPD_CHECK_OBJ) $(LIBS)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ smtpd_check.c $(SMTPD_CHECK_OBJ) \
$(LIBS) $(SYSLIBS)
/* .RE
/* .IP \fBsmtpd_banner\fR
/* Text that follows the \fB220\fR status code in the SMTP greeting banner.
+/* .IP \fBsmtpd_expansion_filter\fR
+/* Controls what characters are allowed in $name expansion of
+/* rbl template responses and other text.
/* .IP \fBsmtpd_recipient_limit\fR
/* Restrict the number of recipients that the SMTP server accepts
/* per message delivery.
/* .IP \fBsmtpd_null_access_lookup_key\fR
/* The lookup key to be used in SMTPD access tables instead of the
/* null sender address. A null sender address cannot be looked up.
-/* .IP \fBmaps_rbl_domains\fR
+/* .IP "\fBmaps_rbl_domains\fR (deprecated)"
/* List of DNS domains that publish the addresses of blacklisted
-/* hosts.
+/* hosts. This is used with the deprecated \fBreject_maps_rbl\fR
+/* restriction.
/* .IP \fBpermit_mx_backup_networks\fR
/* Only domains whose primary MX hosts match the listed networks
/* are eligible for the \fBpermit_mx_backup\fR feature.
/* .IP \fBmaps_rbl_reject_code\fR
/* Server response when a client violates the \fBmaps_rbl_domains\fR
/* restriction.
+/* .IP \fBrbl_reply_maps\fR
+/* Table with template responses, indexed by RBL domain name. These
+/* templates are used by the \fBreject_rbl\fR and \fBreject_rhsbl\fR
+/* restrictions. See also: \fBsmtpd_expansion_filter\fR.
/* .IP \fBreject_code\fR
/* Response code when the client matches a \fBreject\fR restriction.
/* .IP \fBrelay_domains_reject_code\fR
char *var_smtpd_noop_cmds;
char *var_smtpd_null_key;
int var_smtpd_hist_thrsh;
+char *var_smtpd_exp_filter;
/*
* Silly little macros.
VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key, 0, 0,
0,
};
+ static CONFIG_RAW_TABLE raw_table[] = {
+ VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter, 1, 0,
+ 0,
+ };
/*
* Pass control to the single-threaded service skeleton.
single_server_main(argc, argv, smtpd_service,
MAIL_SERVER_INT_TABLE, int_table,
MAIL_SERVER_STR_TABLE, str_table,
+ MAIL_SERVER_RAW_TABLE, raw_table,
MAIL_SERVER_BOOL_TABLE, bool_table,
MAIL_SERVER_TIME_TABLE, time_table,
MAIL_SERVER_PRE_INIT, pre_jail_init,
/* .IP "check_recipient_access maptype:mapname"
/* Look up the resolved recipient address in the named access table,
/* any parent domains of the recipient domain, and the localpart@.
-/* .IP reject_rbl rbl.domain
+/* .IP reject_rbl rbl.domain.tld
/* Look up the reversed client network address in the specified
/* real-time blackhole DNS zone. The \fIrbl_reply_maps\fR configuration
/* parameter is used to generate the template for the reject message.
/* default template is used. The \fImaps_rbl_reject_code\fR
/* configuration parameter specifies the reject status code used in
/* the default template (default: 554).
+/* .IP reject_rhsbl rbl.domain.tld
+/* Look up the sender domain name in the specified real-time
+/* blackhole DNS zone. The \fIrbl_reply_maps\fR configuration
+/* parameter is used to generate the template for the reject message.
+/* If it is not specified, or the rbl domain cannot be found, then a
+/* default template is used. The \fImaps_rbl_reject_code\fR
+/* configuration parameter specifies the reject status code used in
+/* the default template (default: 554).
/* .IP reject_maps_rbl
/* Look up the reversed client network address in the real-time blackhole
/* DNS zones below the domains listed in the "maps_rbl_domains"
static HTABLE *smtpd_rest_classes;
+ /*
+ * Pre-parsed expansion filter.
+ */
+static VSTRING *expand_filter;
+
/*
* The routine that recursively applies restrictions.
*/
char *txt; /* TXT record or null */
} SMTPD_RBL_STATE;
+static void *rbl_pagein(const char *, void *);
+static void rbl_pageout(void *, void *);
+
/*
* Context for RBL $name expansion.
*/
myfree((void *) reply);
}
-/* rbl_pagein - page in an RBL lookup result */
-
-static void *rbl_pagein(const char *query, void *unused_context)
-{
- DNS_RR *txt_list;
- VSTRING *why;
- int dns_status;
- SMTPD_RBL_STATE *rbl;
-
- /*
- * Do the query.
- */
- why = vstring_alloc(10);
- dns_status = dns_lookup(query, T_A, 0, (DNS_RR **) 0,
- (VSTRING *) 0, why);
- if (dns_status != DNS_OK && dns_status != DNS_NOTFOUND)
- msg_warn("%s: RBL lookup error: %s", query, STR(why));
- vstring_free(why);
- if (dns_status != DNS_OK)
- return (0);
-
- /*
- * Save the result.
- */
- rbl = (SMTPD_RBL_STATE *) mymalloc(sizeof(*rbl));
- if (dns_lookup(query, T_TXT, 0, &txt_list,
- (VSTRING *) 0, (VSTRING *) 0) == DNS_OK) {
- rbl->txt = mystrdup(txt_list->data);
- dns_rr_free(txt_list);
- } else
- rbl->txt = 0;
- return ((void *) rbl);
-}
-
-/* rbl_pageout - page out an RBL lookup result */
-
-static void rbl_pageout(void *data, void *unused_context)
-{
- SMTPD_RBL_STATE *rbl = (SMTPD_RBL_STATE *) data;
-
- if (rbl != 0) {
- if (rbl->txt)
- myfree(rbl->txt);
- myfree((char *) rbl);
- }
-}
-
/* smtpd_check_parse - pre-parse restrictions */
static ARGV *smtpd_check_parse(const char *checks)
error_text = vstring_alloc(10);
/*
- * Initialize the resolved address cache.
+ * Initialize the resolved address cache. Note: the cache persists across
+ * SMTP sessions so we cannot make it dependent on session state.
*/
- smtpd_resolve_cache = ctable_create(100, resolve_pagein, resolve_pageout,
- (void *) 0);
+ smtpd_resolve_cache = ctable_create(100, resolve_pagein,
+ resolve_pageout, (void *) 0);
/*
- * Initialize the RBL lookup cache.
+ * Initialize the RBL lookup cache. Note: the cache persists across SMTP
+ * sessions so we cannot make it dependent on session state.
*/
smtpd_rbl_cache = ctable_create(100, rbl_pagein, rbl_pageout, (void *) 0);
if (!has_required(rcpt_restrctions, rcpt_required))
fail_required(VAR_RCPT_CHECKS, rcpt_required);
#endif
+
+ /*
+ * Expand the expansion filter :-)
+ */
+ expand_filter = vstring_alloc(10);
+ unescape(expand_filter, var_smtpd_exp_filter);
}
/* log_whatsup - log as much context as we have */
CHECK_MAIL_ACCESS_RETURN(SMTPD_CHECK_DUNNO);
}
-/* edit_addr - return address or substring thereof */
+/* smtpd_expand_unknown - report unknown macro name */
-static const char *edit_addr(VSTRING *buf, const char *addr, const char *name)
+static void smtpd_expand_unknown(const char *name)
+{
+ msg_warn("unknown macro name \"%s\" in expansion request", name);
+}
+
+/* smtpd_expand_addr - return address or substring thereof */
+
+static const char *smtpd_expand_addr(VSTRING *buf, const char *addr,
+ const char *name, int prefix_len)
{
const char *p;
+ const char *suffix;
/*
- * Return "undefined" when the address is unavailable.
+ * Return NULL only for unknown names in expansion requests.
*/
if (addr == 0)
- return (0);
+ return ("");
+
+ suffix = name + prefix_len;
/*
* "sender" or "recipient".
*/
- if (*name == 0) {
+ if (*suffix == 0) {
if (*addr)
return (addr);
else
*/
#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
- else if (STREQ(name, "_name")) {
+ else if (STREQ(suffix, "_name")) {
if (*addr) {
if ((p = strrchr(addr, '@')) != 0) {
vstring_strncpy(buf, addr, p - addr);
/*
* "sender_domain" or "recipient_domain".
*/
- else if (STREQ(name, "_domain")) {
+ else if (STREQ(suffix, "_domain")) {
if (*addr) {
if ((p = strrchr(addr, '@')) != 0) {
return (p + 1);
} else {
- return (0);
+ return ("");
}
} else
- return (0);
+ return ("");
}
/*
- * Unknown.
+ * Unknown. Return NULL to indicate an "unknown name" error.
*/
- else
+ else {
+ smtpd_expand_unknown(name);
return (0);
+ }
}
/* smtpd_expand_lookup - generic SMTP attribute $name expansion */
/*
* Don't query main.cf parameters, as the result of expansion could
* reveal system-internal information in server replies.
+ *
+ * Return NULL only for non-existent names.
*/
if (STREQ(name, "client")) {
return (state->namaddr);
} else if (STREQ(name, "client_name")) {
return (state->name);
} else if (STREQ(name, "helo_name")) {
- return (state->helo_name ? state->helo_name : 0);
+ return (state->helo_name ? state->helo_name : "");
} else if (STREQN(name, "sender", CONST_LEN("sender"))) {
- return (edit_addr(state->expand_buf, state->sender,
- name + CONST_LEN("sender")));
+ return (smtpd_expand_addr(state->expand_buf, state->sender,
+ name, CONST_LEN("sender")));
} else if (STREQN(name, "recipient", CONST_LEN("recipient"))) {
- return (edit_addr(state->expand_buf, state->recipient,
- name + CONST_LEN("recipient")));
+ return (smtpd_expand_addr(state->expand_buf, state->recipient,
+ name, CONST_LEN("recipient")));
} else {
+ smtpd_expand_unknown(name);
return (0);
}
}
+/* rbl_pagein - page in an RBL lookup result */
+
+static void *rbl_pagein(const char *query, void *unused_context)
+{
+ DNS_RR *txt_list;
+ VSTRING *why;
+ int dns_status;
+ SMTPD_RBL_STATE *rbl;
+
+ /*
+ * Do the query. If the DNS lookup produces no definitive reply, give the
+ * requestor the benefit of the doubt. We can't block all email simply
+ * because an RBL server is unavailable.
+ */
+ why = vstring_alloc(10);
+ dns_status = dns_lookup(query, T_A, 0, (DNS_RR **) 0,
+ (VSTRING *) 0, why);
+ if (dns_status != DNS_OK && dns_status != DNS_NOTFOUND)
+ msg_warn("%s: RBL lookup error: %s", query, STR(why));
+ vstring_free(why);
+ if (dns_status != DNS_OK)
+ return (0);
+
+ /*
+ * Save the result. Yes, we cache negative results as well as positive
+ * results.
+ */
+ rbl = (SMTPD_RBL_STATE *) mymalloc(sizeof(*rbl));
+ if (dns_lookup(query, T_TXT, 0, &txt_list,
+ (VSTRING *) 0, (VSTRING *) 0) == DNS_OK) {
+ rbl->txt = mystrndup(txt_list->data, 512);
+ dns_rr_free(txt_list);
+ } else
+ rbl->txt = mystrdup("");
+ return ((void *) rbl);
+}
+
+/* rbl_pageout - page out an RBL lookup result */
+
+static void rbl_pageout(void *data, void *unused_context)
+{
+ SMTPD_RBL_STATE *rbl = (SMTPD_RBL_STATE *) data;
+
+ if (rbl != 0) {
+ if (rbl->txt)
+ myfree(rbl->txt);
+ myfree((char *) rbl);
+ }
+}
+
/* rbl_expand_lookup - RBL specific $name expansion */
static const char *rbl_expand_lookup(const char *name, int mode,
if (msg_verbose > 1)
msg_info("rbl_expand_lookup: ${%s}", name);
+ /*
+ * Be sure to return NULL only for non-existent names.
+ */
if (STREQ(name, "rbl_code")) {
vstring_sprintf(state->expand_buf, "%d", var_maps_rbl_code);
return (STR(state->expand_buf));
}
if (template) {
why = vstring_alloc(10);
- rbl_exp.state = state; /* XXX */
+ rbl_exp.state = state;
rbl_exp.rbl_state = rbl;
rbl_exp.domain = rbl_domain;
-#define NO_SMTPD_EXP_FILTER ((char *) 0) /* XXX */
if (mac_expand(why, template, MAC_EXP_FLAG_NONE,
- NO_SMTPD_EXP_FILTER, rbl_expand_lookup,
- (char *) &rbl_exp) & MAC_PARSE_ERROR) {
- msg_warn("%s: bad rbl template: %s", myname, template);
+ STR(expand_filter), rbl_expand_lookup,
+ (char *) &rbl_exp) != 0) {
+ msg_warn("%s: bad rbl reply template: %s", myname, template);
template = 0; /* pretend not found */
}
}
if (template) {
result = smtpd_check_reject(state, MAIL_ERROR_POLICY, STR(why));
} else {
+ /* Hard-coded to avoid trouble with future ?: ternary operator. */
result = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d Service unavailable; [%s] blocked using %s%s%s",
var_maps_rbl_code, state->addr,
- rbl_domain, rbl->txt ? ", reason: " : "", rbl->txt);
+ rbl_domain, rbl->txt[0] ?
+ ", reason: " : "", rbl->txt);
}
/*
ARGV *octets;
VSTRING *query;
int i;
- int result;
SMTPD_RBL_STATE *rbl;
if (msg_verbose)
return SMTPD_CHECK_DUNNO;
#endif
- /*
- * Initialize.
- */
- query = vstring_alloc(100);
-
/*
* Reverse the client IPV4 address, tack on the RBL domain name and query
- * the DNS for an A record. If the record exists, the client address is
- * blacklisted. If the DNS lookup produces no definitive reply, give the
- * client the benefit of the doubt. We can't block all email simply
- * because an RBL server is unavailable.
+ * the DNS for an A record.
*/
+ query = vstring_alloc(100);
octets = argv_split(state->addr, ".");
for (i = octets->argc - 1; i >= 0; i--) {
vstring_strcat(query, octets->argv[i]);
argv_free(octets);
vstring_strcat(query, rbl_domain);
rbl = (SMTPD_RBL_STATE *) ctable_locate(smtpd_rbl_cache, STR(query));
+ vstring_free(query);
+ /*
+ * If the record exists, the client address is blacklisted.
+ */
if (rbl == 0) {
- result = SMTPD_CHECK_DUNNO;
+ return (SMTPD_CHECK_DUNNO);
} else {
- result = rbl_reject_reply(state, rbl, rbl_domain);
+ return (rbl_reject_reply(state, rbl, rbl_domain));
}
+}
+
+/* reject_rhsbl - reject if sender domain in real-time blackhole list */
+
+static int reject_rhsbl(SMTPD_STATE *state, const char *rbl_domain)
+{
+ char *myname = "reject_rhsbl";
+ VSTRING *query;
+ SMTPD_RBL_STATE *rbl;
+ const char *domain;
+
+ if (msg_verbose)
+ msg_info("%s: %s", myname, state->sender);
/*
- * Clean up.
+ * Extract the sender domain, tack on the RBL domain name and query the
+ * DNS for an A record.
*/
+ if ((domain = strrchr(state->sender, '@')) == 0)
+ return (SMTPD_CHECK_DUNNO);
+ domain += 1;
+ if (domain[0] == 0 || domain[0] == '#' || domain[0] == '[')
+ return (SMTPD_CHECK_DUNNO);
+
+ query = vstring_alloc(100);
+ vstring_sprintf(query, "%s.%s", domain, rbl_domain);
+ rbl = (SMTPD_RBL_STATE *) ctable_locate(smtpd_rbl_cache, STR(query));
vstring_free(query);
- return (result);
+ /*
+ * If the record exists, the sender domain is blacklisted.
+ */
+ if (rbl == 0) {
+ return (SMTPD_CHECK_DUNNO);
+ } else {
+ return (rbl_reject_reply(state, rbl, rbl_domain));
+ }
}
/* reject_maps_rbl - reject if client address in real-time blackhole list */
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
status = reject_maps_rbl(state);
} else if (strcasecmp(name, REJECT_RBL) == 0) {
- if (*(cpp += 1) == 0)
+ if (*(cpp[1]) == 0)
msg_warn("restriction %s requires domain name argument",
REJECT_RBL);
else
- status = reject_rbl(state, *cpp);
+ status = reject_rbl(state, *(cpp += 1));
}
/*
} else if (strcasecmp(name, REJECT_SENDER_LOGIN_MISMATCH) == 0) {
if (state->sender && *state->sender)
status = reject_sender_login_mismatch(state, state->sender);
+ } else if (strcasecmp(name, REJECT_RHSBL) == 0) {
+ if (cpp[1] == 0)
+ msg_warn("restriction %s requires domain name argument",
+ REJECT_RHSBL);
+ else if (state->sender && *state->sender)
+ status = reject_rhsbl(state, *(cpp += 1));
}
/*
char *var_smtpd_snd_auth_maps;
char *var_double_bounce_sender;
char *var_rbl_reply_maps;
+char *var_smtpd_exp_filter;
typedef struct {
char *name;
VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key,
VAR_DOUBLE_BOUNCE, DEF_DOUBLE_BOUNCE, &var_double_bounce_sender,
VAR_RBL_REPLY_MAPS, DEF_RBL_REPLY_MAPS, &var_rbl_reply_maps,
+ VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter,
0,
};
blackholes.mail-abuse.org $rbl_code client=$client
client_address=$client_address
client_name=$client_name helo_name=$helo_name
- sender=$sender sender_name=$sender_name
- recipient=$recipient recipient_name=$recipient_name
+ sender=$sender sender_name=$sender_name sender_domain=$sender_domain
+ recipient=$recipient recipient_name=$recipient_name recipient_domain=$recipient_domain
+ rbl_code=$rbl_code rbl_domain=$rbl_domain rbl_txt=$rbl_txt
+
+dsn.rfc-ignorant.org $rbl_code client=$client
+ client_address=$client_address
+ client_name=$client_name helo_name=$helo_name
+ sender=$sender sender_name=$sender_name sender_domain=$sender_domain
+ recipient=$recipient recipient_name=$recipient_name recipient_domain=$recipient_domain
rbl_code=$rbl_code rbl_domain=$rbl_domain rbl_txt=$rbl_txt
relay_domains porcupine.org
maps_rbl_domains blackholes.mail-abuse.org
rbl_reply_maps hash:smtpd_check_access
+helo foobar
#
# RBL
#
-client_restrictions reject_maps_rbl
+mail sname@sdomain
+recipient_restrictions reject_maps_rbl
client spike.porcupine.org 168.100.189.2
+rcpt rname@rdomain
client foo 127.0.0.2
+rcpt rname@rdomain
+#
+recipient_restrictions reject_rbl,blackholes.mail-abuse.org
+client spike.porcupine.org 168.100.189.2
+rcpt rname@rdomain
+client foo 127.0.0.2
+rcpt rname@rdomain
+#
+# RHSBL
+#
+recipient_restrictions reject_rhsbl,dsn.rfc-ignorant.org
+client spike.porcupine.org 168.100.189.2
+mail sname@example.tld
+rcpt rname@rdomain
+mail sname@sdomain
+rcpt rname@rdomain
OK
>>> rbl_reply_maps hash:smtpd_check_access
OK
+>>> helo foobar
+OK
>>> #
>>> # RBL
>>> #
->>> client_restrictions reject_maps_rbl
+>>> mail sname@sdomain
+OK
+>>> recipient_restrictions reject_maps_rbl
+OK
+>>> client spike.porcupine.org 168.100.189.2
+OK
+>>> rcpt rname@rdomain
+OK
+>>> client foo 127.0.0.2
+OK
+>>> rcpt rname@rdomain
+./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 client=foo[127.0.0.2] client_address=127.0.0.2 client_name=foo helo_name=foobar sender=sname@sdomain sender_name=sname sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=blackholes.mail-abuse.org rbl_txt=Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<sname@sdomain> to=<rname@rdomain>
+554 client=foo[127.0.0.2] client_address=127.0.0.2 client_name=foo helo_name=foobar sender=sname@sdomain sender_name=sname sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=blackholes.mail-abuse.org rbl_txt=Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
+>>> #
+>>> recipient_restrictions reject_rbl,blackholes.mail-abuse.org
OK
>>> client spike.porcupine.org 168.100.189.2
OK
+>>> rcpt rname@rdomain
+OK
>>> client foo 127.0.0.2
-./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 client=foo[127.0.0.2] client_address=127.0.0.2 client_name=foo helo_name= sender= sender_name= recipient= recipient_name= rbl_code=554 rbl_domain=blackholes.mail-abuse.org rbl_txt=Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
-554 client=foo[127.0.0.2] client_address=127.0.0.2 client_name=foo helo_name= sender= sender_name= recipient= recipient_name= rbl_code=554 rbl_domain=blackholes.mail-abuse.org rbl_txt=Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
+OK
+>>> rcpt rname@rdomain
+./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 client=foo[127.0.0.2] client_address=127.0.0.2 client_name=foo helo_name=foobar sender=sname@sdomain sender_name=sname sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=blackholes.mail-abuse.org rbl_txt=Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<sname@sdomain> to=<rname@rdomain>
+554 client=foo[127.0.0.2] client_address=127.0.0.2 client_name=foo helo_name=foobar sender=sname@sdomain sender_name=sname sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=blackholes.mail-abuse.org rbl_txt=Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
+>>> #
+>>> # RHSBL
+>>> #
+>>> recipient_restrictions reject_rhsbl,dsn.rfc-ignorant.org
+OK
+>>> client spike.porcupine.org 168.100.189.2
+OK
+>>> mail sname@example.tld
+OK
+>>> rcpt rname@rdomain
+./smtpd_check: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar sender=sname@example.tld sender_name=sname sender_domain=example.tld recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN); from=<sname@example.tld> to=<rname@rdomain>
+554 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar sender=sname@example.tld sender_name=sname sender_domain=example.tld recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN)
+>>> mail sname@sdomain
+OK
+>>> rcpt rname@rdomain
+OK
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
- attr_scan64_test attr_scan0_test pcre_test
+ attr_scan64_test attr_scan0_test dict_pcre_test
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
/*
/* The following expansions are implemented:
/* .IP "$name, ${name}, $(name)"
-/* Unconditional expansion. If the named attribute is defined, the
+/* Unconditional expansion. If the named attribute is non-empty, the
/* expansion is the value of the named attribute, optionally subjected
/* to further $name expansions. Otherwise, the expansion is empty.
/* .IP "${name?text}, $(name?text)"
-/* Conditional expansion. If the named attribute is defined, the
+/* Conditional expansion. If the named attribute is non-empty, the
/* expansion is the given text, subjected to another iteration of
/* $name expansion. Otherwise, the expansion is empty.
/* .IP "${name:text}, $(name:text)"
-/* Conditional expansion. If the named attribute is undefined, the
+/* Conditional expansion. If the named attribute is empty or undefined,
/* the expansion is the given text, subjected to another iteration
/* of $name expansion. Otherwise, the expansion is empty.
/* .PP
/* A syntax error was found in \fBpattern\fR, or some macro had
/* an unreasonable nesting depth.
/* .IP MAC_PARSE_UNDEF
-/* A macro was expanded but not defined.
+/* A macro was expanded but its value not defined.
/* SEE ALSO
/* mac_parse(3) locate macro references in string.
/* LICENSE
*/
switch (ch) {
case '?':
- if (text != 0)
+ if (text != 0 && *text != 0)
mac_parse(cp, mac_expand_callback, (char *) mc);
break;
case ':':
- if (text == 0)
+ if (text == 0 || *text == 0)
mac_parse(cp, mac_expand_callback, (char *) mc);
break;
default: