mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
postfix-2.0.16-20031216
This commit is contained in:
committed by
Viktor Dukhovni
parent
7aef2f8c02
commit
49328174e4
@@ -8818,13 +8818,14 @@ Apologies for any names omitted.
|
||||
of a sender address. Code by Liviu Daia. Files:
|
||||
smtpd/smtpd_check.c and documentation.
|
||||
|
||||
The reject_sender_login_mismatch feature is now implemented
|
||||
by elementary features reject_unauth_sender_login_mismatch
|
||||
reject_sender_login_mismatch is now implemented by elementary
|
||||
features reject_unauthenticated_sender_login_mismatch
|
||||
(reject if the client is not SASL logged in but the sender
|
||||
address has an owner in smtpd_sender_login_maps) and
|
||||
reject_auth_sender_login_mismatch (reject if the client is
|
||||
SASL logged in but does not own the sender address). Code
|
||||
by Liviu Daia. Files: smtpd/smtpd_check.c and documentation.
|
||||
reject_authenticated_sender_login_mismatch (reject if the
|
||||
client is SASL logged in but does not own the sender
|
||||
address). Code by Liviu Daia. Files: smtpd/smtpd_check.c
|
||||
and documentation.
|
||||
|
||||
20031207
|
||||
|
||||
@@ -8864,6 +8865,16 @@ Apologies for any names omitted.
|
||||
settings before and after DNS lookup, to avoid surprises
|
||||
in third-party code. File: dns/dns_lookup.c.
|
||||
|
||||
20031216
|
||||
|
||||
Cleanup: easier to parse mailq output (no more space
|
||||
between short queue ID and message status). File:
|
||||
showq/showq.c.
|
||||
|
||||
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.
|
||||
|
||||
Open problems:
|
||||
|
||||
High: when virtual aliasing is turned off after content
|
||||
@@ -8886,9 +8897,8 @@ Open problems:
|
||||
Low: postmap/postalias should not try to open a bogus file
|
||||
when given an unsupported dictionary type.
|
||||
|
||||
Med: do not postpone rejected "MAIL FROM" size information,
|
||||
and find a way to log the sender address in the rejected
|
||||
command.
|
||||
Med: find a way to log the sender address when MAIL FROM
|
||||
is rejected due to lack of disk space.
|
||||
|
||||
Low: after successful delivery, per-queue window += 1/window,
|
||||
after failure, queue window -= 1 (Victor).
|
||||
@@ -8929,8 +8939,8 @@ Open problems:
|
||||
|
||||
Low: postconf -e edits parameters that postconf won't list.
|
||||
|
||||
Low: with quoted-printable, perhaps use =46rom instead of
|
||||
>From.
|
||||
Low: while convering 8bit text to quoted-printable, perhaps
|
||||
use =46rom instead of >From.
|
||||
|
||||
virtual_mailbox_path expression like forward_path, so that
|
||||
people can specify prefix and suffix.
|
||||
|
@@ -16,7 +16,7 @@ This extension is implemented as a separate command, so that it
|
||||
can be used to transmit client or message attributes incrementally.
|
||||
It is not implemented by passing additional parameters via the MAIL
|
||||
FROM command, because doing so would require extending the MAIL
|
||||
FROM command length limit by another 600 or more characters beyond.
|
||||
FROM command length limit by another 600 or more characters.
|
||||
|
||||
Command syntax
|
||||
==============
|
||||
@@ -32,7 +32,7 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
|
||||
xforward-command = XFORWARD 1*( SP name"="value )
|
||||
|
||||
name = ( NAME | ADDR | PROTO | HELO | IDENT )
|
||||
name = ( NAME | ADDR | PROTO | HELO )
|
||||
|
||||
The XFORWARD command can be sent at any time except in the middle
|
||||
of a mail delivery transaction (i.e. between MAIL and DOT). The
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<html> <head> </head> <body> <pre>
|
||||
<html> <body> <pre>
|
||||
SHOWQ(8) SHOWQ(8)
|
||||
|
||||
<b>NAME</b>
|
||||
|
@@ -141,7 +141,7 @@ static int dns_query(const char *name, int type, int flags,
|
||||
{
|
||||
HEADER *reply_header;
|
||||
int len;
|
||||
int saved_options = _res.options;
|
||||
unsigned long saved_options = _res.options;
|
||||
|
||||
/*
|
||||
* Initialize the name service.
|
||||
|
@@ -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 "20031215"
|
||||
#define MAIL_RELEASE_DATE "20031216"
|
||||
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
|
||||
|
@@ -94,7 +94,7 @@ int var_dup_filter_limit;
|
||||
char *var_empty_addr;
|
||||
|
||||
#define STRING_FORMAT "%-10s %8s %-20s %s\n"
|
||||
#define DATA_FORMAT "%-10s%c%8ld %20.20s %s\n"
|
||||
#define SENDER_FORMAT "%-11s%8ld %20.20s %s\n"
|
||||
#define DROP_FORMAT "%-10s%c%8ld %20.20s (maildrop queue, sender UID %u)\n"
|
||||
|
||||
static void showq_reasons(VSTREAM *, BOUNCE_LOG *, HTABLE *);
|
||||
@@ -150,7 +150,9 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
|
||||
start = var_empty_addr;
|
||||
quote_822_local(printable_quoted_addr, start);
|
||||
printable(STR(printable_quoted_addr), '?');
|
||||
vstream_fprintf(client, DATA_FORMAT, id, status,
|
||||
/* quote_822_local() saves buf, so we can reuse its space. */
|
||||
vstring_sprintf(buf, "%s%c", id, status);
|
||||
vstream_fprintf(client, SENDER_FORMAT, STR(buf),
|
||||
msg_size > 0 ? msg_size : size, arrival_time > 0 ?
|
||||
asctime(localtime(&arrival_time)) :
|
||||
asctime(localtime(&mtime)),
|
||||
|
@@ -265,8 +265,6 @@
|
||||
#include <mail_params.h>
|
||||
#include <mail_conf.h>
|
||||
#include <debug_peer.h>
|
||||
#include <mail_error.h>
|
||||
#include <deliver_pass.h>
|
||||
|
||||
/* Single server skeleton. */
|
||||
|
||||
@@ -327,7 +325,6 @@ int smtp_host_lookup_mask;
|
||||
|
||||
static int deliver_message(DELIVER_REQUEST *request)
|
||||
{
|
||||
VSTRING *why;
|
||||
SMTP_STATE *state;
|
||||
int result;
|
||||
|
||||
@@ -349,7 +346,6 @@ static int deliver_message(DELIVER_REQUEST *request)
|
||||
* we can produce understandable diagnostics when something goes wrong
|
||||
* many levels below. The alternative would be to make everything global.
|
||||
*/
|
||||
why = vstring_alloc(100);
|
||||
state = smtp_state_alloc();
|
||||
state->request = request;
|
||||
state->src = request->fp;
|
||||
@@ -360,35 +356,12 @@ static int deliver_message(DELIVER_REQUEST *request)
|
||||
* Optionally deliver mail locally when this machine is the best mail
|
||||
* exchanger.
|
||||
*/
|
||||
if ((state->session = smtp_connect(request->nexthop, why)) == 0) {
|
||||
if (smtp_errno == SMTP_OK) {
|
||||
if (*var_bestmx_transp == 0)
|
||||
msg_panic("smtp_errno botch");
|
||||
state->status = deliver_pass_all(MAIL_CLASS_PRIVATE,
|
||||
var_bestmx_transp,
|
||||
request);
|
||||
} else
|
||||
smtp_site_fail(state, smtp_errno == SMTP_RETRY ? 450 : 550,
|
||||
"%s", vstring_str(why));
|
||||
} else {
|
||||
debug_peer_check(state->session->host, state->session->addr);
|
||||
if (smtp_helo(state) == 0)
|
||||
smtp_xfer(state);
|
||||
if (state->history != 0
|
||||
&& (state->error_mask & name_mask(VAR_NOTIFY_CLASSES,
|
||||
mail_error_masks, var_notify_classes)))
|
||||
smtp_chat_notify(state);
|
||||
/* XXX smtp_xfer() may abort in the middle of DATA. */
|
||||
smtp_session_free(state->session);
|
||||
debug_peer_restore();
|
||||
}
|
||||
result = smtp_connect(state);
|
||||
|
||||
/*
|
||||
* Clean up.
|
||||
*/
|
||||
vstring_free(why);
|
||||
smtp_chat_reset(state);
|
||||
result = state->status;
|
||||
smtp_state_free(state);
|
||||
|
||||
return (result);
|
||||
|
@@ -55,6 +55,7 @@ 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 */
|
||||
} SMTP_STATE;
|
||||
|
||||
#define SMTP_FEATURE_ESMTP (1<<0)
|
||||
@@ -95,9 +96,7 @@ extern void smtp_session_free(SMTP_SESSION *);
|
||||
/*
|
||||
* smtp_connect.c
|
||||
*/
|
||||
extern SMTP_SESSION *smtp_connect(char *, VSTRING *);
|
||||
extern SMTP_SESSION *smtp_connect_host(char *, unsigned, VSTRING *);
|
||||
extern SMTP_SESSION *smtp_connect_domain(char *, unsigned, VSTRING *, int *);
|
||||
extern int smtp_connect(SMTP_STATE *);
|
||||
|
||||
/*
|
||||
* smtp_proto.c
|
||||
|
@@ -6,29 +6,16 @@
|
||||
/* SYNOPSIS
|
||||
/* #include "smtp.h"
|
||||
/*
|
||||
/* SMTP_SESSION *smtp_connect(destination, why)
|
||||
/* char *destination;
|
||||
/* VSTRING *why;
|
||||
/* AUXILIARY FUNCTIONS
|
||||
/* SMTP_SESSION *smtp_connect_domain(name, port, why)
|
||||
/* char *name;
|
||||
/* unsigned port;
|
||||
/* VSTRING *why;
|
||||
/*
|
||||
/* SMTP_SESSION *smtp_connect_host(name, port, why)
|
||||
/* char *name;
|
||||
/* unsigned port;
|
||||
/* VSTRING *why;
|
||||
/* int smtp_connect(state)
|
||||
/* SMTP_STATE *state;
|
||||
/* DESCRIPTION
|
||||
/* This module implements SMTP connection management.
|
||||
/* This module implements SMTP connection management and mail
|
||||
/* delivery.
|
||||
/*
|
||||
/* smtp_connect() attempts to establish an SMTP session with a host
|
||||
/* that represents the named domain.
|
||||
/*
|
||||
/* No session and an smtp_errno of SMTP_OK means that the local
|
||||
/* machine is the best mail exchanger for the specified destination.
|
||||
/* It is left up to the caller to decide if this is a mailer loop
|
||||
/* or if this is a "do what I mean" request.
|
||||
/* that represents the destination domain, or with an optional fallback
|
||||
/* relay when the destination cannot be found, or when all the
|
||||
/* destination servers are unavailable.
|
||||
/*
|
||||
/* The destination is either a host (or domain) name or a numeric
|
||||
/* address. Symbolic or numeric service port information may be
|
||||
@@ -39,32 +26,8 @@
|
||||
/* suppress mail exchanger lookups.
|
||||
/*
|
||||
/* Numerical address information should always be quoted with `[]'.
|
||||
/*
|
||||
/* smtp_connect_domain() attempts to make an SMTP connection to
|
||||
/* the named host or domain and network port (network byte order).
|
||||
/* \fIname\fR is used to look up mail exchanger information via
|
||||
/* the Internet domain name system (DNS).
|
||||
/* When no mail exchanger is listed for \fIname\fR, the request
|
||||
/* is passed to smtp_connect_host().
|
||||
/* Otherwise, mail exchanger hosts are tried in order of preference,
|
||||
/* until one is found that responds. In order to avoid mailer loops,
|
||||
/* the search for mail exchanger hosts stops when a host is found
|
||||
/* that has the same preference as the sending machine.
|
||||
/*
|
||||
/* smtp_connect_host() makes an SMTP connection without looking up
|
||||
/* mail exchanger information. The host can be specified as an
|
||||
/* Internet network address or as a symbolic host name.
|
||||
/* DIAGNOSTICS
|
||||
/* All routines either return an SMTP_SESSION pointer, or
|
||||
/* return a null pointer and set the \fIsmtp_errno\fR
|
||||
/* global variable accordingly:
|
||||
/* .IP SMTP_RETRY
|
||||
/* The connection attempt failed, but should be retried later.
|
||||
/* .IP SMTP_FAIL
|
||||
/* The connection attempt failed.
|
||||
/* .PP
|
||||
/* In addition, a textual description of the error is made available
|
||||
/* via the \fIwhy\fR argument.
|
||||
/* The delivery status is the result value.
|
||||
/* SEE ALSO
|
||||
/* smtp_proto(3) SMTP client protocol
|
||||
/* LICENSE
|
||||
@@ -118,6 +81,9 @@
|
||||
|
||||
#include <mail_params.h>
|
||||
#include <own_inet_addr.h>
|
||||
#include <deliver_pass.h>
|
||||
#include <debug_peer.h>
|
||||
#include <mail_error.h>
|
||||
|
||||
/* DNS library. */
|
||||
|
||||
@@ -130,8 +96,8 @@
|
||||
|
||||
/* smtp_connect_addr - connect to explicit address */
|
||||
|
||||
static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
VSTRING *why)
|
||||
static SMTP_SESSION *smtp_connect_addr(SMTP_STATE *state, DNS_RR *addr,
|
||||
unsigned port)
|
||||
{
|
||||
char *myname = "smtp_connect_addr";
|
||||
struct sockaddr_in sin;
|
||||
@@ -146,11 +112,8 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (addr->data_len > sizeof(sin.sin_addr)) {
|
||||
msg_warn("%s: skip address with length %d", myname, addr->data_len);
|
||||
smtp_errno = SMTP_RETRY;
|
||||
return (0);
|
||||
}
|
||||
if (addr->data_len > sizeof(sin.sin_addr))
|
||||
msg_panic("%s: unexpected address length %d", myname, addr->data_len);
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
@@ -212,9 +175,8 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
conn_stat = sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin));
|
||||
}
|
||||
if (conn_stat < 0) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: %m",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
smtp_errno = SMTP_RETRY;
|
||||
smtp_site_fail(state, 450, "connect to %s[%s] port %u: %m",
|
||||
addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
|
||||
close(sock);
|
||||
return (0);
|
||||
}
|
||||
@@ -223,9 +185,8 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
* Skip this host if it takes no action within some time limit.
|
||||
*/
|
||||
if (read_wait(sock, var_smtp_helo_tmout) < 0) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: read timeout",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
smtp_errno = SMTP_RETRY;
|
||||
smtp_site_fail(state, 450, "connect to %s[%s] port %u: read timeout",
|
||||
addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
|
||||
close(sock);
|
||||
return (0);
|
||||
}
|
||||
@@ -235,9 +196,9 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
*/
|
||||
stream = vstream_fdopen(sock, O_RDWR);
|
||||
if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: server dropped connection without sending the initial SMTP greeting",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
smtp_errno = SMTP_RETRY;
|
||||
smtp_site_fail(state, 450, "connect to %s[%s] port %u: "
|
||||
"server dropped connection without sending the initial SMTP greeting",
|
||||
addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
|
||||
vstream_fclose(stream);
|
||||
return (0);
|
||||
}
|
||||
@@ -247,9 +208,9 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
* Skip this host if it sends a 4xx greeting.
|
||||
*/
|
||||
if (ch == '4' && var_smtp_skip_4xx_greeting) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: server refused mail service",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
smtp_errno = SMTP_RETRY;
|
||||
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);
|
||||
}
|
||||
@@ -258,69 +219,15 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
* Skip this host if it sends a 5xx greeting.
|
||||
*/
|
||||
if (ch == '5' && var_smtp_skip_5xx_greeting) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: server refused mail service",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
smtp_errno = SMTP_RETRY;
|
||||
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)));
|
||||
}
|
||||
|
||||
/* smtp_connect_host - direct connection to host */
|
||||
|
||||
SMTP_SESSION *smtp_connect_host(char *host, unsigned port, VSTRING *why)
|
||||
{
|
||||
SMTP_SESSION *session = 0;
|
||||
DNS_RR *addr_list;
|
||||
DNS_RR *addr;
|
||||
|
||||
/*
|
||||
* Try each address in the specified order until we find one that works.
|
||||
* The addresses belong to the same A record, so we have no information
|
||||
* on what address is "best".
|
||||
*/
|
||||
addr_list = smtp_host_addr(host, why);
|
||||
for (addr = addr_list; addr; addr = addr->next) {
|
||||
if ((session = smtp_connect_addr(addr, port, why)) != 0) {
|
||||
session->best = 1;
|
||||
break;
|
||||
}
|
||||
msg_info("%s (port %d)", vstring_str(why), ntohs(port));
|
||||
}
|
||||
dns_rr_free(addr_list);
|
||||
return (session);
|
||||
}
|
||||
|
||||
/* smtp_connect_domain - connect to smtp server for domain */
|
||||
|
||||
SMTP_SESSION *smtp_connect_domain(char *name, unsigned port, VSTRING *why,
|
||||
int *found_myself)
|
||||
{
|
||||
SMTP_SESSION *session = 0;
|
||||
DNS_RR *addr_list;
|
||||
DNS_RR *addr;
|
||||
|
||||
/*
|
||||
* Try each mail exchanger in order of preference until we find one that
|
||||
* responds. Once we find a server that responds we never try
|
||||
* alternative mail exchangers. The benefit of this is that we will use
|
||||
* backup hosts only when we are unable to reach the primary MX host. If
|
||||
* the primary MX host is reachable but does not want to receive our
|
||||
* mail, there is no point in trying the backup hosts.
|
||||
*/
|
||||
addr_list = smtp_domain_addr(name, why, found_myself);
|
||||
for (addr = addr_list; addr; addr = addr->next) {
|
||||
if ((session = smtp_connect_addr(addr, port, why)) != 0) {
|
||||
session->best = (addr->pref == addr_list->pref);
|
||||
break;
|
||||
}
|
||||
msg_info("%s (port %d)", vstring_str(why), ntohs(port));
|
||||
}
|
||||
dns_rr_free(addr_list);
|
||||
return (session);
|
||||
}
|
||||
|
||||
/* smtp_parse_destination - parse destination */
|
||||
|
||||
static char *smtp_parse_destination(char *destination, char *def_service,
|
||||
@@ -358,81 +265,136 @@ static char *smtp_parse_destination(char *destination, char *def_service,
|
||||
|
||||
/* smtp_connect - establish SMTP connection */
|
||||
|
||||
SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
|
||||
int smtp_connect(SMTP_STATE *state)
|
||||
{
|
||||
SMTP_SESSION *session = 0;
|
||||
char *dest_buf = 0;
|
||||
VSTRING *why = vstring_alloc(100);
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
char *dest_buf;
|
||||
char *host;
|
||||
unsigned port;
|
||||
char *def_service = "smtp"; /* XXX configurable? */
|
||||
ARGV *sites;
|
||||
char *dest;
|
||||
char **cpp;
|
||||
int found_myself = 0;
|
||||
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.
|
||||
* 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).
|
||||
*
|
||||
* After a soft error, log recipient deferrals only when there are no
|
||||
* further possibilities to deliver.
|
||||
*/
|
||||
sites = argv_alloc(1);
|
||||
argv_add(sites, destination, (char *) 0);
|
||||
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");
|
||||
|
||||
for (cpp = sites->argv; (dest = *cpp) != 0; cpp++) {
|
||||
found_myself = 0;
|
||||
state->final = (cpp[1] == 0);
|
||||
|
||||
/*
|
||||
* Parse the destination. Default is to use the SMTP port.
|
||||
* Parse the destination. Default is to use the SMTP port. Look up
|
||||
* the address instead of the mail exchanger when a quoted host is
|
||||
* specified, or when DNS lookups are disabled.
|
||||
*/
|
||||
dest_buf = smtp_parse_destination(dest, def_service, &host, &port);
|
||||
|
||||
/*
|
||||
* Connect to an SMTP server. Skip mail exchanger lookups when a
|
||||
* quoted host is specified, or when DNS lookups are disabled.
|
||||
*/
|
||||
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 == '[') {
|
||||
session = smtp_connect_host(host, port, why);
|
||||
addr_list = smtp_host_addr(host, why);
|
||||
} else {
|
||||
session = smtp_connect_domain(host, port, why, &found_myself);
|
||||
addr_list = smtp_domain_addr(host, why, &found_myself);
|
||||
}
|
||||
myfree(dest_buf);
|
||||
|
||||
/*
|
||||
* Done if we have a session, or if we have no session and this host
|
||||
* is the best MX relay for the destination. Agreed, an errno of OK
|
||||
* after failure is a weird way to reporting progress.
|
||||
* 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.
|
||||
*/
|
||||
if (session != 0 || smtp_errno == SMTP_OK || found_myself)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check. The destination must not be empty or all blanks.
|
||||
* Pay attention to what could be configuration problems, and
|
||||
* pretend that these are recoverable rather than bouncing the
|
||||
* mail.
|
||||
*/
|
||||
if (session == 0 && dest_buf == 0)
|
||||
msg_panic("null destination: \"%s\"", destination);
|
||||
|
||||
/*
|
||||
* Pay attention to what could be configuration problems, and pretend
|
||||
* that these are recoverable rather than bouncing the mail.
|
||||
*/
|
||||
if (session == 0 && smtp_errno == SMTP_FAIL) {
|
||||
if (strcmp(destination, var_relayhost) == 0) {
|
||||
if (strcmp(request->nexthop, var_relayhost) == 0) {
|
||||
msg_warn("%s configuration problem: %s",
|
||||
VAR_RELAYHOST, var_relayhost);
|
||||
smtp_errno = SMTP_RETRY;
|
||||
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_errno = SMTP_RETRY;
|
||||
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));
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to an SMTP server. XXX Limit the number of addresses that
|
||||
* we're willing to try for a non-fallback destination.
|
||||
*
|
||||
* After a soft error, log deferrals and update delivery status values
|
||||
* only when there are no further attempts.
|
||||
*/
|
||||
for (addr = addr_list; addr; addr = addr->next) {
|
||||
if ((state->session = smtp_connect_addr(state, addr, port)) != 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
|
||||
&& (state->error_mask & name_mask(VAR_NOTIFY_CLASSES,
|
||||
mail_error_masks, var_notify_classes)))
|
||||
smtp_chat_notify(state);
|
||||
/* XXX smtp_xfer() may abort in the middle of DATA. */
|
||||
smtp_session_free(state->session);
|
||||
debug_peer_restore();
|
||||
if (state->status == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
dns_rr_free(addr_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
vstring_free(why);
|
||||
argv_free(sites);
|
||||
return (session);
|
||||
return (state->status);
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ SMTP_STATE *smtp_state_alloc(void)
|
||||
state->size_limit = 0;
|
||||
state->space_left = 0;
|
||||
state->mime_state = 0;
|
||||
state->final = 0;
|
||||
return (state);
|
||||
}
|
||||
|
||||
|
@@ -43,6 +43,10 @@
|
||||
/* what appear to be configuration errors - very likely, they
|
||||
/* 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).
|
||||
/*
|
||||
/* 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.
|
||||
@@ -157,10 +161,20 @@ int smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
|
||||
vstring_vsprintf(why, format, ap);
|
||||
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.
|
||||
*/
|
||||
if (soft_error && state->final == 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.
|
||||
*/
|
||||
else {
|
||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
||||
rcpt = request->rcpt_list.info + nrcpt;
|
||||
if (rcpt->offset == 0)
|
||||
@@ -178,6 +192,7 @@ 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));
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
@@ -195,6 +210,7 @@ int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
|
||||
RECIPIENT *rcpt;
|
||||
int status;
|
||||
int nrcpt;
|
||||
int soft_error = SMTP_SOFT(code);
|
||||
va_list ap;
|
||||
VSTRING *why = vstring_alloc(100);
|
||||
|
||||
@@ -205,15 +221,25 @@ int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
|
||||
vstring_vsprintf(why, format, ap);
|
||||
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.
|
||||
*/
|
||||
if (soft_error && state->final == 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.
|
||||
*/
|
||||
else {
|
||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
||||
rcpt = request->rcpt_list.info + nrcpt;
|
||||
if (rcpt->offset == 0)
|
||||
continue;
|
||||
status = (SMTP_SOFT(code) ? defer_append : bounce_append)
|
||||
status = (soft_error ? defer_append : bounce_append)
|
||||
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
|
||||
rcpt->orig_addr, rcpt->address, rcpt->offset,
|
||||
session->namaddr, request->arrival_time,
|
||||
@@ -224,6 +250,7 @@ int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
|
||||
}
|
||||
state->status |= status;
|
||||
}
|
||||
}
|
||||
smtp_check_code(state, code);
|
||||
|
||||
/*
|
||||
@@ -241,14 +268,31 @@ void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
SMTP_SESSION *session = state->session;
|
||||
int status;
|
||||
int soft_error = SMTP_SOFT(code);
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* Don't log deferred recipients yet when there are still untried
|
||||
* possibilities to deliver.
|
||||
*/
|
||||
if (soft_error && state->final == 0) {
|
||||
VSTRING *buf = vstring_alloc(10);
|
||||
|
||||
va_start(ap, format);
|
||||
vstring_vsprintf(buf, format, ap);
|
||||
va_end(ap);
|
||||
msg_info("%s: %s", request->queue_id, vstring_str(buf));
|
||||
vstring_free(buf);
|
||||
status = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a soft error, postpone delivery to this recipient.
|
||||
* Otherwise, generate a bounce record for this recipient.
|
||||
*/
|
||||
else {
|
||||
va_start(ap, format);
|
||||
status = (SMTP_SOFT(code) ? vdefer_append : vbounce_append)
|
||||
status = (soft_error ? vdefer_append : vbounce_append)
|
||||
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
|
||||
rcpt->orig_addr, rcpt->address, rcpt->offset,
|
||||
session->namaddr, request->arrival_time, format, ap);
|
||||
@@ -257,6 +301,7 @@ void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
|
||||
deliver_completed(state->src, rcpt->offset);
|
||||
rcpt->offset = 0;
|
||||
}
|
||||
}
|
||||
smtp_check_code(state, code);
|
||||
state->status |= status;
|
||||
}
|
||||
@@ -287,10 +332,20 @@ int smtp_stream_except(SMTP_STATE *state, int code, char *description)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't log deferred recipients yet when there are still untried
|
||||
* possibilities to deliver. Just log why we're abandoning this host.
|
||||
*/
|
||||
if (state->final == 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.
|
||||
*/
|
||||
else {
|
||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
||||
rcpt = request->rcpt_list.info + nrcpt;
|
||||
if (rcpt->offset == 0)
|
||||
@@ -302,6 +357,7 @@ int smtp_stream_except(SMTP_STATE *state, int code, char *description)
|
||||
request->arrival_time,
|
||||
"%s", vstring_str(why));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
|
@@ -347,6 +347,8 @@
|
||||
#include "smtpd_sasl_glue.h"
|
||||
#include "smtpd_check.h"
|
||||
|
||||
#define RESTRICTION_SEPARATORS ", \t\r\n"
|
||||
|
||||
/*
|
||||
* Eject seat in case of parsing problems.
|
||||
*/
|
||||
@@ -596,7 +598,7 @@ static ARGV *smtpd_check_parse(const char *checks)
|
||||
* encounter. Dictionaries must be opened before entering the chroot
|
||||
* jail.
|
||||
*/
|
||||
while ((name = mystrtok(&bp, " \t\r\n,")) != 0) {
|
||||
while ((name = mystrtok(&bp, RESTRICTION_SEPARATORS)) != 0) {
|
||||
argv_add(argv, name, (char *) 0);
|
||||
if (last && strcasecmp(last, CHECK_POLICY_SERVICE) == 0)
|
||||
policy_client_register(name);
|
||||
@@ -767,7 +769,7 @@ void smtpd_check_init(void)
|
||||
smtpd_rest_classes = htable_create(1);
|
||||
if (*var_rest_classes) {
|
||||
cp = saved_classes = mystrdup(var_rest_classes);
|
||||
while ((name = mystrtok(&cp, " \t\r\n,")) != 0) {
|
||||
while ((name = mystrtok(&cp, RESTRICTION_SEPARATORS)) != 0) {
|
||||
if ((value = mail_conf_lookup_eval(name)) == 0 || *value == 0)
|
||||
msg_fatal("restriction class `%s' needs a definition", name);
|
||||
htable_enter(smtpd_rest_classes, name,
|
||||
@@ -2001,7 +2003,7 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||
*/
|
||||
#define ADDROF(x) ((char *) &(x))
|
||||
|
||||
restrictions = argv_split(value, " \t\r\n,");
|
||||
restrictions = argv_split(value, RESTRICTION_SEPARATORS);
|
||||
memcpy(ADDROF(savebuf), ADDROF(smtpd_check_buf), sizeof(savebuf));
|
||||
status = setjmp(smtpd_check_buf);
|
||||
if (status != 0) {
|
||||
@@ -2837,7 +2839,7 @@ static int reject_maps_rbl(SMTPD_STATE *state)
|
||||
"use \"%s domain-name\" instead",
|
||||
REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT);
|
||||
}
|
||||
while ((rbl_domain = mystrtok(&bp, " \t\r\n,")) != 0) {
|
||||
while ((rbl_domain = mystrtok(&bp, RESTRICTION_SEPARATORS)) != 0) {
|
||||
result = reject_rbl_addr(state, rbl_domain, state->addr,
|
||||
SMTPD_NAME_CLIENT);
|
||||
if (result != SMTPD_CHECK_DUNNO)
|
||||
@@ -2875,7 +2877,7 @@ static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sen
|
||||
if ((owners = check_mail_addr_find(state, sender, smtpd_sender_login_maps,
|
||||
STR(reply->recipient), (char **) 0)) != 0) {
|
||||
cp = saved_owners = mystrdup(owners);
|
||||
while ((name = mystrtok(&cp, ", \t\r\n")) != 0) {
|
||||
while ((name = mystrtok(&cp, RESTRICTION_SEPARATORS)) != 0) {
|
||||
if (strcasecmp(state->sasl_username, name) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
@@ -4179,7 +4181,7 @@ static void rest_class(char *class)
|
||||
if (smtpd_rest_classes == 0)
|
||||
smtpd_rest_classes = htable_create(1);
|
||||
|
||||
if ((name = mystrtok(&cp, " \t\r\n,")) == 0)
|
||||
if ((name = mystrtok(&cp, RESTRICTION_SEPARATORS)) == 0)
|
||||
msg_panic("rest_class: null class name");
|
||||
if ((entry = htable_locate(smtpd_rest_classes, name)) != 0)
|
||||
argv_free((ARGV *) entry->value);
|
||||
|
Reference in New Issue
Block a user