changeset 360:17f21fcd44a8

allow quoted comma separated multiple signers in the dkim_from config entries
author Carl Byington <carl@five-ten-sg.com>
date Mon, 16 Jan 2017 11:13:40 -0800
parents 3dfa93d65701
children 07b88307d90a
files src/context.cpp src/context.h xml/dnsbl.in
diffstat 3 files changed, 62 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/src/context.cpp	Mon Jan 16 08:28:37 2017 -0800
+++ b/src/context.cpp	Mon Jan 16 11:13:40 2017 -0800
@@ -1110,9 +1110,48 @@
 }
 
 
+bool CONTEXT::in_signing_set(const char *s, const char *signers) {
+    size_t n = strlen(s);
+    const char *p = signers;
+    do {
+        if ((strncasecmp(p, s, n) == 0) && ((p[n] == '\0') || (p[n] == ','))) return true;
+        p = strchr(p, ',');
+        if (!p) return false;
+    } while (true);
+}
+
+
 const char *CONTEXT::acceptable_content(recorder &memory, int score, int bulk, const char *queueid, string_set &signers, const char *from, string& msg) {
     DKIMP dk = find_dkim_from(from);
-    bool requirement = false;
+    if (dk) {
+        const char *st = dk->action;
+        for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) {
+            // signed by a white listed signer
+            if ((st == token_signed_white)   && in_signing_set(*s,dk->signer)) {
+                log(queueid, "whitelisted dkim signer %s", *s);
+                return token_white;
+            }
+            // signed by the required signer
+            if ((st == token_require_signed) && in_signing_set(*s,dk->signer)) {
+                log(queueid, "required dkim signer %s", *s);
+                return token_white;
+            }
+            // signed by a black listed signer
+            if ((st == token_signed_black)   && in_signing_set(*s,dk->signer)) {
+                char buf[maxlen];
+                snprintf(buf, sizeof(buf), "Mail rejected - dkim signed by %s", *s);
+                msg = string(buf);
+                return token_black;
+            }
+        }
+        if (st == token_require_signed) {
+            char buf[maxlen];
+            snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer);
+            msg = string(buf);
+            return token_black;
+        }
+    }
+
     for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) {
         const char *st = find_dkim_signer(*s);
         // signed by a white listed signer
@@ -1120,6 +1159,10 @@
             log(queueid, "whitelisted dkim signer %s", *s);
             return token_white;
         }
