summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Hazel <ph10@hermes.cam.ac.uk>2007-03-21 15:10:39 +0000
committerPhilip Hazel <ph10@hermes.cam.ac.uk>2007-03-21 15:10:39 +0000
commit2679d413f3f22e7bbc797f4403cc4333bee0073d (patch)
tree9e9cc16843c4d74c53ed84710e78faa6893e9b7b
parentebeaf99687d0fd6545c95983f0d91e2ddee7fbb7 (diff)
Add RCPT error text to unexpected DATA error.
-rw-r--r--doc/doc-txt/ChangeLog10
-rw-r--r--src/src/smtp_in.c99
-rw-r--r--test/confs/055826
-rw-r--r--test/log/05586
-rw-r--r--test/rejectlog/05586
-rw-r--r--test/scripts/0000-Basic/045814
-rw-r--r--test/scripts/0000-Basic/055819
-rw-r--r--test/stdout/00912
-rw-r--r--test/stdout/01395
-rw-r--r--test/stdout/01754
-rw-r--r--test/stdout/03952
-rw-r--r--test/stdout/045834
-rw-r--r--test/stdout/055830
13 files changed, 231 insertions, 26 deletions
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index bbaa500dc..a34126472 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.496 2007/03/14 12:15:56 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.497 2007/03/21 15:10:39 ph10 Exp $
Change log file for Exim from version 4.21
-------------------------------------------
@@ -182,6 +182,14 @@ PH/40 When Exim receives a message, it writes the login name, uid, and gid of
calls itself on a restart). I have changed the code so that it now always
uses the Exim user.
+PH/41 (Following a suggestion from Tony Finch) If all the RCPT commands in a
+ message are rejected with the same error (e.g. no authentication or bad
+ sender address), and a DATA command is nevertheless sent (as can happen
+ with PIPELINING or a stupid MUA), the error message that was given to the
+ RCPT commands is included in the rejection of the DATA command. This is
+ intended to be helpful for MUAs that show only the final error to their
+ users.
+
Exim version 4.66
-----------------
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index d30d28280..bdac07be7 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/smtp_in.c,v 1.55 2007/02/20 15:58:02 ph10 Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.56 2007/03/21 15:10:39 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -120,12 +120,15 @@ static BOOL helo_seen;
static BOOL helo_accept_junk;
static BOOL count_nonmail;
static BOOL pipelining_advertised;
+static BOOL rcpt_smtp_response_same;
+static BOOL rcpt_in_progress;
static int nonmail_command_count;
static int synprot_error_count;
static int unknown_command_count;
static int sync_cmd_limit;
static int smtp_write_error = 0;
+static uschar *rcpt_smtp_response;
static uschar *smtp_data_buffer;
static uschar *smtp_cmd_data;
@@ -368,28 +371,41 @@ DEBUG(D_receive)
}
va_start(ap, format);
+if (!string_vformat(big_buffer, big_buffer_size, format, ap))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_printf()");
+ smtp_closedown(US"Unexpected error");
+ exim_exit(EXIT_FAILURE);
+ }
+va_end(ap);
+
+/* If this is the first output for a (non-batch) RCPT command, see if all RCPTs
+have had the same. Note: this code is also present in smtp_respond(). It would
+be tidier to have it only in one place, but when it was added, it was easier to
+do it that way, so as not to have to mess with the code for the RCPT command,
+which sometimes uses smtp_printf() and sometimes smtp_respond(). */
+
+if (rcpt_in_progress)
+ {
+ if (rcpt_smtp_response == NULL)
+ rcpt_smtp_response = string_copy(big_buffer);
+ else if (rcpt_smtp_response_same &&
+ Ustrcmp(rcpt_smtp_response, big_buffer) != 0)
+ rcpt_smtp_response_same = FALSE;
+ rcpt_in_progress = FALSE;
+ }
-/* If in a TLS session we have to format the string, and then write it using a
-TLS function. */
+/* Now write the string */
#ifdef SUPPORT_TLS
if (tls_active >= 0)
{
- if (!string_vformat(big_buffer, big_buffer_size, format, ap))
- {
- log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_printf");
- smtp_closedown(US"Unexpected error");
- exim_exit(EXIT_FAILURE);
- }
if (tls_write(big_buffer, Ustrlen(big_buffer)) < 0) smtp_write_error = -1;
}
else
#endif
-/* Otherwise, just use the standard library function. */
-
-if (vfprintf(smtp_out, format, ap) < 0) smtp_write_error = -1;
-va_end(ap);
+if (fprintf(smtp_out, "%s", big_buffer) < 0) smtp_write_error = -1;
}
@@ -961,6 +977,9 @@ message_linecount = 0;
message_size = -1;
acl_added_headers = NULL;
queue_only_policy = FALSE;
+rcpt_smtp_response = NULL;
+rcpt_smtp_response_same = TRUE;
+rcpt_in_progress = FALSE;
deliver_freeze = FALSE; /* Can be set by ACL */
freeze_tell = freeze_tell_config; /* Can be set by ACL */
fake_response = OK; /* Can be set by ACL */
@@ -1954,6 +1973,24 @@ if (codelen > 4)
esclen = codelen - 4;
}
+/* If this is the first output for a (non-batch) RCPT command, see if all RCPTs
+have had the same. Note: this code is also present in smtp_printf(). It would
+be tidier to have it only in one place, but when it was added, it was easier to
+do it that way, so as not to have to mess with the code for the RCPT command,
+which sometimes uses smtp_printf() and sometimes smtp_respond(). */
+
+if (rcpt_in_progress)
+ {
+ if (rcpt_smtp_response == NULL)
+ rcpt_smtp_response = string_copy(msg);
+ else if (rcpt_smtp_response_same &&
+ Ustrcmp(rcpt_smtp_response, msg) != 0)
+ rcpt_smtp_response_same = FALSE;
+ rcpt_in_progress = FALSE;
+ }
+
+/* Not output the message, splitting it up into multiple lines if necessary. */
+
for (;;)
{
uschar *nl = Ustrchr(msg, '\n');
@@ -2123,6 +2160,9 @@ unless the sender_verify_fail log selector has been turned off. */
if (sender_verified_failed != NULL &&
!testflag(sender_verified_failed, af_sverify_told))
{
+ BOOL save_rcpt_in_progress = rcpt_in_progress;
+ rcpt_in_progress = FALSE; /* So as not to treat these as the error */
+
setflag(sender_verified_failed, af_sverify_told);
if (rc != FAIL || (log_extra_selector & LX_sender_verify_fail) != 0)
@@ -2152,6 +2192,8 @@ if (sender_verified_failed != NULL &&
"Verification failed for <%s>\n%s",
sender_verified_failed->address,
sender_verified_failed->user_message));
+
+ rcpt_in_progress = save_rcpt_in_progress;
}
/* Sort out text for logging */
@@ -3304,17 +3346,15 @@ while (done <= 0)
break;
- /* The RCPT command requires an address as an operand. All we do
- here is to parse it for syntactic correctness. There may be any number
- of RCPT commands, specifying multiple senders. We build them all into
- a data structure that is in argc/argv format. The start/end values
- given by parse_extract_address are not used, as we keep only the
- extracted address. */
+ /* The RCPT command requires an address as an operand. There may be any
+ number of RCPT commands, specifying multiple recipients. We build them all
+ into a data structure. The start/end values given by parse_extract_address
+ are not used, as we keep only the extracted address. */
case RCPT_CMD:
HAD(SCH_RCPT);
rcpt_count++;
- was_rcpt = TRUE;
+ was_rcpt = rcpt_in_progress = TRUE;
/* There must be a sender address; if the sender was rejected and
pipelining was advertised, we assume the client was pipelining, and do not
@@ -3504,14 +3544,29 @@ while (done <= 0)
DATA command.
The example in the pipelining RFC 2920 uses 554, but I use 503 here
- because it is the same whether pipelining is in use or not. */
+ because it is the same whether pipelining is in use or not.
+
+ If all the RCPT commands that precede DATA provoked the same error message
+ (often indicating some kind of system error), it is helpful to include it
+ with the DATA rejection (an idea suggested by Tony Finch). */
case DATA_CMD:
HAD(SCH_DATA);
if (!discarded && recipients_count <= 0)
{
+ if (rcpt_smtp_response_same && rcpt_smtp_response != NULL)
+ {
+ uschar *code = US"503";
+ int len = Ustrlen(rcpt_smtp_response);
+ smtp_respond(code, 3, FALSE, US"All RCPT commands were rejected with "
+ "this error:");
+ /* Responses from smtp_printf() will have \r\n on the end */
+ if (len > 2 && rcpt_smtp_response[len-2] == '\r')
+ rcpt_smtp_response[len-2] = 0;
+ smtp_respond(code, 3, FALSE, rcpt_smtp_response);
+ }
if (pipelining_advertised && last_was_rcpt)
- smtp_printf("503 valid RCPT command must precede DATA\r\n");
+ smtp_printf("503 Valid RCPT command must precede DATA\r\n");
else
done = synprot_error(L_smtp_protocol_error, 503, NULL,
US"valid RCPT command must precede DATA");
diff --git a/test/confs/0558 b/test/confs/0558
new file mode 100644
index 000000000..18fe64990
--- /dev/null
+++ b/test/confs/0558
@@ -0,0 +1,26 @@
+# Exim test configuration 0558
+
+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_rcpt = a1
+
+
+# ----- ACLs -----
+
+begin acl
+
+a1:
+ deny message = Special deny message
+ local_parts = ^special
+ deny message = Default deny message\non two lines
+
+# End
diff --git a/test/log/0558 b/test/log/0558
new file mode 100644
index 000000000..3f5f92a55
--- /dev/null
+++ b/test/log/0558
@@ -0,0 +1,6 @@
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userx@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <usery@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userz@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userx@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <specialusery@test.ex>: Special deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userz@test.ex>: Default deny message
diff --git a/test/rejectlog/0558 b/test/rejectlog/0558
new file mode 100644
index 000000000..3f5f92a55
--- /dev/null
+++ b/test/rejectlog/0558
@@ -0,0 +1,6 @@
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userx@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <usery@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userz@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userx@test.ex>: Default deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <specialusery@test.ex>: Special deny message
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <userz@test.ex>: Default deny message
diff --git a/test/scripts/0000-Basic/0458 b/test/scripts/0000-Basic/0458
index c05b4b6ff..d31709e58 100644
--- a/test/scripts/0000-Basic/0458
+++ b/test/scripts/0000-Basic/0458
@@ -16,6 +16,8 @@ rcpt to:<userx@test.ex>
??? 550
DATA
??? 503
+??? 503
+??? 503
QUIT
??? 221
****
@@ -29,6 +31,8 @@ rcpt to:<userx@test.ex>
??? 550
DATA
??? 503
+??? 503
+??? 503
QUIT
??? 221
****
@@ -45,6 +49,8 @@ rcpt to:<userx@test.ex>
??? 503
DATA
??? 503
+??? 503
+??? 503
QUIT
??? 221
****
@@ -58,6 +64,8 @@ rcpt to:<userx@test.ex>
??? 503
DATA
??? 503
+??? 503
+??? 503
QUIT
??? 221
****
@@ -78,6 +86,8 @@ rcpt to:<ph12@test.ex>
??? 550
DATA
??? 503
+??? 503
+??? 503
QUIT
??? 221
****
@@ -95,6 +105,8 @@ rcpt to:<ph12@test.ex>
??? 550
DATA
??? 503
+??? 503
+??? 503
QUIT
??? 221
****
@@ -109,6 +121,8 @@ rcpt to:<userx@test.ex>
??? 503
DATA
??? 503
+??? 503
+??? 503
QUIT
??? 221
****
diff --git a/test/scripts/0000-Basic/0558 b/test/scripts/0000-Basic/0558
new file mode 100644
index 000000000..c6aaf7dd4
--- /dev/null
+++ b/test/scripts/0000-Basic/0558
@@ -0,0 +1,19 @@
+# DATA error after identical RCPT failures
+exim -bs
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+rcpt to:<usery@test.ex>
+rcpt to:<userz@test.ex>
+data
+quit
+****
+exim -bs
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+rcpt to:<specialusery@test.ex>
+rcpt to:<userz@test.ex>
+data
+quit
+****
diff --git a/test/stdout/0091 b/test/stdout/0091
index 10cf780a9..809bad067 100644
--- a/test/stdout/0091
+++ b/test/stdout/0091
@@ -19,6 +19,8 @@
550-Verification failed for <junk@jink.jonk.test.ex>
550-Unrouteable address
550 Sender verify failed
+503-All RCPT commands were rejected with this error:
+503-Sender verify failed
503 valid RCPT command must precede DATA
500 unrecognized command
221 myhost.test.ex closing connection
diff --git a/test/stdout/0139 b/test/stdout/0139
index 3736dd4fd..e19fbb74a 100644
--- a/test/stdout/0139
+++ b/test/stdout/0139
@@ -24,6 +24,11 @@
550-This is a very long blacklisting message, continuing for ages and ages and
550-certainly being longer than 128 characters which was a previous limit on
550 the length that Exim was prepared to handle.
+503-All RCPT commands were rejected with this error:
+503-host is listed in rbl3.test.ex with value 127.0.0.3
+503-This is a very long blacklisting message, continuing for ages and ages and
+503-certainly being longer than 128 characters which was a previous limit on
+503-the length that Exim was prepared to handle.
503 valid RCPT command must precede DATA
500 unrecognized command
500 unrecognized command
diff --git a/test/stdout/0175 b/test/stdout/0175
index 92280840f..10cb2c731 100644
--- a/test/stdout/0175
+++ b/test/stdout/0175
@@ -6,6 +6,8 @@
220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
550 Sender verify failed
+503-All RCPT commands were rejected with this error:
+503-Sender verify failed
503 valid RCPT command must precede DATA
500 unrecognized command
221 the.local.host.name closing connection
@@ -17,6 +19,8 @@
220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
550 Sender verify failed
+503-All RCPT commands were rejected with this error:
+503-Sender verify failed
503 valid RCPT command must precede DATA
500 unrecognized command
221 the.local.host.name closing connection
diff --git a/test/stdout/0395 b/test/stdout/0395
index 03eedb7cf..21f34430a 100644
--- a/test/stdout/0395
+++ b/test/stdout/0395
@@ -9,6 +9,8 @@ rcpt to: userx
220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
501 userx: recipient address must contain a domain
+503-All RCPT commands were rejected with this error:
+503-501 userx: recipient address must contain a domain
503 valid RCPT command must precede DATA
500 unrecognized command
500 unrecognized command
diff --git a/test/stdout/0458 b/test/stdout/0458
index b9b54b4db..8bf719501 100644
--- a/test/stdout/0458
+++ b/test/stdout/0458
@@ -18,7 +18,11 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 550 Administrative prohibition
>>> DATA
??? 503
-<<< 503 valid RCPT command must precede DATA
+<<< 503-All RCPT commands were rejected with this error:
+??? 503
+<<< 503-Administrative prohibition
+??? 503
+<<< 503 Valid RCPT command must precede DATA
>>> QUIT
??? 221
<<< 221 myhost.test.ex closing connection
@@ -37,6 +41,10 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 550 Administrative prohibition
>>> DATA
??? 503
+<<< 503-All RCPT commands were rejected with this error:
+??? 503
+<<< 503-Administrative prohibition
+??? 503
<<< 503 valid RCPT command must precede DATA
>>> QUIT
??? 221
@@ -62,7 +70,11 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 503 sender not yet given
>>> DATA
??? 503
-<<< 503 valid RCPT command must precede DATA
+<<< 503-All RCPT commands were rejected with this error:
+??? 503
+<<< 503-503 sender not yet given
+??? 503
+<<< 503 Valid RCPT command must precede DATA
>>> QUIT
??? 221
<<< 221 myhost.test.ex closing connection
@@ -81,6 +93,10 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 503 sender not yet given
>>> DATA
??? 503
+<<< 503-All RCPT commands were rejected with this error:
+??? 503
+<<< 503-503 sender not yet given
+??? 503
<<< 503 valid RCPT command must precede DATA
>>> QUIT
??? 221
@@ -112,7 +128,11 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 550 Administrative prohibition
>>> DATA
??? 503
-<<< 503 valid RCPT command must precede DATA
+<<< 503-All RCPT commands were rejected with this error:
+??? 503
+<<< 503-Administrative prohibition
+??? 503
+<<< 503 Valid RCPT command must precede DATA
>>> QUIT
??? 221
<<< 221 myhost.test.ex closing connection
@@ -137,6 +157,10 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 550 Administrative prohibition
>>> DATA
??? 503
+<<< 503-All RCPT commands were rejected with this error:
+??? 503
+<<< 503-Administrative prohibition
+??? 503
<<< 503 valid RCPT command must precede DATA
>>> QUIT
??? 221
@@ -159,6 +183,10 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 503 sender not yet given
>>> DATA
??? 503
+<<< 503-All RCPT commands were rejected with this error:
+??? 503
+<<< 503-503 sender not yet given
+??? 503
<<< 503 valid RCPT command must precede DATA
>>> QUIT
??? 221
diff --git a/test/stdout/0558 b/test/stdout/0558
new file mode 100644
index 000000000..aa3c21c74
--- /dev/null
+++ b/test/stdout/0558
@@ -0,0 +1,30 @@
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.ex
+250-SIZE 52428800
+250-PIPELINING
+250 HELP
+250 OK
+550-Default deny message
+550 on two lines
+550-Default deny message
+550 on two lines
+550-Default deny message
+550 on two lines
+503-All RCPT commands were rejected with this error:
+503-Default deny message
+503-on two lines
+503 Valid RCPT command must precede DATA
+221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.ex
+250-SIZE 52428800
+250-PIPELINING
+250 HELP
+250 OK
+550-Default deny message
+550 on two lines
+550 Special deny message
+550-Default deny message
+550 on two lines
+503 Valid RCPT command must precede DATA
+221 myhost.test.ex closing connection