From 447d236c3a15a89d18789de568ae974677f7aaf4 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Thu, 28 Apr 2005 13:06:32 +0000 Subject: [PATCH] Remove details of errors in bounce and delay warning messages, unless explicitly specified (e.g. :fail:) or a message from a remote host. --- doc/doc-txt/ChangeLog | 16 +++++- src/README.UPDATING | 6 ++- src/src/deliver.c | 95 +++++++++++++++------------------- src/src/routers/queryprogram.c | 8 ++- src/src/routers/redirect.c | 11 ++-- src/src/structs.h | 3 +- src/src/transports/smtp.c | 87 ++++++++++++++++++------------- 7 files changed, 131 insertions(+), 95 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index d8272ab92..cbb8e9cbb 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.127 2005/04/27 13:29:32 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.128 2005/04/28 13:06:32 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -249,6 +249,20 @@ PH/41 $message_linecount is a new variable that contains the total number of lines in the message. Compare $body_linecount, which is the count for the body only. +PH/42 Exim no longer gives details of delivery errors for specific addresses in + bounce and delay warning messages, except in certain special cases, which + are as follows: + + (a) An SMTP error message from a remote host; + (b) A message specified in a :fail: redirection; + (c) A message specified in a "fail" command in a system filter; + (d) A message specified in a FAIL return from the queryprogram router; + (e) A message specified by the cannot_route_message router option. + + In these cases only, Exim does include the error details in bounce and + warning messages. There are also a few cases where bland messages such + as "unrouteable address" or "local delivery error" are given. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/README.UPDATING b/src/README.UPDATING index c91c57680..efc123c15 100644 --- a/src/README.UPDATING +++ b/src/README.UPDATING @@ -1,4 +1,4 @@ -$Cambridge: exim/src/README.UPDATING,v 1.6 2005/04/06 16:26:42 ph10 Exp $ +$Cambridge: exim/src/README.UPDATING,v 1.7 2005/04/28 13:06:32 ph10 Exp $ This document contains detailed information about incompatibilities that might be encountered when upgrading from one release of Exim to another. The @@ -50,6 +50,10 @@ uses prefixes or suffixes on addresses that could be used for callouts, and you want the affixes to be retained, you must make sure that rcpt_include_affixes is set on the transport. +3. Bounce and delay warning messages no longer contain details of delivery +errors, except for explicit messages (e.g. generated by :fail:) and SMTP +responses from remote hosts. + Version 4.50 ------------ diff --git a/src/src/deliver.c b/src/src/deliver.c index 78eb65bc6..a7b367d80 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/deliver.c,v 1.13 2005/04/07 15:40:50 ph10 Exp $ */ +/* $Cambridge: exim/src/src/deliver.c,v 1.14 2005/04/28 13:06:32 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -4180,7 +4180,6 @@ if (addr->parent != NULL && testflag(addr, af_hide_child)) printed = US"an undisclosed address"; yield = FALSE; } - else if (!testflag(addr, af_pfr) || addr->parent == NULL) printed = addr->address; @@ -4217,7 +4216,6 @@ return yield; - /************************************************* * Print error for an address * *************************************************/ @@ -4227,53 +4225,62 @@ a bounce or a warning message. It tries to format the message reasonably by introducing newlines. All lines are indented by 4; the initial printing position must be set before calling. +This function used always to print the error. Nowadays we want to restrict it +to cases such as SMTP errors from a remote host, and errors from :fail: and +filter "fail". We no longer pass other information willy-nilly in bounce and +warning messages. Text in user_message is always output; text in message only +if the af_pass_message flag is set. + Arguments: - addr points to the address + addr the address f the FILE to print on + s some leading text Returns: nothing */ static void -print_address_error(address_item *addr, FILE *f) +print_address_error(address_item *addr, FILE *f, uschar *t) { +int count = Ustrlen(t); uschar *s = (addr->user_message != NULL)? addr->user_message : addr->message; -if (addr->basic_errno > 0) - { - fprintf(f, "%s%s", strerror(addr->basic_errno), - (s == NULL)? "" : ":\n "); - } -if (s == NULL) + +if (addr->user_message != NULL) + s = addr->user_message; +else { - if (addr->basic_errno <= 0) fprintf(f, "unknown error"); + if (!testflag(addr, af_pass_message) || addr->message == NULL) return; + s = addr->message; } -else + +fprintf(f, "\n %s", t); + +while (*s != 0) { - int count = 0; - while (*s != 0) + if (*s == '\\' && s[1] == 'n') + { + fprintf(f, "\n "); + s += 2; + count = 0; + } + else { - if (*s == '\\' && s[1] == 'n') + fputc(*s, f); + count++; + if (*s++ == ':' && isspace(*s) && count > 45) { - fprintf(f, "\n "); - s += 2; + fprintf(f, "\n "); /* sic (because space follows) */ count = 0; } - else - { - fputc(*s, f); - count++; - if (*s++ == ':' && isspace(*s) && count > 45) - { - fprintf(f, "\n "); /* sic (because space follows) */ - count = 0; - } - } } } } + + + /************************************************* * Check list of addresses for duplication * *************************************************/ @@ -4994,6 +5001,7 @@ if (process_recipients != RECIP_IGNORE) case RECIP_FAIL_FILTER: new->message = (filter_message == NULL)? US"delivery cancelled" : filter_message; + setflag(new, af_pass_message); goto RECIP_QUEUE_FAILED; /* below */ @@ -6182,26 +6190,15 @@ wording. */ /* Process the addresses, leaving them on the msgchain if they have a file name for a return message. (There has already been a check in - post_process_one() for the existence of data in the message file.) */ + post_process_one() for the existence of data in the message file.) A TRUE + return from print_address_information() means that the address is not + hidden. */ paddr = &msgchain; for (addr = msgchain; addr != NULL; addr = *paddr) { if (print_address_information(addr, f, US" ", US"\n ", US"")) - { - /* A TRUE return from print_address_information() means that the - address is not hidden. If there is a return file, it has already - been checked to ensure it is not empty. Omit the bland "return - message generated" error, but otherwise include error information. */ - - if (addr->return_file < 0 || - addr->message == NULL || - Ustrcmp(addr->message, "return message generated") != 0) - { - fprintf(f, "\n "); - print_address_error(addr, f); - } - } + print_address_error(addr, f, US""); /* End the final line for the address */ @@ -6703,21 +6700,15 @@ else if (addr_defer != (address_item *)(+1)) (addr_defer->next == NULL)? "is": "are"); } - /* List the addresses. For any that are hidden, don't give the delay - reason, because it might expose that which is hidden. Also, do not give - "retry time not reached" because that isn't helpful. */ + /* List the addresses, with error information if allowed */ fprintf(f, "\n"); while (addr_defer != NULL) { address_item *addr = addr_defer; addr_defer = addr->next; - if (print_address_information(addr, f, US" ", US"\n ", US"") && - addr->basic_errno > ERRNO_RETRY_BASE) - { - fprintf(f, "\n Delay reason: "); - print_address_error(addr, f); - } + if (print_address_information(addr, f, US" ", US"\n ", US"")) + print_address_error(addr, f, US"Delay reason: "); fprintf(f, "\n"); } fprintf(f, "\n"); diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index 5d7a51fdf..5282a1fa6 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.3 2005/04/06 14:40:24 ph10 Exp $ */ +/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.4 2005/04/28 13:06:32 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -416,7 +416,11 @@ if (strcmpic(rword, US"accept") != 0) if (strcmpic(rword, US"decline") == 0) return DECLINE; if (strcmpic(rword, US"pass") == 0) return PASS; addr->message = string_copy(rdata); /* data is a message */ - if (strcmpic(rword, US"fail") == 0) return FAIL; + if (strcmpic(rword, US"fail") == 0) + { + setflag(addr, af_pass_message); + return FAIL; + } if (strcmpic(rword, US"freeze") == 0) addr->special_action = SPECIAL_FREEZE; else if (strcmpic(rword, US"defer") != 0) { diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 0153a4d49..8e8fc876c 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.9 2005/04/06 14:40:24 ph10 Exp $ */ +/* $Cambridge: exim/src/src/routers/redirect.c,v 1.10 2005/04/28 13:06:32 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -655,8 +655,13 @@ switch (frc) 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); - if (addr->message == NULL) addr->message = US"forced rejection"; - else addr->user_message = addr->message; + if (addr->message == NULL) + addr->message = US"forced rejection"; + else + { + addr->user_message = addr->message; + setflag(addr, af_pass_message); + } return FAIL; /* As in the case of a system filter, a freeze does not happen after a manual diff --git a/src/src/structs.h b/src/src/structs.h index 791e11c69..645dfc25c 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/structs.h,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */ +/* $Cambridge: exim/src/src/structs.h,v 1.5 2005/04/28 13:06:32 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -498,6 +498,7 @@ typedef struct address_item_propagated { #define af_verify_callout 0x00400000 /* for cached sender verify: callout was specified */ #define af_include_affixes 0x00800000 /* delivered with affixes in RCPT */ #define af_cert_verified 0x01000000 /* delivered with verified TLS cert */ +#define af_pass_message 0x02000000 /* pass message in bounces */ /* These flags must be propagated when a child is created */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index f53d742e4..69b1c1965 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/transports/smtp.c,v 1.10 2005/04/07 10:54:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/transports/smtp.c,v 1.11 2005/04/28 13:06:32 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -313,10 +313,11 @@ host_build_hostlist(&(ob->fallback_hostlist), ob->fallback_hosts, FALSE); status means that an address is not currently being processed. Arguments: - addrlist points to a chain of addresses - errno_value to put in each address's errno field - msg to put in each address's message field - rc to put in each address's transport_return field + addrlist points to a chain of addresses + errno_value to put in each address's errno field + msg to put in each address's message field + rc to put in each address's transport_return field + pass_message if TRUE, set the "pass message" flag in the address If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate @@ -326,7 +327,8 @@ Returns: nothing */ static -void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc) +void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc, + BOOL pass_message) { address_item *addr; int orvalue = 0; @@ -340,7 +342,11 @@ for (addr = addrlist; addr != NULL; addr = addr->next) if (addr->transport_return < PENDING) continue; addr->basic_errno = errno_value; addr->more_errno |= orvalue; - if (msg != NULL) addr->message = msg; + if (msg != NULL) + { + addr->message = msg; + if (pass_message) setflag(addr, af_pass_message); + } addr->transport_return = rc; } } @@ -358,18 +364,19 @@ the yield variable. If no response was actually read, a suitable digit is chosen. Arguments: - host the current host, to get its name for messages - errno_value pointer to the errno value - more_errno from the top address for use with ERRNO_FILTER_FAIL - buffer the SMTP response buffer - yield where to put a one-digit SMTP response code - message where to put an errror message - -Returns: TRUE if an SMTP "QUIT" command should be sent, else FALSE + host the current host, to get its name for messages + errno_value pointer to the errno value + more_errno from the top address for use with ERRNO_FILTER_FAIL + buffer the SMTP response buffer + yield where to put a one-digit SMTP response code + message where to put an errror message + pass_message set TRUE if message is an SMTP response + +Returns: TRUE if an SMTP "QUIT" command should be sent, else FALSE */ static BOOL check_response(host_item *host, int *errno_value, int more_errno, - uschar *buffer, int *yield, uschar **message) + uschar *buffer, int *yield, uschar **message, BOOL *pass_message) { uschar *pl = US""; @@ -444,8 +451,9 @@ if (*errno_value == ERRNO_WRITEINCOMPLETE) if (buffer[0] != 0) { uschar *s = string_printing(buffer); - *message = US string_sprintf("SMTP error from remote mailer after %s%s: " + *message = US string_sprintf("SMTP error from remote mail server after %s%s: " "host %s [%s]: %s", pl, smtp_command, host->name, host->address, s); + *pass_message = TRUE; *yield = buffer[0]; return TRUE; } @@ -623,7 +631,7 @@ while (count-- > 0) uschar *message = string_sprintf("SMTP timeout while connected to %s [%s] " "after RCPT TO:<%s>", host->name, host->address, transport_rcpt_address(addr, include_affixes)); - set_errno(addrlist, save_errno, message, DEFER); + set_errno(addrlist, save_errno, message, DEFER, FALSE); retry_add_item(addr, addr->address_retry_key, 0); host->update_waiting = FALSE; return -1; @@ -646,9 +654,10 @@ while (count-- > 0) else { addr->message = - string_sprintf("SMTP error from remote mailer after RCPT TO:<%s>: " + string_sprintf("SMTP error from remote mail server after RCPT TO:<%s>: " "host %s [%s]: %s", transport_rcpt_address(addr, include_affixes), host->name, host->address, string_printing(buffer)); + setflag(addr, af_pass_message); deliver_msglog("%s %s\n", tod_stamp(tod_log), addr->message); /* The response was 5xx */ @@ -699,8 +708,9 @@ if (pending_DATA != 0 && { int code; uschar *msg; + BOOL pass_message; if (pending_DATA > 0 || (yield & 1) != 0) return -3; - (void)check_response(host, &errno, 0, buffer, &code, &msg); + (void)check_response(host, &errno, 0, buffer, &code, &msg, &pass_message); DEBUG(D_transport) debug_printf("%s\nerror for DATA ignored: pipelining " "is in use and there were no good recipients\n", msg); } @@ -782,6 +792,7 @@ BOOL setting_up = TRUE; BOOL completed_address = FALSE; BOOL esmtp = TRUE; BOOL pending_MAIL; +BOOL pass_message = FALSE; smtp_inblock inblock; smtp_outblock outblock; int max_rcpt = tblock->max_addresses; @@ -822,7 +833,7 @@ if (helo_data == NULL) { uschar *message = string_sprintf("failed to expand helo_data: %s", expand_string_message); - set_errno(addrlist, 0, message, DEFER); + set_errno(addrlist, 0, message, DEFER, FALSE); return ERROR; } @@ -842,7 +853,7 @@ if (ob->authenticated_sender != NULL) { uschar *message = string_sprintf("failed to expand " "authenticated_sender: %s", expand_string_message); - set_errno(addrlist, 0, message, DEFER); + set_errno(addrlist, 0, message, DEFER, FALSE); return ERROR; } } @@ -861,7 +872,7 @@ if (continue_hostname == NULL) if (inblock.sock < 0) { set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno, - NULL, DEFER); + NULL, DEFER, FALSE); return DEFER; } @@ -1186,7 +1197,7 @@ if (continue_hostname == NULL case ERROR: yield = ERROR; - set_errno(addrlist, 0, string_copy(buffer), DEFER); + set_errno(addrlist, 0, string_copy(buffer), DEFER, FALSE); goto SEND_QUIT; } @@ -1202,7 +1213,8 @@ if (continue_hostname == NULL { yield = DEFER; set_errno(addrlist, ERRNO_AUTHFAIL, - string_sprintf("authentication required but %s", fail_reason), DEFER); + string_sprintf("authentication required but %s", fail_reason), DEFER, + FALSE); goto SEND_QUIT; } } @@ -1228,7 +1240,8 @@ if (tblock->filter_command != NULL) if (!rc) { - set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER); + set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER, + FALSE); yield = ERROR; goto SEND_QUIT; } @@ -1368,7 +1381,8 @@ if (mua_wrapper) } if (badaddr != NULL) { - set_errno(addrlist, 0, badaddr->message, FAIL); + set_errno(addrlist, 0, badaddr->message, FAIL, + testflag(badaddr, af_pass_message)); ok = FALSE; } } @@ -1597,7 +1611,7 @@ if (!ok) save_errno = errno; message = NULL; send_quit = check_response(host, &save_errno, addrlist->more_errno, - buffer, &code, &message); + buffer, &code, &message, &pass_message); goto FAILED; SEND_FAILED: @@ -1632,11 +1646,11 @@ if (!ok) { if (code == '5') { - set_errno(addrlist, save_errno, message, FAIL); + set_errno(addrlist, save_errno, message, FAIL, pass_message); } else { - set_errno(addrlist, save_errno, message, DEFER); + set_errno(addrlist, save_errno, message, DEFER, pass_message); yield = DEFER; } } @@ -1662,7 +1676,7 @@ if (!ok) { yield = (save_errno == ERRNO_CHHEADER_FAIL || save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER; - set_errno(addrlist, save_errno, message, DEFER); + set_errno(addrlist, save_errno, message, DEFER, pass_message); } /* Otherwise we have a message-specific error response from the remote @@ -1683,7 +1697,8 @@ if (!ok) { if (mua_wrapper) code = '5'; /* Force hard failure in wrapper mode */ - set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER); + set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER, + pass_message); /* If there's an errno, the message contains just the identity of the host. */ @@ -1747,6 +1762,7 @@ if (completed_address && ok && send_quit) )) { uschar *msg; + BOOL pass_message; if (send_rset) { @@ -1760,7 +1776,8 @@ if (completed_address && ok && send_quit) ob->command_timeout))) { int code; - send_quit = check_response(host, &errno, 0, buffer, &code, &msg); + send_quit = check_response(host, &errno, 0, buffer, &code, &msg, + &pass_message); if (!send_quit) { DEBUG(D_transport) debug_printf("%s\n", msg); @@ -1806,7 +1823,7 @@ if (completed_address && ok && send_quit) /* If RSET failed and there are addresses left, they get deferred. */ - else set_errno(first_addr, errno, msg, DEFER); + else set_errno(first_addr, errno, msg, DEFER, FALSE); } } @@ -2449,7 +2466,7 @@ for (cutoff_retry = 0; expired && if (dont_deliver) { host_item *host2; - set_errno(addrlist, 0, NULL, OK); + set_errno(addrlist, 0, NULL, OK, FALSE); for (addr = addrlist; addr != NULL; addr = addr->next) { addr->host_used = host; -- 2.30.2