Merge tag 'exim-4_82_1'
[exim.git] / src / src / dmarc.c
index c619061..ca1c29b 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 /* Experimental DMARC support.
-   Copyright (c) Todd Lyons <tlyons@exim.org> 2012, 2013
+   Copyright (c) Todd Lyons <tlyons@exim.org> 2012 - 2014
    License: GPL */
 
 /* Portions Copyright (c) 2012, 2013, The Trusted Domain Project;
@@ -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 */
@@ -168,27 +181,27 @@ int dmarc_process() {
     dmarc_abort = TRUE;
   else
   {
-  uschar * errormsg;
-  int dummy, domain;
-  uschar * p;
-  uschar saveend;
-
-  parse_allow_group = TRUE;
-  p = parse_find_address_end(from_header->text, FALSE);
-  saveend = *p; *p = '\0';
-  if ((header_from_sender = parse_extract_address(from_header->text, &errormsg,
-                              &dummy, &dummy, &domain, FALSE)))
-    header_from_sender += domain;
-  *p = saveend;
-
-  /* The opendmarc library extracts the domain from the email address, but
-   * only try to store it if it's not empty.  Otherwise, skip out of DMARC. */
-  if (!header_from_sender || (strcmp( CCS header_from_sender, "") == 0))
-    dmarc_abort = TRUE;
-  libdm_status = dmarc_abort ?
-    DMARC_PARSE_OKAY :
-    opendmarc_policy_store_from_domain(dmarc_pctx, header_from_sender);
-  if (libdm_status != DMARC_PARSE_OKAY)
+    uschar * errormsg;
+    int dummy, domain;
+    uschar * p;
+    uschar saveend;
+
+    parse_allow_group = TRUE;
+    p = parse_find_address_end(from_header->text, FALSE);
+    saveend = *p; *p = '\0';
+    if ((header_from_sender = parse_extract_address(from_header->text, &errormsg,
+                                &dummy, &dummy, &domain, FALSE)))
+      header_from_sender += domain;
+    *p = saveend;
+
+    /* The opendmarc library extracts the domain from the email address, but
+     * only try to store it if it's not empty.  Otherwise, skip out of DMARC. */
+    if (!header_from_sender || (strcmp( CCS header_from_sender, "") == 0))
+      dmarc_abort = TRUE;
+    libdm_status = dmarc_abort ?
+      DMARC_PARSE_OKAY :
+      opendmarc_policy_store_from_domain(dmarc_pctx, header_from_sender);
+    if (libdm_status != DMARC_PARSE_OKAY)
     {
       log_write(0, LOG_MAIN|LOG_PANIC,
                 "failure to store header From: in DMARC: %s, header was '%s'",
@@ -266,24 +279,24 @@ int dmarc_process() {
                     ( vs == PDKIM_VERIFY_INVALID ) ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
                     DMARC_POLICY_DKIM_OUTCOME_NONE;
       libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, (uschar *)sig->domain,
-                                                dkim_result, US"");
+                                                 dkim_result, US"");
       DEBUG(D_receive)
         debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain);
       if (libdm_status != DMARC_PARSE_OKAY)
         log_write(0, LOG_MAIN|LOG_PANIC, "failure to store dkim (%s) for DMARC: %s",
-                            sig->domain, opendmarc_policy_status_to_str(libdm_status));
+                  sig->domain, opendmarc_policy_status_to_str(libdm_status));
 
       dkim_ares_result = ( vs == PDKIM_VERIFY_PASS )    ? ARES_RESULT_PASS :
-                             ( vs == PDKIM_VERIFY_FAIL )    ? ARES_RESULT_FAIL :
-                             ( vs == PDKIM_VERIFY_NONE )    ? ARES_RESULT_NONE :
-                             ( vs == PDKIM_VERIFY_INVALID ) ?
+                         ( vs == PDKIM_VERIFY_FAIL )    ? ARES_RESULT_FAIL :
+                         ( vs == PDKIM_VERIFY_NONE )    ? ARES_RESULT_NONE :
+                         ( vs == PDKIM_VERIFY_INVALID ) ?
                            ( ves == PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE ? ARES_RESULT_PERMERROR :
                              ves == PDKIM_VERIFY_INVALID_BUFFER_SIZE        ? ARES_RESULT_PERMERROR :
                              ves == PDKIM_VERIFY_INVALID_PUBKEY_PARSING     ? ARES_RESULT_PERMERROR :
                              ARES_RESULT_UNKNOWN ) :
                           ARES_RESULT_UNKNOWN;
       dkim_history_buffer = string_sprintf("%sdkim %s %d\n", dkim_history_buffer,
-                                                             sig->domain, dkim_ares_result);
+                                           sig->domain, dkim_ares_result);
       sig = sig->next;
     }
     libdm_status = opendmarc_policy_query_dmarc(dmarc_pctx, US"");
@@ -312,11 +325,21 @@ 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));
     libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx, dmarc_domain,
-                                                         DMARC_MAXHOSTNAMELEN-1);
+                                                  DMARC_MAXHOSTNAMELEN-1);
     dmarc_used_domain = string_copy(dmarc_domain);
     free(dmarc_domain);
     if (libdm_status != DMARC_PARSE_OKAY)
@@ -436,7 +459,7 @@ int dmarc_write_history_file()
 
   if (spf_response != NULL)
     history_buffer = string_sprintf("%sspf %d\n", history_buffer, dmarc_spf_ares_result);
-    // history_buffer = string_sprintf("%sspf -1\n", history_buffer);
+    /* history_buffer = string_sprintf("%sspf -1\n", history_buffer); */
 
   history_buffer = string_sprintf("%s%s", history_buffer, dkim_history_buffer);
   history_buffer = string_sprintf("%spdomain %s\n", history_buffer, dmarc_used_domain);
@@ -614,5 +637,3 @@ uschar *dmarc_auth_results_header(header_line *from_header, uschar *hostname)
 
 #endif /* EXPERIMENTAL_SPF */
 #endif /* EXPERIMENTAL_DMARC */
-
-// vim:sw=2 expandtab