]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-1.1.11-20020922
authorWietse Venema <wietse@porcupine.org>
Sun, 22 Sep 2002 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:28:17 +0000 (06:28 +0000)
14 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/smtpd.8.html
postfix/man/man8/smtpd.8
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_check_access
postfix/src/smtpd/smtpd_exp.in
postfix/src/smtpd/smtpd_exp.ref
postfix/src/util/Makefile.in
postfix/src/util/mac_expand.c

index 444f12d66ce20a19a9cc9976c94ebd3633e24bd4..d1aa037c40aa72beffc69017f1e0d9bcce9c5132 100644 (file)
@@ -6980,12 +6980,31 @@ Apologies for any names omitted.
 
 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:
 
index b8542435dd928c8a0b5a63f27fa570bf7fb09fb4..3e6d36232d8da02d89524b14d4d084a8e47a80a2 100644 (file)
@@ -12,6 +12,34 @@ 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.
 
+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
 ==========================================================
 
index 14e79e9d86f4f3769a0e5bffd2f72bb434cc8155..d5b4000f6feeb0667e1d4eaf8008282e8339385c 100644 (file)
@@ -168,6 +168,10 @@ SMTPD(8)                                                 SMTPD(8)
               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.
@@ -276,36 +280,43 @@ SMTPD(8)                                                 SMTPD(8)
               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.
index 3fbdab4262605dc880d4a1c5288aa67eaa85f329..1076efce66eab7efac7b9f35e607029768ca072e 100644 (file)
@@ -149,6 +149,9 @@ postmaster.
 .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.
@@ -226,9 +229,10 @@ then be used instead of the restriction lists that they represent.
 .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.
@@ -249,6 +253,10 @@ restriction.
 .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
index 6b625a595200898cd31c64fdcd7859910db35187..13fc887447f9f1e18f4c57df4cbe1f35d14ac753 100644 (file)
@@ -1203,6 +1203,7 @@ extern int var_access_map_code;
 #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;
@@ -1226,6 +1227,12 @@ extern int var_smtpd_delay_reject;
 #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.
   */
index 772bd92112d71537d9cb2362eb8c00063899cb8b..e7f91836b41efff2e458c72924c8f261770793a1 100644 (file)
@@ -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      "20020921"
+#define MAIL_RELEASE_DATE      "20020922"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "1.1.11-" MAIL_RELEASE_DATE
index ed185bac94657a12546988d095fec6bded4b50db..0ea8d79ab676c645e0c1067227c4bb4f10e440e8 100644 (file)
@@ -36,7 +36,7 @@ SMTPD_CHECK_OBJ = smtpd_state.o smtpd_peer.o
 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)
index 2a4d16be7bcf95e7dc44f7f4d3653f034b1fe1e5..ac9c1c441191c6d116b0be8af52e20a58dfb02b2 100644 (file)
 /* .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
@@ -393,6 +401,7 @@ char   *var_smtpd_snd_auth_maps;
 char   *var_smtpd_noop_cmds;
 char   *var_smtpd_null_key;
 int     var_smtpd_hist_thrsh;
+char   *var_smtpd_exp_filter;
 
  /*
   * Silly little macros.
@@ -1637,6 +1646,10 @@ int     main(int argc, char **argv)
        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.
@@ -1644,6 +1657,7 @@ int     main(int argc, char **argv)
     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,
index 965820cfac3df5eadcd4795cb4cdeab68788d79a..bfe75394fee75b50d2f73a0219c0156bd217b7a7 100644 (file)
@@ -89,7 +89,7 @@
 /* .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"
@@ -382,6 +390,11 @@ static ARGV *data_restrctions;
 
 static HTABLE *smtpd_rest_classes;
 
+ /*
+  * Pre-parsed expansion filter.
+  */
+static VSTRING *expand_filter;
+
  /*
   * The routine that recursively applies restrictions.
   */
@@ -435,6 +448,9 @@ typedef struct {
     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.
   */
@@ -486,53 +502,6 @@ static void resolve_pageout(void *data, void *unused_context)
     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)
@@ -678,13 +647,15 @@ void    smtpd_check_init(void)
     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);
 
@@ -731,6 +702,12 @@ void    smtpd_check_init(void)
     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 */
@@ -2123,22 +2100,33 @@ static int check_mail_access(SMTPD_STATE *state, const char *table,
     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
@@ -2150,7 +2138,7 @@ static const char *edit_addr(VSTRING *buf, const char *addr, const char *name)
      */
 #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);
@@ -2165,22 +2153,24 @@ static const char *edit_addr(VSTRING *buf, const char *addr, const char *name)
     /*
      * "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 */
@@ -2202,6 +2192,8 @@ static const char *smtpd_expand_lookup(const char *name, int unused_mode,
     /*
      * 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);
@@ -2210,18 +2202,69 @@ static const char *smtpd_expand_lookup(const char *name, int unused_mode,
     } 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,
@@ -2237,6 +2280,9 @@ 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));
@@ -2268,24 +2314,25 @@ static int rbl_reject_reply(SMTPD_STATE *state, SMTPD_RBL_STATE *rbl,
     }
     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);
     }
 
     /*
@@ -2305,7 +2352,6 @@ static int reject_rbl(SMTPD_STATE *state, const char *rbl_domain)
     ARGV   *octets;
     VSTRING *query;
     int     i;
-    int     result;
     SMTPD_RBL_STATE *rbl;
 
     if (msg_verbose)
@@ -2319,18 +2365,11 @@ static int reject_rbl(SMTPD_STATE *state, const char *rbl_domain)
        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]);
@@ -2339,19 +2378,53 @@ static int reject_rbl(SMTPD_STATE *state, const char *rbl_domain)
     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 */
@@ -2529,11 +2602,11 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
        } 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));
        }
 
        /*
@@ -2609,6 +2682,12 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
        } 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));
        }
 
        /*
@@ -3161,6 +3240,7 @@ char   *var_smtpd_null_key;
 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;
@@ -3188,6 +3268,7 @@ static STRING_TABLE string_table[] = {
     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,
 };
 
index 3f031d243e927d3f3b0baa147774fe0524339877..2681a6c09aff75f0b5227e2c52b96d4b53a9a17b 100644 (file)
@@ -34,6 +34,13 @@ ok.domain            OK
 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
index 072f5687319698cbe6205f7f4750be8a5dc84aa9..6e7585797269b3bbcd1897e0a5db959faf12edd0 100644 (file)
@@ -8,9 +8,28 @@ mynetworks 127.0.0.0/8,168.100.189.0/28
 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
index 5f8013ba60c68512a0f5296f7df6841a4c383674..03c58826b615f15fda02f880c62c8cb1c48b5b33 100644 (file)
@@ -13,13 +13,49 @@ OK
 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
index 6f5be131e8127d0cc42946ebfbbe3c75337c42b3..44c89569188ace53e3a7ebb6ee36b815425c984f 100644 (file)
@@ -332,7 +332,7 @@ stream_test: stream_test.c $(LIB)
 
 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
index 7ce3684f172209df14f09bea9bd73cba632fb222..02f64980fb7790bae8eddb7429ba30ccc5bd7246 100644 (file)
 /*
 /*     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
@@ -71,7 +71,7 @@
 /*     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
@@ -170,11 +170,11 @@ static int mac_expand_callback(int type, VSTRING *buf, char *ptr)
         */
        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: