2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-31 06:05:37 +00:00

postfix-2.0.16-20031217

This commit is contained in:
Wietse Venema
2003-12-17 00:00:00 -05:00
committed by Viktor Dukhovni
parent 49328174e4
commit 92cfbcfea3
15 changed files with 346 additions and 219 deletions

View File

@@ -8871,9 +8871,19 @@ Apologies for any names omitted.
between short queue ID and message status). File:
showq/showq.c.
20031216-7
Cleanup: the SMTP client now moves on to the next MX host
when delivery fails in the middle of an SMTP session.
Files: smtp/smtp.c, smtp/smtp_connect.c.
or fallback relay when delivery fails in the middle of an
SMTP session. This includes not only broken connections
(easy) but also includes 4xx SMTP server replies (not easy).
Files: smtp/smtp.c, smtp/smtp_connect.c, smtp_trouble.c.
20031217
Update: LDAP client logging (Liviu Daia) and LDAP client
documentation (Victor Duchovni). Files: util/dict_ldap.c,
conf/sample-ldap.cf, README_FILES/LDAP_README.
Open problems:

View File

@@ -93,7 +93,7 @@ parameters. Defaults are given in parentheses:
server_port = 778
search_base (No default; you must configure this.)
The base at which to conduct the search, e.g.
The RFC2253 base DN at which to conduct the search, e.g.
search_base = dc=your, dc=com
timeout (10 seconds)
@@ -104,19 +104,23 @@ parameters. Defaults are given in parentheses:
The RFC2254 filter used to search the directory, where %s is a
substitute for the address Postfix is trying to resolve, e.g.
query_filter = (&(mail=%s)(paid_up=true))
See sample-ldap.cf for more details.
result_filter (%s)
Filter applied to result attributes. Supports the same expansions
as the query_filter, and can be easily used to append (or prepend)
text.
Format template applied to result attributes. Supports the same
expansions as the query_filter, and can be easily used to append
(or prepend) text. See sample-ldap.cf for more details.
domain (Default is to ignore this.)
domain (Default is no domain list.)
This is a list of domain names, paths to files, or dictionaries.
If specified, only lookups for the domains on this list will be
performed. This means that the LDAP map won't get searched for
'user', nor will it get searched for any domain not listed. This
can significantly reduce the query load on the LDAP server.
When specified, only fully qualified search keys with a
*non-empty* localpart and a matching domain are eligible for
lookup: 'user' lookups, bare domain lookups and "@domain" lookups
are not performed. This can significantly reduce the query load
on the LDAP server.
domain = postfix.org, hash:/etc/postfix/searchdomains
It is best not to use LDAP to store the domains eligible for LDAP
lookups.
result_attribute (maildrop)
The attribute(s) Postfix will read from any directory entries
@@ -127,6 +131,12 @@ parameters. Defaults are given in parentheses:
The attribute(s) of directory entries that can contain DNs or URLs.
If found, a recursive subsequent search is done using their values.
special_result_attribute = member
DN recursion retrieves the same result_attributes as the main
query, including the special attributes for further recursion.
URI processing retrieves only those attributes that are included
in the URI definition and are *also* listed in "result_attribute".
If the URI lists any of the map's special result attributes, these
are also retrieved and used recursively.
scope (sub)
The LDAP search scope: sub, base, or one. These translate into

View File

@@ -22,6 +22,13 @@ snapshot release). Patches change the patchlevel and the release
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
Major changes with Postfix snapshot 2.0.16-20031217
===================================================
The SMTP client now moves on to the next MX host (or fallback relay)
when delivery fails in the middle of a session. This includes both
broken connections as well as 4XX replies to SMTP commands.
Incompatible changes with Postfix snapshot 2.0.16-20031215
==========================================================

View File

