-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.14 2005/08/02 09:24:45 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.22 2006/02/23 12:41:23 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2006 */
/* See the file NOTICE for conditions of use and distribution. */
#include "../exim.h"
(void *)offsetof(smtp_transport_options_block, interface) },
{ "keepalive", opt_bool,
(void *)offsetof(smtp_transport_options_block, keepalive) },
+ { "lmtp_ignore_quota", opt_bool,
+ (void *)offsetof(smtp_transport_options_block, lmtp_ignore_quota) },
{ "max_rcpt", opt_int | opt_public,
(void *)offsetof(transport_instance, max_addresses) },
{ "multi_domain", opt_bool | opt_public,
FALSE, /* hosts_override */
FALSE, /* hosts_randomize */
TRUE, /* keepalive */
+ FALSE, /* lmtp_ignore_quota */
TRUE /* retry_include_ip_address */
#ifdef SUPPORT_TLS
,NULL, /* tls_certificate */
tblock pointer to the transport instance block
addrlist list of addresses about to be transported
tf if not NULL, pointer to block in which to return options
+ uid the uid that will be set (not used)
+ gid the gid that will be set (not used)
errmsg place for error message (not used)
Returns: OK always (FAIL, DEFER not used)
static int
smtp_transport_setup(transport_instance *tblock, address_item *addrlist,
- transport_feedback *tf, uschar **errmsg)
+ transport_feedback *tf, uid_t uid, gid_t gid, uschar **errmsg)
{
smtp_transport_options_block *ob =
(smtp_transport_options_block *)(tblock->options_block);
errmsg = errmsg; /* Keep picky compilers happy */
+uid = uid;
+gid = gid;
/* Pass back options if required. This interface is getting very messy. */
Returns: nothing
*/
-static
-void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
+static void
+set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
BOOL pass_message)
{
address_item *addr;
}
/* No data was read. If there is no errno, this must be the EOF (i.e.
-connection closed) case, which causes deferral. Otherwise, put the host's
-identity in the message, leaving the errno value to be interpreted as well. In
-all cases, we have to assume the connection is now dead. */
+connection closed) case, which causes deferral. An explicit connection reset
+error has the same effect. Otherwise, put the host's identity in the message,
+leaving the errno value to be interpreted as well. In all cases, we have to
+assume the connection is now dead. */
-if (*errno_value == 0)
+if (*errno_value == 0 || *errno_value == ECONNRESET)
{
*errno_value = ERRNO_SMTPCLOSED;
*message = US string_sprintf("Remote host %s [%s] closed connection "
}
else
{
- log_write(0, LOG_MAIN, "%s [%s]: %s",
- host->name,
- host->address,
- strerror(addr->basic_errno));
- deliver_msglog("%s %s [%s]: %s\n",
- tod_stamp(tod_log),
- host->name,
- host->address,
+ uschar *msg =
+ ((log_extra_selector & LX_outgoing_port) != 0)?
+ string_sprintf("%s [%s]:%d", host->name, host->address,
+ (host->port == PORT_NONE)? 25 : host->port)
+ :
+ string_sprintf("%s [%s]", host->name, host->address);
+ log_write(0, LOG_MAIN, "%s %s", msg, strerror(addr->basic_errno));
+ deliver_msglog("%s %s %s\n", tod_stamp(tod_log), msg,
strerror(addr->basic_errno));
}
}
failed by one of them.
host host to deliver to
host_af AF_INET or AF_INET6
- port TCP/IP port to use, in host byte order
+ port default TCP/IP port to use, in host byte order
interface interface to bind to, or NULL
tblock transport instance block
copy_host TRUE if host set in addr->host_used must be copied, because
smtp_inblock inblock;
smtp_outblock outblock;
int max_rcpt = tblock->max_addresses;
+uschar *igquotstr = US"";
uschar *local_authenticated_sender = authenticated_sender;
uschar *helo_data;
uschar *message = NULL;
ob->command_timeout)) goto RESPONSE_FAILED;
}
+ /* Set IGNOREQUOTA if the response to LHLO specifies support and the
+ lmtp_ignore_quota option was set. */
+
+ igquotstr = (lmtp && ob->lmtp_ignore_quota &&
+ pcre_exec(regex_IGNOREQUOTA, NULL, CS buffer, Ustrlen(CS buffer), 0,
+ PCRE_EOPT, NULL, 0) >= 0)? US" IGNOREQUOTA" : US"";
+
/* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
#ifdef SUPPORT_TLS
int require_auth;
uschar *fail_reason = US"server did not advertise AUTH support";
+ /* Set for IGNOREQUOTA if the response to LHLO specifies support and the
+ lmtp_ignore_quota option was set. */
+
+ igquotstr = (lmtp && ob->lmtp_ignore_quota &&
+ pcre_exec(regex_IGNOREQUOTA, NULL, CS buffer, Ustrlen(CS buffer), 0,
+ PCRE_EOPT, NULL, 0) >= 0)? US" IGNOREQUOTA" : US"";
+
/* If the response to EHLO specified support for the SIZE parameter, note
this, provided size_addition is non-negative. */
/* Failure by some other means. In effect, the authenticator
decided it wasn't prepared to handle this case. Typically this
is the result of "fail" in an expansion string. Do we need to
- log anything here? */
+ log anything here? Feb 2006: a message is now put in the buffer
+ if logging is required. */
case CANCELLED:
+ if (*buffer != 0)
+ log_write(0, LOG_MAIN, "%s authenticator cancelled "
+ "authentication H=%s [%s] %s", au->name, host->name,
+ host->address, buffer);
break;
/* Internal problem, message in buffer. */
yield as OK, because this error can often mean that there is a problem with
just one address, so we don't want to delay the host. */
- count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>\r\n",
- transport_rcpt_address(addr, tblock->rcpt_include_affixes));
+ count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n",
+ transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr);
if (count < 0) goto SEND_FAILED;
if (count > 0)
{
}
/* SMTP, or success return from LMTP for this address. Pass back the
- actual port used. */
+ actual host that was used. */
addr->transport_return = OK;
addr->more_errno = delivery_time;
- thost->port = port;
addr->host_used = thost;
addr->special_action = flag;
addr->message = conf;
}
-/* Sort out the port. Set up a string for adding to the retry key if the port
-number is not the standard SMTP port. */
+/* Sort out the default port. */
if (!smtp_get_port(ob->port, addrlist, &port, tid)) return FALSE;
-pistring = string_sprintf(":%d", port);
-if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
/* For each host-plus-IP-address on the list:
if (host->address == NULL)
{
+ int new_port;
+ host_item *hh;
uschar *canonical_name;
if (host->status >= hstatus_unusable)
DEBUG(D_transport) debug_printf("getting address for %s\n", host->name);
+ /* The host name is permitted to have an attached port. Find it, and
+ strip it from the name. Just remember it for now. */
+
+ new_port = host_item_get_port(host);
+
+ /* Count hosts looked up */
+
hosts_looked_up++;
/* Find by name if so configured, or if it's an IP address. We don't
just copy the IP address, because we need the test-for-local to happen. */
- if (ob->gethostbyname || string_is_ip_address(host->name, NULL) > 0)
+ if (ob->gethostbyname || string_is_ip_address(host->name, NULL) != 0)
rc = host_find_byname(host, NULL, &canonical_name, TRUE);
else
{
&canonical_name, NULL);
}
+ /* Update the host (and any additional blocks, resulting from
+ multihoming) with a host-specific port, if any. */
+
+ for (hh = host; hh != nexthost; hh = hh->next) hh->port = new_port;
+
/* Failure to find the host at this time (usually DNS temporary failure)
is really a kind of routing failure rather than a transport failure.
Therefore we add a retry item of the routing kind, not to stop us trying
deliver_host = host->name;
deliver_host_address = host->address;
+ /* Set up a string for adding to the retry key if the port number is not
+ the standard SMTP port. A host may have its own port setting that overrides
+ the default. */
+
+ pistring = string_sprintf(":%d", (host->port == PORT_NONE)?
+ port : host->port);
+ if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
+
/* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
string changes upon expansion, we must add it to the key that is used for
retries, because connections to the same host from a different interface