From 8c8b8274fc537766da72eab2f79a62d1603d6638 Mon Sep 17 00:00:00 2001 From: Todd Lyons Date: Sat, 12 Apr 2014 10:42:52 -0700 Subject: [PATCH] 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 17e8091ce..0d4652bd2 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 2395267e8..d0503d9e8 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 22a051582..32a1b9678 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 7a3252eaa..d2ac8ca79 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 62f653b23..839b91dcc 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 088c267f2..1cc39fc09 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 */ -- 2.30.2