(1) Update version number to 4.64. (2) Ignore callout cached information
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Tue, 5 Sep 2006 13:24:10 +0000 (13:24 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Tue, 5 Sep 2006 13:24:10 +0000 (13:24 +0000)
that MAIL FROM:<> is rejected when verifying a recipient using a
non-null MAIL address.

12 files changed:
doc/doc-txt/ChangeLog
src/src/dbstuff.h
src/src/macros.h
src/src/verify.c
src/src/version.c
test/confs/0538 [new file with mode: 0644]
test/log/0538 [new file with mode: 0644]
test/rejectlog/0538 [new file with mode: 0644]
test/runtest
test/scripts/0000-Basic/0538 [new file with mode: 0644]
test/stderr/0376
test/stdout/0538 [new file with mode: 0644]

index 3187570b8964d4a350cc53dbf92d99c54e137ba3..6e70b4f13ba54c81dc48e47b824240f6b1499663 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.386 2006/08/21 11:31:43 fanf2 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.387 2006/09/05 13:24:10 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -11,6 +11,18 @@ TF/01 In the add_headers option to the mail command in an Exim filter,
       header after the first one which had an odd number of characters
       in the field name.
 
       header after the first one which had an odd number of characters
       in the field name.
 
+PH/01 If a server that rejects MAIL FROM:<> was the target of a sender
+      callout verification, Exim cached a "reject" for the entire domain. This
+      is correct for most verifications, but it is not correct for a recipient
+      verification with use_sender or use_postmaster set, because in that case
+      the callout does not use MAIL FROM:<>. Exim now distinguishes the special
+      case of MAIL FROM:<> rejection from other early rejections (e.g.
+      rejection of HELO). When verifying a recipient using a non-null MAIL
+      address, the cache is ignored if it shows MAIL FROM:<> rejection.
+      Whatever the result of the callout, the value of the domain cache is
+      left unchanged (for any other kind of callout, getting as far as trying
+      RCPT means that the domain itself is ok).
+
 
 Exim version 4.63
 -----------------
 
 Exim version 4.63
 -----------------
index 06facfb095b9120a103eff0848c852e1dc886bb3..2b51b0ba8f15fd186cc573f504af6f6f485fea6d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/dbstuff.h,v 1.4 2006/02/07 11:19:00 ph10 Exp $ */
+/* $Cambridge: exim/src/src/dbstuff.h,v 1.5 2006/09/05 13:24:10 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -564,9 +564,11 @@ performed on them. There are two groups of records:
 2. keyed by domain -
      Domain response upto MAIL FROM:<>, postmaster, random local part;
 
 2. keyed by domain -
      Domain response upto MAIL FROM:<>, postmaster, random local part;
 
-If a record exists, the result field is either ccache_accept or ccache_reject.
-The other fields, however, (which are only relevant to domain records) may also
-contain ccache_unknown if that particular test has not been done.
+If a record exists, the result field is either ccache_accept or ccache_reject,
+or, for a domain record only, ccache_reject_mfnull when MAIL FROM:<> was
+rejected. The other fields, however, (which are only relevant to domain
+records) may also contain ccache_unknown if that particular test has not been
+done.
 
 Originally, there was only one structure, used for both types. However, it got
 expanded for domain records, so it got split. To make it possible for Exim to
 
 Originally, there was only one structure, used for both types. However, it got
 expanded for domain records, so it got split. To make it possible for Exim to
index 59c05e6978f5553437501e8384e5c1b07b942679..0b0215bdcde03c7d72f349fac8d0e71e0ba57e89 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/macros.h,v 1.26 2006/06/28 16:00:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/macros.h,v 1.27 2006/09/05 13:24:10 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -626,7 +626,8 @@ enum { v_none, v_sender, v_recipient, v_expn };
 
 #define ccache_unknown         0       /* test hasn't been done */
 #define ccache_accept          1
 
 #define ccache_unknown         0       /* test hasn't been done */
 #define ccache_accept          1
-#define ccache_reject          2
+#define ccache_reject          2       /* All rejections except */
+#define ccache_reject_mfnull   3       /* MAIL FROM:<> was rejected */
 
 /* Options for lookup functions */
 
 
 /* Options for lookup functions */
 
index 841285fdca72364d0ca5b2dac374abebf4b9e956..7833789464a5f575c0fe1cc47325b5a6fbee581e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/verify.c,v 1.37 2006/06/30 15:36:08 ph10 Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.38 2006/09/05 13:24:10 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -148,6 +148,7 @@ BOOL callout_no_cache = (options & vopt_callout_no_cache) != 0;
 BOOL callout_random = (options & vopt_callout_random) != 0;
 
 int yield = OK;
 BOOL callout_random = (options & vopt_callout_random) != 0;
 
 int yield = OK;
+int old_domain_cache_result = ccache_accept;
 BOOL done = FALSE;
 uschar *address_key;
 uschar *from_address;
 BOOL done = FALSE;
 uschar *address_key;
 uschar *from_address;
@@ -228,10 +229,18 @@ if (dbm_file != NULL)
 
   if (cache_record != NULL)
     {
 
   if (cache_record != NULL)
     {
-    /* If an early command (up to and including MAIL FROM:<>) was rejected,
-    there is no point carrying on. The callout fails. */
-
-    if (cache_record->result == ccache_reject)
+    /* In most cases, if an early command (up to and including MAIL FROM:<>)
+    was rejected, there is no point carrying on. The callout fails. However, if
+    we are doing a recipient verification with use_sender or use_postmaster
+    set, a previous failure of MAIL FROM:<> doesn't count, because this time we
+    will be using a non-empty sender. We have to remember this situation so as
+    not to disturb the cached domain value if this whole verification succeeds
+    (we don't want it turning into "accept"). */
+
+    old_domain_cache_result = cache_record->result;
+
+    if (cache_record->result == ccache_reject ||
+         (*from_address == 0 && cache_record->result == ccache_reject_mfnull))
       {
       setflag(addr, af_verify_nsfail);
       HDEBUG(D_verify)
       {
       setflag(addr, af_verify_nsfail);
       HDEBUG(D_verify)
@@ -462,50 +471,73 @@ for (host = host_list; host != NULL && !done; host = host->next)
     continue;
     }
 
     continue;
     }
 
-  /* Wait for initial response, and then run the initial SMTP commands. The
-  smtp_write_command() function leaves its command in big_buffer. This is
-  used in error responses. Initialize it in case the connection is
-  rejected. */
+  /* Wait for initial response, and send HELO. The smtp_write_command()
+  function leaves its command in big_buffer. This is used in error responses.
+  Initialize it in case the connection is rejected. */
 
   Ustrcpy(big_buffer, "initial connection");
 
   done =
     smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
       '2', callout) &&
 
   Ustrcpy(big_buffer, "initial connection");
 
   done =
     smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
       '2', callout) &&
-
     smtp_write_command(&outblock, FALSE, "%s %s\r\n", helo,
       smtp_active_hostname) >= 0 &&
     smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
     smtp_write_command(&outblock, FALSE, "%s %s\r\n", helo,
       smtp_active_hostname) >= 0 &&
     smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
-      '2', callout) &&
+      '2', callout);
 
 
+  /* Failure to accept HELO is cached; this blocks the whole domain for all
+  senders. I/O errors and defer responses are not cached. */
+
+  if (!done)
+    {
+    *failure_ptr = US"mail";     /* At or before MAIL */
+    if (errno == 0 && responsebuffer[0] == '5')
+      {
+      setflag(addr, af_verify_nsfail);
+      new_domain_record.result = ccache_reject;
+      }
+    }
+
+  /* Send the MAIL command */
+
+  else done =
     smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n",
       from_address) >= 0 &&
     smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
       '2', callout);
 
     smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n",
       from_address) >= 0 &&
     smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
       '2', callout);
 
