Add recognition of SMTP error codes in bespoke messages.
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 13 Jul 2006 13:53:32 +0000 (13:53 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 13 Jul 2006 13:53:32 +0000 (13:53 +0000)
22 files changed:
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/README.UPDATING
src/src/exim.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/receive.c
src/src/routers/redirect.c
src/src/routers/redirect.h
src/src/smtp_in.c
test/aux-fixed/0536.aliases [new file with mode: 0644]
test/confs/0536 [new file with mode: 0644]
test/log/0536 [new file with mode: 0644]
test/mail/0536.oksender [new file with mode: 0644]
test/mail/0536.user1 [new file with mode: 0644]
test/mail/0536.user2 [new file with mode: 0644]
test/paniclog/0536 [new file with mode: 0644]
test/rejectlog/0536 [new file with mode: 0644]
test/scripts/0000-Basic/0536 [new file with mode: 0644]
test/stderr/0536 [new file with mode: 0644]
test/stdout/0536 [new file with mode: 0644]

index 90a8a83504284edaf4f7fc554e3748e9827b51af..b4d476aacb87607fb64d7c0901c0b440727abfd0 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.372 2006/07/07 14:36:04 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.373 2006/07/13 13:53:32 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -89,6 +89,10 @@ PH/14 In the default configuration, change the use of "message" in ACL warn
 PH/15 Diagnose a filter syntax error for "seen", "unseen", or "noerror" if not
       not followed by a command (e.g. "seen endif").
 
+PH/16 Recognize SMTP codes at the start of "message" in ACLs and after :fail:
+      and :defer: in a redirect router. Add forbid_smtp_code to suppress the
+      latter.
+
 
 Exim version 4.62
 -----------------
index 4f7ca84709c1c0d2fb5525079d7b4332bd505615..1ec1bdd2cf5ee19784963327447da1be0e334917 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/NewStuff,v 1.104 2006/06/28 16:00:23 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/NewStuff,v 1.105 2006/07/13 13:53:32 ph10 Exp $
 
 New Features in Exim
 --------------------
@@ -31,6 +31,19 @@ Version 4.63
    Variables such as $authenticated_ sender are also available. It is possible
    to specify added header lines in this ACL.
 
+3. 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.
+
 
 Version 4.62
 ------------
index 05f89f40e12001bdb562aadfeef4db58217de06b..e4975ba6a77db839f7eeb6b13400120c890f4caf 100644 (file)
@@ -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
 -----------------
 
index a40ded77e7ea2af2bae92662347cc8e48c911ce6..3ac7d83134ec3916ad65fddf3e4963ee4e51e8ce 100644 (file)
@@ -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. */
index 2728d79f13f62a3e79d442b0075e8c07173b0662..32b3d2d248f03b3ac5ef963d9adb791c87a8b13a 100644 (file)
@@ -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);
index 4455f384eaeb377258c8e67cdc65980382c4328f..2a6aba59273e0d4f35c8a9e6e15d6c70f27c0a03 100644 (file)
@@ -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;
index 53272ceef1be14bdd91c050269864a46e5807eac..a235869c1b375b1c310949b0fe883bae08bb042d 100644 (file)
@@ -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) */
index f711e9ca85a61328721770c0e86c29bbc477befd..3f430f1aa20ff3f47a836ec266e88e5db2369ad6 100644 (file)
@@ -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);
       }
