diff src/dnsbl.cpp @ 350:f4ca91f49cb6

send the original mail from address to the verify server, not the srs/pvrs unwrapped version; recognize our own dkim signatures
author Carl Byington <carl@five-ten-sg.com>
date Mon, 26 Dec 2016 09:31:57 -0800
parents 8fe6d5120771
children f5a6740cabee
line wrap: on
line diff
--- a/src/dnsbl.cpp	Fri Dec 23 09:47:40 2016 -0800
+++ b/src/dnsbl.cpp	Mon Dec 26 09:31:57 2016 -0800
@@ -98,7 +98,8 @@
 const int maxlen = 1000;    // used for snprintf buffers
 regex_t srs_pattern;        // used to detect srs coding in mail addresses
 regex_t prvs_pattern;       // used to detect prvs coding in mail addresses
-regex_t dkim_pattern;       // used to detect dkim signatures in authentication header generated by the upstream opendkim milter
+regex_t dkim_r_pattern;     // used to detect dkim signatures authenticated by the upstream opendkim milter
+regex_t dkim_s_pattern;     // used to detect dkim signatures generated by the upstream opendkim milter
 regex_t from_pattern;       // used to extract the senders mail domain from the body from: header
 
 pthread_mutex_t  config_mutex;
@@ -522,6 +523,7 @@
     ip                      = 0;
     helo                    = NULL;
     mailaddr                = NULL;
+    origaddr                = NULL;
     fromaddr                = NULL;
     header_count            = 0;
     dkim_ok                 = true;
@@ -572,6 +574,7 @@
         delayer.pop_front();
     }
     if (mailaddr)        free((void*)mailaddr);
+    if (origaddr)        free((void*)origaddr);
     if (fromaddr)        free((void*)fromaddr);
     if (queueid)         free((void*)queueid);
     if (authenticated)   free((void*)authenticated);
@@ -589,6 +592,7 @@
         ctx                     = NULL;
         eom                     = false;
         mailaddr                = NULL;
+        origaddr                = NULL;
         fromaddr                = NULL;
         header_count            = 0;
         dkim_ok                 = true;
@@ -716,7 +720,7 @@
     return rs;
 }
 
-void mlfiPriv::need_content_filter(const char *rcpt, CONTEXT &con) {
+void mlfiPriv::need_content_filter(CONTEXT &con) {
     if (!memory) {
         // first recipient that needs content filtering sets
         // some of the content filtering parameters
@@ -1186,6 +1190,7 @@
 {
     mlfiPriv &priv     = *MLFIPRIV;
     CONFIG &dc         = *priv.pc;
+    priv.origaddr      = to_lower_string(from[0], false);
     priv.mailaddr      = to_lower_string(from[0]);
     priv.queueid       = strdup(smfi_getsymval(ctx, (char*)"i"));
     priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}");
@@ -1302,8 +1307,8 @@
     }
     else if ((fromvalue == token_white) && !self) {
         // whitelisting based on envelope from value, but ignore it if
-        // we have a dkim requirement for that domain
-        const char *domain = strchr(priv.mailaddr, '@');
+        // we have a dkim requirement for the original domain
+        const char *domain = strchr(priv.origaddr, '@');
         if (domain) {
             DKIMP dk = con.find_dkim_from(domain+1);
             if (dk && (dk->action == token_require_signed)) {
@@ -1367,9 +1372,9 @@
     }
 
     if (ver) {
-        // try to verify this from/to pair of addresses even if it might be explicitly whitelisted
+        // try to verify the original from/to pair of addresses even if it might be explicitly whitelisted
         const char *loto = to_lower_string(rcptaddr, false);
-        bool rc = ver->ok(priv.queueid, priv.mailaddr, loto);
+        bool rc = ver->ok(priv.queueid, priv.origaddr, loto);
         free((void*)loto);
         if (!rc) {
             smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user");
@@ -1427,7 +1432,7 @@
                 smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts");
                 return SMFIS_TEMPFAIL;
             }
-            priv.need_content_filter(rcptaddr, con);
+            priv.need_content_filter(con);
             char bu[maxlen];
             bool uri = false;
             // content filtering implies also checking helo name on uribl (if enabled)
@@ -1482,13 +1487,12 @@
     if (priv.dkim_ok) {
         if ((priv.header_count == 1) && (strcasecmp(headerf, "DKIM-Filter") != 0)) priv.dkim_ok = false;
         if (priv.header_count == 2) {
-            if (strcasecmp(headerf, "Authentication-Results") != 0) priv.dkim_ok = false;
-            if (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) != 0) priv.dkim_ok = false;
-            if (priv.dkim_ok) {
+            if ((strcasecmp(headerf, "Authentication-Results") == 0) &&
+                (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) == 0)) {
                 const int nmatch = 2;
                 regmatch_t match[nmatch];
                 while (true) {
-                    if (0 == regexec(&dkim_pattern, value, nmatch, match, 0)) {
+                    if (0 == regexec(&dkim_r_pattern, value, nmatch, match, 0)) {
                         int s1 = match[1].rm_so;    // domain
                         int e1 = match[1].rm_eo;
                         if (s1 != -1) {
@@ -1503,6 +1507,19 @@
                     else break;
                 }
             }
+            else if (strcasecmp(headerf, "DKIM-Signature") == 0) {
+                const int nmatch = 2;
+                regmatch_t match[nmatch];
+                if (0 == regexec(&dkim_s_pattern, value, nmatch, match, 0)) {
+                    int s1 = match[1].rm_so;    // domain
+                    int e1 = match[1].rm_eo;
+                    if (s1 != -1) {
+                        value[e1] = '\0';
+                        priv.dkim_signers.insert(strdup(value+s1));
+                    }
+                }
+            }
+            else priv.dkim_ok = false;
         }
     }
 
@@ -1510,8 +1527,7 @@
     if ((!priv.fromaddr) && (strcasecmp(headerf, "from") == 0)) {
         const int nmatch = 2;
         regmatch_t match[nmatch];
-        int err = regexec(&from_pattern, value, nmatch, match, 0);
-        if (err == 0) {
+        if (0 == regexec(&from_pattern, value, nmatch, match, 0)) {
             int s1 = match[1].rm_so;    // domain
             int e1 = match[1].rm_eo;
             if (s1 != -1) {
@@ -1887,8 +1903,14 @@
         exit(3);
     }
 
-    // setup dkim signature detection
-    if (regcomp(&dkim_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) {
+    // setup dkim results signature detection
+    if (regcomp(&dkim_r_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) {
+        printf("cannot compile regex pattern to find dkim results gnatures\n");
+        exit(3);
+    }
+
+    // setup dkim results signature detection
+    if (regcomp(&dkim_s_pattern, " d=([^;]+);", REG_ICASE | REG_EXTENDED)) {
         printf("cannot compile regex pattern to find dkim signatures\n");
         exit(3);
     }