[exim-cvs] Add expansion for DMARC policy

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] Add expansion for DMARC policy
Gitweb: http://git.exim.org/exim.git/commitdiff/8c8b8274fc537766da72eab2f79a62d1603d6638
Commit:     8c8b8274fc537766da72eab2f79a62d1603d6638
Parent:     364e49ab87bf81774f12f8b0e21509eb51c88b71
Author:     Todd Lyons <tlyons@???>
AuthorDate: Sat Apr 12 10:42:52 2014 -0700
Committer:  Todd Lyons <tlyons@???>
CommitDate: Tue Apr 15 12:58:55 2014 -0700


    Add expansion for DMARC policy


    New variable is $dmarc_domain_policy
---
 doc/doc-txt/ChangeLog             |    4 ++++
 doc/doc-txt/experimental-spec.txt |   19 +++++++++++++++++--
 src/src/dmarc.c                   |   23 +++++++++++++++++++++++
 src/src/expand.c                  |    1 +
 src/src/globals.c                 |    1 +
 src/src/globals.h                 |    1 +
 6 files changed, 47 insertions(+), 2 deletions(-)


diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 17e8091..0d4652b 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -75,6 +75,10 @@ JH/12 Expand items in router/transport headers_add or headers_remove lists
       they may be empty; requires that headers_remove items with embedded
       colons must have them doubled (or the list-separator changed).


+TL/07 Add new dmarc expansion variable $dmarc_domain_policy to directly
+      view the policy declared in the DMARC record. Currently, $dmarc_status
+      is a combined value of both the record presence and the result of the
+      analysis.


Exim version 4.82
-----------------
diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt
index 2395267..d0503d9 100644
--- a/doc/doc-txt/experimental-spec.txt
+++ b/doc/doc-txt/experimental-spec.txt
@@ -775,7 +775,7 @@ fails.

Of course, you can also use any other lookup method that Exim
supports, including LDAP, Postgres, MySQL, etc, as long as the
-result is a list of colon-separated strings;
+result is a list of colon-separated strings.

Several expansion variables are set before the DATA ACL is
processed, and you can use them in this ACL. The following
@@ -783,7 +783,10 @@ expansion variables are available:

   o $dmarc_status
     This is a one word status indicating what the DMARC library
-    thinks of the email.
+    thinks of the email.  It is a combination of the results of
+    DMARC record lookup and the SPF/DKIM/DMARC processing results
+    (if a DMARC record was found).  The actual policy declared
+    in the DMARC record is in a separate expansion variable.


   o $dmarc_status_text
     This is a slightly longer, human readable status.
@@ -792,6 +795,11 @@ expansion variables are available:
     This is the domain which DMARC used to look up the DMARC
     policy record.


+  o $dmarc_domain_policy
+    This is the policy declared in the DMARC record.  Valid values
+    are "none", "reject" and "quarantine".  It is blank when there
+    is any error, including no DMARC record.
+
   o $dmarc_ar_header
     This is the entire Authentication-Results header which you can
     add using an add_header modifier.
@@ -827,6 +835,9 @@ b. Configure, somewhere before the DATA ACL, the control option to
   warn    !domains       = +screwed_up_dmarc_records
           control        = dmarc_enable_forensic


+  warn    condition      = (lookup if destined to mailing list)
+          set acl_m_mailing_list = 1
+
 (DATA ACL)
   warn    dmarc_status   = accept : none : off
           !authenticated = *
@@ -842,6 +853,10 @@ b. Configure, somewhere before the DATA ACL, the control option to
           set $acl_m_quarantine = 1
           # Do something in a transport with this flag variable


+  deny    condition      = ${if eq{$dmarc_domain_policy}{reject}}
+          condition      = ${if eq{$acl_m_mailing_list}{1}}
+          message        = Messages from $dmarc_used_domain break mailing lists
+
   deny    dmarc_status   = reject
           !authenticated = *
           message        = Message from $domain_used_domain failed sender's DMARC policy, REJECT