@@ -27,18 +27,62 @@
#version = 2
# The query_filter parameter specifies the filter used for queries.
# The replacement for "%s" is the address input into the map; e.g.
# for alias maps, the "user" part (the RFC 2822 local-part) of
# "user@domain.com" for To: addresses destined for local delivery
# (those matching $mydestination or a virtual domain), and all of
# "user@domain.com" (the RFC 2822 addr-spec) for other addresses.
# "%u" provides just the user portion of the input, and "%d" provides
# just the hostname.
#
# This parameter supports the following '%' expansions:
#
# %s - This is replaced by the input key. RFC 2254 quoting is
# used to make sure that the input key does not add
# unexpected metacharacters.
#
# %u - When the input key is an address of the form user@domain,
# %u is replaced by the (2254) quoted local part of the address.
# if no domain is specified, %u is replaced by the entire search
# string.
#
# %d - When the input key is an address of the form user@domain,
# %d is replaced by the (2254) quoted domain part of the address.
# When the input key has no domain qualifier, %d is replaced by the
# entire search string.
#
# The "domain" parameter described below limits the input keys to
# addresses in matching domains. When the "domain parameter is non-empty,
# LDAP queries for unqualified addresses or addresses in non-matching
# domains are suppressed and return no results.
#
# A non-empty value must be specified explicitly for this parameter. The empty
# default will not work.
#
# NOTE: DO NOT put double-quotes around the query filter!
#
#query_filter = (mailacceptinggeneralid=%s)
# The result_filter parameter specifies the filter to be applied
# to the result attribute(s). See query_filter for valid expansions.
# The result_filter parameter is printf-like format template that
# is applied separately to each result attribute of matching entries.
#
# This parameter supports the following '%' expansions:
#
# %s - This is replaced by the value of the result attribute.
#
# %u - When the result attribute is an address of the form user@domain,
# %u is replaced local part of the address, if the result attribute
# is unqualified, %u is replaced by the entire attribute value.
#
# %d - When a result attribute is an address of the form user@domain,
# %d is replaced by the domain part of the attribute value.
# If an attribute value is unqualified %d is replaced by the entire
# attribute value.
#
# For example, using "result_filter = smtp:[%s]" allows one to use a
# mailHost attribute as the basis of a transport(5) table. After applying
# the result filter, multiple values are concatenated as comma separated
# strings. The expansion_limit and size_limit parameters explained below
# allow one to restrict the number of values in the result, which is
# especially useful for maps that should return a single value.
#
# The default value %s (no quotes!) specifies that each attribute value
# should be used as is.
#
# NOTE: DO NOT put double-quotes around the result filter!
#
#result_filter = %s
@@ -49,10 +93,23 @@
# The special_result_attribute lists the attribute(s) of an
# entry which contain links, either ldap url's or distinguished names.
# The entries referenced by these links are (recursively) treated as if
# they were contained in the referencing entity.
#
#special_result_attribute =
# The entries referenced by these links are (recursively) treated as if
# they were contained in the referencing entity. The result_attributes
# of the referenced entries are retrieved and added to the query result.
# The special result attributes of the referenced entries are evaluated
# recursively.
#
# Note that for URI references, only the search base, scope, query filter
# and attributes are taken from the URI, the scheme, host and port are
# taken from the map definition. Extensions (even critical) are ignored.
# Of the attributes listed in the URI, only those listed in result_attribute
# are used in the search results, and only those listed in
# special_result_attribute are used for further recursion.
#
# The default value of this parameter is empty.
#
#special_result_attribute = uniquemember
# The scope parameter specifies the LDAP search scope: sub, base, or one.
#
@@ -113,7 +170,11 @@
#dereference = 0
# The domain parameter limits the LDAP searches to just things in
# (exactly) the specified list of domains.
# (exactly) the specified list of domains. When the "domain" parameter
# is non-empty, LDAP queries for unqualified addresses or addresses in
# non-matching domains are suppressed and return no results. This includes
# queries for catchall addresses with no local part (i.e. @domain.tld),
# which are also skipped.
#
#domain =

View File

@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
#define MAIL_RELEASE_DATE "20031216"
#define MAIL_RELEASE_DATE "20031217"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE

View File

@@ -75,11 +75,6 @@ smtp.o: ../../include/recipient_list.h
smtp.o: ../../include/mail_params.h
smtp.o: ../../include/mail_conf.h
smtp.o: ../../include/debug_peer.h
smtp.o: ../../include/mail_error.h
smtp.o: ../../include/deliver_pass.h
smtp.o: ../../include/mail_proto.h
smtp.o: ../../include/iostuff.h
smtp.o: ../../include/attr.h
smtp.o: ../../include/mail_server.h
smtp.o: smtp.h
smtp.o: smtp_sasl.h
@@ -94,12 +89,16 @@ smtp_addr.o: ../../include/stringops.h
smtp_addr.o: ../../include/myrand.h
smtp_addr.o: ../../include/mail_params.h
smtp_addr.o: ../../include/own_inet_addr.h
smtp_addr.o: ../../include/deliver_pass.h
smtp_addr.o: ../../include/deliver_request.h
smtp_addr.o: ../../include/vstream.h
smtp_addr.o: ../../include/recipient_list.h
smtp_addr.o: ../../include/mail_proto.h
smtp_addr.o: ../../include/iostuff.h
smtp_addr.o: ../../include/attr.h
smtp_addr.o: ../../include/dns.h
smtp_addr.o: smtp.h
smtp_addr.o: ../../include/vstream.h
smtp_addr.o: ../../include/argv.h
smtp_addr.o: ../../include/deliver_request.h
smtp_addr.o: ../../include/recipient_list.h
smtp_addr.o: smtp_addr.h
smtp_chat.o: smtp_chat.c
smtp_chat.o: ../../include/sys_defs.h
@@ -137,6 +136,9 @@ smtp_connect.o: ../../include/host_port.h
smtp_connect.o: ../../include/sane_connect.h
smtp_connect.o: ../../include/mail_params.h
smtp_connect.o: ../../include/own_inet_addr.h
smtp_connect.o: ../../include/debug_peer.h
smtp_connect.o: ../../include/mail_error.h
smtp_connect.o: ../../include/name_mask.h
smtp_connect.o: ../../include/dns.h
smtp_connect.o: smtp.h
smtp_connect.o: ../../include/argv.h