index d94240ebc447c37db161e104e005129fb0932922..2a9d5e3b2c150966fb83172be7a2fb983537ce67 100644 (file)
@@ -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
index 996f0b003ec772c430e672a0d082a7ecda4c82fa..6825430fd62f8e9d7c791901c68ee0885355e927 100644 (file)
@@ -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;
index 99ac3fb1a3f402f866aa47163ef01c2cf510e2bf..881bfff58793cebd610443338ba2b9da96f09551 100644 (file)
@@ -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.
diff --git a/test/aux-fixed/0536.aliases b/test/aux-fixed/0536.aliases
new file mode 100644 (file)
index 0000000..535399b
--- /dev/null
@@ -0,0 +1,9 @@
+user20:  :fail: No code
+user21:  :fail: 590 Main code
+user22:  :fail: 590 5.4.3 Main and extended code
+user23:  :fail: 490 4.5.6 Wrong code
+
+user30:  :defer: No code
+user31:  :defer: 490 Main code
+user32:  :defer: 490 4.4.3 Main and extended code
+user33:  :defer: 390 3.5.6 Wrong code
diff --git a/test/confs/0536 b/test/confs/0536
new file mode 100644 (file)
index 0000000..0aa7c52
--- /dev/null
@@ -0,0 +1,104 @@
+# Exim test configuration 0536
+
+FORBID_SMTP_CODE = false
+
+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 = rcpt
+acl_not_smtp = not_smtp
+
+trusted_users = CALLER
+
+
+# ----- ACLs -----
+
+begin ACL
+
+rcpt:
+  deny local_parts = user1
+       message     = No code
+  deny local_parts = user2
+       message     = 599 Main code
+  deny local_parts = user3
+       message     = 599 Main code\non two lines
+  deny local_parts = user4
+       message     = 599 5.2.3 Main and extended code
+  deny local_parts = user5
+       message     = 599 5.12.3 Main and extended code\non two lines
+  deny local_parts = user6
+       message     = 299 Wrong code
+  deny local_parts = user7
+       message     = 299 Wrong code
+       log_message = A different log message
+
+  defer local_parts = user8
+        message     = 499 4.12.343 Main and extended code\non two lines
+  defer local_parts = user9
+        message     = 499 4.1234.343 Main and extended code\non two lines
+  defer local_parts = user10
+        message     = 399 Wrong code
+
+  deny local_parts = user20
+       !verify     = recipient
+  deny local_parts = user21
+       !verify     = recipient
+  deny local_parts = user22
+       !verify     = recipient
+  deny local_parts = user23
+       !verify     = recipient
+
+  deny local_parts = user30
+       !verify     = recipient
+  deny local_parts = user31
+       !verify     = recipient
+  deny local_parts = user32
+       !verify     = recipient
+  deny local_parts = user33
+       !verify     = recipient
+
+  deny message = Should not get this
+
+not_smtp:
+  accept senders = : oksender@test.ex
+
+  deny senders = user1@test.ex
+       message = No code
+
+  deny senders = user2@test.ex
+       message = 599 Main code
+
+  deny message = Should not get this
+
+# ----- Routers -----
+
+begin routers
+
+r1:
+  driver = redirect
+  allow_fail
+  allow_defer
+  data = ${lookup{$local_part}lsearch{DIR/aux-fixed/TESTNUM.aliases}}
+  forbid_smtp_code = FORBID_SMTP_CODE
+
+r2:
+  driver = accept
+  transport = t1
+
+# ----- Transports -----
+
+begin transports
+
+t1:
+  driver = appendfile
+  file = DIR/test-mail/$local_part
+  user = CALLER
+
diff --git a/test/log/0536 b/test/log/0536
new file mode 100644 (file)
index 0000000..ab5fe84
--- /dev/null
@@ -0,0 +1,41 @@
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user1@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user2@test.ex>: 599 Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user3@test.ex>: 599 Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user4@test.ex>: 599 5.2.3 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user5@test.ex>: 599 5.12.3 Main and extended code
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "299 Wrong code"
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user6@test.ex>: 550 Wrong code
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "299 Wrong code"
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user7@test.ex>: A different log message
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user8@test.ex>: 499 4.12.343 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user9@test.ex>: 499 4.1234.343 Main and extended code
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 4) in "399 Wrong code"
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user10@test.ex>: 451 Wrong code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user20@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user21@test.ex>: 590 Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user22@test.ex>: 590 5.4.3 Main and extended code
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "490 4.5.6 Wrong code"
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user23@test.ex>: 550 Wrong code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user30@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user31@test.ex>: 490 Main code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user32@test.ex>: 490 4.4.3 Main and extended code
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 4) in "390 3.5.6 Wrong code"
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user33@test.ex>: 451 Wrong code
+1999-03-02 09:44:33 10HmaX-0005vi-00 F=<user1@test.ex> rejected by non-SMTP ACL: No code
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => user1 <user1@test.ex> R=r2 T=t1
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 F=<user2@test.ex> rejected by non-SMTP ACL: 599 Main code
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaY-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmbA-0005vi-00 => user2 <user2@test.ex> R=r2 T=t1
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= oksender@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbB-0005vi-00 ** user22@test.ex R=r1: 590 5.4.3 Main and extended code
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= <> R=10HmbB-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmbC-0005vi-00 => oksender <oksender@test.ex> R=r2 T=t1
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user20@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user21@test.ex>: Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user22@test.ex>: Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user23@test.ex>: Wrong code
diff --git a/test/mail/0536.oksender b/test/mail/0536.oksender
new file mode 100644 (file)
index 0000000..9a3e0ea
--- /dev/null
@@ -0,0 +1,32 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Received: from EXIMUSER by myhost.test.ex with local (Exim x.yz)
+       id 10HmbC-0005vi-00
+       for oksender@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: user22@test.ex
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@myhost.test.ex>
+To: oksender@test.ex
+Subject: Mail delivery failed: returning message to sender
+Message-Id: <E10HmbC-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+This message was created automatically by mail delivery software.
+
+A message that you sent could not be delivered to one or more of its
+recipients. This is a permanent error. The following address(es) failed:
+
+  user22@test.ex
+    590 5.4.3 Main and extended code
+
+------ This is a copy of the message, including all the headers. ------
+
+Return-path: <oksender@test.ex>
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <oksender@test.ex>)
+       id 10HmbB-0005vi-00
+       for user22@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
+From: oksender@test.ex
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+
diff --git a/test/mail/0536.user1 b/test/mail/0536.user1
new file mode 100644 (file)
index 0000000..b918842
--- /dev/null
@@ -0,0 +1,27 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Received: from EXIMUSER by myhost.test.ex with local (Exim x.yz)
+       id 10HmaZ-0005vi-00
+       for user1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@myhost.test.ex>
+To: user1@test.ex
+Subject: Mail failure - rejected by local scanning code
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+A message that you sent was rejected by the local scanning code that
+checks incoming messages on this system. The following error was given:
+
+  No code
+
+------ This is a copy of your message, including all the headers. ------
+
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <user1@test.ex>)
+       id 10HmaX-0005vi-00
+       for user1@myhost.test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: user1@test.ex
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+
diff --git a/test/mail/0536.user2 b/test/mail/0536.user2
new file mode 100644 (file)
index 0000000..64bd158
--- /dev/null
@@ -0,0 +1,27 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Received: from EXIMUSER by myhost.test.ex with local (Exim x.yz)
+       id 10HmbA-0005vi-00
+       for user2@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@myhost.test.ex>
+To: user2@test.ex
+Subject: Mail failure - rejected by local scanning code
+Message-Id: <E10HmbA-0005vi-00@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+A message that you sent was rejected by the local scanning code that
+checks incoming messages on this system. The following error was given:
+
+  599 Main code
+
+------ This is a copy of your message, including all the headers. ------
+
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <user2@test.ex>)
+       id 10HmaY-0005vi-00
+       for user1@myhost.test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: user2@test.ex
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+
diff --git a/test/paniclog/0536 b/test/paniclog/0536
new file mode 100644 (file)
index 0000000..38a1ee0
--- /dev/null
@@ -0,0 +1,5 @@
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "299 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "299 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 4) in "399 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "490 4.5.6 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 4) in "390 3.5.6 Wrong code"
diff --git a/test/rejectlog/0536 b/test/rejectlog/0536
new file mode 100644 (file)
index 0000000..bf06473
--- /dev/null
@@ -0,0 +1,42 @@
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user1@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user2@test.ex>: 599 Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user3@test.ex>: 599 Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user4@test.ex>: 599 5.2.3 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user5@test.ex>: 599 5.12.3 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user6@test.ex>: 550 Wrong code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user7@test.ex>: A different log message
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user8@test.ex>: 499 4.12.343 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user9@test.ex>: 499 4.1234.343 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user10@test.ex>: 451 Wrong code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user20@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user21@test.ex>: 590 Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user22@test.ex>: 590 5.4.3 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user23@test.ex>: 550 Wrong code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user30@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user31@test.ex>: 490 Main code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user32@test.ex>: 490 4.4.3 Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <user33@test.ex>: 451 Wrong code
+1999-03-02 09:44:33 10HmaX-0005vi-00 F=<user1@test.ex> rejected by non-SMTP ACL: No code
+Envelope-from: <user1@test.ex>
+Envelope-to: <user1@myhost.test.ex>
+P Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <user1@test.ex>)
+       id 10HmaX-0005vi-00
+       for user1@myhost.test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+I Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+F From: user1@test.ex
+  Date: Tue, 2 Mar 1999 09:44:33 +0000
+1999-03-02 09:44:33 10HmaY-0005vi-00 F=<user2@test.ex> rejected by non-SMTP ACL: 599 Main code
+Envelope-from: <user2@test.ex>
+Envelope-to: <user1@myhost.test.ex>
+P Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <user2@test.ex>)
+       id 10HmaY-0005vi-00
+       for user1@myhost.test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+I Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+F From: user2@test.ex
+  Date: Tue, 2 Mar 1999 09:44:33 +0000
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user20@test.ex>: No code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user21@test.ex>: Main code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user22@test.ex>: Main and extended code
+1999-03-02 09:44:33 U=CALLER F=<> rejected RCPT <user23@test.ex>: Wrong code
diff --git a/test/scripts/0000-Basic/0536 b/test/scripts/0000-Basic/0536
new file mode 100644 (file)
index 0000000..30be876
--- /dev/null
@@ -0,0 +1,42 @@
+# Specifying SMTP codes in bespoke error messages
+exim -bs
+ehlo test.ex
+mail from:<>
+rcpt to:<user1@test.ex>
+rcpt to:<user2@test.ex>
+rcpt to:<user3@test.ex>
+rcpt to:<user4@test.ex>
+rcpt to:<user5@test.ex>
+rcpt to:<user6@test.ex>
+rcpt to:<user7@test.ex>
+rcpt to:<user8@test.ex>
+rcpt to:<user9@test.ex>
+rcpt to:<user10@test.ex>
+rcpt to:<user20@test.ex>
+rcpt to:<user21@test.ex>
+rcpt to:<user22@test.ex>
+rcpt to:<user23@test.ex>
+rcpt to:<user30@test.ex>
+rcpt to:<user31@test.ex>
+rcpt to:<user32@test.ex>
+rcpt to:<user33@test.ex>
+quit
+****
+1
+exim -f user1@test.ex user1
+****
+1
+exim -f user2@test.ex user1
+****
+exim -odi -f oksender@test.ex user22@test.ex
+****
+exim -DFORBID_SMTP_CODE=true -bs
+ehlo test.ex
+mail from:<>
+rcpt to:<user20@test.ex>
+rcpt to:<user21@test.ex>
+rcpt to:<user22@test.ex>
+rcpt to:<user23@test.ex>
+quit
+****
+no_msglog_check
diff --git a/test/stderr/0536 b/test/stderr/0536
new file mode 100644 (file)
index 0000000..38a1ee0
--- /dev/null
@@ -0,0 +1,5 @@
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "299 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "299 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 4) in "399 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 5) in "490 4.5.6 Wrong code"
+1999-03-02 09:44:33 configured error code starts with incorrect digit (expected 4) in "390 3.5.6 Wrong code"
diff --git a/test/stdout/0536 b/test/stdout/0536
new file mode 100644 (file)
index 0000000..cc4ce1e
--- /dev/null
@@ -0,0 +1,40 @@
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+550 No code\r
+599 Main code\r
+599-Main code\r
+599 on two lines\r
+599 5.2.3 Main and extended code\r
+599-5.12.3 Main and extended code\r
+599 5.12.3 on two lines\r
+550 Wrong code\r
+550 Wrong code\r
+499-4.12.343 Main and extended code\r
+499 4.12.343 on two lines\r
+499-4.1234.343 Main and extended code\r
+499 on two lines\r
+451 Wrong code\r
+550 No code\r
+590 Main code\r
+590 5.4.3 Main and extended code\r
+550 Wrong code\r
+451 Temporary local problem - please try later\r
+490 Temporary local problem - please try later\r
+490 4.4.3 Temporary local problem - please try later\r
+451 Temporary local problem - please try later\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-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+550 No code\r
+550 Main code\r
+550 Main and extended code\r
+550 Wrong code\r
+221 myhost.test.ex closing connection\r