diff --git a/src/src/dmarc.c b/src/src/dmarc.c
index 22a0515..32a1b96 100644
--- a/src/src/dmarc.c
+++ b/src/src/dmarc.c
@@ -38,6 +38,18 @@ u_char *header_from_sender = NULL;
 int history_file_status    = DMARC_HIST_OK;
 uschar *dkim_history_buffer= NULL;


+typedef struct dmarc_exim_p {
+  uschar *name;
+  int    value;
+} dmarc_exim_p;
+
+static dmarc_exim_p dmarc_policy_description[] = {
+  { US"",           DMARC_RECORD_P_UNSPECIFIED },
+  { US"none",       DMARC_RECORD_P_NONE },
+  { US"quarantine", DMARC_RECORD_P_QUARANTINE },
+  { US"reject",     DMARC_RECORD_P_REJECT },
+  { NULL,           0 }
+};
 /* Accept an error_block struct, initialize if empty, parse to the
  * end, and append the two strings passed to it.  Used for adding
  * variable amounts of value:pair data to the forensic emails. */
@@ -147,6 +159,7 @@ int dmarc_store_data(header_line *hdr) {
 int dmarc_process() {
     int sr, origin;             /* used in SPF section */
     int dmarc_spf_result  = 0;  /* stores spf into dmarc conn ctx */
+    int tmp_ans, c;
     pdkim_signature *sig  = NULL;
     BOOL has_dmarc_record = TRUE;
     u_char **ruf; /* forensic report addressees, if called for */
@@ -308,6 +321,16 @@ int dmarc_process() {
         has_dmarc_record = FALSE;
         break;
     }
+
+  /* Store the policy string in an expandable variable. */
+    libdm_status = opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans);
+    for (c=0; dmarc_policy_description[c].name != NULL; c++) {
+      if (tmp_ans == dmarc_policy_description[c].value) {
+        dmarc_domain_policy = string_sprintf("%s",dmarc_policy_description[c].name);
+        break;
+      }
+    }
+
     /* Can't use exim's string manipulation functions so allocate memory
      * for libopendmarc using its max hostname length definition. */
     uschar *dmarc_domain = (uschar *)calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar));
diff --git a/src/src/expand.c b/src/src/expand.c
index 7a3252e..d2ac8ca 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -468,6 +468,7 @@ static var_entry var_table[] = {
 #endif
 #ifdef EXPERIMENTAL_DMARC
   { "dmarc_ar_header",     vtype_stringptr,   &dmarc_ar_header },
+  { "dmarc_domain_policy", vtype_stringptr,   &dmarc_domain_policy },
   { "dmarc_status",        vtype_stringptr,   &dmarc_status },
   { "dmarc_status_text",   vtype_stringptr,   &dmarc_status_text },
   { "dmarc_used_domain",   vtype_stringptr,   &dmarc_used_domain },
diff --git a/src/src/globals.c b/src/src/globals.c
index 62f653b..839b91d 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -598,6 +598,7 @@ BOOL    dkim_disable_verify      = FALSE;
 #ifdef EXPERIMENTAL_DMARC
 BOOL    dmarc_has_been_checked  = FALSE;
 uschar *dmarc_ar_header         = NULL;
+uschar *dmarc_domain_policy     = NULL;
 uschar *dmarc_forensic_sender   = NULL;
 uschar *dmarc_history_file      = NULL;
 uschar *dmarc_status            = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index 088c267..1cc39fc 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -354,6 +354,7 @@ extern BOOL    dkim_disable_verify;    /* Set via ACL control statement. When se
 #ifdef EXPERIMENTAL_DMARC
 extern BOOL    dmarc_has_been_checked; /* Global variable to check if test has been called yet */
 extern uschar *dmarc_ar_header;        /* Expansion variable, suggested header for dmarc auth results */
+extern uschar *dmarc_domain_policy;    /* Expansion for declared policy of used domain */
 extern uschar *dmarc_forensic_sender;  /* Set sender address for forensic reports */
 extern uschar *dmarc_history_file;     /* Expansion variable, file to store dmarc results */
 extern uschar *dmarc_status;           /* Expansion variable, one word value */