summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilip Hazel <ph10@hermes.cam.ac.uk>2006-07-13 13:53:32 +0000
committerPhilip Hazel <ph10@hermes.cam.ac.uk>2006-07-13 13:53:32 +0000
commita5bd321b2f16ff323e3e268d59606e89b747a901 (patch)
tree1808bda34b675ef151fda9d89599bd05c9ad942e /src
parent41609df58fdd3fe023b91baece7d18a595f57e56 (diff)
Add recognition of SMTP error codes in bespoke messages.
Diffstat (limited to 'src')
-rw-r--r--src/README.UPDATING18
-rw-r--r--src/src/exim.c9
-rw-r--r--src/src/functions.h4
-rw-r--r--src/src/globals.c35
-rw-r--r--src/src/globals.h5
-rw-r--r--src/src/receive.c22
-rw-r--r--src/src/routers/redirect.c32
-rw-r--r--src/src/routers/redirect.h3
-rw-r--r--src/src/smtp_in.c92
9 files changed, 158 insertions, 62 deletions
diff --git a/src/README.UPDATING b/src/README.UPDATING
index 05f89f40e..e4975ba6a 100644
--- a/src/README.UPDATING
+++ b/src/README.UPDATING
@@ -1,4 +1,4 @@
-$Cambridge: exim/src/README.UPDATING,v 1.11 2006/02/20 16:31:49 ph10 Exp $
+$Cambridge: exim/src/README.UPDATING,v 1.12 2006/07/13 13:53:33 ph10 Exp $
This document contains detailed information about incompatibilities that might
be encountered when upgrading from one release of Exim to another. The
@@ -28,6 +28,22 @@ The rest of this document contains information about changes in 4.xx releases
that might affect a running system.
+Exim version 4.63
+-----------------
+
+When an SMTP error message is specified in a "message" modifier in an ACL, or
+in a :fail: or :defer: message in a redirect router, Exim now checks the start
+of the message for an SMTP error code. This consists of three digits followed
+by a space, optionally followed by an extended code of the form n.n.n, also
+followed by a space. If this is the case and the very first digit is the same
+as the default error code, the code from the message is used instead. If the
+very first digit is incorrect, a panic error is logged, and the default code is
+used. This is an incompatible change, but it is not expected to affect many (if
+any) configurations. It is possible to suppress the use of the supplied code in
+a redirect router by setting the smtp_error_code option false. In this case,
+any SMTP code is quietly ignored.
+
+
Exim version 4.61
-----------------
diff --git a/src/src/exim.c b/src/src/exim.c
index a40ded77e..3ac7d8313 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.c,v 1.40 2006/06/28 16:00:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim.c,v 1.41 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -1492,6 +1492,13 @@ using mac_ismsgid, which uses this. */
regex_ismsgid =
regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", FALSE, TRUE);
+/* Precompile the regular expression that is used for matching an SMTP error
+code, possibly extended, at the start of an error message. */
+
+regex_smtp_code =
+ regex_must_compile(US"^\\d\\d\\d\\s(?:\\d\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\s)?",
+ FALSE, TRUE);
+
/* If the program is called as "mailq" treat it as equivalent to "exim -bp";
this seems to be a generally accepted convention, since one finds symbolic
links called "mailq" in standard OS configurations. */
diff --git a/src/src/functions.h b/src/src/functions.h
index 2728d79f1..32b3d2d24 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/functions.h,v 1.24 2006/03/08 11:13:07 ph10 Exp $ */
+/* $Cambridge: exim/src/src/functions.h,v 1.25 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -266,7 +266,7 @@ extern BOOL smtp_get_port(uschar *, address_item *, int *, uschar *);
extern int smtp_getc(void);
extern int smtp_handle_acl_fail(int, int, uschar *, uschar *);
extern BOOL smtp_read_response(smtp_inblock *, uschar *, int, int, int);
-extern void smtp_respond(int, BOOL, uschar *);
+extern void smtp_respond(uschar *, int, BOOL, uschar *);
extern void smtp_send_prohibition_message(int, uschar *);
extern int smtp_setup_msg(void);
extern BOOL smtp_start_session(void);
diff --git a/src/src/globals.c b/src/src/globals.c
index 4455f384e..2a6aba592 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.c,v 1.54 2006/06/28 16:00:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.c,v 1.55 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -211,22 +211,22 @@ uschar *acl_wherenames[] = { US"RCPT",
US"VRFY"
};
-int acl_wherecodes[] = { 550, /* RCPT */
- 550, /* MAIL */
- 550, /* PREDATA */
- 550, /* MIME */
- 550, /* DATA */
- 0, /* not SMTP; not relevant */
- 503, /* AUTH */
- 550, /* connect */
- 458, /* ETRN */
- 550, /* EXPN */
- 550, /* HELO/EHLO */
- 0, /* MAILAUTH; not relevant */
- 0, /* not SMTP; not relevant */
- 0, /* QUIT; not relevant */
- 550, /* STARTTLS */
- 252 /* VRFY */
+uschar *acl_wherecodes[] = { US"550", /* RCPT */
+ US"550", /* MAIL */
+ US"550", /* PREDATA */
+ US"550", /* MIME */
+ US"550", /* DATA */
+ US"0", /* not SMTP; not relevant */
+ US"503", /* AUTH */
+ US"550", /* connect */
+ US"458", /* ETRN */
+ US"550", /* EXPN */
+ US"550", /* HELO/EHLO */
+ US"0", /* MAILAUTH; not relevant */
+ US"0", /* not SMTP; not relevant */
+ US"0", /* QUIT; not relevant */
+ US"550", /* STARTTLS */
+ US"252" /* VRFY */
};
BOOL active_local_from_check = FALSE;
@@ -866,6 +866,7 @@ const pcre *regex_From = NULL;
const pcre *regex_IGNOREQUOTA = NULL;
const pcre *regex_PIPELINING = NULL;
const pcre *regex_SIZE = NULL;
+const pcre *regex_smtp_code = NULL;
const pcre *regex_ismsgid = NULL;
#ifdef WITH_CONTENT_SCAN
uschar *regex_match_string = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index 53272ceef..a235869c1 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.h,v 1.38 2006/06/28 16:00:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.h,v 1.39 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -131,7 +131,7 @@ extern BOOL acl_temp_details; /* TRUE to give details for 4xx error */
extern uschar *acl_var[ACL_CVARS+ACL_MVARS]; /* User ACL variables */
extern uschar *acl_verify_message; /* User message for verify failure */
extern string_item *acl_warn_logged; /* Logged lines */
-extern int acl_wherecodes[]; /* Response codes for ACL fails */
+extern uschar *acl_wherecodes[]; /* Response codes for ACL fails */
extern uschar *acl_wherenames[]; /* Names for messages */
extern BOOL active_local_from_check;/* For adding Sender: (switchable) */
extern BOOL active_local_sender_retain; /* For keeping Sender: (switchable) */
@@ -556,6 +556,7 @@ extern const pcre *regex_From; /* For recognizing "From_" lines */
extern const pcre *regex_IGNOREQUOTA; /* For recognizing IGNOREQUOTA (LMTP) */
extern const pcre *regex_PIPELINING; /* For recognizing PIPELINING */
extern const pcre *regex_SIZE; /* For recognizing SIZE settings */
+extern const pcre *regex_smtp_code; /* For recognizing SMTP codes */
extern const pcre *regex_ismsgid; /* Compiled r.e. for message it */
#ifdef WITH_CONTENT_SCAN
extern uschar *regex_match_string; /* regex that matched a line (regex ACL condition) */
diff --git a/src/src/receive.c b/src/src/receive.c
index f711e9ca8..3f430f1aa 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/receive.c,v 1.27 2006/03/06 16:05:12 ph10 Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.28 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -1067,7 +1067,7 @@ if (mbox_file == NULL) {
"acl_smtp_mime: error while creating mbox spool file, message temporarily rejected.");
Uunlink(spool_name);
unspool_mbox();
- smtp_respond(451, TRUE, US"temporary local problem");
+ smtp_respond(US"451", 3, TRUE, US"temporary local problem");
message_id[0] = 0; /* Indicate no message accepted */
*smtp_reply_ptr = US""; /* Indicate reply already sent */
return FALSE; /* Indicate skip to end of receive function */
@@ -3110,9 +3110,9 @@ else
{
uschar *istemp = US"";
uschar *s = NULL;
+ uschar *smtp_code;
int size = 0;
int sptr = 0;
- int code;
errmsg = local_scan_data;
@@ -3129,7 +3129,7 @@ else
/* Fall through */
case LOCAL_SCAN_REJECT:
- code = 550;
+ smtp_code = US"550";
if (errmsg == NULL) errmsg = US"Administrative prohibition";
break;
@@ -3139,7 +3139,7 @@ else
case LOCAL_SCAN_TEMPREJECT:
TEMPREJECT:
- code = 451;
+ smtp_code = US"451";
if (errmsg == NULL) errmsg = US"Temporary local problem";
istemp = US"temporarily ";
break;
@@ -3157,14 +3157,14 @@ else
{
if (!smtp_batched_input)
{
- smtp_respond(code, TRUE, errmsg);
+ smtp_respond(smtp_code, 3, TRUE, errmsg);
message_id[0] = 0; /* Indicate no message accepted */
smtp_reply = US""; /* Indicate reply already sent */
goto TIDYUP; /* Skip to end of function */
}
else
{
- moan_smtp_batch(NULL, "%d %s", code, errmsg);
+ moan_smtp_batch(NULL, "%s %s", smtp_code, errmsg);
/* Does not return */
}
}
@@ -3483,8 +3483,8 @@ if (smtp_input)
if (smtp_reply == NULL)
{
if (fake_response != OK)
- smtp_respond(fake_response == DEFER ? 450 : 550,
- TRUE, fake_response_text);
+ smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
+ fake_response_text);
else
smtp_printf("250 OK id=%s\r\n", message_id);
if (host_checking)
@@ -3494,8 +3494,8 @@ if (smtp_input)
else if (smtp_reply[0] != 0)
{
if (fake_response != OK && (smtp_reply[0] == '2'))
- smtp_respond(fake_response == DEFER ? 450 : 550,
- TRUE, fake_response_text);
+ smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
+ fake_response_text);
else
smtp_printf("%.1024s\r\n", smtp_reply);
}
diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c
index d94240ebc..2a9d5e3b2 100644
--- a/src/src/routers/redirect.c
+++ b/src/src/routers/redirect.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/routers/redirect.c,v 1.16 2006/06/27 14:34:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/redirect.c,v 1.17 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -71,6 +71,8 @@ optionlist redirect_router_options[] = {
(void *)offsetof(redirect_router_options_block, forbid_pipe) },
{ "forbid_sieve_filter",opt_bit | (RDON_SIEVE_FILTER << 16),
(void *)offsetof(redirect_router_options_block, bit_options) },
+ { "forbid_smtp_code", opt_bool,
+ (void *)offsetof(redirect_router_options_block, forbid_smtp_code) },
{ "hide_child_in_errmsg", opt_bool,
(void *)offsetof(redirect_router_options_block, hide_child_in_errmsg) },
{ "ignore_eacces", opt_bit | (RDON_EACCES << 16),
@@ -169,6 +171,7 @@ redirect_router_options_block redirect_router_option_defaults = {
FALSE, /* forbid_file */
FALSE, /* forbid_filter_reply */
FALSE, /* forbid_pipe */
+ FALSE, /* forbid_smtp_code */
FALSE, /* hide_child_in_errmsg */
FALSE, /* one_time */
FALSE, /* qualify_preserve_domain */
@@ -711,26 +714,39 @@ switch (frc)
break;
/* FF_DEFER and FF_FAIL can arise only as a result of explicit commands
- (:fail: in an alias file or "fail" in a filter). If a configured message was
- supplied, allow it to be included in an SMTP response after verifying. */
+ (:defer: or :fail: in an alias file or "fail" in a filter). If a configured
+ message was supplied, allow it to be included in an SMTP response after
+ verifying. Remove any SMTP code if it is not allowed. */
case FF_DEFER:
- if (addr->message == NULL) addr->message = US"forced defer";
- else addr->user_message = addr->message;
- return DEFER;
+ yield = DEFER;
+ goto SORT_MESSAGE;
case FF_FAIL:
if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
return xrc;
add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
+ yield = FAIL;
+
+ SORT_MESSAGE:
if (addr->message == NULL)
- addr->message = US"forced rejection";
+ addr->message = (yield == FAIL)? US"forced rejection" : US"forced defer";
else
{
+ int ovector[3];
+ if (ob->forbid_smtp_code &&
+ pcre_exec(regex_smtp_code, NULL, CS addr->message,
+ Ustrlen(addr->message), 0, PCRE_EOPT,
+ ovector, sizeof(ovector)/sizeof(int)) >= 0)
+ {
+ DEBUG(D_route) debug_printf("SMTP code at start of error message "
+ "is ignored because forbid_smtp_code is set\n");
+ addr->message += ovector[1];
+ }
addr->user_message = addr->message;
setflag(addr, af_pass_message);
}
- return FAIL;
+ return yield;
/* As in the case of a system filter, a freeze does not happen after a manual
thaw. In case deliveries were set up by the filter, we set the child count
diff --git a/src/src/routers/redirect.h b/src/src/routers/redirect.h
index 996f0b003..6825430fd 100644
--- a/src/src/routers/redirect.h
+++ b/src/src/routers/redirect.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/routers/redirect.h,v 1.7 2006/02/07 11:19:02 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/redirect.h,v 1.8 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -51,6 +51,7 @@ typedef struct {
BOOL forbid_file;
BOOL forbid_filter_reply;
BOOL forbid_pipe;
+ BOOL forbid_smtp_code;
BOOL hide_child_in_errmsg;
BOOL one_time;
BOOL qualify_preserve_domain;
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 99ac3fb1a..881bfff58 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.38 2006/04/19 10:58:21 ph10 Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.39 2006/07/13 13:53:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -1767,7 +1767,8 @@ responses. If no_multiline_responses is TRUE (it can be set from an ACL), we
output nothing for non-final calls, and only the first line for anything else.
Arguments:
- code SMTP code
+ code SMTP code, may involve extended status codes
+ codelen length of smtp code; uf > 3 there's an ESC
final FALSE if the last line isn't the final line
msg message text, possibly containing newlines
@@ -1775,26 +1776,36 @@ Returns: nothing
*/
void
-smtp_respond(int code, BOOL final, uschar *msg)
+smtp_respond(uschar* code, int codelen, BOOL final, uschar *msg)
{
+int esclen = 0;
+uschar *esc = US"";
+
if (!final && no_multiline_responses) return;
+if (codelen > 3)
+ {
+ esc = code + 4;
+ esclen = codelen - 4;
+ }
+
for (;;)
{
uschar *nl = Ustrchr(msg, '\n');
if (nl == NULL)
{
- smtp_printf("%d%c%s\r\n", code, final? ' ':'-', msg);
+ smtp_printf("%.3s%c%.*s%s\r\n", code, final? ' ':'-', esclen, esc, msg);
return;
}
else if (nl[1] == 0 || no_multiline_responses)
{
- smtp_printf("%d%c%.*s\r\n", code, final? ' ':'-', (int)(nl - msg), msg);
+ smtp_printf("%.3s%c%.*s%.*s\r\n", code, final? ' ':'-', esclen, esc,
+ (int)(nl - msg), msg);
return;
}
else
{
- smtp_printf("%d-%.*s\r\n", code, (int)(nl - msg), msg);
+ smtp_printf("%.3s-%.*s%.*s\r\n", code, esclen, esc, (int)(nl - msg), msg);
msg = nl + 1;
while (isspace(*msg)) msg++;
}
@@ -1814,13 +1825,18 @@ logging the incident, and sets up the error response. A message containing
newlines is turned into a multiline SMTP response, but for logging, only the
first line is used.
-There's a table of the response codes to use in globals.c, along with the table
-of names. VFRY is special. Despite RFC1123 it defaults disabled in Exim.
-However, discussion in connection with RFC 821bis (aka RFC 2821) has concluded
-that the response should be 252 in the disabled state, because there are broken
-clients that try VRFY before RCPT. A 5xx response should be given only when the
-address is positively known to be undeliverable. Sigh. Also, for ETRN, 458 is
-given on refusal, and for AUTH, 503.
+There's a table of default permanent failure response codes to use in
+globals.c, along with the table of names. VFRY is special. Despite RFC1123 it
+defaults disabled in Exim. However, discussion in connection with RFC 821bis
+(aka RFC 2821) has concluded that the response should be 252 in the disabled
+state, because there are broken clients that try VRFY before RCPT. A 5xx
+response should be given only when the address is positively known to be
+undeliverable. Sigh. Also, for ETRN, 458 is given on refusal, and for AUTH,
+503.
+
+From Exim 4.63, it is possible to override the response code details by
+providing a suitable response code string at the start of the message provided
+in user_msg. The code's first digit is checked for validity.
Arguments:
where where the ACL was called from
@@ -1837,8 +1853,10 @@ Returns: 0 in most cases
int
smtp_handle_acl_fail(int where, int rc, uschar *user_msg, uschar *log_msg)
{
-int code = acl_wherecodes[where];
BOOL drop = rc == FAIL_DROP;
+int codelen = 3;
+int ovector[3];
+uschar *smtp_code;
uschar *lognl;
uschar *sender_info = US"";
uschar *what =
@@ -1853,6 +1871,41 @@ uschar *what =
if (drop) rc = FAIL;
+/* Set the default SMTP code */
+
+smtp_code = (rc != FAIL)? US"451" : acl_wherecodes[where];
+
+/* Check a user message for starting with a response code and optionally an
+extended status code. If found, check that the first digit is valid, and if so,
+use it instead of the default code. */
+
+if (user_msg != NULL)
+ {
+ int n = pcre_exec(regex_smtp_code, NULL, CS user_msg, Ustrlen(user_msg), 0,
+ PCRE_EOPT, ovector, sizeof(ovector)/sizeof(int));
+ if (n >= 0)
+ {
+ if (user_msg[0] != smtp_code[0])
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "configured error code starts with "
+ "incorrect digit (expected %c) in \"%s\"", smtp_code[0], user_msg);
+
+ /* If log_msg == user_msg (the default set in acl.c if no log message is
+ specified, we must adjust the log message to show the code that is
+ actually going to be used. */
+
+ if (log_msg == user_msg)
+ log_msg = string_sprintf("%s %s", smtp_code, log_msg + ovector[1]);
+ }
+ else
+ {
+ smtp_code = user_msg;
+ codelen = ovector[1]; /* Includes final space */
+ }
+ user_msg += ovector[1]; /* Chop the code off the message */
+ }
+ }
+
/* We used to have sender_address here; however, there was a bug that was not
updating sender_address after a rewrite during a verify. When this bug was
fixed, sender_address at this point became the rewritten address. I'm not sure
@@ -1888,7 +1941,7 @@ if (sender_verified_failed != NULL &&
string_sprintf(": %s", sender_verified_failed->message));
if (rc == FAIL && sender_verified_failed->user_message != NULL)
- smtp_respond(code, FALSE, string_sprintf(
+ smtp_respond(smtp_code, codelen, FALSE, string_sprintf(
testflag(sender_verified_failed, af_verify_pmfail)?
"Postmaster verification failed while checking <%s>\n%s\n"
"Several RFCs state that you are required to have a postmaster\n"
@@ -1918,7 +1971,7 @@ if (lognl != NULL) *lognl = 0;
always a 5xx one - see comments at the start of this function. If the original
rc was FAIL_DROP we drop the connection and yield 2. */
-if (rc == FAIL) smtp_respond(code, TRUE, (user_msg == NULL)?
+if (rc == FAIL) smtp_respond(smtp_code, codelen, TRUE, (user_msg == NULL)?
US"Administrative prohibition" : user_msg);
/* Send temporary failure response to the command. Don't give any details,
@@ -1937,12 +1990,13 @@ else
sender_verified_failed != NULL &&
sender_verified_failed->message != NULL)
{
- smtp_respond(451, FALSE, sender_verified_failed->message);
+ smtp_respond(smtp_code, codelen, FALSE, sender_verified_failed->message);
}
- smtp_respond(451, TRUE, user_msg);
+ smtp_respond(smtp_code, codelen, TRUE, user_msg);
}
else
- smtp_printf("451 Temporary local problem - please try later\r\n");
+ smtp_respond(smtp_code, codelen, TRUE,
+ US"Temporary local problem - please try later");
}
/* Log the incident. If the connection is not forcibly to be dropped, return 0.