mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-29 13:18:12 +00:00
postfix-3.5.25
This commit is contained in:
parent
785f1727c1
commit
090083cc2f
@ -25433,3 +25433,83 @@ Apologies for any names omitted.
|
||||
Files: mantools/postlink, proto/postconf.proto,
|
||||
global/mail_params.h, global/smtp_stream.c, global/smtp_stream.h,
|
||||
smtpd/smtpd.c, smtpd/smtpd_check.[hc].
|
||||
|
||||
20231102
|
||||
|
||||
Bugfix (defect introduced: Postfix 2.3, date 20051222): the
|
||||
Dovecot auth client did not reset the 'reason' from a
|
||||
previous Dovecot auth service response, before parsing the
|
||||
next Dovecot auth server response in the same SMTP session.
|
||||
Reported by Stephan Bosch, File: xsasl/xsasl_dovecot_server.c.
|
||||
|
||||
20231105
|
||||
|
||||
Cleanup: Postfix SMTP server response with an empty
|
||||
authentication failure reason. File: smtpd/smtpd_sasl_glue.c.
|
||||
|
||||
20231208
|
||||
|
||||
Bugfix (defect introduced: Postfix 3.1, date: 20151128):
|
||||
"postqueue -j" produced broken JSON when escaping a control
|
||||
character as \uXXXX. Found during code maintenance. File:
|
||||
postqueue/showq_json.c.
|
||||
|
||||
20231211
|
||||
|
||||
Cleanup: posttls-finger certificate match expectations for
|
||||
all TLS security levels, including warnings for levels that
|
||||
don't implement certificate matching. Viktor Dukhovni.
|
||||
File: posttls-finger.c.
|
||||
|
||||
20231213
|
||||
|
||||
Bugfix (defect introduced: Postfix 2.3): after prepending
|
||||
a message header with a Postfix access table PREPEND action,
|
||||
a Milter request to delete or update an existing header
|
||||
could have no effect, or it could target the wrong instance
|
||||
of an existing header. Root cause: the fix dated 20141018
|
||||
for the Postfix Milter client was incomplete. The client
|
||||
did correctly hide the first, Postfix-generated, Received:
|
||||
header when sending message header information to a Milter
|
||||
with the smfi_header() application callback function, but
|
||||
it was still hiding the first header (instead of the first
|
||||
Received: header) when handling requests from a Milter to
|
||||
delete or update an existing header. Problem report by
|
||||
Carlos Velasco. This change was verified to have no effect
|
||||
on requests from a Milter to add or insert a header. File:
|
||||
cleanup/cleanup_milter.c.
|
||||
|
||||
20240124
|
||||
|
||||
Workaround: tlsmgr logfile spam. Some OS lies under load:
|
||||
it says that a socket is readable, then it says that the
|
||||
socket has unread data, and then it says that read returns
|
||||
EOF, causing Postfix to spam the log with a warning message.
|
||||
File: tlsmgr/tlsmgr.c.
|
||||
|
||||
Bugfix (defect introduced: Postfix 3.4): the SMTP server's
|
||||
BDAT command handler could be tricked to read $message_size_limit
|
||||
bytes into memory. Found during code maintenance. File:
|
||||
smtpd/smtpd.c.
|
||||
|
||||
20240209
|
||||
|
||||
Performance: eliminate worst-case behavior where the queue
|
||||
manager defers delivery to all destinations over a specific
|
||||
delivery transport, after only a single delivery agent
|
||||
failure. The scheduler now throttles one destination, and
|
||||
allows deliveries to other destinations to keep making
|
||||
progress. Files: *qmgr/qmgr_deliver.c.
|
||||
|
||||
20240226
|
||||
|
||||
Safety: drop and log over-size DNS responses resulting in
|
||||
more than 100 records. This 20x larger than the number of
|
||||
server addresses that the Postfix SMTP client is willing
|
||||
to consider when delivering mail, and is well below the
|
||||
number of records that could cause a tail recursion crash
|
||||
in dns_rr_append() as reported by Toshifumi Sakaguchi. This
|
||||
also limits the number of DNS requests from check_*_*_access
|
||||
restrictions. Files: dns/dns.h, dns/dns_lookup.c, dns/dns_rr.c,
|
||||
dns/test_dns_lookup.c, posttls-finger/posttls-finger.c,
|
||||
smtp/smtp_addr.c, smtpd/smtpd_check.c.
|
||||
|
@ -119,6 +119,7 @@
|
||||
#include <dsn_util.h>
|
||||
#include <xtext.h>
|
||||
#include <info_log_addr_form.h>
|
||||
#include <header_opts.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@ -754,14 +755,26 @@ static const char *cleanup_add_header(void *context, const char *name,
|
||||
*/
|
||||
}
|
||||
|
||||
/* hidden_header - respect milter header hiding protocol */
|
||||
|
||||
static int hidden_header(VSTRING *buf, ARGV *auto_hdrs, int *hide_done)
|
||||
{
|
||||
char **cpp;
|
||||
int mask;
|
||||
|
||||
for (cpp = auto_hdrs->argv, mask = 1; *cpp; cpp++, mask <<= 1)
|
||||
if ((*hide_done & mask) == 0 && strncmp(*cpp, STR(buf), LEN(buf)) == 0)
|
||||
return (*hide_done |= mask);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* cleanup_find_header_start - find specific header instance */
|
||||
|
||||
static off_t cleanup_find_header_start(CLEANUP_STATE *state, ssize_t index,
|
||||
const char *header_label,
|
||||
VSTRING *buf,
|
||||
int *prec_type,
|
||||
int allow_ptr_backup,
|
||||
int skip_headers)
|
||||
int allow_ptr_backup)
|
||||
{
|
||||
const char *myname = "cleanup_find_header_start";
|
||||
off_t curr_offset; /* offset after found record */
|
||||
@ -770,7 +783,7 @@ static off_t cleanup_find_header_start(CLEANUP_STATE *state, ssize_t index,
|
||||
int rec_type = REC_TYPE_ERROR;
|
||||
int last_type;
|
||||
ssize_t len;
|
||||
int hdr_count = 0;
|
||||
int hide_done = 0;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: index %ld name \"%s\"",
|
||||
@ -912,11 +925,10 @@ static off_t cleanup_find_header_start(CLEANUP_STATE *state, ssize_t index,
|
||||
break;
|
||||
}
|
||||
/* This the start of a message header. */
|
||||
else if (hdr_count++ < skip_headers)
|
||||
/* Reset the saved PTR record and update last_type. */ ;
|
||||
else if ((header_label == 0
|
||||
|| (strncasecmp(header_label, STR(buf), len) == 0
|
||||
&& (strlen(header_label) == len)))
|
||||
&& strlen(header_label) == len
|
||||
&& !hidden_header(buf, state->auto_hdrs, &hide_done)))
|
||||
&& --index == 0) {
|
||||
/* If we have a saved PTR record, it points to start of header. */
|
||||
break;
|
||||
@ -1182,15 +1194,12 @@ static const char *cleanup_ins_header(void *context, ssize_t index,
|
||||
*/
|
||||
#define NO_HEADER_NAME ((char *) 0)
|
||||
#define ALLOW_PTR_BACKUP 1
|
||||
#define SKIP_ONE_HEADER 1
|
||||
#define DONT_SKIP_HEADERS 0
|
||||
|
||||
if (index < 1)
|
||||
index = 1;
|
||||
old_rec_offset = cleanup_find_header_start(state, index, NO_HEADER_NAME,
|
||||
old_rec_buf, &old_rec_type,
|
||||
ALLOW_PTR_BACKUP,
|
||||
DONT_SKIP_HEADERS);
|
||||
ALLOW_PTR_BACKUP);
|
||||
if (old_rec_offset == CLEANUP_FIND_HEADER_IOERROR)
|
||||
/* Warning and errno->error mapping are done elsewhere. */
|
||||
CLEANUP_INS_HEADER_RETURN(cleanup_milter_error(state, 0));
|
||||
@ -1270,8 +1279,7 @@ static const char *cleanup_upd_header(void *context, ssize_t index,
|
||||
rec_buf = vstring_alloc(100);
|
||||
old_rec_offset = cleanup_find_header_start(state, index, new_hdr_name,
|
||||
rec_buf, &last_type,
|
||||
NO_PTR_BACKUP,
|
||||
SKIP_ONE_HEADER);
|
||||
NO_PTR_BACKUP);
|
||||
if (old_rec_offset == CLEANUP_FIND_HEADER_IOERROR)
|
||||
/* Warning and errno->error mapping are done elsewhere. */
|
||||
CLEANUP_UPD_HEADER_RETURN(cleanup_milter_error(state, 0));
|
||||
@ -1333,8 +1341,7 @@ static const char *cleanup_del_header(void *context, ssize_t index,
|
||||
|
||||
rec_buf = vstring_alloc(100);
|
||||
header_offset = cleanup_find_header_start(state, index, hdr_name, rec_buf,
|
||||
&last_type, NO_PTR_BACKUP,
|
||||
SKIP_ONE_HEADER);
|
||||
&last_type, NO_PTR_BACKUP);
|
||||
if (header_offset == CLEANUP_FIND_HEADER_IOERROR)
|
||||
/* Warning and errno->error mapping are done elsewhere. */
|
||||
CLEANUP_DEL_HEADER_RETURN(cleanup_milter_error(state, 0));
|
||||
|
@ -148,11 +148,17 @@ typedef struct DNS_RR {
|
||||
unsigned int ttl; /* always */
|
||||
unsigned int dnssec_valid; /* DNSSEC validated */
|
||||
unsigned short pref; /* T_MX only */
|
||||
/* Assume that flags lives in what was previously padding */
|
||||
unsigned short flags; /* DNS_RR_FLAG_XX, see below */
|
||||
struct DNS_RR *next; /* linkage */
|
||||
size_t data_len; /* actual data size */
|
||||
char data[1]; /* actually a bunch of data */
|
||||
} DNS_RR;
|
||||
|
||||
#define DNS_RR_FLAG_TRUNCATED (1<<0)
|
||||
|
||||
#define DNS_RR_IS_TRUNCATED(rr) ((rr)->flags & DNS_RR_FLAG_TRUNCATED)
|
||||
|
||||
/*
|
||||
* dns_strerror.c
|
||||
*/
|
||||
@ -186,6 +192,7 @@ extern int dns_rr_compare_pref_any(DNS_RR *, DNS_RR *);
|
||||
extern int dns_rr_compare_pref(DNS_RR *, DNS_RR *);
|
||||
extern DNS_RR *dns_rr_shuffle(DNS_RR *);
|
||||
extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
|
||||
extern int var_dns_rr_list_limit;
|
||||
|
||||
/*
|
||||
* dns_rr_to_pa.c
|
||||
|
@ -911,6 +911,8 @@ static int dns_get_answer(const char *orig_name, DNS_REPLY *reply, int type,
|
||||
resource_found++;
|
||||
rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0;
|
||||
*rrlist = dns_rr_append(*rrlist, rr);
|
||||
if (DNS_RR_IS_TRUNCATED(*rrlist))
|
||||
break;
|
||||
} else if (status == DNS_NULLMX) {
|
||||
CORRUPT(status); /* TODO: use better name */
|
||||
} else if (not_found_status != DNS_RETRY)
|
||||
@ -1135,8 +1137,11 @@ int dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist,
|
||||
name, dns_strtype(type), dns_str_resflags(flags));
|
||||
status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
|
||||
fqdn, why, rcode, lflags);
|
||||
if (rrlist && rr)
|
||||
if (rrlist && rr) {
|
||||
*rrlist = dns_rr_append(*rrlist, rr);
|
||||
if (DNS_RR_IS_TRUNCATED(*rrlist))
|
||||
break;
|
||||
}
|
||||
if (status == DNS_OK) {
|
||||
if (lflags & DNS_REQ_FLAG_STOP_OK)
|
||||
break;
|
||||
@ -1187,8 +1192,11 @@ int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist,
|
||||
name, dns_strtype(type), dns_str_resflags(flags));
|
||||
status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
|
||||
fqdn, why, rcode, lflags);
|
||||
if (rrlist && rr)
|
||||
if (rrlist && rr) {
|
||||
*rrlist = dns_rr_append(*rrlist, rr);
|
||||
if (DNS_RR_IS_TRUNCATED(*rrlist))
|
||||
break;
|
||||
}
|
||||
if (status == DNS_OK) {
|
||||
if (lflags & DNS_REQ_FLAG_STOP_OK)
|
||||
break;
|
||||
|
@ -49,6 +49,8 @@
|
||||
/* DNS_RR *dns_rr_remove(list, record)
|
||||
/* DNS_RR *list;
|
||||
/* DNS_RR *record;
|
||||
/*
|
||||
/* int var_dns_rr_list_limit;
|
||||
/* DESCRIPTION
|
||||
/* The routines in this module maintain memory for DNS resource record
|
||||
/* information, and maintain lists of DNS resource records.
|
||||
@ -65,9 +67,17 @@
|
||||
/*
|
||||
/* dns_rr_copy() makes a copy of a resource record.
|
||||
/*
|
||||
/* dns_rr_append() appends a resource record to a (list of) resource
|
||||
/* record(s).
|
||||
/* A null input list is explicitly allowed.
|
||||
/* dns_rr_append() appends an input resource record list to
|
||||
/* an output list. Null arguments are explicitly allowed.
|
||||
/* When the result would be longer than var_dns_rr_list_limit
|
||||
/* (default: 100), dns_rr_append() logs a warning, flags the
|
||||
/* output list as truncated, and discards the excess elements.
|
||||
/* Once an output list is flagged as truncated (test with
|
||||
/* DNS_RR_IS_TRUNCATED()), the caller is expected to stop
|
||||
/* trying to append records to that list. Note: the 'truncated'
|
||||
/* flag is transitive, i.e. when appending a input list that
|
||||
/* was flagged as truncated to an output list, the output list
|
||||
/* will also be flagged as truncated.
|
||||
/*
|
||||
/* dns_rr_sort() sorts a list of resource records into ascending
|
||||
/* order according to a user-specified criterion. The result is the
|
||||
@ -108,6 +118,16 @@
|
||||
|
||||
#include "dns.h"
|
||||
|
||||
/*
|
||||
* A generous safety limit for the number of DNS resource records that the
|
||||
* Postfix DNS client library will admit into a list. The default value 100
|
||||
* is 20x the default limit on the number address records that the Postfix
|
||||
* SMTP client is willing to consider.
|
||||
*
|
||||
* Mutable, to make code testable.
|
||||
*/
|
||||
int var_dns_rr_list_limit = 100;
|
||||
|
||||
/* dns_rr_create - fill in resource record structure */
|
||||
|
||||
DNS_RR *dns_rr_create(const char *qname, const char *rname,
|
||||
@ -129,6 +149,7 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname,
|
||||
memcpy(rr->data, data, data_len);
|
||||
rr->data_len = data_len;
|
||||
rr->next = 0;
|
||||
rr->flags = 0;
|
||||
return (rr);
|
||||
}
|
||||
|
||||
@ -163,14 +184,58 @@ DNS_RR *dns_rr_copy(DNS_RR *src)
|
||||
return (dst);
|
||||
}
|
||||
|
||||
/* dns_rr_append - append resource record to list */
|
||||
/* dns_rr_append_with_limit - append resource record to limited list */
|
||||
|
||||
static void dns_rr_append_with_limit(DNS_RR *list, DNS_RR *rr, int limit)
|
||||
{
|
||||
|
||||
/*
|
||||
* Pre: list != 0, all lists are concatenated with dns_rr_append().
|
||||
*
|
||||
* Post: all elements have the DNS_RR_FLAG_TRUNCATED flag value set, or all
|
||||
* elements have it cleared, so that there is no need to update code in
|
||||
* legacy stable releases that deletes or reorders elements.
|
||||
*/
|
||||
if (limit <= 1) {
|
||||
if (list->next || rr) {
|
||||
msg_warn("DNS record count limit (%d) exceeded -- dropping"
|
||||
" excess record(s) after qname=%s qtype=%s",
|
||||
var_dns_rr_list_limit, list->qname,
|
||||
dns_strtype(list->type));
|
||||
list->flags |= DNS_RR_FLAG_TRUNCATED;
|
||||
dns_rr_free(list->next);
|
||||
dns_rr_free(rr);
|
||||
list->next = 0;
|
||||
}
|
||||
} else {
|
||||
if (list->next == 0 && rr) {
|
||||
list->next = rr;
|
||||
rr = 0;
|
||||
}
|
||||
if (list->next) {
|
||||
dns_rr_append_with_limit(list->next, rr, limit - 1);
|
||||
list->flags |= list->next->flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* dns_rr_append - append resource record(s) to list, or discard */
|
||||
|
||||
DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr)
|
||||
{
|
||||
if (list == 0) {
|
||||
list = rr;
|
||||
|
||||
/*
|
||||
* Note: rr is not length checked; when multiple lists are concatenated,
|
||||
* the output length may be a small multiple of var_dns_rr_list_limit.
|
||||
*/
|
||||
if (rr == 0)
|
||||
return (list);
|
||||
if (list == 0)
|
||||
return (rr);
|
||||
if (!DNS_RR_IS_TRUNCATED(list)) {
|
||||
dns_rr_append_with_limit(list, rr, var_dns_rr_list_limit);
|
||||
} else {
|
||||
list->next = dns_rr_append(list->next, rr);
|
||||
dns_rr_free(rr);
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
|
@ -119,9 +119,11 @@ int main(int argc, char **argv)
|
||||
vstream_printf("%s: fqdn: %s\n", name, vstring_str(fqdn));
|
||||
buf = vstring_alloc(100);
|
||||
print_rr(buf, rr);
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
if (DNS_RR_IS_TRUNCATED(rr))
|
||||
msg_warn("one or more excess DNS_RR records were dropped");
|
||||
dns_rr_free(rr);
|
||||
vstring_free(buf);
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
}
|
||||
}
|
||||
myfree((void *) types);
|
||||
|
@ -20,8 +20,8 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20240121"
|
||||
#define MAIL_VERSION_NUMBER "3.5.24"
|
||||
#define MAIL_RELEASE_DATE "20240304"
|
||||
#define MAIL_VERSION_NUMBER "3.5.25"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
|
||||
|
@ -285,6 +285,7 @@ static void qmgr_deliver_update(int unused_event, void *context)
|
||||
* The queue itself won't go away before we dispose of the current queue
|
||||
* entry.
|
||||
*/
|
||||
#if 0
|
||||
if (status == DELIVER_STAT_CRASH) {
|
||||
message->flags |= DELIVER_STAT_DEFER;
|
||||
#if 0
|
||||
@ -319,6 +320,7 @@ static void qmgr_deliver_update(int unused_event, void *context)
|
||||
qmgr_defer_transport(transport, &dsb->dsn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This message must be tried again.
|
||||
@ -333,7 +335,9 @@ static void qmgr_deliver_update(int unused_event, void *context)
|
||||
*/
|
||||
#define SUSPENDED "delivery temporarily suspended: "
|
||||
|
||||
if (status == DELIVER_STAT_DEFER) {
|
||||
if (status == DELIVER_STAT_CRASH)
|
||||
DSN_SIMPLE(&dsb->dsn, "4.3.0", "unknown mail transport error");
|
||||
if (status == DELIVER_STAT_CRASH || status == DELIVER_STAT_DEFER) {
|
||||
message->flags |= DELIVER_STAT_DEFER;
|
||||
if (VSTRING_LEN(dsb->status)) {
|
||||
/* Sanitize the DSN status/reason from the delivery agent. */
|
||||
|
@ -96,7 +96,7 @@ static char *json_quote(VSTRING *result, const char *text)
|
||||
VSTRING_ADDCH(result, 't');
|
||||
break;
|
||||
default:
|
||||
vstring_sprintf(result, "\\u%04X", ch);
|
||||
vstring_sprintf_append(result, "\\u%04X", ch);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -1244,6 +1244,8 @@ static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host,
|
||||
msg_fatal("host %s: conversion error for address family %d: %m",
|
||||
host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
|
||||
addr_list = dns_rr_append(addr_list, addr);
|
||||
if (DNS_RR_IS_TRUNCATED(addr_list))
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
if (found == 0) {
|
||||
@ -1281,6 +1283,8 @@ static DNS_RR *mx_addr_list(STATE *state, DNS_RR *mx_names)
|
||||
msg_panic("%s: bad resource type: %d", myname, rr->type);
|
||||
addr_list = addr_one(state, addr_list, (char *) rr->data, res_opt,
|
||||
rr->pref);
|
||||
if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
|
||||
break;
|
||||
}
|
||||
return (addr_list);
|
||||
}
|
||||
@ -2048,8 +2052,20 @@ static void parse_match(STATE *state, int argc, char *argv[])
|
||||
{
|
||||
#ifdef USE_TLS
|
||||
|
||||
/*
|
||||
* DANE match names are configured late, once the TLSA records are in
|
||||
* hand. For now, prepare to fall back to "secure".
|
||||
*/
|
||||
switch (state->level) {
|
||||
case TLS_LEV_SECURE:
|
||||
default:
|
||||
state->match = 0;
|
||||
if (*argv)
|
||||
msg_warn("TLS level '%s' does not implement certificate matching",
|
||||
str_tls_level(state->level));
|
||||
break;
|
||||
case TLS_LEV_DANE:
|
||||
case TLS_LEV_DANE_ONLY:
|
||||
case TLS_LEV_SECURE:
|
||||
state->match = argv_alloc(2);
|
||||
while (*argv)
|
||||
argv_split_append(state->match, *argv++, "");
|
||||
@ -2069,11 +2085,6 @@ static void parse_match(STATE *state, int argc, char *argv[])
|
||||
tls_dane_add_ee_digests((TLS_DANE *) state->dane,
|
||||
state->mdalg, *argv++, "");
|
||||
break;
|
||||
case TLS_LEV_DANE:
|
||||
case TLS_LEV_DANE_ONLY:
|
||||
state->match = argv_alloc(2);
|
||||
argv_add(state->match, "nexthop", "hostname", ARGV_END);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -290,6 +290,7 @@ static void qmgr_deliver_update(int unused_event, void *context)
|
||||
* The queue itself won't go away before we dispose of the current queue
|
||||
* entry.
|
||||
*/
|
||||
#if 0
|
||||
if (status == DELIVER_STAT_CRASH) {
|
||||
message->flags |= DELIVER_STAT_DEFER;
|
||||
#if 0
|
||||
@ -324,6 +325,7 @@ static void qmgr_deliver_update(int unused_event, void *context)
|
||||
qmgr_defer_transport(transport, &dsb->dsn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This message must be tried again.
|
||||
@ -338,7 +340,9 @@ static void qmgr_deliver_update(int unused_event, void *context)
|
||||
*/
|
||||
#define SUSPENDED "delivery temporarily suspended: "
|
||||
|
||||
if (status == DELIVER_STAT_DEFER) {
|
||||
if (status == DELIVER_STAT_CRASH)
|
||||
DSN_SIMPLE(&dsb->dsn, "4.3.0", "unknown mail transport error");
|
||||
if (status == DELIVER_STAT_CRASH || status == DELIVER_STAT_DEFER) {
|
||||
message->flags |= DELIVER_STAT_DEFER;
|
||||
if (VSTRING_LEN(dsb->status)) {
|
||||
/* Sanitize the DSN status/reason from the delivery agent. */
|
||||
|
@ -230,6 +230,8 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
|
||||
msg_fatal("host %s: conversion error for address family "
|
||||
"%d: %m", host, res0->ai_addr->sa_family);
|
||||
addr_list = dns_rr_append(addr_list, addr);
|
||||
if (DNS_RR_IS_TRUNCATED(addr_list))
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
if (found == 0) {
|
||||
@ -287,6 +289,8 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, DSN_BUF *why)
|
||||
msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
|
||||
addr_list = smtp_addr_one(addr_list, (char *) rr->data, res_opt,
|
||||
rr->pref, why);
|
||||
if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
|
||||
break;
|
||||
}
|
||||
return (addr_list);
|
||||
}
|
||||
@ -381,6 +385,13 @@ static DNS_RR *smtp_balance_inet_proto(DNS_RR *addr_list, int misc_flags,
|
||||
* relative list order is unchanged, but some elements are removed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Ensure that dns_rr_append() won't interfere with the protocol
|
||||
* balancing goals.
|
||||
*/
|
||||
if (addr_limit > var_dns_rr_list_limit)
|
||||
addr_limit = var_dns_rr_list_limit;
|
||||
|
||||
/*
|
||||
* Count the number of IPv6 and IPv4 addresses.
|
||||
*/
|
||||
|
@ -4053,14 +4053,31 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
/*
|
||||
* Read lines from the fragment. The last line may continue in the
|
||||
* next fragment, or in the next chunk.
|
||||
*
|
||||
* If smtp_get_noexcept() stopped after var_line_limit bytes and did not
|
||||
* emit a queue file record, then that means smtp_get_noexcept()
|
||||
* stopped after CR and hit EOF as it tried to find out if the next
|
||||
* byte is LF. In that case, read the first byte from the next
|
||||
* fragment or chunk, and if that first byte is LF, then
|
||||
* smtp_get_noexcept() strips off the trailing CRLF and returns '\n'
|
||||
* as it always does after reading a complete line.
|
||||
*/
|
||||
do {
|
||||
int can_read = var_line_limit - LEN(state->bdat_get_buffer);
|
||||
|
||||
if (smtp_get_noexcept(state->bdat_get_buffer,
|
||||
state->bdat_get_stream,
|
||||
var_line_limit,
|
||||
can_read > 0 ? can_read : 1, /* Peek one */
|
||||
SMTP_GET_FLAG_APPEND) == '\n') {
|
||||
/* Stopped at end-of-line. */
|
||||
curr_rec_type = REC_TYPE_NORM;
|
||||
} else if (LEN(state->bdat_get_buffer) > var_line_limit) {
|
||||
/* Undo peeking, and output the buffer as REC_TYPE_CONT. */
|
||||
vstream_ungetc(state->bdat_get_stream,
|
||||
vstring_end(state->bdat_get_buffer)[-1]);
|
||||
vstring_truncate(state->bdat_get_buffer,
|
||||
LEN(state->bdat_get_buffer) - 1);
|
||||
curr_rec_type = REC_TYPE_CONT;
|
||||
} else if (!vstream_feof(state->bdat_get_stream)) {
|
||||
/* Stopped at var_line_limit. */
|
||||
curr_rec_type = REC_TYPE_CONT;
|
||||
|
@ -2985,6 +2985,7 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
|
||||
struct addrinfo *res;
|
||||
int status;
|
||||
INET_PROTO_INFO *proto_info;
|
||||
int server_addr_count = 0;
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
@ -3134,6 +3135,15 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
|
||||
msg_info("%s: %s host address check: %s",
|
||||
myname, dns_strtype(type), (char *) server->data);
|
||||
for (res = res0; res != 0; res = res->ai_next) {
|
||||
server_addr_count += 1;
|
||||
if (server_addr_count > var_dns_rr_list_limit) {
|
||||
msg_warn("%s: %s server address count limit (%d) exceeded"
|
||||
" for %s %s -- ignoring the remainder", myname,
|
||||
dns_strtype(type), var_dns_rr_list_limit,
|
||||
reply_class, reply_name);
|
||||
freeaddrinfo(res0);
|
||||
CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
|
||||
}
|
||||
if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("skipping address family %d for host %s",
|
||||
|
@ -321,18 +321,20 @@ int smtpd_sasl_authenticate(SMTPD_STATE *state,
|
||||
}
|
||||
}
|
||||
if (status != XSASL_AUTH_DONE) {
|
||||
const char *reason = (*STR(state->sasl_reply) ? STR(state->sasl_reply) :
|
||||
"(reason unavailable)");
|
||||
|
||||
sasl_username = xsasl_server_get_username(state->sasl_server);
|
||||
msg_warn("%s: SASL %.100s authentication failed: %s, sasl_username=%.100s",
|
||||
state->namaddr, sasl_method, *STR(state->sasl_reply) ?
|
||||
STR(state->sasl_reply) : "(reason unavailable)",
|
||||
state->namaddr, sasl_method, reason,
|
||||
sasl_username ? sasl_username : "(unavailable)");
|
||||
/* RFC 4954 Section 6. */
|
||||
if (status == XSASL_AUTH_TEMP)
|
||||
smtpd_chat_reply(state, "454 4.7.0 Temporary authentication failure: %s",
|
||||
STR(state->sasl_reply));
|
||||
reason);
|
||||
else
|
||||
smtpd_chat_reply(state, "535 5.7.8 Error: authentication failed: %s",
|
||||
STR(state->sasl_reply));
|
||||
reason);
|
||||
return (-1);
|
||||
}
|
||||
/* RFC 4954 Section 6. */
|
||||
|
@ -818,6 +818,23 @@ static void tlsmgr_service(VSTREAM *client_stream, char *unused_service,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround: some OS lies under load. It tells the Postfix event
|
||||
* handler that a server socket is readable, then it tells peekfd() that
|
||||
* the socket has unread data, and then it tells vstring_get_null() that
|
||||
* there is none, causing Postfix to spam the log with warning messages.
|
||||
* Close the stream to stop such nonsense; the client can reconnect if it
|
||||
* still wants to talk to us.
|
||||
*
|
||||
* XXX Why is this problem not reported for the other five
|
||||
* multi_server-based Postfix services?
|
||||
*/
|
||||
else if (vstream_ferror(client_stream) || vstream_feof(client_stream)) {
|
||||
multi_server_disconnect(client_stream);
|
||||
return;
|
||||
/* Note: client_stream is now a dangling pointer. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol error.
|
||||
*/
|
||||
|
@ -542,6 +542,8 @@ static void xsasl_dovecot_parse_reply_args(XSASL_DOVECOT_SERVER *server,
|
||||
myfree(server->username);
|
||||
server->username = 0;
|
||||
}
|
||||
VSTRING_RESET(reply);
|
||||
VSTRING_TERMINATE(reply);
|
||||
|
||||
/*
|
||||
* Note: TAB is part of the Dovecot protocol and must not appear in
|
||||
|
Loading…
x
Reference in New Issue
Block a user