mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
postfix-2.11-20130403
This commit is contained in:
committed by
Viktor Dukhovni
parent
fc52b35219
commit
46a1d9a44f
@@ -18400,3 +18400,13 @@ Apologies for any names omitted.
|
||||
|
||||
Cleanup: "zero time limit" corner case in read_wait() and
|
||||
write_wait() emulation. Files: util/poll_fd.c, util/iostuff.h.
|
||||
|
||||
20130401
|
||||
|
||||
Refactoring: allow smtp_session_alloc() to fail gracefully
|
||||
and report an error.
|
||||
|
||||
20130403
|
||||
|
||||
Documentation: in smtpd.c, the comment that justifies the
|
||||
454 reply for "TLS unavailable" cited the wrong RFC.
|
||||
|
@@ -8,6 +8,49 @@ Wish list:
|
||||
|
||||
Spellcheck and double-word check.
|
||||
|
||||
Begin code revision, after DANE support stabilizes. This
|
||||
should be one pass that changes only names and no code.
|
||||
|
||||
Generally, macro and function names should make a program
|
||||
more clear, not merely reduce the number of programmer
|
||||
keystrokes; similar considerations hold for variable names
|
||||
and constants. Avoid 1-letter names except "for i=1 to
|
||||
some_bound". Instead of bare numbers use named constants
|
||||
in function argument lists.
|
||||
|
||||
Code clarity: replace "valid" with or "dnssec_valid".
|
||||
|
||||
Code clarity: replace obscure macro/function names: for
|
||||
example SMTP_X(XXX) -> VAR_SMTP(XXX), as the purpose is to
|
||||
choose between VAR_SMTP_XXX or VAR_LMTP_XXX; replace
|
||||
digestpl() etc. with names that make clear what operation
|
||||
is being performed (in this case, update a digest with the
|
||||
contents of a buffer with the specified length). Replace r
|
||||
with res_opt, ditto for other 1-letter names.
|
||||
|
||||
Code consistency: replace the VSTRING-based digest output
|
||||
loop with a tls_digest_encode() call.
|
||||
|
||||
Code clarity: rename tls_fingerprint() to tls_cert_fprint()
|
||||
(compute certifate fingerprint). Keep tls_pkey_fprint()
|
||||
(compute public-key fingerprint). Rename tls_fprint() to
|
||||
tls_data_fprint() (compute fingerprint for arbitrary data).
|
||||
|
||||
Collect SMTP client connection-management state in one
|
||||
iterator object, that provides the same information for
|
||||
SMTP reuse policy, TLS policy, and SASL password lookups.
|
||||
|
||||
Unnecessary complexity: the SMTP_SESSION "tls" field is
|
||||
mandatory (always allocated) therefore the content can be
|
||||
a permanent part of the SMTP_SESSION structure, just like
|
||||
SASL-related information. This avoids silly indirections
|
||||
all over the code, as well as awkward smtp_tls_sess_alloc()
|
||||
error semantics.
|
||||
|
||||
Provide an iterator object API that provides consistent
|
||||
search key generation for SMTP reuse policy, TLS policy,
|
||||
and SASL password lookups.
|
||||
|
||||
We have smtp_host_lookup, smtp_dns_resolver_options, and
|
||||
now smtp_dns_support_level. Of these, smtp_dns_resolver_options
|
||||
is orthogonal but the rest has overlap.
|
||||
@@ -18,6 +61,8 @@ Wish list:
|
||||
for several releases before the deprecated feature can be
|
||||
removed.
|
||||
|
||||
End code revision, after DANE support stabilizes.
|
||||
|
||||
It would be nice if the result from one table lookup could
|
||||
serve as input for another (e.g. virtual aliases before the
|
||||
list of valid recipients). For this to work the magical
|
||||
|
@@ -462,12 +462,10 @@ ReliantUNIX-?.5.43) SYSTYPE=ReliantUnix543
|
||||
: ${CC=cc}
|
||||
CCARGS="$CCARGS \$(WARN)"
|
||||
# Darwin > 1.3 uses awk and flat_namespace
|
||||
# MacOS X 10.8.x (Darwin 12.x) needs libresolv, likely much
|
||||
# older earlier also, but I don't have access to test systems.
|
||||
case $RELEASE in
|
||||
1.[0-3]) AWK=gawk;;
|
||||
?.*|1[0-1].*) AWK=awk; SYSLIBS="-flat_namespace";;
|
||||
*) AWK=awk; SYSLIBS="-lresolv -flat_namespace";;
|
||||
*) AWK=awk
|
||||
SYSLIBS="$SYSLIBS -flat_namespace";;
|
||||
esac
|
||||
# Darwin 7 adds IPv6 support, BIND_8_COMPAT, NO_NETINFO
|
||||
case $RELEASE in
|
||||
@@ -483,6 +481,11 @@ ReliantUNIX-?.5.43) SYSTYPE=ReliantUnix543
|
||||
?.*) CCARGS="$CCARGS -DRESOLVE_H_NEEDS_NAMESER8_COMPAT_H";;
|
||||
*) CCARGS="$CCARGS -DRESOLVE_H_NEEDS_ARPA_NAMESER_COMPAT_H";;
|
||||
esac
|
||||
# Darwin 12.x (MacOS X 10.8.x), maybe earlier, needs libresolv.
|
||||
case $RELEASE in
|
||||
?.*|1[0-1].*) ;;
|
||||
*) SYSLIBS="$SYSLIBS -lresolv";;
|
||||
esac
|
||||
# kqueue and/or poll are broken in MacOS X 10.5 (Darwin 9).
|
||||
# kqueue works in Mac OS X 10.8 (Darwin 12).
|
||||
case $RELEASE in
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20130331"
|
||||
#define MAIL_RELEASE_DATE "20130403"
|
||||
#define MAIL_VERSION_NUMBER "2.11"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@@ -149,6 +149,7 @@ typedef struct SMTP_STATE {
|
||||
#define SMTP_MISC_FLAG_COMPLETE_SESSION (1<<8)
|
||||
#define SMTP_MISC_FLAG_PREF_IPV6 (1<<9)
|
||||
#define SMTP_MISC_FLAG_PREF_IPV4 (1<<10)
|
||||
#define SMTP_MISC_FLAG_NO_TLS (1<<11)
|
||||
|
||||
#define SMTP_MISC_FLAG_CONN_CACHE_MASK \
|
||||
(SMTP_MISC_FLAG_CONN_LOAD | SMTP_MISC_FLAG_CONN_STORE)
|
||||
@@ -259,19 +260,21 @@ typedef struct SMTP_SESSION {
|
||||
SMTP_STATE *state; /* back link */
|
||||
} SMTP_SESSION;
|
||||
|
||||
extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *, const char *,
|
||||
const char *, unsigned, time_t, int);
|
||||
extern SMTP_SESSION *smtp_session_alloc(DSN_BUF *, const char *, const char *,
|
||||
const char *, unsigned, int);
|
||||
extern void smtp_session_new_stream(SMTP_SESSION *, VSTREAM *, time_t, int);
|
||||
extern int smtp_sess_tls_check(const char *, const char *, unsigned, int);
|
||||
extern void smtp_session_free(SMTP_SESSION *);
|
||||
extern int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *);
|
||||
extern SMTP_SESSION *smtp_session_activate(int, VSTRING *, VSTRING *);
|
||||
|
||||
#ifdef USE_TLS
|
||||
extern void smtp_tls_list_init(void);
|
||||
|
||||
/*
|
||||
* smtp_tls_sess.c
|
||||
*/
|
||||
extern SMTP_TLS_SESS *smtp_tls_sess_alloc(const char *, const char *,
|
||||
extern void smtp_tls_list_init(void);
|
||||
extern SMTP_TLS_SESS *smtp_tls_sess_alloc(DSN_BUF *, const char *, const char *,
|
||||
unsigned, int);
|
||||
extern SMTP_TLS_SESS *smtp_tls_sess_free(SMTP_TLS_SESS *);
|
||||
|
||||
|
@@ -293,6 +293,17 @@ static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa,
|
||||
int saved_errno;
|
||||
VSTREAM *stream;
|
||||
time_t start_time;
|
||||
SMTP_SESSION *session;
|
||||
|
||||
/*
|
||||
* Session construction is cheap, and can now tempfail when TLSA lookups
|
||||
* don't work at the DANE security level. This also handles table lookup
|
||||
* errors more gracefully. So construct the session, and then connect. If
|
||||
* the connection fails, tear down the session.
|
||||
*/
|
||||
if ((session = smtp_session_alloc(why, destination, name, addr,
|
||||
port, sess_flags)) == 0)
|
||||
return (0);
|
||||
|
||||
start_time = time((time_t *) 0);
|
||||
if (var_smtp_conn_tmout > 0) {
|
||||
@@ -311,6 +322,7 @@ static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa,
|
||||
else
|
||||
dsb_simple(why, "4.4.1", "connect to %s[%s]: %m", name, addr);
|
||||
close(sock);
|
||||
smtp_session_free(session);
|
||||
return (0);
|
||||
}
|
||||
stream = vstream_fdopen(sock, O_RDWR);
|
||||
@@ -326,10 +338,13 @@ static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa,
|
||||
vstream_tweak_tcp(stream);
|
||||
|
||||
/*
|
||||
* Bundle up what we have into a nice SMTP_SESSION object.
|
||||
* Update the SMTP_SESSION state with this newly-created stream, and make
|
||||
* it subject to the new-stream connection caching policy (as opposed to
|
||||
* the reused-stream caching policy).
|
||||
*/
|
||||
return (smtp_session_alloc(stream, destination, name, addr,
|
||||
port, start_time, sess_flags));
|
||||
smtp_session_new_stream(session, stream, start_time, sess_flags);
|
||||
|
||||
return (session);
|
||||
}
|
||||
|
||||
/* smtp_parse_destination - parse host/port destination */
|
||||
|
@@ -274,6 +274,7 @@ SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, const char *addr,
|
||||
* credentials or the wrong TLS policy.
|
||||
*/
|
||||
if ((var_smtp_tls_per_site && *var_smtp_tls_per_site)
|
||||
|| (var_smtp_tls_policy && *var_smtp_tls_policy)
|
||||
|| (var_smtp_sasl_passwd && *var_smtp_sasl_passwd))
|
||||
return (0);
|
||||
|
||||
|
@@ -6,16 +6,27 @@
|
||||
/* SYNOPSIS
|
||||
/* #include "smtp.h"
|
||||
/*
|
||||
/* SMTP_SESSION *smtp_session_alloc(stream, dest, host, addr,
|
||||
/* port, start, flags)
|
||||
/* VSTREAM *stream;
|
||||
/* SMTP_SESSION *smtp_session_alloc(why, dest, host, addr,
|
||||
/* port, flags)
|
||||
/* DSN_BUF *why;
|
||||
/* char *dest;
|
||||
/* char *host;
|
||||
/* char *addr;
|
||||
/* unsigned port;
|
||||
/* int flags;
|
||||
/*
|
||||
/* void smtp_session_new_stream(session, stream, start, flags)
|
||||
/* SMTP_SESSION *session;
|
||||
/* VSTREAM *stream;
|
||||
/* time_t start;
|
||||
/* int flags;
|
||||
/*
|
||||
/* int smtp_sess_tls_check(dest, host, port, valid)
|
||||
/* char *dest;
|
||||
/* char *host;
|
||||
/* unsigned port;
|
||||
/* int valid;
|
||||
/*
|
||||
/* void smtp_session_free(session)
|
||||
/* SMTP_SESSION *session;
|
||||
/*
|
||||
@@ -30,13 +41,24 @@
|
||||
/* VSTRING *endp_prop;
|
||||
/* DESCRIPTION
|
||||
/* smtp_session_alloc() allocates memory for an SMTP_SESSION structure
|
||||
/* and initializes it with the given stream and destination, host name
|
||||
/* and address information. The host name and address strings are
|
||||
/* copied. The port is in network byte order.
|
||||
/* When TLS is enabled, smtp_session_alloc() looks up the
|
||||
/* per-site TLS policies for TLS enforcement and certificate
|
||||
/* verification. The resulting policy is stored into the
|
||||
/* SMTP_SESSION object.
|
||||
/* and initializes it with the given destination, host name and address
|
||||
/* information. The host name and address strings are copied. The port
|
||||
/* is in network byte order. When TLS is enabled, smtp_session_alloc()
|
||||
/* looks up the per-site TLS policies for TLS enforcement and certificate
|
||||
/* verification. The resulting policy is stored into the SMTP_SESSION
|
||||
/* object. Table and DNS lookups can fail during TLS policy creation,
|
||||
/* when this happens, "why" is updated with the error reason and a null
|
||||
/* session pointer is returned.
|
||||
/*
|
||||
/* smtp_session_new_stream() updates an SMTP_SESSION structure
|
||||
/* with a newly-created stream that was created at the specified
|
||||
/* start time, and makes it subject to the specified connection
|
||||
/* caching policy.
|
||||
/*
|
||||
/* smtp_sess_tls_check() returns true if TLS use is mandatory, invalid
|
||||
/* or indeterminate. The return value is false only if TLS is optional.
|
||||
/* This is not yet used anywhere, it can be used to safely enable TLS
|
||||
/* policy with smtp_reuse_addr().
|
||||
/*
|
||||
/* smtp_session_free() destroys an SMTP_SESSION structure and its
|
||||
/* members, making memory available for reuse. It will handle the
|
||||
@@ -61,6 +83,8 @@
|
||||
/* The address of the host that we are connected to.
|
||||
/* .IP port
|
||||
/* The remote port, network byte order.
|
||||
/* .IP valid
|
||||
/* The DNSSEC validation status of the host name.
|
||||
/* .IP start
|
||||
/* The time when this connection was opened.
|
||||
/* .IP flags
|
||||
@@ -72,6 +96,8 @@
|
||||
/* Enable re-use of cached SMTP or LMTP connections.
|
||||
/* .IP SMTP_MISC_FLAG_CONN_STORE
|
||||
/* Enable saving of cached SMTP or LMTP connections.
|
||||
/* .IP SMTP_MISC_FLAG_NO_TLS
|
||||
/* Used only internally in smtp_session.c
|
||||
/* .RE
|
||||
/* SMTP_MISC_FLAG_CONN_MASK corresponds with both _LOAD and _STORE.
|
||||
/* .IP dest_prop
|
||||
@@ -117,7 +143,6 @@
|
||||
#include <vstream.h>
|
||||
#include <stringops.h>
|
||||
#include <valid_hostname.h>
|
||||
#include <name_code.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
@@ -134,15 +159,16 @@
|
||||
|
||||
/* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */
|
||||
|
||||
SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
|
||||
SMTP_SESSION *smtp_session_alloc(DSN_BUF *why, const char *dest,
|
||||
const char *host, const char *addr,
|
||||
unsigned port, time_t start,
|
||||
int flags)
|
||||
unsigned port, int flags)
|
||||
{
|
||||
const char *myname = "smtp_session_alloc";
|
||||
SMTP_SESSION *session;
|
||||
int valid = (flags & SMTP_MISC_FLAG_TLSA_HOST);
|
||||
|
||||
session = (SMTP_SESSION *) mymalloc(sizeof(*session));
|
||||
session->stream = stream;
|
||||
session->stream = 0;
|
||||
session->dest = mystrdup(dest);
|
||||
session->host = mystrdup(host);
|
||||
session->addr = mystrdup(addr);
|
||||
@@ -168,29 +194,75 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
|
||||
|
||||
session->send_proto_helo = 0;
|
||||
|
||||
if (flags & SMTP_MISC_FLAG_CONN_STORE)
|
||||
CACHE_THIS_SESSION_UNTIL(start + var_smtp_reuse_time);
|
||||
else
|
||||
DONT_CACHE_THIS_SESSION;
|
||||
session->reuse_count = 0;
|
||||
USE_NEWBORN_SESSION; /* He's not dead Jim! */
|
||||
|
||||
#ifdef USE_SASL_AUTH
|
||||
smtp_sasl_connect(session);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When the destination argument of smtp_tls_sess_alloc() is null, a
|
||||
* trivial TLS policy (level = "none") is returned unconditionally and
|
||||
* the other arguments are not used. Soon the DSN_BUF "why" argument
|
||||
* will be optional when the caller is not interested in the error
|
||||
* status.
|
||||
*/
|
||||
#define NO_DSN_BUF (DSN_BUF *) 0
|
||||
#define NO_DEST (char *) 0
|
||||
#define NO_HOST (char *) 0
|
||||
#define NO_PORT 0
|
||||
#define NO_FLAGS 0
|
||||
|
||||
#ifdef USE_TLS
|
||||
session->tls_context = 0;
|
||||
session->tls_retry_plain = 0;
|
||||
session->tls_nexthop = 0;
|
||||
session->tls =
|
||||
smtp_tls_sess_alloc(dest, host, port, flags & SMTP_MISC_FLAG_TLSA_HOST);
|
||||
if (flags & SMTP_MISC_FLAG_NO_TLS)
|
||||
session->tls = smtp_tls_sess_alloc(NO_DSN_BUF, NO_DEST, NO_HOST,
|
||||
NO_PORT, NO_FLAGS);
|
||||
else {
|
||||
if (why == 0)
|
||||
msg_panic("%s: null error buffer", myname);
|
||||
session->tls = smtp_tls_sess_alloc(why, dest, host, port, valid);
|
||||
}
|
||||
if (!session->tls) {
|
||||
smtp_session_free(session);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
session->state = 0;
|
||||
debug_peer_check(host, addr);
|
||||
return (session);
|
||||
}
|
||||
|
||||
/* smtp_session_new_stream - finalize session with newly-created connection */
|
||||
|
||||
void smtp_session_new_stream(SMTP_SESSION *session, VSTREAM *stream,
|
||||
time_t start, int flags)
|
||||
{
|
||||
const char *myname = "smtp_session_new_stream";
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (session->stream != 0)
|
||||
msg_panic("%s: session exists", myname);
|
||||
|
||||
session->stream = stream;
|
||||
|
||||
/*
|
||||
* Make the session subject to the new-stream connection caching policy,
|
||||
* as opposed to the reused-stream connection caching policy at the
|
||||
* bottom of this module. Both policies are enforced in this file, not
|
||||
* one policy here and the other at some random place in smtp_connect.c.
|
||||
*/
|
||||
if (flags & SMTP_MISC_FLAG_CONN_STORE)
|
||||
CACHE_THIS_SESSION_UNTIL(start + var_smtp_reuse_time);
|
||||
else
|
||||
DONT_CACHE_THIS_SESSION;
|
||||
session->reuse_count = 0;
|
||||
}
|
||||
|
||||
/* smtp_session_free - destroy SMTP_SESSION structure and contents */
|
||||
|
||||
void smtp_session_free(SMTP_SESSION *session)
|
||||
@@ -232,6 +304,32 @@ void smtp_session_free(SMTP_SESSION *session)
|
||||
myfree((char *) session);
|
||||
}
|
||||
|
||||
/* smtp_sess_tls_check - does session require tls */
|
||||
|
||||
int smtp_sess_tls_check(const char *dest, const char *host, unsigned port,
|
||||
int valid)
|
||||
{
|
||||
#ifdef USE_TLS
|
||||
static DSN_BUF *why;
|
||||
SMTP_TLS_SESS *tls;
|
||||
|
||||
if (!why)
|
||||
why = dsb_create();
|
||||
|
||||
tls = smtp_tls_sess_alloc(why, dest, host, ntohs(port), valid);
|
||||
dsb_reset(why);
|
||||
|
||||
if (tls && tls->level >= TLS_LEV_NONE && tls->level <= TLS_LEV_MAY)
|
||||
return (0);
|
||||
if (tls)
|
||||
smtp_tls_sess_free(tls);
|
||||
return (1);
|
||||
#else
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* smtp_session_passivate - passivate an SMTP_SESSION object */
|
||||
|
||||
int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
|
||||
@@ -372,11 +470,15 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
|
||||
|
||||
/*
|
||||
* Allright, bundle up what we have sofar.
|
||||
*
|
||||
* Caller is responsible for not reusing plain-text connections when TLS is
|
||||
* required. With TLS disabled, a trivial TLS policy (level "none") is
|
||||
* returned without fail, with no other ways for session setup to fail,
|
||||
* we assume it must succeed.
|
||||
*/
|
||||
#define NO_FLAGS 0
|
||||
|
||||
session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), dest, host,
|
||||
addr, port, (time_t) 0, NO_FLAGS);
|
||||
session = smtp_session_alloc(NO_DSN_BUF, dest, host, addr, port,
|
||||
SMTP_MISC_FLAG_NO_TLS);
|
||||
session->stream = vstream_fdopen(fd, O_RDWR);
|
||||
session->features = (features | SMTP_FEATURE_FROM_CACHE);
|
||||
CACHE_THIS_SESSION_UNTIL(expire_time);
|
||||
session->reuse_count = ++reuse_count;
|
||||
|
@@ -8,7 +8,8 @@
|
||||
/*
|
||||
/* void smtp_tls_list_init()
|
||||
/*
|
||||
/* SMTP_TLS_SESS *smtp_tls_sess_alloc(dest, host, port, valid)
|
||||
/* SMTP_TLS_SESS *smtp_tls_sess_alloc(why, dest, host, port, valid)
|
||||
/* DSN_BUF *why;
|
||||
/* char *dest;
|
||||
/* char *host;
|
||||
/* unsigned port;
|
||||
@@ -21,8 +22,12 @@
|
||||
/* policy engine.
|
||||
/*
|
||||
/* smtp_tls_sess_alloc() allocates memory for an SMTP_TLS_SESS structure
|
||||
/* and initializes it based on the given information. NOTE: the
|
||||
/* port is in network byte order.
|
||||
/* and initializes it based on the given information. Any required
|
||||
/* table and DNS lookups can fail. When this happens, "why" is updated
|
||||
/* with the error reason and a null pointer is returned. NOTE: the
|
||||
/* port is in network byte order. If "dest" is null, no policy checks are
|
||||
/* made, rather a trivial policy with tls disabled is returned (the
|
||||
/* remaining arguments are unused in this case and may be null).
|
||||
/*
|
||||
/* smtp_tls_sess_free() destroys an SMTP_TLS_SESS structure and its
|
||||
/* members. A null pointer is returned for convenience.
|
||||
@@ -126,8 +131,9 @@ static const char *policy_name(int tls_level)
|
||||
|
||||
/* tls_site_lookup - look up per-site TLS security level */
|
||||
|
||||
static void tls_site_lookup(int *site_level, const char *site_name,
|
||||
const char *site_class)
|
||||
static void tls_site_lookup(SMTP_TLS_SESS *tls, int *site_level,
|
||||
const char *site_name, const char *site_class,
|
||||
DSN_BUF *why)
|
||||
{
|
||||
const char *lookup;
|
||||
|
||||
@@ -154,19 +160,27 @@ static void tls_site_lookup(int *site_level, const char *site_name,
|
||||
if (*site_level < TLS_LEV_VERIFY)
|
||||
*site_level = TLS_LEV_VERIFY;
|
||||
} else {
|
||||
msg_warn("Table %s: ignoring unknown TLS policy '%s' for %s %s",
|
||||
var_smtp_tls_per_site, lookup, site_class, site_name);
|
||||
msg_warn("%s: unknown TLS policy '%s' for %s %s",
|
||||
tls_per_site->title, lookup, site_class, site_name);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
return;
|
||||
}
|
||||
} else if (tls_per_site->error) {
|
||||
msg_fatal("%s lookup error for %s", tls_per_site->title, site_name);
|
||||
msg_warn("%s: %s \"%s\": per-site table lookup error",
|
||||
tls_per_site->title, site_class, site_name);
|
||||
dsb_simple(why, "4.3.0", "Temporary lookup error");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* tls_policy_lookup_one - look up destination TLS policy */
|
||||
|
||||
static int tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
static void tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
const char *site_name,
|
||||
const char *site_class)
|
||||
const char *site_class, DSN_BUF *why)
|
||||
{
|
||||
const char *lookup;
|
||||
char *policy;
|
||||
@@ -178,35 +192,37 @@ static int tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
static VSTRING *cbuf;
|
||||
|
||||
#undef FREE_RETURN
|
||||
#define FREE_RETURN(x) do { myfree(saved_policy); return (x); } while (0)
|
||||
#define FREE_RETURN do { myfree(saved_policy); return; } while (0)
|
||||
|
||||
#define WHERE \
|
||||
vstring_str(vstring_sprintf(cbuf, "%s, %s \"%s\"", \
|
||||
tls_policy->title, site_class, site_name))
|
||||
|
||||
if ((lookup = maps_find(tls_policy, site_name, 0)) == 0) {
|
||||
if (tls_policy->error) {
|
||||
msg_fatal("%s lookup error for %s",
|
||||
tls_policy->title, site_name);
|
||||
/* XXX session->stream has no longjmp context yet. */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (cbuf == 0)
|
||||
cbuf = vstring_alloc(10);
|
||||
|
||||
#define WHERE \
|
||||
vstring_str(vstring_sprintf(cbuf, "TLS policy table, %s \"%s\"", \
|
||||
site_class, site_name))
|
||||
|
||||
if ((lookup = maps_find(tls_policy, site_name, 0)) == 0) {
|
||||
if (tls_policy->error) {
|
||||
msg_warn("%s: policy table lookup error", WHERE);
|
||||
dsb_simple(why, "4.3.0", "Temporary lookup error");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
}
|
||||
return;
|
||||
}
|
||||
saved_policy = policy = mystrdup(lookup);
|
||||
|
||||
if ((tok = mystrtok(&policy, "\t\n\r ,")) == 0) {
|
||||
msg_warn("%s: invalid empty policy", WHERE);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
FREE_RETURN(1); /* No further lookups */
|
||||
FREE_RETURN;
|
||||
}
|
||||
*site_level = tls_level_lookup(tok);
|
||||
if (*site_level == TLS_LEV_INVALID) {
|
||||
/* tls_level_lookup() logs no warning. */
|
||||
msg_warn("%s: invalid security level \"%s\"", WHERE, tok);
|
||||
FREE_RETURN(1); /* No further lookups */
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
FREE_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -216,7 +232,7 @@ static int tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0)
|
||||
msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
|
||||
WHERE, tok);
|
||||
FREE_RETURN(1);
|
||||
FREE_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -225,23 +241,26 @@ static int tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
*/
|
||||
while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0) {
|
||||
if ((err = split_nameval(tok, &name, &val)) != 0) {
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
msg_warn("%s: malformed attribute/value pair \"%s\": %s",
|
||||
WHERE, tok, err);
|
||||
break;
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
FREE_RETURN;
|
||||
}
|
||||
/* Only one instance per policy. */
|
||||
if (!strcasecmp(name, "ciphers")) {
|
||||
if (*val == 0) {
|
||||
msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
break;
|
||||
FREE_RETURN;
|
||||
}
|
||||
if (tls->grade) {
|
||||
msg_warn("%s: attribute \"%s\" is specified multiple times",
|
||||
WHERE, name);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
break;
|
||||
FREE_RETURN;
|
||||
}
|
||||
tls->grade = mystrdup(val);
|
||||
continue;
|
||||
@@ -251,8 +270,9 @@ static int tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
if (tls->protocols) {
|
||||
msg_warn("%s: attribute \"%s\" is specified multiple times",
|
||||
WHERE, name);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
break;
|
||||
FREE_RETURN;
|
||||
}
|
||||
tls->protocols = mystrdup(val);
|
||||
continue;
|
||||
@@ -264,13 +284,15 @@ static int tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
if (*site_level <= TLS_LEV_ENCRYPT) {
|
||||
msg_warn("%s: attribute \"%s\" invalid at security level "
|
||||
"\"%s\"", WHERE, name, policy_name(*site_level));
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
break;
|
||||
FREE_RETURN;
|
||||
}
|
||||
if (*val == 0) {
|
||||
msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
break;
|
||||
FREE_RETURN;
|
||||
}
|
||||
if (tls->matchargv == 0)
|
||||
tls->matchargv = argv_split(val, delim);
|
||||
@@ -283,25 +305,27 @@ static int tls_policy_lookup_one(SMTP_TLS_SESS *tls, int *site_level,
|
||||
if (tls->exclusions) {
|
||||
msg_warn("%s: attribute \"%s\" is specified multiple times",
|
||||
WHERE, name);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
break;
|
||||
FREE_RETURN;
|
||||
}
|
||||
tls->exclusions = vstring_strcpy(vstring_alloc(10), val);
|
||||
continue;
|
||||
} else {
|
||||
}
|
||||
msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
|
||||
dsb_simple(why, "4.7.5", "client TLS configuration problem");
|
||||
*site_level = TLS_LEV_INVALID;
|
||||
break;
|
||||
FREE_RETURN;
|
||||
}
|
||||
}
|
||||
FREE_RETURN(1);
|
||||
|
||||
FREE_RETURN;
|
||||
}
|
||||
|
||||
/* tls_policy_lookup - look up destination TLS policy */
|
||||
|
||||
static void tls_policy_lookup(SMTP_TLS_SESS *tls, int *site_level,
|
||||
const char *site_name,
|
||||
const char *site_class)
|
||||
const char *site_class, DSN_BUF *why)
|
||||
{
|
||||
|
||||
/*
|
||||
@@ -312,22 +336,13 @@ static void tls_policy_lookup(SMTP_TLS_SESS *tls, int *site_level,
|
||||
* sub-domains of the recipient domain.
|
||||
*/
|
||||
if (!valid_hostname(site_name, DONT_GRIPE)) {
|
||||
tls_policy_lookup_one(tls, site_level, site_name, site_class);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX For clarity consider using ``do { .. } while'', instead of using
|
||||
* ``while { .. }'' with loop control at the bottom.
|
||||
*/
|
||||
while (1) {
|
||||
/* Try the given domain */
|
||||
if (tls_policy_lookup_one(tls, site_level, site_name, site_class))
|
||||
return;
|
||||
/* Re-try with parent domain */
|
||||
if ((site_name = strchr(site_name + 1, '.')) == 0)
|
||||
tls_policy_lookup_one(tls, site_level, site_name, site_class, why);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
tls_policy_lookup_one(tls, site_level, site_name, site_class, why);
|
||||
} while (*site_level == TLS_LEV_NOTFOUND
|
||||
&& (site_name = strchr(site_name + 1, '.')) != 0);
|
||||
}
|
||||
|
||||
/* set_cipher_grade - Set cipher grade and exclusions */
|
||||
@@ -390,10 +405,10 @@ static void set_cipher_grade(SMTP_TLS_SESS *tls)
|
||||
|
||||
/* smtp_tls_sess_alloc - session TLS policy parameters */
|
||||
|
||||
SMTP_TLS_SESS *smtp_tls_sess_alloc(const char *dest, const char *host,
|
||||
unsigned port, int valid)
|
||||
SMTP_TLS_SESS *smtp_tls_sess_alloc(DSN_BUF *why, const char *dest,
|
||||
const char *host, unsigned port, int valid)
|
||||
{
|
||||
const char *myname = "session_tls_init";
|
||||
const char *myname = "smtp_tls_sess_alloc";
|
||||
int global_level;
|
||||
int site_level;
|
||||
SMTP_TLS_SESS *tls = (SMTP_TLS_SESS *) mymalloc(sizeof(*tls));
|
||||
@@ -404,6 +419,9 @@ SMTP_TLS_SESS *smtp_tls_sess_alloc(const char *dest, const char *host,
|
||||
tls->exclusions = 0;
|
||||
tls->matchargv = 0;
|
||||
|
||||
if (!dest)
|
||||
return (tls);
|
||||
|
||||
/*
|
||||
* Compute the global TLS policy. This is the default policy level when
|
||||
* no per-site policy exists. It also is used to override a wild-card
|
||||
@@ -433,13 +451,12 @@ SMTP_TLS_SESS *smtp_tls_sess_alloc(const char *dest, const char *host,
|
||||
site_level = TLS_LEV_NOTFOUND;
|
||||
|
||||
if (tls_policy) {
|
||||
tls_policy_lookup(tls, &site_level, dest, "next-hop destination");
|
||||
tls_policy_lookup(tls, &site_level, dest, "next-hop destination", why);
|
||||
} else if (tls_per_site) {
|
||||
tls_site_lookup(&site_level, dest, "next-hop destination");
|
||||
if (strcasecmp(dest, host) != 0)
|
||||
tls_site_lookup(&site_level, host, "server hostname");
|
||||
if (msg_verbose)
|
||||
msg_info("%s TLS level: %s", "site", policy_name(site_level));
|
||||
tls_site_lookup(tls, &site_level, dest, "next-hop destination", why);
|
||||
if (site_level != TLS_LEV_INVALID
|
||||
&& strcasecmp(dest, host) != 0)
|
||||
tls_site_lookup(tls, &site_level, host, "server hostname", why);
|
||||
|
||||
/*
|
||||
* Override a wild-card per-site policy with a more specific global
|
||||
@@ -460,10 +477,16 @@ SMTP_TLS_SESS *smtp_tls_sess_alloc(const char *dest, const char *host,
|
||||
if (site_level == TLS_LEV_MAY && global_level > TLS_LEV_MAY)
|
||||
site_level = global_level;
|
||||
}
|
||||
if (site_level == TLS_LEV_NOTFOUND)
|
||||
switch (site_level) {
|
||||
case TLS_LEV_INVALID:
|
||||
return (smtp_tls_sess_free(tls));
|
||||
case TLS_LEV_NOTFOUND:
|
||||
tls->level = global_level;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
tls->level = site_level;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use main.cf protocols setting if not set in per-destination table.
|
||||
|
@@ -4347,14 +4347,14 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
state->port, var_smtpd_tmout);
|
||||
if (state->tlsproxy == 0) {
|
||||
state->error_mask |= MAIL_ERROR_SOFTWARE;
|
||||
/* RFC 4954 Section 6. */
|
||||
/* RFC 3207 Section 4. */
|
||||
smtpd_chat_reply(state, "454 4.7.0 TLS not available due to local problem");
|
||||
return (-1);
|
||||
}
|
||||
#else /* USE_TLSPROXY */
|
||||
if (smtpd_tls_ctx == 0) {
|
||||
state->error_mask |= MAIL_ERROR_SOFTWARE;
|
||||
/* RFC 4954 Section 6. */
|
||||
/* RFC 3207 Section 4. */
|
||||
smtpd_chat_reply(state, "454 4.7.0 TLS not available due to local problem");
|
||||
return (-1);
|
||||
}
|
||||
|
Reference in New Issue
Block a user