--- a/opendmarc/opendmarc.c 2016-12-21 18:01:21.322036404 +0100 +++ b/opendmarc/opendmarc.c 2016-12-21 18:01:48.893181823 +0100 @@ -2057,6 +2057,7 @@ char *apolicy = NULL; char *aresult = NULL; char *adisposition = NULL; + char *deliveryresult = NULL; char *hostname = NULL; char *authservid = NULL; char *spfaddr; @@ -2774,6 +2775,154 @@ } /* + ** Enact policy based on DMARC results. + */ + + result = DMARC_RESULT_ACCEPT; + + switch (policy) + { + case DMARC_POLICY_ABSENT: /* No DMARC record found */ + case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */ + aresult = "none"; + ret = SMFIS_ACCEPT; + result = DMARC_RESULT_ACCEPT; + break; + + case DMARC_POLICY_NONE: /* Alignment failed, but policy is none: */ + aresult = "fail"; /* Accept and report */ + ret = SMFIS_ACCEPT; + result = DMARC_RESULT_ACCEPT; + break; + + case DMARC_POLICY_PASS: /* Explicit accept */ + aresult = "pass"; + ret = SMFIS_ACCEPT; + result = DMARC_RESULT_ACCEPT; + break; + + case DMARC_POLICY_REJECT: /* Explicit reject */ + aresult = "fail"; + + if (conf->conf_overridemlm != NULL && + (dmarcf_checkhost(cc->cctx_host, conf->conf_overridemlm) || + (dmarcf_checkip((struct sockaddr *)&cc->cctx_ip, conf->conf_overridemlm)))) + { + if (conf->conf_dolog) + { + syslog(LOG_INFO, "%s: overriding policy for mail from %s: MLM", + dfc->mctx_jobid, dfc->mctx_fromdomain); + } + ret = SMFIS_ACCEPT; + result = DMARC_RESULT_OVRD_MAILING_LIST; + } + else + { + if (conf->conf_rejectfail && random() % 100 < pct) + { + snprintf(replybuf, sizeof replybuf, + "rejected by DMARC policy for %s", pdomain); + + status = dmarcf_setreply(ctx, DMARC_REJECT_SMTP, + DMARC_REJECT_ESC, replybuf); + if (status != MI_SUCCESS && conf->conf_dolog) + { + syslog(LOG_ERR, "%s: smfi_setreply() failed", + dfc->mctx_jobid); + } + + ret = SMFIS_REJECT; + result = DMARC_RESULT_REJECT; + } + + if (conf->conf_copyfailsto != NULL) + { + status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto); + if (status != MI_SUCCESS && conf->conf_dolog) + { + syslog(LOG_ERR, "%s: smfi_addrcpt() failed", + dfc->mctx_jobid); + } + } + } + + break; + + case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */ + aresult = "fail"; + + if (conf->conf_overridemlm != NULL && + (dmarcf_checkhost(cc->cctx_host, conf->conf_overridemlm) || + (dmarcf_checkip((struct sockaddr *)&cc->cctx_ip, conf->conf_overridemlm)))) + { + if (conf->conf_dolog) + { + syslog(LOG_INFO, "%s: overriding policy for mail from %s: MLM", + dfc->mctx_jobid, dfc->mctx_fromdomain); + } + ret = SMFIS_ACCEPT; + result = DMARC_RESULT_OVRD_MAILING_LIST; + } + else + { + if (conf->conf_rejectfail && random() % 100 < pct && + conf->conf_holdquarantinedmessages) + { + snprintf(replybuf, sizeof replybuf, + "quarantined by DMARC policy for %s", + pdomain); + + status = smfi_quarantine(ctx, replybuf); + if (status != MI_SUCCESS && conf->conf_dolog) + { + syslog(LOG_ERR, "%s: smfi_quarantine() failed", + dfc->mctx_jobid); + } + + ret = SMFIS_ACCEPT; + result = DMARC_RESULT_QUARANTINE; + } + + if (conf->conf_copyfailsto != NULL) + { + status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto); + if (status != MI_SUCCESS && conf->conf_dolog) + { + syslog(LOG_ERR, "%s: smfi_addrcpt() failed", + dfc->mctx_jobid); + } + } + } + + break; + + default: + aresult = "temperror"; + ret = SMFIS_TEMPFAIL; + result = DMARC_RESULT_TEMPFAIL; + break; + } + + /* prepare human readable dispositon string for later processing */ + switch (result) + { + case DMARC_RESULT_REJECT: + adisposition = "reject"; + deliveryresult = "reject"; + break; + + case DMARC_RESULT_QUARANTINE: + adisposition = "quarantine"; + deliveryresult = "policy"; + break; + + default: + adisposition = "none"; + deliveryresult = "delivered"; + break; + } + + /* ** Generate a failure report. */ @@ -2931,8 +3080,11 @@ "Auth-Failure: dmarc\n"); dmarcf_dstring_printf(dfc->mctx_afrf, - "Authentication-Results: %s; dmarc=fail header.from=%s\n", - authservid, + "Authentication-Results: %s;\n", + authservid); + dmarcf_dstring_printf(dfc->mctx_afrf, + " dmarc=%s (p=%s dis=%s) header.from=%s\n", + aresult, apolicy, adisposition, dfc->mctx_fromdomain); dmarcf_dstring_printf(dfc->mctx_afrf, @@ -2949,6 +3101,20 @@ cc->cctx_host); dmarcf_dstring_printf(dfc->mctx_afrf, + "Source-Port: %u\n", + cc->cctx_ip.ss_family == AF_INET6 ? ntohs(((struct sockaddr_in6*) &cc->cctx_ip)->sin6_port) : ntohs(((struct sockaddr_in*) &cc->cctx_ip)->sin_port)); + + dmarcf_dstring_printf(dfc->mctx_afrf, + "Identity-Alignment: %s%s%s\n", + align_dkim == DMARC_POLICY_DKIM_ALIGNMENT_PASS ? "dkim" : "", + ((align_dkim == DMARC_POLICY_DKIM_ALIGNMENT_PASS) && (align_spf == DMARC_POLICY_SPF_ALIGNMENT_PASS)) ? ", " : ((align_dkim != DMARC_POLICY_DKIM_ALIGNMENT_PASS) && (align_spf != DMARC_POLICY_SPF_ALIGNMENT_PASS)) ? "none" : "", + align_spf == DMARC_POLICY_SPF_ALIGNMENT_PASS ? "spf" : ""); + + dmarcf_dstring_printf(dfc->mctx_afrf, + "Delivery-Result: %s\n", + deliveryresult); + + dmarcf_dstring_printf(dfc->mctx_afrf, "Reported-Domain: %s\n\n", dfc->mctx_fromdomain); @@ -3015,151 +3181,6 @@ } } - /* - ** Enact policy based on DMARC results. - */ - - result = DMARC_RESULT_ACCEPT; - - switch (policy) - { - case DMARC_POLICY_ABSENT: /* No DMARC record found */ - case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */ - aresult = "none"; - ret = SMFIS_ACCEPT; - result = DMARC_RESULT_ACCEPT; - break; - - case DMARC_POLICY_NONE: /* Alignment failed, but policy is none: */ - aresult = "fail"; /* Accept and report */ - ret = SMFIS_ACCEPT; - result = DMARC_RESULT_ACCEPT; - break; - - case DMARC_POLICY_PASS: /* Explicit accept */ - aresult = "pass"; - ret = SMFIS_ACCEPT; - result = DMARC_RESULT_ACCEPT; - break; - - case DMARC_POLICY_REJECT: /* Explicit reject */ - aresult = "fail"; - - if (conf->conf_overridemlm != NULL && - (dmarcf_checkhost(cc->cctx_host, conf->conf_overridemlm) || - (dmarcf_checkip((struct sockaddr *)&cc->cctx_ip, conf->conf_overridemlm)))) - { - if (conf->conf_dolog) - { - syslog(LOG_INFO, "%s: overriding policy for mail from %s: MLM", - dfc->mctx_jobid, dfc->mctx_fromdomain); - } - ret = SMFIS_ACCEPT; - result = DMARC_RESULT_OVRD_MAILING_LIST; - } - else - { - if (conf->conf_rejectfail && random() % 100 < pct) - { - snprintf(replybuf, sizeof replybuf, - "rejected by DMARC policy for %s", pdomain); - - status = dmarcf_setreply(ctx, DMARC_REJECT_SMTP, - DMARC_REJECT_ESC, replybuf); - if (status != MI_SUCCESS && conf->conf_dolog) - { - syslog(LOG_ERR, "%s: smfi_setreply() failed", - dfc->mctx_jobid); - } - - ret = SMFIS_REJECT; - result = DMARC_RESULT_REJECT; - } - - if (conf->conf_copyfailsto != NULL) - { - status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto); - if (status != MI_SUCCESS && conf->conf_dolog) - { - syslog(LOG_ERR, "%s: smfi_addrcpt() failed", - dfc->mctx_jobid); - } - } - } - - break; - - case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */ - aresult = "fail"; - - if (conf->conf_overridemlm != NULL && - (dmarcf_checkhost(cc->cctx_host, conf->conf_overridemlm) || - (dmarcf_checkip((struct sockaddr *)&cc->cctx_ip, conf->conf_overridemlm)))) - { - if (conf->conf_dolog) - { - syslog(LOG_INFO, "%s: overriding policy for mail from %s: MLM", - dfc->mctx_jobid, dfc->mctx_fromdomain); - } - ret = SMFIS_ACCEPT; - result = DMARC_RESULT_OVRD_MAILING_LIST; - } - else - { - if (conf->conf_rejectfail && random() % 100 < pct && - conf->conf_holdquarantinedmessages) - { - snprintf(replybuf, sizeof replybuf, - "quarantined by DMARC policy for %s", - pdomain); - - status = smfi_quarantine(ctx, replybuf); - if (status != MI_SUCCESS && conf->conf_dolog) - { - syslog(LOG_ERR, "%s: smfi_quarantine() failed", - dfc->mctx_jobid); - } - - ret = SMFIS_ACCEPT; - result = DMARC_RESULT_QUARANTINE; - } - - if (conf->conf_copyfailsto != NULL) - { - status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto); - if (status != MI_SUCCESS && conf->conf_dolog) - { - syslog(LOG_ERR, "%s: smfi_addrcpt() failed", - dfc->mctx_jobid); - } - } - } - - break; - - default: - aresult = "temperror"; - ret = SMFIS_TEMPFAIL; - result = DMARC_RESULT_TEMPFAIL; - break; - } - - /* prepare human readable dispositon string for later processing */ - switch (result) - { - case DMARC_RESULT_REJECT: - adisposition = "reject"; - break; - - case DMARC_RESULT_QUARANTINE: - adisposition = "quarantine"; - break; - - default: - adisposition = "none"; - break; - } - if (conf->conf_dolog) { syslog(LOG_INFO, "%s: %s %s", dfc->mctx_jobid,