diff -urN exim-4.04/src/acl.c exim-4.04.hdrerrors/src/acl.c --- exim-4.04/src/acl.c Wed May 15 01:18:57 2002 +++ exim-4.04.hdrerrors/src/acl.c Thu May 16 01:50:47 2002 @@ -418,6 +418,7 @@ BOOL verify_header_sender = FALSE; BOOL defer_ok = FALSE; BOOL callout_defer_ok = FALSE; +BOOL check_postmaster = FALSE; BOOL no_details = FALSE; address_item *sender_vaddr = NULL; uschar *verify_sender_address = NULL; @@ -456,7 +457,18 @@ /* Check that all relevant header lines have the correct syntax */ if (strcmpic(ss+7, US"syntax") == 0) - return verify_check_headers(log_msgptr); + { + int ret; + + ret=verify_check_headers(log_msgptr); + /* We want to return the log message back to the user too (unless overriden + * by a message statement in the ACL) -- Marc */ + if (*log_msgptr) + { + *user_msgptr = string_sprintf("Rejected during DATA, bad syntax: %s", *log_msgptr); + } + return ret; + } /* Check that there is at least one verifiable sender address in the relevant header lines. This can be followed by callout and defer options, just like @@ -496,6 +508,7 @@ if (strcmpic(ss, US"defer_ok") == 0) defer_ok = TRUE; else if (strcmpic(ss, US"no_details") == 0) no_details = TRUE; else if (strcmpic(ss, US"callout_defer_ok") == 0) callout_defer_ok = TRUE; + else if (strcmpic(ss, US"check_postmaster") == 0) check_postmaster = TRUE; else if (strncmpic(ss, US"callout", 7) == 0) { ss += 7; @@ -527,9 +540,16 @@ if (verify_header_sender) { - rc = verify_check_header_address(log_msgptr, callout); + rc = verify_check_header_address(log_msgptr, user_msgptr, callout); if (rc == FAIL && *log_msgptr == NULL) *log_msgptr = US"there is no valid sender in any header line"; + + /* We want to return the log message back to the user too (unless overriden + * by a message statement in the ACL) -- Marc */ + if (*log_msgptr && ! *user_msgptr) + { + *user_msgptr = string_sprintf("Rejected during DATA: %s", *log_msgptr); + } } /* Handle a sender address. The default is to verify *the* sender address, but @@ -577,7 +597,8 @@ if (verify_sender_address[0] != 0) { /* options=0 means not recipient, don't qualify, not expn */ - rc = verify_address(sender_vaddr, NULL, 0, callout); + rc = verify_address(sender_vaddr, NULL, + vopt_check_postmaster*check_postmaster, callout); HDEBUG(D_acl) debug_printf("----------- end verify ------------\n"); if (rc == OK) { @@ -647,11 +668,14 @@ if (rc != OK && verify_sender_address != NULL) { - *log_msgptr = *user_msgptr = - (rc == DEFER && *basic_errno == ERRNO_CALLOUTDEFER)? + *log_msgptr = (rc == DEFER && *basic_errno == ERRNO_CALLOUTDEFER)? US"Sender verify callout did not complete" : (rc == DEFER)? US"Sender verify did not complete" : US"Sender verify failed"; + *user_msgptr = (rc == DEFER && *basic_errno == ERRNO_CALLOUTDEFER)? + US"Sender verify callout did not complete\nThe mail server for this domain may be temporarily unreachable\nor this address may not be reachable on the internet\n(you then need to masquerade the header or create an MX record for it)\nTalk to your mail administrator for details" : + (rc == DEFER)? US"Sender verify did not complete" : + US"Sender verify failed"; sender_verified_failed = sender_vaddr; } @@ -892,7 +916,6 @@ "message" is a user message that will be included in an SMTP response. Unless it is empty, it overrides any previously set user message. If there isn't a log message set, we make it the same as the user message. */ - if (rc == msgcond[verb]) { uschar *expmessage; diff -urN exim-4.04/src/functions.h exim-4.04.hdrerrors/src/functions.h --- exim-4.04/src/functions.h Thu Apr 18 01:08:31 2002 +++ exim-4.04.hdrerrors/src/functions.h Wed May 15 23:37:47 2002 @@ -264,7 +264,7 @@ extern int verify_address(address_item *, FILE *, int, int); extern int verify_check_dnsbl(uschar **); -extern int verify_check_header_address(uschar **, int); +extern int verify_check_header_address(uschar **, uschar **, int); extern int verify_check_headers(uschar **); extern int verify_check_host(uschar **); extern int verify_check_this_host(uschar **, unsigned int *, uschar*, diff -urN exim-4.04/src/macros.h exim-4.04.hdrerrors/src/macros.h --- exim-4.04/src/macros.h Wed May 15 01:18:57 2002 +++ exim-4.04.hdrerrors/src/macros.h Sun May 12 10:20:13 2002 @@ -524,6 +524,7 @@ #define vopt_is_recipient 0x01 #define vopt_qualify 0x02 #define vopt_expn 0x04 +#define vopt_check_postmaster 0x08 /* Options for lookup functions */ diff -urN exim-4.04/src/verify.c exim-4.04.hdrerrors/src/verify.c --- exim-4.04/src/verify.c Wed May 15 01:18:57 2002 +++ exim-4.04.hdrerrors/src/verify.c Thu May 16 01:50:51 2002 @@ -66,6 +66,7 @@ BOOL full_info = (f == NULL)? FALSE : (debug_selector != 0); BOOL is_recipient = (options & vopt_is_recipient) != 0; BOOL expn = (options & vopt_expn) != 0; +BOOL check_postmaster = (options & vopt_check_postmaster) != 0; int i; int yield = OK; int verify_type = expn? v_expn : @@ -292,41 +293,106 @@ smtp_write_command(&outblock, FALSE, "MAIL FROM:<>\r\n") >= 0 && smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), - '2', callout) && - - smtp_write_command(&outblock, FALSE, "RCPT TO:<%.1000s>\r\n", - addr->rcpt) >= 0 && - smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), '2', callout)) { - done = TRUE; /* Address accepted */ - } - - /* For any failure other than a negative response, we just close the - connection and carry on. We can identify a negative response by the fact - that errno is zero. For I/O errors it will be non-zero - - Set up different error texts for logging and for sending back to the - caller as an SMTP response. Log in all cases, using a one-line format. - For sender callouts, give a full response to the caller, but for - recipient callouts, don't give the IP address because this may be an - internal host whose identity is not to be widely broadcast. */ + /* For any failure other than a negative response, we just close the + connection and carry on. We can identify a negative response by the fact + that errno is zero. For I/O errors it will be non-zero */ + + + if (smtp_write_command(&outblock, FALSE, "RCPT TO:<%.1000s>\r\n", + addr->rcpt) >= 0 && + smtp_read_response(&inblock,responsebuffer,sizeof(responsebuffer), + '2', callout)) + { + if (! check_postmaster) + { + done = TRUE; /* Address accepted */ + } + else if ( + /* We issue a RSET because some sites only accept one receipient for <> */ + smtp_write_command(&outblock, FALSE, "RSET\r\n") >= 0 && + smtp_read_response(&inblock, responsebuffer, + sizeof(responsebuffer), '2', callout) && + smtp_write_command(&outblock, FALSE, "MAIL FROM:<>\r\n") >= 0 + && + smtp_read_response(&inblock, responsebuffer, + sizeof(responsebuffer), '2', callout) && + smtp_write_command(&outblock, FALSE, "RCPT TO:\r\n", + addr->domain) >= 0 && + smtp_read_response(&inblock, responsebuffer, + sizeof(responsebuffer), '2', callout) + ) + { + done = TRUE; /* Address accepted */ + } + else + { + addr->message = + string_sprintf("Failed postmaster callout: response to \"%s\" from %s [%s] was %s", + big_buffer, host->name, host->address, + string_printing(responsebuffer)); + + /* Would be embarassing if this ran when you're doing a callout on + one of your own servers, wouldn't it? :-) -- Marc */ + addr->user_message = is_recipient? + string_sprintf("Callout verification failed (while checking for postmaster account):\n%s", responsebuffer) + : + string_sprintf("Called: %s [%s]\nSent: %s\nResponse: %s\nSeveral RFCs state that you are required to have a postmaster mailbox\nfor each domain that you send mail from\nThey need to be routed to the person responsible for mail at your site\nWe cannot accept mail from domains that cannot be contacted at the\npostmaster address to sort out possible problems\nPlease create a postmaster account for your domain", + host->name, host->address, big_buffer, responsebuffer); + + /* Hard rejection ends the process */ + if (responsebuffer[0] == '5') /* Address rejected */ + { + rc = FAIL; + done = TRUE; + } + } + } + + else if (errno == 0) + { + /* Set up different error texts for logging and for sending back to + the caller as an SMTP response. Log in all cases, using a one-line + format. For sender callouts, give a full response to the caller, but + for recipient callouts, don't give the IP address because this may be + an internal host whose identity is not to be widely broadcast. */ + addr->message = + string_sprintf("response to \"%s\" from %s [%s] was %s", + big_buffer, host->name, host->address, + string_printing(responsebuffer)); + + addr->user_message = is_recipient? + string_sprintf("Callout verification failed:\n%s", responsebuffer) + : + string_sprintf("Called: %s [%s]\nSent: %s\nResponse: %s", + host->name, host->address, big_buffer, responsebuffer); + + /* Hard rejection ends the process */ + if (responsebuffer[0] == '5') /* Address rejected */ + { + rc = FAIL; + done = TRUE; + } + } + } else if (errno == 0) { addr->message = - string_sprintf("response to \"%s\" from %s [%s] was %s", + string_sprintf("Failed MAIL FROM: <>: response to \"%s\" from %s [%s] was %s", big_buffer, host->name, host->address, string_printing(responsebuffer)); + /* Would be embarassing if this ran when you're doing a callout on one + * of your own servers, wouldn't it? :-) -- Marc */ addr->user_message = is_recipient? - string_sprintf("Callout verification failed:\n%s", responsebuffer) + string_sprintf("Callout verification failed (MAIL FROM: <> rejected):\n%s", responsebuffer) : - string_sprintf("Called: %s\nSent: %s\nResponse: %s", - host->address, big_buffer, responsebuffer); + string_sprintf("Called: %s [%s]\nSent: %s\nResponse: %s\nThis does not help fight spam effectively, breaks RFCs,\nand prevents you from getting mail bounces back from us,\nAs a result, we cannot accept mail from you until you fix this", + host->name, host->address, big_buffer, responsebuffer); /* Hard rejection ends the process */ - if (responsebuffer[0] == '5') /* Address rejected */ { rc = FAIL; @@ -348,8 +414,10 @@ { rc = DEFER; if (addr->host_list->next != NULL || addr->message == NULL) - addr->user_message = addr->message = - string_sprintf("Could not complete %s callout check", + addr->user_message = + string_sprintf("Could not complete %s callout check\nThe mail server for this domain may be temporarily unreachable\nor this address may not be reachable on the internet\n(you then need to masquerade the header or create an MX record for it)\nTalk to your mail administrator for details", + is_recipient? "recipient" : "sender"); + addr->message = string_sprintf("Could not complete %s callout check", is_recipient? "recipient" : "sender"); addr->basic_errno = ERRNO_CALLOUTDEFER; } @@ -697,7 +765,8 @@ one. Arguments: - error_ptr points to where to put an error message + log_msgptr points to the error message we sent to the logs + user_msgptr points to the error message we sent back to the user callout timeout for callout check (passed to verify_address()) Returns: result of the verification attempt: OK, FAIL, or DEFER; @@ -708,7 +774,8 @@ */ int -verify_check_header_address(uschar **parse_error_ptr, int callout) +verify_check_header_address(uschar **log_msgptr, uschar **user_msgptr, + int callout) { static int header_types[] = { htype_sender, htype_reply_to, htype_from }; int yield = FAIL; @@ -737,6 +806,7 @@ address verifications. */ while (isspace(ss[-1])) ss--; + terminator = *ss; *ss = 0; @@ -758,34 +828,43 @@ else { int start, end, domain; - uschar *address = parse_extract_address(s, parse_error_ptr, &start, + uschar *address = parse_extract_address(s, log_msgptr, &start, &end, &domain, FALSE); + + /* We must restore the shortened string before running the + verification, so the headers are correct, in case there is any + rewriting. */ + *ss = terminator; + if (address == NULL) + { new_ok = FAIL; + /* If verification failed because of a syntax error, fail this + function, and ensure that the failing address gets added to the + error message. */ + if (*log_msgptr != NULL) + { + while (ss > s && isspace(ss[-1])) ss--; + *log_msgptr = + string_sprintf("syntax error in '%.*s' header when scanning for " + "sender: %s in \"%.*s\"", + endname - h->text, h->text, *log_msgptr, ss - s, s); + return FAIL; + } + } else { vaddr = deliver_make_addr(address, FALSE); - /* We must restore the shortened string before running the - verification, so the headers are correct, in case there is any - rewriting. */ - *ss = terminator; new_ok = verify_address(vaddr, NULL, 0, callout); - } - } - *ss = terminator; /* This catches all the other cases */ - - /* If verification failed because of a syntax error, fail this function, - and ensure that the failing address gets added to the error message. */ - - if (new_ok == FAIL && *parse_error_ptr != NULL) - { - while (ss > s && isspace(ss[-1])) ss--; - *parse_error_ptr = - string_sprintf("syntax error in '%.*s' header when scanning for " - "sender: %s in \"%.*s\"", - endname - h->text, h->text, *parse_error_ptr, ss - s, s); - return FAIL; + if (new_ok != OK) + { + *user_msgptr=string_sprintf("Cannot accept '%.*s' header address %s \nbecause it couldn't be verified:\n%s", endname - h->text, h->text, address, vaddr->user_message); + *log_msgptr=string_sprintf("Cannot accept '%.*s' header address %s because it couldn't be verified: %s", endname - h->text, h->text, address, vaddr->message); + /* Not quite sure why I should set this here, but smtp_in needs it */ + acl_callout_defer = TRUE; + } + } } /* Success or defer */ diff -urN exim-4.04/src/acl.c exim-4.04.hdrerrors/src/acl.c --- exim-4.04/src/version.c Wed May 15 01:18:57 2002 +++ exim-4.04.hdrerrors/src/version.c Thu May 16 01:50:47 2002 @@ -10,7 +10,7 @@ #include "exim.h" -#define THIS_VERSION "4.05" +#define THIS_VERSION "4.05-VA-mm1" /* The header file cnumber.h contains a single line containing the