summaryrefslogtreecommitdiff
path: root/network/opendmarc/patches/ticket180.patch
diff options
context:
space:
mode:
Diffstat (limited to 'network/opendmarc/patches/ticket180.patch')
-rw-r--r--network/opendmarc/patches/ticket180.patch280
1 files changed, 280 insertions, 0 deletions
diff --git a/network/opendmarc/patches/ticket180.patch b/network/opendmarc/patches/ticket180.patch
new file mode 100644
index 0000000000..cd38c39c38
--- /dev/null
+++ b/network/opendmarc/patches/ticket180.patch
@@ -0,0 +1,280 @@
+diff --git a/opendmarc/opendmarc-config.h b/opendmarc/opendmarc-config.h
+index 7ba394b..28f605e 100644
+--- a/opendmarc/opendmarc-config.h
++++ b/opendmarc/opendmarc-config.h
+@@ -36,6 +36,7 @@ struct configdef dmarcf_config[] =
+ { "IgnoreHosts", CONFIG_TYPE_STRING, FALSE },
+ { "IgnoreMailFrom", CONFIG_TYPE_STRING, FALSE },
+ { "MilterDebug", CONFIG_TYPE_INTEGER, FALSE },
++ { "OverrideMLM", CONFIG_TYPE_STRING, FALSE },
+ { "PidFile", CONFIG_TYPE_STRING, FALSE },
+ { "PublicSuffixList", CONFIG_TYPE_STRING, FALSE },
+ { "RecordAllMessages", CONFIG_TYPE_BOOLEAN, FALSE },
+diff --git a/opendmarc/opendmarc.c b/opendmarc/opendmarc.c
+index ba04312..07e089d 100644
+--- a/opendmarc/opendmarc.c
++++ b/opendmarc/opendmarc.c
+@@ -168,6 +168,7 @@ struct dmarcf_config
+ char * conf_ignorelist;
+ char ** conf_trustedauthservids;
+ char ** conf_ignoredomains;
++ struct list * conf_overridemlm;
+ };
+
+ /* LIST -- basic linked list of strings */
+@@ -1221,6 +1222,18 @@ dmarcf_config_load(struct config *data, struct dmarcf_config *conf,
+ if (str != NULL)
+ dmarcf_mkarray(str, &conf->conf_ignoredomains);
+
++ str = NULL;
++ (void) config_get(data, "OverrideMLM", &str, sizeof str);
++ if (str != NULL)
++ {
++ if (!dmarcf_loadlist(str, &conf->conf_overridemlm))
++ {
++ fprintf(stderr,
++ "%s: can't load override MLM list from %s: %s\n",
++ progname, str, strerror(errno));
++ }
++ }
++
+ (void) config_get(data, "AuthservIDWithJobID",
+ &conf->conf_authservidwithjobid,
+ sizeof conf->conf_authservidwithjobid);
+@@ -2982,30 +2995,45 @@ mlfi_eom(SMFICTX *ctx)
+ case DMARC_POLICY_REJECT: /* Explicit reject */
+ aresult = "fail";
+
+- if (conf->conf_rejectfail && random() % 100 < pct)
++ if (conf->conf_overridemlm != NULL &&
++ (dmarcf_checkhost(cc->cctx_host, conf->conf_overridemlm) ||
++ (dmarcf_checkip((struct sockaddr *)&cc->cctx_ip, conf->conf_overridemlm))))
+ {
+- 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)
++ if (conf->conf_dolog)
+ {
+- syslog(LOG_ERR, "%s: smfi_setreply() failed",
+- dfc->mctx_jobid);
++ syslog(LOG_INFO, "%s: overriding policy for mail from %s: MLM",
++ dfc->mctx_jobid, dfc->mctx_fromdomain);
+ }
+-
+- ret = SMFIS_REJECT;
+- result = DMARC_RESULT_REJECT;
++ ret = SMFIS_ACCEPT;
++ result = DMARC_RESULT_OVRD_MAILING_LIST;
+ }
+-
+- if (conf->conf_copyfailsto != NULL)
++ else
+ {
+- status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto);
+- if (status != MI_SUCCESS && conf->conf_dolog)
++ 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)
+ {
+- syslog(LOG_ERR, "%s: smfi_addrcpt() failed",
+- dfc->mctx_jobid);
++ status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto);
++ if (status != MI_SUCCESS && conf->conf_dolog)
++ {
++ syslog(LOG_ERR, "%s: smfi_addrcpt() failed",
++ dfc->mctx_jobid);
++ }
+ }
+ }
+
+@@ -3014,30 +3042,45 @@ mlfi_eom(SMFICTX *ctx)
+ case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */
+ aresult = "fail";
+
+- if (conf->conf_rejectfail && random() % 100 < pct)
++ if (conf->conf_overridemlm != NULL &&
++ (dmarcf_checkhost(cc->cctx_host, conf->conf_overridemlm) ||
++ (dmarcf_checkip((struct sockaddr *)&cc->cctx_ip, conf->conf_overridemlm))))
+ {
+- snprintf(replybuf, sizeof replybuf,
+- "quarantined by DMARC policy for %s",
+- pdomain);
+-
+- status = smfi_quarantine(ctx, replybuf);
+- if (status != MI_SUCCESS && conf->conf_dolog)
++ if (conf->conf_dolog)
+ {
+- syslog(LOG_ERR, "%s: smfi_quarantine() failed",
+- dfc->mctx_jobid);
++ syslog(LOG_INFO, "%s: overriding policy for mail from %s: MLM",
++ dfc->mctx_jobid, dfc->mctx_fromdomain);
+ }
+-
+ ret = SMFIS_ACCEPT;
+- result = DMARC_RESULT_QUARANTINE;
++ result = DMARC_RESULT_OVRD_MAILING_LIST;
+ }
+-
+- if (conf->conf_copyfailsto != NULL)
++ else
+ {
+- status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto);
+- if (status != MI_SUCCESS && conf->conf_dolog)
++ if (conf->conf_rejectfail && random() % 100 < pct)
++ {
++ 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)
+ {
+- syslog(LOG_ERR, "%s: smfi_addrcpt() failed",
+- dfc->mctx_jobid);
++ status = dmarcf_addrcpt(ctx, conf->conf_copyfailsto);
++ if (status != MI_SUCCESS && conf->conf_dolog)
++ {
++ syslog(LOG_ERR, "%s: smfi_addrcpt() failed",
++ dfc->mctx_jobid);
++ }
+ }
+ }
+
+diff --git a/opendmarc/opendmarc.conf.5.in b/opendmarc/opendmarc.conf.5.in
+index bdf2550..9ee16ae 100644
+--- a/opendmarc/opendmarc.conf.5.in
++++ b/opendmarc/opendmarc.conf.5.in
+@@ -190,6 +190,14 @@ Sets the debug level to be requested from the milter library. The
+ default is 0.
+
+ .TP
++.I OverrideMLM (string)
++Specifies the path to a file that contains a list of hostnames, IP
++addresses, and/or CIDR expressions identifying hosts that run
++mailing lists. Mails from these systems will be accepted even if
++all DMARC tests fail. Such cases will be reported as "override/
++reason: MLM"
++
++.TP
+ .I PidFile (string)
+ Specifies the path to a file that should be created at process start
+ containing the process ID.
+diff --git a/opendmarc/opendmarc.conf.sample b/opendmarc/opendmarc.conf.sample
+index 97b210f..fbfa49d 100644
+--- a/opendmarc/opendmarc.conf.sample
++++ b/opendmarc/opendmarc.conf.sample
+@@ -212,6 +212,17 @@
+ #
+ # MilterDebug 0
+
++## OverrideMLM (path)
++## default (none)
++##
++## Specifies the path to a file that contains a list of hostnames, IP
++## addresses, and/or CIDR expressions identifying hosts that run
++## mailing lists. Mails from these systems will be accepted even if
++## all DMARC tests fail. Such cases will be reported as "override/
++## reason: MLM"
++#
++# OverrideMLM /usr/local/etc/opendmarc/overrideMLM.conf
++
+ ## PidFile path
+ ## default (none)
+ ##
+diff --git a/opendmarc/opendmarc.h b/opendmarc/opendmarc.h
+index c1d6593..f9b1e0b 100644
+--- a/opendmarc/opendmarc.h
++++ b/opendmarc/opendmarc.h
+@@ -52,6 +52,12 @@
+ #define DMARC_RESULT_ACCEPT 2
+ #define DMARC_RESULT_TEMPFAIL 3
+ #define DMARC_RESULT_QUARANTINE 4
++#define DMARC_RESULT_OVRD_FORWARDED 5
++#define DMARC_RESULT_OVRD_SAMPLED_OUT 6
++#define DMARC_RESULT_OVRD_TRUSTED_FORWARDER 7
++#define DMARC_RESULT_OVRD_MAILING_LIST 8
++#define DMARC_RESULT_OVRD_LOCAL_POLICY 9
++#define DMARC_RESULT_OVRD_OTHER 10
+
+ /* prototypes, etc., exported for test.c */
+ extern char *progname;
+diff --git a/reports/opendmarc-reports.in b/reports/opendmarc-reports.in
+index 2da1c31..a489c95 100755
+--- a/reports/opendmarc-reports.in
++++ b/reports/opendmarc-reports.in
+@@ -91,6 +91,8 @@ my $ipaddr;
+ my $fromdomain;
+ my $envdomain;
+ my $dkimdomain;
++my $reason;
++my $comment;
+
+ my $repdest;
+
+@@ -609,6 +611,8 @@ foreach (@$domainset)
+ while ($dbi_a = $dbi_s->fetchrow_arrayref())
+ {
+ undef $msgid;
++ undef $reason;
++ undef $comment;
+
+ if (defined($dbi_a->[0]))
+ {
+@@ -656,6 +660,12 @@ foreach (@$domainset)
+ case 1 { $dispstr = "reject"; }
+ case 2 { $dispstr = "none"; }
+ case 4 { $dispstr = "quarantine"; }
++ case 5 { $dispstr = "none"; $reason = "forwarded"; }
++ case 6 { $dispstr = "none"; $reason = "sampled_out"; }
++ case 7 { $dispstr = "none"; $reason = "trusted_forwarder"; }
++ case 8 { $dispstr = "none"; $reason = "mailing_list"; }
++ case 9 { $dispstr = "none"; $reason = "local_policy"; $comment = ""; }
++ case 10 { $dispstr = "none"; $reason = "other"; $comment = ""; }
+ else { $dispstr = "unknown"; }
+ }
+
+@@ -697,6 +707,16 @@ foreach (@$domainset)
+ print $tmpout " <disposition>$dispstr</disposition>\n";
+ print $tmpout " <dkim>$align_dkimstr</dkim>\n";
+ print $tmpout " <spf>$align_spfstr</spf>\n";
++ if (defined($reason))
++ {
++ print $tmpout " <reason>\n";
++ print $tmpout " <type>$reason</type>\n";
++ if (defined($comment))
++ {
++ print $tmpout " <comment>$comment</$comment>\n";
++ }
++ print $tmpout " </reason>\n";
++ }
+ print $tmpout " </policy_evaluated>\n";
+ print $tmpout " </row>\n";
+ print $tmpout " <identifiers>\n";