View File

@@ -315,10 +315,8 @@ bool var_smtp_defer_mxaddr;
bool var_smtp_send_xforward;
/*
* Global variables. smtp_errno is set by the address lookup routines and by
* the connection management routines.
* Global variables.
*/
int smtp_errno;
int smtp_host_lookup_mask;
/* deliver_message - deliver message with extreme prejudice */

View File

@@ -55,7 +55,8 @@ typedef struct SMTP_STATE {
off_t size_limit; /* server limit or unknown */
int space_left; /* output length control */
struct MIME_STATE *mime_state; /* mime state machine */
int final; /* last possibility to deliver */
int final_server; /* final mail server */
int backup_server; /* relayhost or fallback relay */
} SMTP_STATE;
#define SMTP_FEATURE_ESMTP (1<<0)
@@ -73,7 +74,6 @@ typedef struct SMTP_STATE {
/*
* smtp.c
*/
extern int smtp_errno; /* XXX can we get rid of this? */
extern int smtp_host_lookup_mask; /* host lookup methods to use */
#define SMTP_MASK_DNS (1<<0)

View File

@@ -6,14 +6,13 @@
/* SYNOPSIS
/* #include "smtp_addr.h"
/*
/* DNS_RR *smtp_domain_addr(name, why, found_myself)
/* DNS_RR *smtp_domain_addr(state, name)
/* SMTP_STATE *state;
/* char *name;
/* VSTRING *why;
/* int *found_myself;
/*
/* DNS_RR *smtp_host_addr(name, why)
/* DNS_RR *smtp_host_addr(state, name)
/* SMTP_STATE *state;
/* char *name;
/* VSTRING *why;
/* DESCRIPTION
/* This module implements Internet address lookups. By default,
/* lookups are done via the Internet domain name service (DNS).
@@ -27,7 +26,7 @@
/* so that it contains only hosts that are more preferred than the
/* local mail server itself. When the "best MX is local" feature
/* is enabled, the local system is allowed to be the best mail
/* exchanger, and the result is a null list pointer. Otherwise,
/* exchanger, and mail is delivered accordingly. Otherwise,
/* mailer loops are treated as an error.
/*
/* When no mail exchanger is listed in the DNS for \fIname\fR, the
@@ -47,16 +46,7 @@
/* when DNS lookups are explicitly disabled.
/*
/* All routines either return a DNS_RR pointer, or return a null
/* pointer and set the \fIsmtp_errno\fR global variable accordingly:
/* .IP SMTP_RETRY
/* The request failed due to a soft error, and should be retried later.
/* .IP SMTP_FAIL
/* The request attempt failed due to a hard error.
/* .IP SMTP_OK
/* The local machine is the best mail exchanger.
/* .PP
/* In addition, a textual description of the problem is made available
/* via the \fIwhy\fR argument.
/* pointer and report any problems via the smtp_trouble(3) module.
/* LICENSE
/* .ad
/* .fi
@@ -119,6 +109,7 @@ static int h_errno = TRY_AGAIN;
#include <mail_params.h>
#include <own_inet_addr.h>
#include <deliver_pass.h>
/* DNS library. */
@@ -129,6 +120,9 @@ static int h_errno = TRY_AGAIN;
#include "smtp.h"
#include "smtp_addr.h"
#define ERROR_CLASS_RETRY 450
#define ERROR_CLASS_FAIL 550
/* smtp_print_addr - print address list */
static void smtp_print_addr(char *what, DNS_RR *addr_list)
@@ -152,7 +146,8 @@ static void smtp_print_addr(char *what, DNS_RR *addr_list)
/* smtp_addr_one - address lookup for one host name */
static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
VSTRING *why, int *error_class)
{
char *myname = "smtp_addr_one";
struct in_addr inaddr;
@@ -185,13 +180,13 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRI
addr_list = dns_rr_append(addr_list, addr);
return (addr_list);
default:
smtp_errno = SMTP_RETRY;
*error_class = ERROR_CLASS_RETRY;
return (addr_list);
case DNS_FAIL:
smtp_errno = SMTP_FAIL;
*error_class = ERROR_CLASS_FAIL;
return (addr_list);
case DNS_NOTFOUND:
smtp_errno = SMTP_FAIL;
*error_class = ERROR_CLASS_FAIL;
/* maybe gethostbyname() will succeed */
break;
}
@@ -204,12 +199,13 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRI
memset((char *) &fixed, 0, sizeof(fixed));
if ((hp = gethostbyname(host)) == 0) {
vstring_sprintf(why, "%s: %s", host, HSTRERROR(h_errno));
smtp_errno = (h_errno == TRY_AGAIN ? SMTP_RETRY : SMTP_FAIL);
*error_class = (h_errno == TRY_AGAIN ?
ERROR_CLASS_RETRY : ERROR_CLASS_FAIL);
} else if (hp->h_addrtype != AF_INET) {
vstring_sprintf(why, "%s: host not found", host);
msg_warn("%s: unknown address family %d for %s",
myname, hp->h_addrtype, host);
smtp_errno = SMTP_FAIL;
*error_class = ERROR_CLASS_FAIL;
} else {
while (hp->h_addr_list[0]) {
addr_list = dns_rr_append(addr_list,
@@ -230,16 +226,17 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRI
/* smtp_addr_list - address lookup for a list of mail exchangers */
static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why)
static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why, int *error_class)
{
DNS_RR *addr_list = 0;
DNS_RR *rr;
/*
* As long as we are able to look up any host address, we ignore problems
* with DNS lookups.
* with DNS lookups (except if we're backup MX, and all the better MX
* hosts can't be found).
*
* XXX 2821: update smtp_errno (0->FAIL upon unrecoverable lookup error,
* XXX 2821: update error_class (0->FAIL upon unrecoverable lookup error,
* any->RETRY upon temporary lookup error) so that we can correctly
* handle the case of no resolvable MX host. Currently this is always
* treated as a soft error. RFC 2821 wants a more precise response.
@@ -247,7 +244,8 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why)
for (rr = mx_names; rr; rr = rr->next) {
if (rr->type != T_MX)
msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
addr_list = smtp_addr_one(addr_list, (char *) rr->data, rr->pref, why);
addr_list = smtp_addr_one(addr_list, (char *) rr->data, rr->pref,
why, error_class);
}
return (addr_list);
}
@@ -330,13 +328,16 @@ static int smtp_compare_pref(DNS_RR *a, DNS_RR *b)
/* smtp_domain_addr - mail exchanger address lookup */
DNS_RR *smtp_domain_addr(char *name, VSTRING *why, int *found_myself)
DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *name)
{
DELIVER_REQUEST *request = state->request;
DNS_RR *mx_names;
DNS_RR *addr_list = 0;
DNS_RR *self = 0;
unsigned best_pref;
unsigned best_found;
int error_class;
VSTRING *why = vstring_alloc(1);
/*
* Preferences from DNS use 0..32767, fall-backs use 32768+.
@@ -390,26 +391,40 @@ DNS_RR *smtp_domain_addr(char *name, VSTRING *why, int *found_myself)
* that an IP address is listed only under one hostname. However, looking
* at hostnames provides a partial solution for MX hosts behind a NAT
* gateway.
*
* Defer host lookup errors if a) there are more mail servers or b) we are
* looking up a relayhost or fallback relay.
*/
#define DEFER_HOST_LOOKUP_ERROR(s) \
((s)->final_server == 0 || (s)->backup_server)
switch (dns_lookup(name, T_MX, 0, &mx_names, (VSTRING *) 0, why)) {
default:
smtp_errno = SMTP_RETRY;
if (var_ign_mx_lookup_err)
addr_list = smtp_host_addr(name, why);
addr_list = smtp_host_addr(state, name);
else
smtp_site_fail(state, ERROR_CLASS_RETRY,
"%s: %s", request->queue_id, vstring_str(why));
break;
case DNS_FAIL:
smtp_errno = SMTP_FAIL;
if (var_ign_mx_lookup_err)
addr_list = smtp_host_addr(name, why);
addr_list = smtp_host_addr(state, name);
else {
smtp_site_fail(state, DEFER_HOST_LOOKUP_ERROR(state) ?
ERROR_CLASS_RETRY : ERROR_CLASS_FAIL,
"%s: %s", request->queue_id, vstring_str(why));
}
break;
case DNS_OK:
mx_names = dns_rr_sort(mx_names, smtp_compare_pref);
best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE);
addr_list = smtp_addr_list(mx_names, why);
addr_list = smtp_addr_list(mx_names, why, &error_class);
dns_rr_free(mx_names);
if (addr_list == 0) {
if (var_smtp_defer_mxaddr)
smtp_errno = SMTP_RETRY;
if (var_smtp_defer_mxaddr || DEFER_HOST_LOOKUP_ERROR(state))
error_class = ERROR_CLASS_RETRY;
smtp_site_fail(state, error_class,
"%s: %s", request->queue_id, vstring_str(why));
msg_warn("no MX host for %s has a valid A record", name);
break;
}
@@ -420,18 +435,23 @@ DNS_RR *smtp_domain_addr(char *name, VSTRING *why, int *found_myself)
addr_list = smtp_truncate_self(addr_list, self->pref);
if (addr_list == 0) {
if (best_pref != best_found) {
vstring_sprintf(why, "unable to find primary relay for %s",
name);
smtp_errno = SMTP_RETRY;
smtp_site_fail(state, ERROR_CLASS_RETRY,
"%s: unable to find primary relay for %s",
request->queue_id, name);
} else if (*var_bestmx_transp != 0) { /* we're best MX */
smtp_errno = SMTP_OK;
state->status =
deliver_pass_all(MAIL_CLASS_PRIVATE, var_bestmx_transp,
request);
state->final_server = 1;
} else {
msg_warn("mailer loop: best MX host for %s is local",
name);
vstring_sprintf(why, "mail for %s loops back to myself",
name);
smtp_errno = SMTP_FAIL;
msg_warn("%s is best MX host for %s but no local, virtual "
"or remote delivery is configured for that domain",
var_myhostname, request->nexthop);
smtp_site_fail(state, ERROR_CLASS_FAIL,
"%s: mail for %s loops back to myself",
request->queue_id, name);
}
break;
}
}
if (addr_list && addr_list->next && var_smtp_rand_addr) {
@@ -440,32 +460,43 @@ DNS_RR *smtp_domain_addr(char *name, VSTRING *why, int *found_myself)
}
break;
case DNS_NOTFOUND:
addr_list = smtp_host_addr(name, why);
addr_list = smtp_host_addr(state, name);
break;
}
/*
* Clean up.
*/
*found_myself = (self != 0);
vstring_free(why);
return (addr_list);
}
/* smtp_host_addr - direct host lookup */
DNS_RR *smtp_host_addr(char *host, VSTRING *why)
DNS_RR *smtp_host_addr(SMTP_STATE *state, char *host)
{
DELIVER_REQUEST *request = state->request;
DNS_RR *addr_list;
int error_class;
VSTRING *why = vstring_alloc(1);
/*
* If the host is specified by numerical address, just convert the
* address to internal form. Otherwise, the host is specified by name.
*/
#define PREF0 0
addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why);
if (addr_list && addr_list->next && var_smtp_rand_addr)
addr_list = dns_rr_shuffle(addr_list);
if (msg_verbose)
smtp_print_addr(host, addr_list);
addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why, &error_class);
if (addr_list == 0) {
if (DEFER_HOST_LOOKUP_ERROR(state))
error_class = ERROR_CLASS_RETRY;
smtp_site_fail(state, error_class,
"%s: %s", request->queue_id, vstring_str(why));
} else {
if (addr_list->next && var_smtp_rand_addr)
addr_list = dns_rr_shuffle(addr_list);
if (msg_verbose)
smtp_print_addr(host, addr_list);
}
vstring_free(why);
return (addr_list);
}

