mirror of
https://github.com/vdukhovni/postfix
synced 2025-09-02 15:15:24 +00:00
postfix-2.0.16-20031217
This commit is contained in:
committed by
Viktor Dukhovni
parent
49328174e4
commit
92cfbcfea3
@@ -8871,9 +8871,19 @@ Apologies for any names omitted.
|
|||||||
between short queue ID and message status). File:
|
between short queue ID and message status). File:
|
||||||
showq/showq.c.
|
showq/showq.c.
|
||||||
|
|
||||||
|
20031216-7
|
||||||
|
|
||||||
Cleanup: the SMTP client now moves on to the next MX host
|
Cleanup: the SMTP client now moves on to the next MX host
|
||||||
when delivery fails in the middle of an SMTP session.
|
or fallback relay when delivery fails in the middle of an
|
||||||
Files: smtp/smtp.c, smtp/smtp_connect.c.
|
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:
|
Open problems:
|
||||||
|
|
||||||
|
@@ -93,7 +93,7 @@ parameters. Defaults are given in parentheses:
|
|||||||
server_port = 778
|
server_port = 778
|
||||||
|
|
||||||
search_base (No default; you must configure this.)
|
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
|
search_base = dc=your, dc=com
|
||||||
|
|
||||||
timeout (10 seconds)
|
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
|
The RFC2254 filter used to search the directory, where %s is a
|
||||||
substitute for the address Postfix is trying to resolve, e.g.
|
substitute for the address Postfix is trying to resolve, e.g.
|
||||||
query_filter = (&(mail=%s)(paid_up=true))
|
query_filter = (&(mail=%s)(paid_up=true))
|
||||||
|
See sample-ldap.cf for more details.
|
||||||
|
|
||||||
result_filter (%s)
|
result_filter (%s)
|
||||||
Filter applied to result attributes. Supports the same expansions
|
Format template applied to result attributes. Supports the same
|
||||||
as the query_filter, and can be easily used to append (or prepend)
|
expansions as the query_filter, and can be easily used to append
|
||||||
text.
|
(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.
|
This is a list of domain names, paths to files, or dictionaries.
|
||||||
If specified, only lookups for the domains on this list will be
|
When specified, only fully qualified search keys with a
|
||||||
performed. This means that the LDAP map won't get searched for
|
*non-empty* localpart and a matching domain are eligible for
|
||||||
'user', nor will it get searched for any domain not listed. This
|
lookup: 'user' lookups, bare domain lookups and "@domain" lookups
|
||||||
can significantly reduce the query load on the LDAP server.
|
are not performed. This can significantly reduce the query load
|
||||||
|
on the LDAP server.
|
||||||
domain = postfix.org, hash:/etc/postfix/searchdomains
|
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)
|
result_attribute (maildrop)
|
||||||
The attribute(s) Postfix will read from any directory entries
|
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.
|
The attribute(s) of directory entries that can contain DNs or URLs.
|
||||||
If found, a recursive subsequent search is done using their values.
|
If found, a recursive subsequent search is done using their values.
|
||||||
special_result_attribute = member
|
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)
|
scope (sub)
|
||||||
The LDAP search scope: sub, base, or one. These translate into
|
The LDAP search scope: sub, base, or one. These translate into
|
||||||
|
@@ -22,6 +22,13 @@ snapshot release). Patches change the patchlevel and the release
|
|||||||
date. Snapshots change only the release date, unless they include
|
date. Snapshots change only the release date, unless they include
|
||||||
the same bugfixes as a patch release.
|
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
|
Incompatible changes with Postfix snapshot 2.0.16-20031215
|
||||||
==========================================================
|
==========================================================
|
||||||
|
|
||||||
|
@@ -27,18 +27,62 @@
|
|||||||
#version = 2
|
#version = 2
|
||||||
|
|
||||||
# The query_filter parameter specifies the filter used for queries.
|
# 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
|
# This parameter supports the following '%' expansions:
|
||||||
# "user@domain.com" for To: addresses destined for local delivery
|
#
|
||||||
# (those matching $mydestination or a virtual domain), and all of
|
# %s - This is replaced by the input key. RFC 2254 quoting is
|
||||||
# "user@domain.com" (the RFC 2822 addr-spec) for other addresses.
|
# used to make sure that the input key does not add
|
||||||
# "%u" provides just the user portion of the input, and "%d" provides
|
# unexpected metacharacters.
|
||||||
# just the hostname.
|
#
|
||||||
|
# %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)
|
#query_filter = (mailacceptinggeneralid=%s)
|
||||||
|
|
||||||
# The result_filter parameter specifies the filter to be applied
|
# The result_filter parameter is printf-like format template that
|
||||||
# to the result attribute(s). See query_filter for valid expansions.
|
# 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
|
#result_filter = %s
|
||||||
|
|
||||||
@@ -49,10 +93,23 @@
|
|||||||
|
|
||||||
# The special_result_attribute lists the attribute(s) of an
|
# The special_result_attribute lists the attribute(s) of an
|
||||||
# entry which contain links, either ldap url's or distinguished names.
|
# 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.
|
# The scope parameter specifies the LDAP search scope: sub, base, or one.
|
||||||
#
|
#
|
||||||
@@ -113,7 +170,11 @@
|
|||||||
#dereference = 0
|
#dereference = 0
|
||||||
|
|
||||||
# The domain parameter limits the LDAP searches to just things in
|
# 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 =
|
#domain =
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
* Patches change the patchlevel and the release date. Snapshots change the
|
* Patches change the patchlevel and the release date. Snapshots change the
|
||||||
* release date only, unless they include the same bugfix as a patch release.
|
* 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 VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
|
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
|
||||||
|
@@ -75,11 +75,6 @@ smtp.o: ../../include/recipient_list.h
|
|||||||
smtp.o: ../../include/mail_params.h
|
smtp.o: ../../include/mail_params.h
|
||||||
smtp.o: ../../include/mail_conf.h
|
smtp.o: ../../include/mail_conf.h
|
||||||
smtp.o: ../../include/debug_peer.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: ../../include/mail_server.h
|
||||||
smtp.o: smtp.h
|
smtp.o: smtp.h
|
||||||
smtp.o: smtp_sasl.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/myrand.h
|
||||||
smtp_addr.o: ../../include/mail_params.h
|
smtp_addr.o: ../../include/mail_params.h
|
||||||
smtp_addr.o: ../../include/own_inet_addr.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: ../../include/dns.h
|
||||||
smtp_addr.o: smtp.h
|
smtp_addr.o: smtp.h
|
||||||
smtp_addr.o: ../../include/vstream.h
|
|
||||||
smtp_addr.o: ../../include/argv.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_addr.o: smtp_addr.h
|
||||||
smtp_chat.o: smtp_chat.c
|
smtp_chat.o: smtp_chat.c
|
||||||
smtp_chat.o: ../../include/sys_defs.h
|
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/sane_connect.h
|
||||||
smtp_connect.o: ../../include/mail_params.h
|
smtp_connect.o: ../../include/mail_params.h
|
||||||
smtp_connect.o: ../../include/own_inet_addr.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: ../../include/dns.h
|
||||||
smtp_connect.o: smtp.h
|
smtp_connect.o: smtp.h
|
||||||
smtp_connect.o: ../../include/argv.h
|
smtp_connect.o: ../../include/argv.h
|
||||||
|
@@ -315,10 +315,8 @@ bool var_smtp_defer_mxaddr;
|
|||||||
bool var_smtp_send_xforward;
|
bool var_smtp_send_xforward;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global variables. smtp_errno is set by the address lookup routines and by
|
* Global variables.
|
||||||
* the connection management routines.
|
|
||||||
*/
|
*/
|
||||||
int smtp_errno;
|
|
||||||
int smtp_host_lookup_mask;
|
int smtp_host_lookup_mask;
|
||||||
|
|
||||||
/* deliver_message - deliver message with extreme prejudice */
|
/* deliver_message - deliver message with extreme prejudice */
|
||||||
|
@@ -55,7 +55,8 @@ typedef struct SMTP_STATE {
|
|||||||
off_t size_limit; /* server limit or unknown */
|
off_t size_limit; /* server limit or unknown */
|
||||||
int space_left; /* output length control */
|
int space_left; /* output length control */
|
||||||
struct MIME_STATE *mime_state; /* mime state machine */
|
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;
|
} SMTP_STATE;
|
||||||
|
|
||||||
#define SMTP_FEATURE_ESMTP (1<<0)
|
#define SMTP_FEATURE_ESMTP (1<<0)
|
||||||
@@ -73,7 +74,6 @@ typedef struct SMTP_STATE {
|
|||||||
/*
|
/*
|
||||||
* smtp.c
|
* smtp.c
|
||||||
*/
|
*/
|
||||||
extern int smtp_errno; /* XXX can we get rid of this? */
|
|
||||||
extern int smtp_host_lookup_mask; /* host lookup methods to use */
|
extern int smtp_host_lookup_mask; /* host lookup methods to use */
|
||||||
|
|
||||||
#define SMTP_MASK_DNS (1<<0)
|
#define SMTP_MASK_DNS (1<<0)
|
||||||
|
@@ -6,14 +6,13 @@
|
|||||||
/* SYNOPSIS
|
/* SYNOPSIS
|
||||||
/* #include "smtp_addr.h"
|
/* #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;
|
/* 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;
|
/* char *name;
|
||||||
/* VSTRING *why;
|
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* This module implements Internet address lookups. By default,
|
/* This module implements Internet address lookups. By default,
|
||||||
/* lookups are done via the Internet domain name service (DNS).
|
/* 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
|
/* so that it contains only hosts that are more preferred than the
|
||||||
/* local mail server itself. When the "best MX is local" feature
|
/* local mail server itself. When the "best MX is local" feature
|
||||||
/* is enabled, the local system is allowed to be the best mail
|
/* 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.
|
/* mailer loops are treated as an error.
|
||||||
/*
|
/*
|
||||||
/* When no mail exchanger is listed in the DNS for \fIname\fR, the
|
/* When no mail exchanger is listed in the DNS for \fIname\fR, the
|
||||||
@@ -47,16 +46,7 @@
|
|||||||
/* when DNS lookups are explicitly disabled.
|
/* when DNS lookups are explicitly disabled.
|
||||||
/*
|
/*
|
||||||
/* All routines either return a DNS_RR pointer, or return a null
|
/* All routines either return a DNS_RR pointer, or return a null
|
||||||
/* pointer and set the \fIsmtp_errno\fR global variable accordingly:
|
/* pointer and report any problems via the smtp_trouble(3) module.
|
||||||
/* .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.
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@@ -119,6 +109,7 @@ static int h_errno = TRY_AGAIN;
|
|||||||
|
|
||||||
#include <mail_params.h>
|
#include <mail_params.h>
|
||||||
#include <own_inet_addr.h>
|
#include <own_inet_addr.h>
|
||||||
|
#include <deliver_pass.h>
|
||||||
|
|
||||||
/* DNS library. */
|
/* DNS library. */
|
||||||
|
|
||||||
@@ -129,6 +120,9 @@ static int h_errno = TRY_AGAIN;
|
|||||||
#include "smtp.h"
|
#include "smtp.h"
|
||||||
#include "smtp_addr.h"
|
#include "smtp_addr.h"
|
||||||
|
|
||||||
|
#define ERROR_CLASS_RETRY 450
|
||||||
|
#define ERROR_CLASS_FAIL 550
|
||||||
|
|
||||||
/* smtp_print_addr - print address list */
|
/* smtp_print_addr - print address list */
|
||||||
|
|
||||||
static void smtp_print_addr(char *what, DNS_RR *addr_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 */
|
/* 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";
|
char *myname = "smtp_addr_one";
|
||||||
struct in_addr inaddr;
|
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);
|
addr_list = dns_rr_append(addr_list, addr);
|
||||||
return (addr_list);
|
return (addr_list);
|
||||||
default:
|
default:
|
||||||
smtp_errno = SMTP_RETRY;
|
*error_class = ERROR_CLASS_RETRY;
|
||||||
return (addr_list);
|
return (addr_list);
|
||||||
case DNS_FAIL:
|
case DNS_FAIL:
|
||||||
smtp_errno = SMTP_FAIL;
|
*error_class = ERROR_CLASS_FAIL;
|
||||||
return (addr_list);
|
return (addr_list);
|
||||||
case DNS_NOTFOUND:
|
case DNS_NOTFOUND:
|
||||||
smtp_errno = SMTP_FAIL;
|
*error_class = ERROR_CLASS_FAIL;
|
||||||
/* maybe gethostbyname() will succeed */
|
/* maybe gethostbyname() will succeed */
|
||||||
break;
|
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));
|
memset((char *) &fixed, 0, sizeof(fixed));
|
||||||
if ((hp = gethostbyname(host)) == 0) {
|
if ((hp = gethostbyname(host)) == 0) {
|
||||||
vstring_sprintf(why, "%s: %s", host, HSTRERROR(h_errno));
|
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) {
|
} else if (hp->h_addrtype != AF_INET) {
|
||||||
vstring_sprintf(why, "%s: host not found", host);
|
vstring_sprintf(why, "%s: host not found", host);
|
||||||
msg_warn("%s: unknown address family %d for %s",
|
msg_warn("%s: unknown address family %d for %s",
|
||||||
myname, hp->h_addrtype, host);
|
myname, hp->h_addrtype, host);
|
||||||
smtp_errno = SMTP_FAIL;
|
*error_class = ERROR_CLASS_FAIL;
|
||||||
} else {
|
} else {
|
||||||
while (hp->h_addr_list[0]) {
|
while (hp->h_addr_list[0]) {
|
||||||
addr_list = dns_rr_append(addr_list,
|
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 */
|
/* 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 *addr_list = 0;
|
||||||
DNS_RR *rr;
|
DNS_RR *rr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As long as we are able to look up any host address, we ignore problems
|
* 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
|
* any->RETRY upon temporary lookup error) so that we can correctly
|
||||||
* handle the case of no resolvable MX host. Currently this is always
|
* handle the case of no resolvable MX host. Currently this is always
|
||||||
* treated as a soft error. RFC 2821 wants a more precise response.
|
* 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) {
|
for (rr = mx_names; rr; rr = rr->next) {
|
||||||
if (rr->type != T_MX)
|
if (rr->type != T_MX)
|
||||||
msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
|
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);
|
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 */
|
/* 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 *mx_names;
|
||||||
DNS_RR *addr_list = 0;
|
DNS_RR *addr_list = 0;
|
||||||
DNS_RR *self = 0;
|
DNS_RR *self = 0;
|
||||||
unsigned best_pref;
|
unsigned best_pref;
|
||||||
unsigned best_found;
|
unsigned best_found;
|
||||||
|
int error_class;
|
||||||
|
VSTRING *why = vstring_alloc(1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Preferences from DNS use 0..32767, fall-backs use 32768+.
|
* 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
|
* that an IP address is listed only under one hostname. However, looking
|
||||||
* at hostnames provides a partial solution for MX hosts behind a NAT
|
* at hostnames provides a partial solution for MX hosts behind a NAT
|
||||||
* gateway.
|
* 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)) {
|
switch (dns_lookup(name, T_MX, 0, &mx_names, (VSTRING *) 0, why)) {
|
||||||
default:
|
default:
|
||||||
smtp_errno = SMTP_RETRY;
|
|
||||||
if (var_ign_mx_lookup_err)
|
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;
|
break;
|
||||||
case DNS_FAIL:
|
case DNS_FAIL:
|
||||||
smtp_errno = SMTP_FAIL;
|
|
||||||
if (var_ign_mx_lookup_err)
|
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;
|
break;
|
||||||
case DNS_OK:
|
case DNS_OK:
|
||||||
mx_names = dns_rr_sort(mx_names, smtp_compare_pref);
|
mx_names = dns_rr_sort(mx_names, smtp_compare_pref);
|
||||||
best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE);
|
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);
|
dns_rr_free(mx_names);
|
||||||
if (addr_list == 0) {
|
if (addr_list == 0) {
|
||||||
if (var_smtp_defer_mxaddr)
|
if (var_smtp_defer_mxaddr || DEFER_HOST_LOOKUP_ERROR(state))
|
||||||
smtp_errno = SMTP_RETRY;
|
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);
|
msg_warn("no MX host for %s has a valid A record", name);
|
||||||
break;
|
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);
|
addr_list = smtp_truncate_self(addr_list, self->pref);
|
||||||
if (addr_list == 0) {
|
if (addr_list == 0) {
|
||||||
if (best_pref != best_found) {
|
if (best_pref != best_found) {
|
||||||
vstring_sprintf(why, "unable to find primary relay for %s",
|
smtp_site_fail(state, ERROR_CLASS_RETRY,
|
||||||
name);
|
"%s: unable to find primary relay for %s",
|
||||||
smtp_errno = SMTP_RETRY;
|
request->queue_id, name);
|
||||||
} else if (*var_bestmx_transp != 0) { /* we're best MX */
|
} 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 {
|
} else {
|
||||||
msg_warn("mailer loop: best MX host for %s is local",
|
msg_warn("%s is best MX host for %s but no local, virtual "
|
||||||
name);
|
"or remote delivery is configured for that domain",
|
||||||
vstring_sprintf(why, "mail for %s loops back to myself",
|
var_myhostname, request->nexthop);
|
||||||
name);
|
smtp_site_fail(state, ERROR_CLASS_FAIL,
|
||||||
smtp_errno = SMTP_FAIL;
|
"%s: mail for %s loops back to myself",
|
||||||
|
request->queue_id, name);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addr_list && addr_list->next && var_smtp_rand_addr) {
|
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;
|
break;
|
||||||
case DNS_NOTFOUND:
|
case DNS_NOTFOUND:
|
||||||
addr_list = smtp_host_addr(name, why);
|
addr_list = smtp_host_addr(state, name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up.
|
* Clean up.
|
||||||
*/
|
*/
|
||||||
*found_myself = (self != 0);
|
vstring_free(why);
|
||||||
return (addr_list);
|
return (addr_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* smtp_host_addr - direct host lookup */
|
/* 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;
|
DNS_RR *addr_list;
|
||||||
|
int error_class;
|
||||||
|
VSTRING *why = vstring_alloc(1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the host is specified by numerical address, just convert the
|
* If the host is specified by numerical address, just convert the
|
||||||
* address to internal form. Otherwise, the host is specified by name.
|
* address to internal form. Otherwise, the host is specified by name.
|
||||||
*/
|
*/
|
||||||
#define PREF0 0
|
#define PREF0 0
|
||||||
addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why);
|
addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why, &error_class);
|
||||||
if (addr_list && addr_list->next && var_smtp_rand_addr)
|
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);
|
addr_list = dns_rr_shuffle(addr_list);
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
smtp_print_addr(host, addr_list);
|
smtp_print_addr(host, addr_list);
|
||||||
|
}
|
||||||
|
vstring_free(why);
|
||||||
return (addr_list);
|
return (addr_list);
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,8 @@
|
|||||||
/*
|
/*
|
||||||
* Internal interfaces.
|
* Internal interfaces.
|
||||||
*/
|
*/
|
||||||
extern DNS_RR *smtp_host_addr(char *, VSTRING *);
|
extern DNS_RR *smtp_host_addr(SMTP_STATE *state, char *);
|
||||||
extern DNS_RR *smtp_domain_addr(char *, VSTRING *, int *);
|
extern DNS_RR *smtp_domain_addr(SMTP_STATE *state, char *);
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
/* NAME
|
/* NAME
|
||||||
/* smtp_connect 3
|
/* smtp_connect 3
|
||||||
/* SUMMARY
|
/* SUMMARY
|
||||||
/* connect to SMTP server
|
/* connect to SMTP server and deliver
|
||||||
/* SYNOPSIS
|
/* SYNOPSIS
|
||||||
/* #include "smtp.h"
|
/* #include "smtp.h"
|
||||||
/*
|
/*
|
||||||
@@ -81,7 +81,6 @@
|
|||||||
|
|
||||||
#include <mail_params.h>
|
#include <mail_params.h>
|
||||||
#include <own_inet_addr.h>
|
#include <own_inet_addr.h>
|
||||||
#include <deliver_pass.h>
|
|
||||||
#include <debug_peer.h>
|
#include <debug_peer.h>
|
||||||
#include <mail_error.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);
|
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)));
|
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)
|
int smtp_connect(SMTP_STATE *state)
|
||||||
{
|
{
|
||||||
VSTRING *why = vstring_alloc(100);
|
|
||||||
DELIVER_REQUEST *request = state->request;
|
DELIVER_REQUEST *request = state->request;
|
||||||
char *dest_buf;
|
char *dest_buf;
|
||||||
char *host;
|
char *host;
|
||||||
@@ -276,27 +253,41 @@ int smtp_connect(SMTP_STATE *state)
|
|||||||
ARGV *sites;
|
ARGV *sites;
|
||||||
char *dest;
|
char *dest;
|
||||||
char **cpp;
|
char **cpp;
|
||||||
int found_myself;
|
|
||||||
DNS_RR *addr_list;
|
DNS_RR *addr_list;
|
||||||
DNS_RR *addr;
|
DNS_RR *addr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First try to deliver to the indicated destination, then try to deliver
|
* 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
|
* to the optional fall-back relays.
|
||||||
* primary destination to be a list (we did for some time in the past).
|
|
||||||
*
|
*
|
||||||
* After a soft error, log recipient deferrals only when there are no
|
* Future proofing: do a null destination sanity check in case we allow the
|
||||||
* further possibilities to deliver.
|
* primary destination to be a list, as it could be just a bunch of
|
||||||
|
* separators.
|
||||||
*/
|
*/
|
||||||
sites = argv_alloc(1);
|
sites = argv_alloc(1);
|
||||||
argv_add(sites, request->nexthop, (char *) 0);
|
argv_add(sites, request->nexthop, (char *) 0);
|
||||||
if (sites->argc == 0)
|
if (sites->argc == 0)
|
||||||
msg_panic("null destination: \"%s\"", request->nexthop);
|
msg_panic("null destination: \"%s\"", request->nexthop);
|
||||||
|
if (*var_fallback_relay)
|
||||||
argv_split_append(sites, var_fallback_relay, ", \t\r\n");
|
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++) {
|
for (cpp = sites->argv; (dest = *cpp) != 0; cpp++) {
|
||||||
found_myself = 0;
|
state->final_server = (cpp[1] == 0);
|
||||||
state->final = (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
|
* 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)
|
if (msg_verbose)
|
||||||
msg_info("connecting to \"%s\" port \"%d\"", host, ntohs(port));
|
msg_info("connecting to \"%s\" port \"%d\"", host, ntohs(port));
|
||||||
if (var_disable_dns || *dest == '[') {
|
if (var_disable_dns || *dest == '[') {
|
||||||
addr_list = smtp_host_addr(host, why);
|
addr_list = smtp_host_addr(state, host);
|
||||||
} else {
|
} else {
|
||||||
addr_list = smtp_domain_addr(host, why, &found_myself);
|
addr_list = smtp_domain_addr(state, host);
|
||||||
}
|
}
|
||||||
myfree(dest_buf);
|
myfree(dest_buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle host lookup problems. XXX It would be nice if the address
|
* No address list. The mail has / has not been delivered. What to do
|
||||||
* lookup routines could do their own smtp_site_fail() calls instead
|
* next (skip remaining hosts / try to deliver) is recorded in the
|
||||||
* of having us make sense of things from a distance. The
|
* state->final_server attribute.
|
||||||
* complication is that an unrecoverable host lookup error may still
|
|
||||||
* be followed by an attempt to deliver via a fallback relay.
|
|
||||||
*/
|
*/
|
||||||
if (addr_list == 0) {
|
if (addr_list == 0) {
|
||||||
|
if (state->backup_server)
|
||||||
/*
|
msg_warn("%s or %s configuration problem",
|
||||||
* Mail loops back to myself. An smtp_errno of OK means that we
|
VAR_RELAYHOST, VAR_FALLBACK_RELAY);
|
||||||
* 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -371,10 +324,10 @@ int smtp_connect(SMTP_STATE *state)
|
|||||||
*/
|
*/
|
||||||
for (addr = addr_list; addr; addr = addr->next) {
|
for (addr = addr_list; addr; addr = addr->next) {
|
||||||
if ((state->session = smtp_connect_addr(state, addr, port)) != 0) {
|
if ((state->session = smtp_connect_addr(state, addr, port)) != 0) {
|
||||||
|
state->final_server = (cpp[1] == 0 && addr->next == 0);
|
||||||
state->status = 0;
|
state->status = 0;
|
||||||
state->session->best = (addr->pref == addr_list->pref);
|
state->session->best = (addr->pref == addr_list->pref);
|
||||||
debug_peer_check(state->session->host, state->session->addr);
|
debug_peer_check(state->session->host, state->session->addr);
|
||||||
state->final = (cpp[1] == 0 && addr->next == 0);
|
|
||||||
if (smtp_helo(state) == 0)
|
if (smtp_helo(state) == 0)
|
||||||
smtp_xfer(state);
|
smtp_xfer(state);
|
||||||
if (state->history != 0
|
if (state->history != 0
|
||||||
@@ -384,17 +337,23 @@ int smtp_connect(SMTP_STATE *state)
|
|||||||
/* XXX smtp_xfer() may abort in the middle of DATA. */
|
/* XXX smtp_xfer() may abort in the middle of DATA. */
|
||||||
smtp_session_free(state->session);
|
smtp_session_free(state->session);
|
||||||
debug_peer_restore();
|
debug_peer_restore();
|
||||||
if (state->status == 0)
|
if (state->status == 0 || state->final_server)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dns_rr_free(addr_list);
|
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.
|
* Cleanup.
|
||||||
*/
|
*/
|
||||||
vstring_free(why);
|
|
||||||
argv_free(sites);
|
argv_free(sites);
|
||||||
return (state->status);
|
return (state->status);
|
||||||
}
|
}
|
||||||
|
@@ -197,10 +197,13 @@ int smtp_helo(SMTP_STATE *state)
|
|||||||
/*
|
/*
|
||||||
* Read and parse the server's SMTP greeting banner.
|
* 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,
|
return (smtp_site_fail(state, resp->code,
|
||||||
"host %s refused to talk to me: %s",
|
"host %s refused to talk to me: %s",
|
||||||
session->namaddr, translit(resp->str, "\n", " ")));
|
session->namaddr, translit(resp->str, "\n", " ")));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX Some PIX firewall versions require flush before ".<CR><LF>" so it
|
* XXX Some PIX firewall versions require flush before ".<CR><LF>" so it
|
||||||
|
@@ -72,7 +72,8 @@ SMTP_STATE *smtp_state_alloc(void)
|
|||||||
state->size_limit = 0;
|
state->size_limit = 0;
|
||||||
state->space_left = 0;
|
state->space_left = 0;
|
||||||
state->mime_state = 0;
|
state->mime_state = 0;
|
||||||
state->final = 0;
|
state->final_server = 0;
|
||||||
|
state->backup_server = 0;
|
||||||
return (state);
|
return (state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,35 +44,53 @@
|
|||||||
/* would suffer the same problem and just cause more trouble.
|
/* would suffer the same problem and just cause more trouble.
|
||||||
/*
|
/*
|
||||||
/* In case of a soft error, action depends on whether there are
|
/* In case of a soft error, action depends on whether there are
|
||||||
/* more possibilities to deliver (log one generic record) or whether
|
/* more mail servers (log an informational record only and try
|
||||||
/* the error happens with the last possibility (log each recipient).
|
/* 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
|
/* smtp_site_fail() handles the case where the program fails to
|
||||||
/* complete the initial SMTP handshake: the server is not reachable,
|
/* complete the initial SMTP handshake: the server is not reachable,
|
||||||
/* is not running, does not want talk to us, or we talk to ourselves.
|
/* 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
|
/* The \fIcode\fR gives an error status code; the \fIformat\fR
|
||||||
/* argument gives a textual description. The policy is: soft
|
/* argument gives a textual description.
|
||||||
/* error: defer delivery of all messages to this domain; hard
|
/* The policy is: soft error, non-final server: log an informational
|
||||||
/* error: bounce all recipients of this message.
|
/* 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.
|
/* The result is non-zero.
|
||||||
/*
|
/*
|
||||||
/* smtp_mesg_fail() handles the case where the smtp server
|
/* smtp_mesg_fail() handles the case where the smtp server
|
||||||
/* does not accept the sender address or the message data.
|
/* does not accept the sender address or the message data.
|
||||||
/* The policy is: soft errors: defer delivery of this message;
|
/* The policy is: soft error, non-final server: log an informational
|
||||||
/* hard error: bounce all recipients of this message.
|
/* 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.
|
/* The result is non-zero.
|
||||||
/*
|
/*
|
||||||
/* smtp_rcpt_fail() handles the case where a recipient is not
|
/* smtp_rcpt_fail() handles the case where a recipient is not
|
||||||
/* accepted by the server for reasons other than that the server
|
/* accepted by the server for reasons other than that the server
|
||||||
/* recipient limit is reached. The policy is: soft error: defer
|
/* recipient limit is reached.
|
||||||
/* delivery to this recipient; hard error: bounce this recipient.
|
/* 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
|
/* smtp_stream_except() handles the exceptions generated by
|
||||||
/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
|
/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
|
||||||
/* The \fIexception\fR argument specifies the type of problem.
|
/* The \fIexception\fR argument specifies the type of problem.
|
||||||
/* The \fIdescription\fR argument describes at what stage of
|
/* The \fIdescription\fR argument describes at what stage of
|
||||||
/* the SMTP dialog the problem happened. The policy is to defer
|
/* the SMTP dialog the problem happened.
|
||||||
/* delivery of all messages to the same domain. The result is non-zero.
|
/* 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
|
/* DIAGNOSTICS
|
||||||
/* Panic: unknown exception code.
|
/* Panic: unknown exception code.
|
||||||
/* SEE ALSO
|
/* SEE ALSO
|
||||||
@@ -141,7 +159,7 @@ static void smtp_check_code(SMTP_STATE *state, int code)
|
|||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
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,...)
|
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);
|
va_end(ap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't log deferred recipients yet when there are still untried
|
* Don't defer the recipients just yet when there are still more mail
|
||||||
* possibilities to deliver. Just log why we're abandoning this host.
|
* 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));
|
msg_info("%s: %s", request->queue_id, vstring_str(why));
|
||||||
state->status |= -1;
|
state->status |= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a soft error, postpone further deliveries to this domain.
|
* Defer or bounce all the remaining recipients and raise the final mail
|
||||||
* Otherwise, generate a bounce record for each recipient.
|
* server flag.
|
||||||
*/
|
*/
|
||||||
else {
|
else {
|
||||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
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)
|
if (soft_error && request->hop_status == 0)
|
||||||
request->hop_status = mystrdup(vstring_str(why));
|
request->hop_status = mystrdup(vstring_str(why));
|
||||||
|
state->final_server = 1;
|
||||||
}
|
}
|
||||||
|
smtp_check_code(state, code);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cleanup.
|
* Cleanup.
|
||||||
@@ -201,7 +222,7 @@ int smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
|
|||||||
return (-1);
|
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,...)
|
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);
|
va_end(ap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't log deferred recipients yet when there are still untried
|
* Don't defer the recipients just yet when there are still more mail
|
||||||
* possibilities to deliver. Just log why we're abandoning this host.
|
* 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));
|
msg_info("%s: %s", request->queue_id, vstring_str(why));
|
||||||
state->status |= -1;
|
state->status |= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a soft error, postpone delivery of this message. Otherwise,
|
* Defer or bounce all the remaining recipients and raise the final mail
|
||||||
* generate a bounce record for each recipient.
|
* server flag.
|
||||||
*/
|
*/
|
||||||
else {
|
else {
|
||||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
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->status |= status;
|
||||||
}
|
}
|
||||||
|
state->final_server = 1;
|
||||||
}
|
}
|
||||||
smtp_check_code(state, code);
|
smtp_check_code(state, code);
|
||||||
|
|
||||||
@@ -260,7 +283,7 @@ int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
|
|||||||
return (-1);
|
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,
|
void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
|
||||||
char *format,...)
|
char *format,...)
|
||||||
@@ -272,10 +295,11 @@ void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't log deferred recipients yet when there are still untried
|
* Don't defer this recipient record just yet when there are still more
|
||||||
* possibilities to deliver.
|
* 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);
|
VSTRING *buf = vstring_alloc(10);
|
||||||
|
|
||||||
va_start(ap, format);
|
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.
|
* Defer or bounce this specific recipient.
|
||||||
* Otherwise, generate a bounce record for this 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 {
|
else {
|
||||||
va_start(ap, format);
|
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
|
* Don't defer the recipients just yet when there are still more mail
|
||||||
* possibilities to deliver. Just log why we're abandoning this host.
|
* 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));
|
msg_info("%s: %s", request->queue_id, vstring_str(why));
|
||||||
state->status |= -1;
|
state->status |= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point, the status of individual recipients remains unresolved.
|
* Final server. Defer all the remaining recipients.
|
||||||
* All we know is that we should stay away from this host for a while.
|
|
||||||
*/
|
*/
|
||||||
else {
|
else {
|
||||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
||||||
|
@@ -154,6 +154,7 @@
|
|||||||
#include <lber.h>
|
#include <lber.h>
|
||||||
#include <ldap.h>
|
#include <ldap.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Older APIs have weird memory freeing behavior.
|
* 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)
|
static void dict_ldap_logprint(LDAP_CONST char *data)
|
||||||
{
|
{
|
||||||
char *myname = "dict_ldap_debug";
|
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
|
#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;
|
dict_errno = 0;
|
||||||
|
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
@@ -573,16 +598,6 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
|||||||
&(dict_ldap->dereference)) != LDAP_OPT_SUCCESS)
|
&(dict_ldap->dereference)) != LDAP_OPT_SUCCESS)
|
||||||
msg_warn("%s: Unable to set dereference option.", myname);
|
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. */
|
/* Chase referrals. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user