DMARC: Fix forensic-report envelopes to permit non-null. Bug 1896
authorJeremy Harris <jgh146exb@wizmail.org>
Wed, 22 Aug 2018 23:05:28 +0000 (00:05 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 22 Aug 2018 23:06:42 +0000 (00:06 +0100)
doc/doc-txt/ChangeLog
doc/doc-txt/experimental-spec.txt
src/src/dmarc.c
src/src/functions.h
src/src/moan.c

index 333ae731c95182d3fd0973566151007600ed3590..5f45d69c111258fc24830b72d98e4454dd70d2a0 100644 (file)
@@ -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
 -----------------
index 7805c258e3404b7442c5952ec7876b2030ddf69a..0ad7f0de9a01f502fa49ff41072ed4c37e3a81ff 100644 (file)
@@ -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,
index a7e08c5e8a7a0ef77af2146f66d8fdcf5f40f07e..efb2ef0a26673ee50647cc8d1805b2725611d6e2 100644 (file)
@@ -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);
       }
index 9b105774ebfdd5bfb44733c29be41d3269ea59cf..58cab823845d8669cd25791db8f39a04e9cbc05f 100644 (file)
@@ -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);
index c89f5c238aae43fbc009f0d4497a0f4cbe0f9ae0..1dcc6c4991b6c1e3ca27afc91f6745eaddd4425a 100644 (file)
@@ -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++;