* 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;
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. */
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 */
dmarc_abort = TRUE;
else
{
- /* I strongly encourage anybody who can make this better to contact me directly!
- * <cannonball> Is this an insane way to extract the email address from the From: header?
- * <jgh_hm> it's sure a horrid layer-crossing....
- * <cannonball> I'm not denying that :-/
- * <jgh_hm> there may well be no better though
- */
- header_from_sender = expand_string(
- string_sprintf("${domain:${extract{1}{:}{${addresses:\\N%s\\N}}}}",
- from_header->text) );
- 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 == NULL) || (strcmp( CCS header_from_sender, "") == 0))
++ if (!header_from_sender || (strcmp( CCS header_from_sender, "") == 0))
+ dmarc_abort = TRUE;
- libdm_status = (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'",
( 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"");
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)
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);
#endif /* EXPERIMENTAL_SPF */
#endif /* EXPERIMENTAL_DMARC */
-
-// vim:sw=2 expandtab