View File

@@ -16,8 +16,8 @@
/*
* Internal interfaces.
*/
extern DNS_RR *smtp_host_addr(char *, VSTRING *);
extern DNS_RR *smtp_domain_addr(char *, VSTRING *, int *);
extern DNS_RR *smtp_host_addr(SMTP_STATE *state, char *);
extern DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *);
/* LICENSE
/* .ad

View File

@@ -2,7 +2,7 @@
/* NAME
/* smtp_connect 3
/* SUMMARY
/* connect to SMTP server
/* connect to SMTP server and deliver
/* SYNOPSIS
/* #include "smtp.h"
/*
@@ -81,7 +81,6 @@
#include <mail_params.h>
#include <own_inet_addr.h>
#include <deliver_pass.h>
#include <debug_peer.h>
#include <mail_error.h>
@@ -204,27 +203,6 @@ static SMTP_SESSION *smtp_connect_addr(SMTP_STATE *state, DNS_RR *addr,
}
vstream_ungetc(stream, ch);
/*
* Skip this host if it sends a 4xx greeting.
*/
if (ch == '4' && var_smtp_skip_4xx_greeting) {
smtp_site_fail(state, 450, "connect to %s[%s] port %u: "
"server refused mail service",
addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
vstream_fclose(stream);
return (0);
}
/*
* Skip this host if it sends a 5xx greeting.
*/
if (ch == '5' && var_smtp_skip_5xx_greeting) {
smtp_site_fail(state, 450, "connect to %s[%s] port %u: "
"server refused mail service",
addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
vstream_fclose(stream);
return (0);
}
return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
}
@@ -267,7 +245,6 @@ static char *smtp_parse_destination(char *destination, char *def_service,
int smtp_connect(SMTP_STATE *state)
{
VSTRING *why = vstring_alloc(100);
DELIVER_REQUEST *request = state->request;
char *dest_buf;
char *host;
@@ -276,27 +253,41 @@ int smtp_connect(SMTP_STATE *state)
ARGV *sites;
char *dest;
char **cpp;
int found_myself;
DNS_RR *addr_list;
DNS_RR *addr;
/*
* First try to deliver to the indicated destination, then try to deliver
* to the optional fall-back relays. Sanity check in case we allow the
* primary destination to be a list (we did for some time in the past).
* to the optional fall-back relays.
*
* After a soft error, log recipient deferrals only when there are no
* further possibilities to deliver.
* Future proofing: do a null destination sanity check in case we allow the
* primary destination to be a list, as it could be just a bunch of
* separators.
*/
sites = argv_alloc(1);
argv_add(sites, request->nexthop, (char *) 0);
if (sites->argc == 0)
msg_panic("null destination: \"%s\"", request->nexthop);
argv_split_append(sites, var_fallback_relay, ", \t\r\n");
if (*var_fallback_relay)
argv_split_append(sites, var_fallback_relay, ", \t\r\n");
/*
* Don't give up after any soft error until we have tried all servers.
*
* Don't give up after a hard host lookup error until we have tried the
* fallback relay servers.
*
* Don't bounce mail after host lookup problems with a relayhost or with
* fallback relays.
*
* All this means that error handling and error reporting depends on whether
* there are more mail servers (state->final_server), or whether we're
* looking up a relayhost or fallback relay (state->backup_server).
*/
for (cpp = sites->argv; (dest = *cpp) != 0; cpp++) {
found_myself = 0;
state->final = (cpp[1] == 0);
state->final_server = (cpp[1] == 0);
state->backup_server =
(cpp > sites->argv || strcmp(request->nexthop, var_relayhost) == 0);
/*
* Parse the destination. Default is to use the SMTP port. Look up
@@ -307,59 +298,21 @@ int smtp_connect(SMTP_STATE *state)
if (msg_verbose)
msg_info("connecting to \"%s\" port \"%d\"", host, ntohs(port));
if (var_disable_dns || *dest == '[') {
addr_list = smtp_host_addr(host, why);
addr_list = smtp_host_addr(state, host);
} else {
addr_list = smtp_domain_addr(host, why, &found_myself);
addr_list = smtp_domain_addr(state, host);
}
myfree(dest_buf);
/*
* Handle host lookup problems. XXX It would be nice if the address
* lookup routines could do their own smtp_site_fail() calls instead
* of having us make sense of things from a distance. The
* complication is that an unrecoverable host lookup error may still
* be followed by an attempt to deliver via a fallback relay.
* No address list. The mail has / has not been delivered. What to do
* next (skip remaining hosts / try to deliver) is recorded in the
* state->final_server attribute.
*/
if (addr_list == 0) {
/*
* Mail loops back to myself. An smtp_errno of OK means that we
* should hand off the mail to a local transport. This hand-off
* should not happen with fallback relays.
*/
if (smtp_errno == SMTP_OK && cpp == sites->argv) {
state->status =
deliver_pass_all(MAIL_CLASS_PRIVATE, var_bestmx_transp,
request);
break;
}
if (found_myself) {
smtp_site_fail(state, 450,
"%s: %s", request->queue_id, vstring_str(why));
break;
}
/*
* Pay attention to what could be configuration problems, and
* pretend that these are recoverable rather than bouncing the
* mail.
*/
if (strcmp(request->nexthop, var_relayhost) == 0) {
msg_warn("%s configuration problem: %s",
VAR_RELAYHOST, var_relayhost);
smtp_site_fail(state, 450,
"%s: %s", request->queue_id, vstring_str(why));
continue;
}
if (cpp > sites->argv && sites->argc > 1) {
msg_warn("%s problem: %s",
VAR_FALLBACK_RELAY, var_fallback_relay);
smtp_site_fail(state, 450,
"%s: %s", request->queue_id, vstring_str(why));
continue;
}
smtp_site_fail(state, cpp[1] || smtp_errno == SMTP_RETRY ? 450 : 550,
"%s: %s", request->queue_id, vstring_str(why));
if (state->backup_server)
msg_warn("%s or %s configuration problem",
VAR_RELAYHOST, VAR_FALLBACK_RELAY);
}
/*
@@ -371,10 +324,10 @@ int smtp_connect(SMTP_STATE *state)
*/
for (addr = addr_list; addr; addr = addr->next) {
if ((state->session = smtp_connect_addr(state, addr, port)) != 0) {
state->final_server = (cpp[1] == 0 && addr->next == 0);
state->status = 0;
state->session->best = (addr->pref == addr_list->pref);
debug_peer_check(state->session->host, state->session->addr);
state->final = (cpp[1] == 0 && addr->next == 0);
if (smtp_helo(state) == 0)
smtp_xfer(state);
if (state->history != 0
@@ -384,17 +337,23 @@ int smtp_connect(SMTP_STATE *state)
/* XXX smtp_xfer() may abort in the middle of DATA. */
smtp_session_free(state->session);
debug_peer_restore();
if (state->status == 0)
if (state->status == 0 || state->final_server)
break;
}
}
dns_rr_free(addr_list);
/*
* In case someone has raised the "final server" flag before we have
* tried all fallback servers.
*/
if (state->final_server)
break;
}
/*
* Cleanup.
*/
vstring_free(why);
argv_free(sites);
return (state->status);
}

View File

@@ -197,10 +197,13 @@ int smtp_helo(SMTP_STATE *state)
/*
* Read and parse the server's SMTP greeting banner.
*/
if (((resp = smtp_chat_resp(state))->code / 100) != 2)
if ((resp = smtp_chat_resp(state))->code / 100 != 2) {
if (var_smtp_skip_5xx_greeting && resp->code / 100 == '5')
resp->code -= 100;
return (smtp_site_fail(state, resp->code,
"host %s refused to talk to me: %s",
session->namaddr, translit(resp->str, "\n", " ")));
}
/*
* XXX Some PIX firewall versions require flush before ".<CR><LF>" so it

View File

@@ -72,7 +72,8 @@ SMTP_STATE *smtp_state_alloc(void)
state->size_limit = 0;
state->space_left = 0;
state->mime_state = 0;
state->final = 0;
state->final_server = 0;
state->backup_server = 0;
return (state);
}

View File

@@ -44,35 +44,53 @@
/* would suffer the same problem and just cause more trouble.
/*
/* In case of a soft error, action depends on whether there are
/* more possibilities to deliver (log one generic record) or whether
/* the error happens with the last possibility (log each recipient).
/* more mail servers (log an informational record only and try
/* the other servers) or whether this is the final server (log
/* recipient delivery status records).
/*
/* In the case of a hard error that affects all recipients,
/* recipient delivery status records are logged, and the
/* final server flag is raised so that any remaining mail
/* servers are skipped.
/*
/* smtp_site_fail() handles the case where the program fails to
/* complete the initial SMTP handshake: the server is not reachable,
/* is not running, does not want talk to us, or we talk to ourselves.
/* The \fIcode\fR gives an error status code; the \fIformat\fR
/* argument gives a textual description. The policy is: soft
/* error: defer delivery of all messages to this domain; hard
/* error: bounce all recipients of this message.
/* argument gives a textual description.
/* The policy is: soft error, non-final server: log an informational
/* record why the host is being skipped; soft error, final server:
/* defer delivery of all remaining recipients; hard error: bounce all
/* remaining recipients and set the "final server" flag so that any
/* remaining mail servers will be skipped.
/* The result is non-zero.
/*
/* smtp_mesg_fail() handles the case where the smtp server
/* does not accept the sender address or the message data.
/* The policy is: soft errors: defer delivery of this message;
/* hard error: bounce all recipients of this message.
/* The policy is: soft error, non-final server: log an informational
/* record why the host is being skipped; soft error, final server:
/* defer delivery of all remaining recipients; hard error: bounce all
/* remaining recipients and set the "final server" flag so that any
/* remaining mail servers will be skipped.
/* The result is non-zero.
/*
/* smtp_rcpt_fail() handles the case where a recipient is not
/* accepted by the server for reasons other than that the server
/* recipient limit is reached. The policy is: soft error: defer
/* delivery to this recipient; hard error: bounce this recipient.
/* recipient limit is reached.
/* The policy is: soft error, non-final server: log an informational
/* record why the recipient is being skipped; soft error, final server:
/* defer delivery of this recipient; hard error: bounce this
/* recipient. This routine does not change the "final server" flag.
/*
/* smtp_stream_except() handles the exceptions generated by
/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
/* The \fIexception\fR argument specifies the type of problem.
/* The \fIdescription\fR argument describes at what stage of
/* the SMTP dialog the problem happened. The policy is to defer
/* delivery of all messages to the same domain. The result is non-zero.
/* the SMTP dialog the problem happened.
/* The policy is: non-final server: log an informational record
/* with the reason why the host is being skipped; final server:
/* defer delivery of all remaining recipients.
/* The result is non-zero.
/* DIAGNOSTICS
/* Panic: unknown exception code.
/* SEE ALSO
@@ -141,7 +159,7 @@ static void smtp_check_code(SMTP_STATE *state, int code)
state->error_mask |= MAIL_ERROR_PROTOCOL;
}
/* smtp_site_fail - defer site or bounce recipients */
/* smtp_site_fail - skip site, defer all recipients, or bounce all recipients */
int smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
{
@@ -162,17 +180,18 @@ int smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
va_end(ap);
/*
* Don't log deferred recipients yet when there are still untried
* possibilities to deliver. Just log why we're abandoning this host.
* Don't defer the recipients just yet when there are still more mail
* servers. Just log something informative to show why we're skipping
* this host.
*/
if (soft_error && state->final == 0) {
if (soft_error && state->final_server == 0) {
msg_info("%s: %s", request->queue_id, vstring_str(why));
state->status |= -1;
}
/*
* If this is a soft error, postpone further deliveries to this domain.
* Otherwise, generate a bounce record for each recipient.
* Defer or bounce all the remaining recipients and raise the final mail
* server flag.
*/
else {
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
@@ -192,7 +211,9 @@ int smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
}
if (soft_error && request->hop_status == 0)
request->hop_status = mystrdup(vstring_str(why));
state->final_server = 1;
}
smtp_check_code(state, code);
/*
* Cleanup.
@@ -201,7 +222,7 @@ int smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
return (-1);
}
/* smtp_mesg_fail - defer message or bounce all recipients */
/* smtp_mesg_fail - skip site, defer all recipients, or bounce all recipients */
int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
{
@@ -222,17 +243,18 @@ int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
va_end(ap);
/*
* Don't log deferred recipients yet when there are still untried
* possibilities to deliver. Just log why we're abandoning this host.
* Don't defer the recipients just yet when there are still more mail
* servers. Just log something informative to show why we're skipping
* this host.
*/
if (soft_error && state->final == 0) {
if (soft_error && state->final_server == 0) {
msg_info("%s: %s", request->queue_id, vstring_str(why));
state->status |= -1;
}
/*
* If this is a soft error, postpone delivery of this message. Otherwise,
* generate a bounce record for each recipient.
* Defer or bounce all the remaining recipients and raise the final mail
* server flag.
*/
else {
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
@@ -250,6 +272,7 @@ int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
}
state->status |= status;
}
state->final_server = 1;
}
smtp_check_code(state, code);
@@ -260,7 +283,7 @@ int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
return (-1);
}
/* smtp_rcpt_fail - defer or bounce recipient */
/* smtp_rcpt_fail - skip, defer, or bounce recipient */
void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
char *format,...)
@@ -272,10 +295,11 @@ void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
va_list ap;
/*
* Don't log deferred recipients yet when there are still untried
* possibilities to deliver.
* Don't defer this recipient record just yet when there are still more
* mail servers. Just log something informative to show why we're
* skipping this recipient now.
*/
if (soft_error && state->final == 0) {
if (soft_error && state->final_server == 0) {
VSTRING *buf = vstring_alloc(10);
va_start(ap, format);
@@ -287,8 +311,15 @@ void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
}
/*
* If this is a soft error, postpone delivery to this recipient.
* Otherwise, generate a bounce record for this recipient.
* Defer or bounce this specific recipient.
*
* If this is a hard error, we must not raise the final mail server flag. We
* may still make another SMTP connection to deliver deferred recipients.
*
* If this is a soft error, we got here because the final mail server flag
* was already set.
*
* So don't touch that final mail server flag!
*/
else {
va_start(ap, format);
@@ -333,17 +364,16 @@ int smtp_stream_except(SMTP_STATE *state, int code, char *description)
}
/*
* Don't log deferred recipients yet when there are still untried
* possibilities to deliver. Just log why we're abandoning this host.
* Don't defer the recipients just yet when there are still more mail
* servers. Just log why we're abandoning this host.
*/
if (state->final == 0) {
if (state->final_server == 0) {
msg_info("%s: %s", request->queue_id, vstring_str(why));
state->status |= -1;
}
/*
* At this point, the status of individual recipients remains unresolved.
* All we know is that we should stay away from this host for a while.
* Final server. Defer all the remaining recipients.
*/
else {
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {

View File

@@ -154,6 +154,7 @@
#include <lber.h>
#include <ldap.h>
#include <string.h>
#include <ctype.h>
/*
* Older APIs have weird memory freeing behavior.
@@ -259,8 +260,17 @@ static void dict_ldap_timeout(int unused_sig)
static void dict_ldap_logprint(LDAP_CONST char *data)
{
char *myname = "dict_ldap_debug";
char *buf,
*p;
msg_info("%s: %s", myname, data);
buf = mystrdup(data);
if (*buf) {
p = buf + strlen(buf) - 1;
while (p - buf >= 0 && ISSPACE(*p))
*p-- = 0;
}
msg_info("%s: %s", myname, buf);
myfree(buf);
}
@@ -481,6 +491,21 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
#endif
#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
if (dict_ldap->debuglevel > 0 &&
ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
(LDAP_CONST *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
msg_warn("%s: Unable to set ber logprint function.", myname);
#if defined(LBER_OPT_DEBUG_LEVEL)
if (ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
&(dict_ldap->debuglevel)) != LBER_OPT_SUCCESS)
msg_warn("%s: Unable to set BER debug level.", myname);
#endif
if (ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL,
&(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS)
msg_warn("%s: Unable to set LDAP debug level.", myname);
#endif
dict_errno = 0;
if (msg_verbose)
@@ -573,16 +598,6 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
&(dict_ldap->dereference)) != LDAP_OPT_SUCCESS)
msg_warn("%s: Unable to set dereference option.", myname);
#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
if (dict_ldap->debuglevel > 0 &&
ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
(LDAP_CONST *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
msg_warn("%s: Unable to set ber logprint function.", myname);
if (ldap_set_option(dict_ldap->ld, LDAP_OPT_DEBUG_LEVEL,
&(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS)
msg_warn("%s: Unable to set LDAP debug level.", myname);
#endif
/* Chase referrals. */
/*