+    }
+
+    for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) {
+        const char *st = find_dkim_signer(*s);
         // signed by a black listed signer
         if (st == token_black) {
             char buf[maxlen];
@@ -1127,37 +1170,6 @@
             msg = string(buf);
             return token_black;
         }
-
-        if (dk) {
-            st = dk->action;
-            // signed by a white listed signer
-            if ((st == token_signed_white)   && (strcasecmp(*s,dk->signer) == 0)) {
-                log(queueid, "whitelisted dkim signer %s", *s);
-                return token_white;
-            }
-            // signed by the required signer
-            if ((st == token_require_signed) && (strcasecmp(*s,dk->signer) == 0)) {
-                log(queueid, "required dkim signer %s", *s);
-                requirement = true;
-            }
-            // signed by a black listed signer
-            if ((st == token_signed_black)   && (strcasecmp(*s,dk->signer) == 0)) {
-                char buf[maxlen];
-                snprintf(buf, sizeof(buf), "Mail rejected - dkim signed by %s", dk->signer);
-                msg = string(buf);
-                return token_black;
-            }
-        }
-    }
-
-    if (dk && (dk->action == token_require_signed)) {
-        if (requirement) return token_white;
-        else {
-            char buf[maxlen];
-            snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer);
-            msg = string(buf);
-            return token_black;
-        }
     }
 
     if (spamassassin_limit && (score > spamassassin_limit)) {
@@ -1239,7 +1251,7 @@
         for (dkimp_map::iterator i=dkim_from_names.begin(); i!=dkim_from_names.end(); i++) {
             const char *n = (*i).first;
             DKIM &d = *(*i).second;
-            printf("%s             %s %s %s; \n", indent, n, d.action, d.signer);
+            printf("%s             %s %s \"%s\"; \n", indent, n, d.action, d.signer);
         }
         printf("%s         }; \n", indent);
         if (content_suffix) {
@@ -1533,11 +1545,11 @@
         else {
             const char *signer = have;
             const char *action = tok.next();
-            if ((action == token_white) || (action == token_black)) {
+            if ((action == token_white) || (action == token_black) || (action == token_unknown)) {
                 me.add_dkim_signer(signer, action);
             }
             else {
-                tok.token_error("white/black", action);
+                tok.token_error("white/black/unknown", action);
             }
         }
     }
--- a/src/context.h	Mon Jan 16 08:28:37 2017 -0800
+++ b/src/context.h	Mon Jan 16 11:13:40 2017 -0800
@@ -313,6 +313,7 @@
     dnswlp_list&    get_dnswl_list();
 
     void        log(const char *queueid, const char *msg, const char *v);
+    bool        in_signing_set(const char *s, const char *signers);
     const char *acceptable_content(recorder &memory, int score, int bulk, const char *queueid, string_set &signers, const char *from, string& msg);
     bool        ignore_host(const char *host);
 
--- a/xml/dnsbl.in	Mon Jan 16 08:28:37 2017 -0800
+++ b/xml/dnsbl.in	Mon Jan 16 11:13:40 2017 -0800
@@ -744,8 +744,9 @@
 DCCBULK    = "dcc_bulk_threshold"   (INTEGER | "many" | "off")
 
 DKIMSIGNER = "dkim_signer" "{" {SIGNING_DOMAIN DEF [";"]}+ "}"
-DKIMFROM   = "dkim_from"   "{" {HEADER_FROM_DOMAIN DKIMVALUE SIGNING_DOMAIN [";"]}+ "}"
+DKIMFROM   = "dkim_from"   "{" {HEADER_FROM_DOMAIN DKIMVALUE SIGNERS [";"]}+ "}"
 DKIMVALUE  = "signed_white" | "signed_black" | "require_signed"
+SIGNERS    = quoted comma separated SIGNING_DOMAINs no whitespace
 
 ENV-TO     = "env_to"     "{" {(TO-ADDR | DCC-TO)}+ "}"
 TO-ADDR    = ADDRESS [";"]
@@ -771,10 +772,10 @@
 DEFAULT_IP_LIMIT    = INTEGER
 DAILY_MULTIPLE_IP   = INTEGER
 
-DEF        = ("white" | "black")
-DEFAULT    = (DEF | "unknown" | "inherit" | "")
+DEF        = ("white" | "black" | "unknown")
+DEFAULT    = (DEF | "inherit" | "")
 ADDRESS    = (USER@ | DOMAIN | USER@DOMAIN)
-VALUE      = ("white" | "black" | "unknown" | "inherit" | CHILD-CONTEXT-NAME)]]></literallayout>
+VALUE      = (DEF | "inherit" | CHILD-CONTEXT-NAME)]]></literallayout>
         </refsect1>
 
         <refsect1 id='sample.5'>
@@ -835,6 +836,15 @@
     require_rdns    yes;
 
     content on {
+        dkim_signer {
+            credit.paypal.com   require_signed  credit.paypal.com;
+            paypal.com          require_signed  paypal.com;
+            dhl.com             require_signed  dhl.com;
+            adp.com             require_signed  "adp.com,bmi.adp.com";
+        };
+        dkim_from {
+            accounts.google.com     white;
+        };
         filter    sbl-xbl.spamhaus.org        "Mail containing %s rejected - sbl; see http://www.spamhaus.org/query/bl?ip=%s";
         uribl     multi.surbl.org             "Mail containing %s rejected - surbl; see http://www.surbl.org/surbl-analysis?d=%s";
         #uribl    multi.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";