-/* $Cambridge: exim/src/src/smtp_in.c,v 1.32 2006/02/13 16:23:57 ph10 Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.38 2006/04/19 10:58:21 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
DEBUG(D_receive)
{
+ uschar *cr, *end;
va_start(ap, format);
(void) string_vformat(big_buffer, big_buffer_size, format, ap);
+ va_end(ap);
+ end = big_buffer + Ustrlen(big_buffer);
+ while ((cr = Ustrchr(big_buffer, '\r')) != NULL) /* lose CRs */
+ memmove(cr, cr + 1, (end--) - cr);
debug_printf("SMTP>> %s", big_buffer);
}
raw_recipients_count = recipients_count = recipients_list_max = 0;
message_linecount = 0;
message_size = -1;
-acl_warn_headers = NULL;
+acl_added_headers = NULL;
queue_only_policy = FALSE;
deliver_freeze = FALSE; /* Can be set by ACL */
freeze_tell = freeze_tell_config; /* Can be set by ACL */
return FALSE;
}
- /* Test with TCP Wrappers if so configured */
+ /* Test with TCP Wrappers if so configured. There is a problem in that
+ hosts_ctl() returns 0 (deny) under a number of system failure circumstances,
+ such as disks dying. In these cases, it is desirable to reject with a 4xx
+ error instead of a 5xx error. There isn't a "right" way to detect such
+ problems. The following kludge is used: errno is zeroed before calling
+ hosts_ctl(). If the result is "reject", a 5xx error is given only if the
+ value of errno is 0 or ENOENT (which happens if /etc/hosts.{allow,deny} does
+ not exist). */
#ifdef USE_TCP_WRAPPERS
+ errno = 0;
if (!hosts_ctl("exim",
(sender_host_name == NULL)? STRING_UNKNOWN : CS sender_host_name,
(sender_host_address == NULL)? STRING_UNKNOWN : CS sender_host_address,
(sender_ident == NULL)? STRING_UNKNOWN : CS sender_ident))
{
- HDEBUG(D_receive) debug_printf("tcp wrappers rejection\n");
- log_write(L_connection_reject,
- LOG_MAIN|LOG_REJECT, "refused connection from %s "
- "(tcp wrappers)", host_and_ident(FALSE));
- smtp_printf("554 SMTP service not available\r\n");
+ if (errno == 0 || errno == ENOENT)
+ {
+ HDEBUG(D_receive) debug_printf("tcp wrappers rejection\n");
+ log_write(L_connection_reject,
+ LOG_MAIN|LOG_REJECT, "refused connection from %s "
+ "(tcp wrappers)", host_and_ident(FALSE));
+ smtp_printf("554 SMTP service not available\r\n");
+ }
+ else
+ {
+ int save_errno = errno;
+ HDEBUG(D_receive) debug_printf("tcp wrappers rejected with unexpected "
+ "errno value %d\n", save_errno);
+ log_write(L_connection_reject,
+ LOG_MAIN|LOG_REJECT, "temporarily refused connection from %s "
+ "(tcp wrappers errno=%d)", host_and_ident(FALSE), save_errno);
+ smtp_printf("451 Temporary local problem - please try later\r\n");
+ }
return FALSE;
}
#endif
/* If there's been a sender verification failure with a specific message, and
we have not sent a response about it yet, do so now, as a preliminary line for
-failures, but not defers. However, log it in both cases. */
+failures, but not defers. However, always log it for defer, and log it for fail
+unless the sender_verify_fail log selector has been turned off. */
if (sender_verified_failed != NULL &&
!testflag(sender_verified_failed, af_sverify_told))
{
setflag(sender_verified_failed, af_sverify_told);
- log_write(0, LOG_MAIN|LOG_REJECT, "%s sender verify %s for <%s>%s",
- host_and_ident(TRUE),
- ((sender_verified_failed->special_action & 255) == DEFER)? "defer" : "fail",
- sender_verified_failed->address,
- (sender_verified_failed->message == NULL)? US"" :
- string_sprintf(": %s", sender_verified_failed->message));
+ if (rc != FAIL || (log_extra_selector & LX_sender_verify_fail) != 0)
+ log_write(0, LOG_MAIN|LOG_REJECT, "%s sender verify %s for <%s>%s",
+ host_and_ident(TRUE),
+ ((sender_verified_failed->special_action & 255) == DEFER)? "defer":"fail",
+ sender_verified_failed->address,
+ (sender_verified_failed->message == NULL)? US"" :
+ string_sprintf(": %s", sender_verified_failed->message));
if (rc == FAIL && sender_verified_failed->user_message != NULL)
smtp_respond(code, FALSE, string_sprintf(
switch(smtp_read_command(TRUE))
{
/* The AUTH command is not permitted to occur inside a transaction, and may
- occur successfully only once per connection, and then only when we've
- advertised it. Actually, that isn't quite true. When TLS is started, all
- previous information about a connection must be discarded, so a new AUTH is
- permitted at that time.
+ occur successfully only once per connection. Actually, that isn't quite
+ true. When TLS is started, all previous information about a connection must
+ be discarded, so a new AUTH is permitted at that time.
+
+ AUTH may only be used when it has been advertised. However, it seems that
+ there are clients that send AUTH when it hasn't been advertised, some of
+ them even doing this after HELO. And there are MTAs that accept this. Sigh.
+ So there's a get-out that allows this to happen.
AUTH is initially labelled as a "nonmail command" so that one occurrence
doesn't get counted. We change the label here so that multiple failing
authentication_failed = TRUE;
cmd_list[CMD_LIST_AUTH].is_mail_cmd = FALSE;
- if (!auth_advertised)
+ if (!auth_advertised && !allow_auth_unadvertised)
{
done = synprot_error(L_smtp_protocol_error, 503, NULL,
US"AUTH command used when not advertised");
}
/* Search for an authentication mechanism which is configured for use
- as a server and which has been advertised. */
+ as a server and which has been advertised (unless, sigh, allow_auth_
+ unadvertised is set). */
for (au = auths; au != NULL; au = au->next)
{
if (strcmpic(s, au->public_name) == 0 && au->server &&
- au->advertised) break;
+ (au->advertised || allow_auth_unadvertised)) break;
}
if (au == NULL)
#endif
(void)fwrite(s, 1, ptr, smtp_out);
- DEBUG(D_receive) debug_printf("SMTP>> %s", s);
+ DEBUG(D_receive)
+ {
+ uschar *cr;
+ while ((cr = Ustrchr(s, '\r')) != NULL) /* lose CRs */
+ memmove(cr, cr + 1, (ptr--) - (cr - s));
+ debug_printf("SMTP>> %s", s);
+ }
helo_seen = TRUE;
break; /* HELO/EHLO */
break;
case DEFER:
- s = (addr->message != NULL)?
- string_sprintf("451 <%s> %s", address, addr->message) :
+ s = (addr->user_message != NULL)?
+ string_sprintf("451 <%s> %s", address, addr->user_message) :
string_sprintf("451 Cannot resolve <%s> at this time", address);
break;
case FAIL:
- s = (addr->message != NULL)?
- string_sprintf("550 <%s> %s", address, addr->message) :
+ s = (addr->user_message != NULL)?
+ string_sprintf("550 <%s> %s", address, addr->user_message) :
string_sprintf("550 <%s> is not deliverable", address);
log_write(0, LOG_MAIN, "VRFY failed for %s %s",
smtp_cmd_argument, host_and_ident(TRUE));