+ uschar * dmarc_domain;
+
+ /* Use the envelope sender domain for this part of DMARC */
+ spf_sender_domain = expand_string(US"$sender_address_domain");
+ if (!spf_response)
+ {
+ /* No spf data means null envelope sender so generate a domain name
+ * from the sender_helo_name */
+ if (!spf_sender_domain)
+ {
+ spf_sender_domain = sender_helo_name;
+ log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n",
+ spf_sender_domain);
+ DEBUG(D_receive)
+ debug_printf("DMARC using synthesized SPF sender domain = %s\n",
+ spf_sender_domain);
+ }
+ dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE;
+ dmarc_spf_ares_result = ARES_RESULT_UNKNOWN;
+ origin = DMARC_POLICY_SPF_ORIGIN_HELO;
+ spf_human_readable = US"";
+ }
+ else
+ {
+ sr = spf_response->result;
+ dmarc_spf_result = sr == SPF_RESULT_NEUTRAL ? DMARC_POLICY_SPF_OUTCOME_NONE :
+ sr == SPF_RESULT_PASS ? DMARC_POLICY_SPF_OUTCOME_PASS :
+ sr == SPF_RESULT_FAIL ? DMARC_POLICY_SPF_OUTCOME_FAIL :
+ sr == SPF_RESULT_SOFTFAIL ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL :
+ DMARC_POLICY_SPF_OUTCOME_NONE;
+ dmarc_spf_ares_result = sr == SPF_RESULT_NEUTRAL ? ARES_RESULT_NEUTRAL :
+ sr == SPF_RESULT_PASS ? ARES_RESULT_PASS :
+ sr == SPF_RESULT_FAIL ? ARES_RESULT_FAIL :
+ sr == SPF_RESULT_SOFTFAIL ? ARES_RESULT_SOFTFAIL :
+ sr == SPF_RESULT_NONE ? ARES_RESULT_NONE :
+ sr == SPF_RESULT_TEMPERROR ? ARES_RESULT_TEMPERROR :
+ sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR :
+ ARES_RESULT_UNKNOWN;
+ origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM;
+ spf_human_readable = US spf_response->header_comment;
+ DEBUG(D_receive)
+ debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain);
+ }
+ if (strcmp( CCS spf_sender_domain, "") == 0)
+ dmarc_abort = TRUE;
+ if (!dmarc_abort)
+ {
+ libdm_status = opendmarc_policy_store_spf(dmarc_pctx, spf_sender_domain,
+ dmarc_spf_result, origin, spf_human_readable);
+ if (libdm_status != DMARC_PARSE_OKAY)
+ log_write(0, LOG_MAIN|LOG_PANIC, "failure to store spf for DMARC: %s",
+ opendmarc_policy_status_to_str(libdm_status));
+ }
+
+ /* Now we cycle through the dkim signature results and put into
+ * the opendmarc context, further building the DMARC reply. */
+ dkim_history_buffer = US"";
+ while (sig)
+ {
+ int dkim_result, dkim_ares_result, vs, ves;
+
+ vs = sig->verify_status & ~PDKIM_VERIFY_POLICY;
+ ves = sig->verify_ext_status;
+ dkim_result = vs == PDKIM_VERIFY_PASS ? DMARC_POLICY_DKIM_OUTCOME_PASS :
+ vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL :
+ vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
+ DMARC_POLICY_DKIM_OUTCOME_NONE;
+ libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, US sig->domain,
+/* The opendmarc project broke its API in a way we can't detect * easily.
+ * The EDITME provides a DMARC_API variable */
+#if DMARC_API >= 100400
+ sig->selector,
+#endif
+ 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));
+
+ 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 ?
+ ves == PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE ? ARES_RESULT_PERMERROR :
+ ves == PDKIM_VERIFY_INVALID_BUFFER_SIZE ? ARES_RESULT_PERMERROR :
+ ves == PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD ? ARES_RESULT_PERMERROR :
+ ves == PDKIM_VERIFY_INVALID_PUBKEY_IMPORT ? 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 = sig->next;
+ }
+
+ /* Look up DMARC policy record in DNS. We do this explicitly, rather than
+ letting the dmarc library do it with opendmarc_policy_query_dmarc(), so that
+ our dns access path is used for debug tracing and for the testsuite
+ diversion. */
+
+ libdm_status = (rr = dmarc_dns_lookup(header_from_sender))
+ ? opendmarc_policy_store_dmarc(dmarc_pctx, rr, header_from_sender, NULL)
+ : DMARC_DNS_ERROR_NO_RECORD;
+ switch (libdm_status)