-  /* If the host gave an initial error, or does not accept HELO or MAIL
-  FROM:<>, arrange to cache this information, but don't record anything for an
-  I/O error or a defer. Do not cache rejections when a non-empty sender has
-  been used, because that blocks the whole domain for all senders. */
+  /* If the host does not accept MAIL FROM:<>, arrange to cache this
+  information, but again, don't record anything for an I/O error or a defer. Do
+  not cache rejections of MAIL when a non-empty sender has been used, because
+  that blocks the whole domain for all senders. */
 
   if (!done)
     {
 
   if (!done)
     {
-    *failure_ptr = US"mail";
+    *failure_ptr = US"mail";     /* At or before MAIL */
     if (errno == 0 && responsebuffer[0] == '5')
       {
       setflag(addr, af_verify_nsfail);
     if (errno == 0 && responsebuffer[0] == '5')
       {
       setflag(addr, af_verify_nsfail);
-      if (from_address[0] == 0) new_domain_record.result = ccache_reject;
+      if (from_address[0] == 0)
+        new_domain_record.result = ccache_reject_mfnull;
       }
     }
 
   /* Otherwise, proceed to check a "random" address (if required), then the
   given address, and the postmaster address (if required). Between each check,
   issue RSET, because some servers accept only one recipient after MAIL
       }
     }
 
   /* Otherwise, proceed to check a "random" address (if required), then the
   given address, and the postmaster address (if required). Between each check,
   issue RSET, because some servers accept only one recipient after MAIL
-  FROM:<>. */
+  FROM:<>.
+
+  Before doing this, set the result in the domain cache record to "accept",
+  unless its previous value was ccache_reject_mfnull. In that case, the domain
+  rejects MAIL FROM:<> and we want to continue to remember that. When that is
+  the case, we have got here only in the case of a recipient verification with
+  a non-null sender. */
 
   else
     {
 
   else
     {
-    new_domain_record.result = ccache_accept;
+    new_domain_record.result =
+      (old_domain_cache_result == ccache_reject_mfnull)?
+        ccache_reject_mfnull: ccache_accept;
 
     /* Do the random local part check first */
 
 
     /* Do the random local part check first */
 
@@ -685,7 +717,7 @@ However, there may be domain-specific information to cache in both cases.
 The value of the result field in the new_domain record is ccache_unknown if
 there was an error before or with MAIL FROM:, and errno was not zero,
 implying some kind of I/O error. We don't want to write the cache in that case.
 The value of the result field in the new_domain record is ccache_unknown if
 there was an error before or with MAIL FROM:, and errno was not zero,
 implying some kind of I/O error. We don't want to write the cache in that case.
-Otherwise the value is ccache_accept or ccache_reject. */
+Otherwise the value is ccache_accept, ccache_reject, or ccache_reject_mfnull. */
 
 if (!callout_no_cache && new_domain_record.result != ccache_unknown)
   {
 
 if (!callout_no_cache && new_domain_record.result != ccache_unknown)
   {
index 179ebaa9081b45360c59f2f0895e743b285ee603..e83905eb4276cfa0841547845c2f2956646c97fa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/version.c,v 1.17 2006/06/27 13:39:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/version.c,v 1.18 2006/09/05 13:24:10 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -12,7 +12,7 @@
 #include "exim.h"
 
 
 #include "exim.h"
 
 
-#define THIS_VERSION  "4.63"
+#define THIS_VERSION  "4.64"
 
 
 /* The header file cnumber.h contains a single line containing the
 
 
 /* The header file cnumber.h contains a single line containing the
diff --git a/test/confs/0538 b/test/confs/0538
new file mode 100644 (file)
index 0000000..7f89ccc
--- /dev/null
@@ -0,0 +1,43 @@
+# Exim test configuration 0538
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+rfc1413_query_timeout = 0s
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+acl_smtp_mail = check_mail
+acl_smtp_rcpt = check_rcpt
+
+
+# ----- ACLs -----
+
+begin acl
+
+check_mail:
+  accept  sender_domains = broken.example
+          endpass
+          verify = sender/callout
+  accept
+
+check_rcpt:
+  accept  verify = recipient/callout=use_sender
+
+
+# ----- Routers -----
+
+begin routers
+
+r1:
+  driver = manualroute
+  route_list = * "<= 127.0.0.1:PORT_S"
+  self = send
+  verify_only
+
+
+# End
diff --git a/test/log/0538 b/test/log/0538
new file mode 100644 (file)
index 0000000..8b63bdb
--- /dev/null
@@ -0,0 +1,4 @@
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userx@broken.example>: response to "MAIL FROM:<>" from 127.0.0.1 [127.0.0.1] was: 550 I'm misconfigured
+1999-03-02 09:44:33 U=CALLER rejected MAIL <userx@broken.example>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userx@broken.example>
+1999-03-02 09:44:33 U=CALLER rejected MAIL <userx@broken.example>: Sender verify failed
diff --git a/test/rejectlog/0538 b/test/rejectlog/0538
new file mode 100644 (file)
index 0000000..8b63bdb
--- /dev/null
@@ -0,0 +1,4 @@
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userx@broken.example>: response to "MAIL FROM:<>" from 127.0.0.1 [127.0.0.1] was: 550 I'm misconfigured
+1999-03-02 09:44:33 U=CALLER rejected MAIL <userx@broken.example>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userx@broken.example>
+1999-03-02 09:44:33 U=CALLER rejected MAIL <userx@broken.example>: Sender verify failed
index 992f02915945640046018374e0b829d121a894fc..66a0197b94dc6e1a1a150b504d09c8db322dacdf 100755 (executable)
@@ -1,6 +1,6 @@
 #! /usr/bin/perl -w
 
 #! /usr/bin/perl -w
 
-# $Cambridge: exim/test/runtest,v 1.13 2006/07/26 14:39:13 ph10 Exp $
+# $Cambridge: exim/test/runtest,v 1.14 2006/09/05 13:24:10 ph10 Exp $
 
 ###############################################################################
 # This is the controlling script for the "new" test suite for Exim. It should #
 
 ###############################################################################
 # This is the controlling script for the "new" test suite for Exim. It should #
@@ -23,7 +23,7 @@ use Socket;
 
 # Start by initializing some global variables
 
 
 # Start by initializing some global variables
 
-$testversion = "4.63 (24-Jul-06)";
+$testversion = "4.64 (05-Sep-06)";
 
 $cf = "bin/cf";
 $cr = "\r";
 
 $cf = "bin/cf";
 $cr = "\r";
diff --git a/test/scripts/0000-Basic/0538 b/test/scripts/0000-Basic/0538
new file mode 100644 (file)
index 0000000..c464f3b
--- /dev/null
@@ -0,0 +1,39 @@
+# callout for recipient/use_sender after mail from:<> rejection
+need_ipv4
+#
+# Do a sender address verify that rejects MAIL FROM:<>
+server PORT_S
+220 Welcome
+HELO
+250 Hi
+MAIL FROM
+550 I'm misconfigured
+QUIT
+221 Bye
+****
+exim -bs
+mail from:<userx@broken.example>
+quit
+****
+# Now do a recipient verify for the same domain, with use_sender
+server PORT_S
+220 Welcome
+HELO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+221 Bye
+****
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery@broken.example>
+quit
+****
+# A final check that the cache works for sender address
+exim -bs
+mail from:<userx@broken.example>
+quit
+****
index f5155322096631ed9ec5518cd8d75f0b1644574e..3a63675780b15a84e8a75cb22c2a32f6ad84b1e5 100644 (file)
@@ -143,7 +143,7 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
   SMTP<< 550 REJECT MAIL FROM
   SMTP>> QUIT
 wrote callout cache domain record:
   SMTP<< 550 REJECT MAIL FROM
   SMTP>> QUIT
 wrote callout cache domain record:
-  result=2 postmaster=0 random=0
+  result=3 postmaster=0 random=0
 LOG: MAIN REJECT
   H=[V4NET.0.0.1] U=root sender verify fail for <ok@localhost>: response to "MAIL FROM:<>" from 127.0.0.1 [127.0.0.1] was: 550 REJECT MAIL FROM
 LOG: MAIN REJECT
 LOG: MAIN REJECT
   H=[V4NET.0.0.1] U=root sender verify fail for <ok@localhost>: response to "MAIL FROM:<>" from 127.0.0.1 [127.0.0.1] was: 550 REJECT MAIL FROM
 LOG: MAIN REJECT
diff --git a/test/stdout/0538 b/test/stdout/0538
new file mode 100644 (file)
index 0000000..c7bd592
--- /dev/null
@@ -0,0 +1,50 @@
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+550-Callback setup failed while verifying <userx@broken.example>\r
+550-Called:   127.0.0.1\r
+550-Sent:     MAIL FROM:<>\r
+550-Response: 550 I'm misconfigured\r
+550-The initial connection, or a HELO or MAIL FROM:<> command was\r
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards\r
+550-RFC requirements, and stops you from receiving standard bounce\r
+550-messages. This host does not accept mail from domains whose servers\r
+550-refuse bounces.\r
+550 Sender verify failed\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250 OK\r
+250 Accepted\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+550-Callback setup failed while verifying <userx@broken.example>\r
+550-(result of an earlier callout reused).\r
+550-The initial connection, or a HELO or MAIL FROM:<> command was\r
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards\r
+550-RFC requirements, and stops you from receiving standard bounce\r
+550-messages. This host does not accept mail from domains whose servers\r
+550-refuse bounces.\r
+550 Sender verify failed\r
+221 myhost.test.ex closing connection\r
+
+******** SERVER ********
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Welcome
+HELO myhost.test.ex
+250 Hi
+MAIL FROM:<>
+550 I'm misconfigured
+QUIT
+221 Bye
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Welcome
+HELO myhost.test.ex
+250 Hi
+MAIL FROM:<userx@ok.example>
+250 OK
+RCPT TO:<usery@broken.example>
+250 OK
+QUIT
+221 Bye
+End of script