From 5455f54826fe81cddb761ca943ea0b1ef5836dbc Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Thu, 23 Aug 2018 00:05:28 +0100 Subject: [PATCH] DMARC: Fix forensic-report envelopes to permit non-null. Bug 1896 --- doc/doc-txt/ChangeLog | 4 +++ doc/doc-txt/experimental-spec.txt | 12 ++++++-- src/src/dmarc.c | 17 ++++-------- src/src/functions.h | 2 ++ src/src/moan.c | 46 +++++++++++++++++++++++++------ 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 333ae731c..5f45d69c1 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -104,6 +104,10 @@ JH/21 Change as many as possible of the global flags into one-bit bitfields; the that the byte-sized flag variables are not interspersed among pointer variables, giving a better chance of good packing by the compiler. +JH/22 Bug 1896: Fix the envelope from for DMARC forensic reports to be possibly + non-null, to avoid issues with sites running BATV. Previously reports were + sent with an empty envelope sender so looked like bounces. + Exim version 4.91 ----------------- diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index 7805c258e..0ad7f0de9 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -447,11 +447,19 @@ dmarc_history_file Defines the location of a file to log results directory of this file is writable by the user exim runs as. -dmarc_forensic_sender The email address to use when sending a +dmarc_forensic_sender Alternate email address to use when sending a forensic report detailing alignment failures if a sender domain's dmarc record specifies it and you have configured Exim to send them. - Default: do-not-reply@$default_hostname + + If set, this is expanded and used for the + From: header line; the address is extracted + from it and used for the envelope from. + If not set, the From: header is expanded from + the dsn_from option, and <> is used for the + envelope from. + + Default: unset. 3. By default, the DMARC processing will run for any remote, diff --git a/src/src/dmarc.c b/src/src/dmarc.c index a7e08c5e8..efb2ef0a2 100644 --- a/src/src/dmarc.c +++ b/src/src/dmarc.c @@ -178,14 +178,11 @@ if ( dmarc_policy == DMARC_POLICY_REJECT && action == DMARC_RESULT_REJECT eblock = add_to_eblock(eblock, US"Sender IP Address", sender_host_address); eblock = add_to_eblock(eblock, US"Received Date", tod_stamp(tod_full)); eblock = add_to_eblock(eblock, US"SPF Alignment", - (sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?US"yes":US"no"); + sa == DMARC_POLICY_SPF_ALIGNMENT_PASS ? US"yes" : US"no"); eblock = add_to_eblock(eblock, US"DKIM Alignment", - (da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?US"yes":US"no"); + da == DMARC_POLICY_DKIM_ALIGNMENT_PASS ? US"yes" : US"no"); eblock = add_to_eblock(eblock, US"DMARC Results", dmarc_status_text); - /* Set a sane default envelope sender */ - dsn_from = dmarc_forensic_sender ? dmarc_forensic_sender : - dsn_from ? dsn_from : - string_sprintf("do-not-reply@%s",primary_hostname); + for (c = 0; ruf[c]; c++) { recipient = string_copylc(ruf[c]); @@ -199,12 +196,8 @@ if ( dmarc_policy == DMARC_POLICY_REJECT && action == DMARC_RESULT_REJECT if (host_checking || f.running_in_test_harness) continue; - save_sender = sender_address; - sender_address = recipient; - send_status = moan_to_sender(ERRMESS_DMARC_FORENSIC, eblock, - header_list, message_file, FALSE); - sender_address = save_sender; - if (!send_status) + if (!moan_send_message(recipient, ERRMESS_DMARC_FORENSIC, eblock, + header_list, message_file, NULL)) log_write(0, LOG_MAIN|LOG_PANIC, "failure to send DMARC forensic report to %s", recipient); } diff --git a/src/src/functions.h b/src/src/functions.h index 9b105774e..58cab8238 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -322,6 +322,8 @@ extern uschar *moan_check_errorcopy(uschar *); extern BOOL moan_skipped_syntax_errors(uschar *, error_block *, uschar *, BOOL, uschar *); extern void moan_smtp_batch(uschar *, const char *, ...) PRINTF_FUNCTION(2,3); +extern BOOL moan_send_message(uschar *, int, error_block *eblock, + header_line *, FILE *, uschar *); extern void moan_tell_someone(uschar *, address_item *, const uschar *, const char *, ...) PRINTF_FUNCTION(4,5); extern BOOL moan_to_sender(int, error_block *, header_line *, FILE *, BOOL); diff --git a/src/src/moan.c b/src/src/moan.c index c89f5c238..1dcc6c499 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -29,7 +29,7 @@ void moan_write_from(FILE *f) { uschar *s = expand_string(dsn_from); -if (s == NULL) +if (!s) { log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand dsn_from (using default): %s", expand_string_message); @@ -61,7 +61,7 @@ Arguments: Returns: TRUE if message successfully sent */ -static BOOL +BOOL moan_send_message(uschar *recipient, int ident, error_block *eblock, header_line *headers, FILE *message_file, uschar *firstline) { @@ -71,9 +71,31 @@ int status; int count = 0; int size_limit = bounce_return_size_limit; FILE * fp; -int pid = child_open_exim(&fd); +int pid; -/* Creation of child failed */ +#ifdef EXPERIMENTAL_DMARC +uschar * s, * s2; + +/* For DMARC if there is a specific sender set, expand the variable for the +header From: and grab the address from that for the envelope FROM. */ + +if ( ident == ERRMESS_DMARC_FORENSIC + && dmarc_forensic_sender + && (s = expand_string(dmarc_forensic_sender)) + && *s + && (s2 = expand_string(string_sprintf("${address:%s}", s))) + && *s2 + ) + pid = child_open_exim2(&fd, s2, bounce_sender_authentication); +else + { + s = NULL; + pid = child_open_exim(&fd); + } + +#else +pid = child_open_exim(&fd); +#endif if (pid < 0) { @@ -88,7 +110,14 @@ else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid); fp = fdopen(fd, "wb"); if (errors_reply_to) fprintf(fp, "Reply-To: %s\n", errors_reply_to); fprintf(fp, "Auto-Submitted: auto-replied\n"); -moan_write_from(fp); + +#ifdef EXPERIMENTAL_DMARC +if (s) + fprintf(fp, "From: %s\n", s); +else +#endif + moan_write_from(fp); + fprintf(fp, "To: %s\n", recipient); switch(ident) @@ -203,14 +232,13 @@ switch(ident) case ERRMESS_DMARC_FORENSIC: bounce_return_message = TRUE; bounce_return_body = FALSE; - fprintf(fp, - "Subject: DMARC Forensic Report for %s from IP %s\n\n", - ((eblock == NULL) ? US"Unknown" : eblock->text2), + fprintf(fp, "Subject: DMARC Forensic Report for %s from IP %s\n\n", + eblock ? eblock->text2 : US"Unknown", sender_host_address); fprintf(fp, "A message claiming to be from you has failed the published DMARC\n" "policy for your domain.\n\n"); - while (eblock != NULL) + while (eblock) { fprintf(fp, " %s: %s\n", eblock->text1, eblock->text2); count++; -- 2.30.2