mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-22 09:57:34 +00:00
postfix-2.11-20130326
This commit is contained in:
parent
6896772b76
commit
c771f8cafb
@ -18332,7 +18332,7 @@ Apologies for any names omitted.
|
||||
src/dns/dns_strtype.c, src/dns/test_dns_lookup.c,
|
||||
|
||||
Cleanup: the personality switch between "smtp" and "lmtp".
|
||||
This streamlies the swicth in the SMTP/LMTP protocol, DNS
|
||||
This streamlines the switch in the SMTP/LMTP protocol, DNS
|
||||
MX lookups, and configuration parameter names in error
|
||||
messages. Viktor Dukhovni. Files: src/smtp/smtp.c,
|
||||
src/smtp/smtp.h, src/smtp/smtp_chat.c, src/smtp/smtp_connect.c,
|
||||
@ -18357,3 +18357,20 @@ Apologies for any names omitted.
|
||||
|
||||
Portability: support for NetBSD 5.x, NetBSD 6.x and DragonFly
|
||||
BSD. Viktor Dukhovni. Files: makedefs, src/util/sys_defs.h.
|
||||
|
||||
20130326
|
||||
|
||||
Cleanup: new module that consolidates all system-dependent
|
||||
code to enforce read/write timeouts. This includes a final
|
||||
workaround for MacOS X that uses poll() first, and select()
|
||||
if that fails. This makes their /dev/urandom workaround
|
||||
unnecessary. Files: util/poll_fd.c, util/iostuff.h. Removed:
|
||||
util/readable.c, util/writable.c, util/read_wait.c,
|
||||
util/write_wait.c.
|
||||
|
||||
Cleanup: refactor TLS digest functions, improved signature
|
||||
for TLS session cache. Viktor Dukhovni. Files: src/smtp/smtp.c,
|
||||
src/smtp/smtp_proto.c, src/smtpd/smtpd.c, src/tls/Makefile.in,
|
||||
src/tls/tls.h, src/tls/tls_client.c, src/tls/tls_fprint.c,
|
||||
src/tls/tls_level.c, src/tls/tls_misc.c, src/tls/tls_server.c,
|
||||
src/tls/tls_verify.c, src/tlsproxy/tlsproxy.c.
|
||||
|
@ -689,7 +689,9 @@ SMTPD(8) SMTPD(8)
|
||||
|
||||
<b><a href="postconf.5.html#smtpd_log_access_permit_actions">smtpd_log_access_permit_actions</a> (empty)</b>
|
||||
Enable logging of the named "permit" actions in
|
||||
SMTP server access lists.
|
||||
SMTP server access lists (by default, the SMTP
|
||||
server logs "reject" actions but not "permit"
|
||||
actions).
|
||||
|
||||
<b>KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS</b>
|
||||
As of Postfix version 2.0, the SMTP server rejects mail
|
||||
|
@ -569,7 +569,8 @@ What remote SMTP clients are allowed to use the XCLIENT feature.
|
||||
Available in Postfix version 2.10 and later:
|
||||
.IP "\fBsmtpd_log_access_permit_actions (empty)\fR"
|
||||
Enable logging of the named "permit" actions in SMTP server
|
||||
access lists.
|
||||
access lists (by default, the SMTP server logs "reject" actions but
|
||||
not "permit" actions).
|
||||
.SH "KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS"
|
||||
.na
|
||||
.nf
|
||||
|
@ -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 "20130325"
|
||||
#define MAIL_RELEASE_DATE "20130326"
|
||||
#define MAIL_VERSION_NUMBER "2.11"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -1110,7 +1110,7 @@ static void pre_init(char *unused_name, char **unused_argv)
|
||||
eckey_file = var_smtp_tls_eckey_file,
|
||||
CAfile = var_smtp_tls_CAfile,
|
||||
CApath = var_smtp_tls_CApath,
|
||||
fpt_dgst = var_smtp_tls_fpt_dgst);
|
||||
mdalg = var_smtp_tls_fpt_dgst);
|
||||
smtp_tls_list_init();
|
||||
#else
|
||||
msg_warn("TLS has been selected, but TLS support is not compiled in");
|
||||
|
@ -751,15 +751,6 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
DONT_CACHE_THIS_SESSION;
|
||||
|
||||
/*
|
||||
* As of Postfix 2.5, tls_client_start() tries hard to always complete
|
||||
* the TLS handshake. It records the verification and match status in the
|
||||
* resulting TLScontext. It is now up to the application to abort the TLS
|
||||
* connection if it chooses.
|
||||
*
|
||||
* XXX When tls_client_start() fails then we don't know what state the SMTP
|
||||
* connection is in, so we give up on this connection even if we are not
|
||||
* required to use TLS.
|
||||
*
|
||||
* The following assumes sites that use TLS in a perverse configuration:
|
||||
* multiple hosts per hostname, or even multiple hosts per IP address.
|
||||
* All this without a shared TLS session cache, and they still want to
|
||||
@ -779,15 +770,28 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
* ehlo response name to build a lookup key that works for split caches
|
||||
* (that announce distinct names) behind a load balancer.
|
||||
*
|
||||
* XXX: The TLS library may salt the serverid with further details of the
|
||||
* protocol and cipher requirements.
|
||||
* XXX: The TLS library will salt the serverid with further details of the
|
||||
* protocol and cipher requirements including the server ehlo response.
|
||||
* Deferring the helo to the digested suffix results in more predictable
|
||||
* SSL session lookup key lengths.
|
||||
*/
|
||||
serverid = vstring_alloc(10);
|
||||
vstring_sprintf(serverid, "%s:%s:%u",
|
||||
state->service, session->addr, ntohs(session->port));
|
||||
|
||||
/*
|
||||
* As of Postfix 2.5, tls_client_start() tries hard to always complete
|
||||
* the TLS handshake. It records the verification and match status in the
|
||||
* resulting TLScontext. It is now up to the application to abort the TLS
|
||||
* connection if it chooses.
|
||||
*
|
||||
* XXX When tls_client_start() fails then we don't know what state the SMTP
|
||||
* connection is in, so we give up on this connection even if we are not
|
||||
* required to use TLS.
|
||||
*
|
||||
* Large parameter lists are error-prone, so we emulate a language feature
|
||||
* that C does not have natively: named parameter lists.
|
||||
*/
|
||||
serverid = vstring_alloc(10);
|
||||
vstring_sprintf(serverid, "%s:%s:%u:%s", state->service, session->addr,
|
||||
ntohs(session->port), session->helo ? session->helo : "");
|
||||
session->tls_context =
|
||||
TLS_CLIENT_START(&tls_props,
|
||||
ctx = smtp_tls_ctx,
|
||||
@ -798,12 +802,13 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
host = session->host,
|
||||
namaddr = session->namaddrport,
|
||||
serverid = vstring_str(serverid),
|
||||
helo = session->helo,
|
||||
protocols = session->tls_protocols,
|
||||
cipher_grade = session->tls_grade,
|
||||
cipher_exclusions
|
||||
= vstring_str(session->tls_exclusions),
|
||||
matchargv = session->tls_matchargv,
|
||||
fpt_dgst = var_smtp_tls_fpt_dgst);
|
||||
mdalg = var_smtp_tls_fpt_dgst);
|
||||
vstring_free(serverid);
|
||||
|
||||
if (session->tls_context == 0) {
|
||||
@ -851,7 +856,7 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
|
||||
SMTP_RESP_FAKE(&fake, "4.7.5"),
|
||||
"Server certificate not trusted"));
|
||||
if (session->tls_level > TLS_LEV_ENCRYPT)
|
||||
if (session->tls_level >= TLS_LEV_DANE)
|
||||
if (!TLS_CERT_IS_MATCHED(session->tls_context))
|
||||
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
|
||||
SMTP_RESP_FAKE(&fake, "4.7.5"),
|
||||
|
@ -529,7 +529,8 @@
|
||||
/* Available in Postfix version 2.10 and later:
|
||||
/* .IP "\fBsmtpd_log_access_permit_actions (empty)\fR"
|
||||
/* Enable logging of the named "permit" actions in SMTP server
|
||||
/* access lists.
|
||||
/* access lists (by default, the SMTP server logs "reject" actions but
|
||||
/* not "permit" actions).
|
||||
/* KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS
|
||||
/* .ad
|
||||
/* .fi
|
||||
@ -4206,7 +4207,7 @@ static void smtpd_start_tls(SMTPD_STATE *state)
|
||||
namaddr = state->namaddr,
|
||||
cipher_grade = cipher_grade,
|
||||
cipher_exclusions = STR(cipher_exclusions),
|
||||
fpt_dgst = var_smtpd_tls_fpt_dgst);
|
||||
mdalg = var_smtpd_tls_fpt_dgst);
|
||||
|
||||
#endif /* USE_TLSPROXY */
|
||||
|
||||
@ -5148,7 +5149,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
|
||||
var_smtpd_tls_mand_proto :
|
||||
var_smtpd_tls_proto,
|
||||
ask_ccert = ask_client_cert,
|
||||
fpt_dgst = var_smtpd_tls_fpt_dgst);
|
||||
mdalg = var_smtpd_tls_fpt_dgst);
|
||||
else
|
||||
msg_warn("No server certs available. TLS won't be enabled");
|
||||
#endif /* USE_TLSPROXY */
|
||||
|
@ -1,11 +1,11 @@
|
||||
SHELL = /bin/sh
|
||||
SRCS = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c \
|
||||
SRCS = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c tls_fprint.c \
|
||||
tls_prng_exch.c tls_stream.c tls_bio_ops.c tls_misc.c tls_dh.c \
|
||||
tls_rsa.c tls_verify.c tls_certkey.c tls_session.c \
|
||||
tls_client.c tls_server.c tls_scache.c tls_mgr.c tls_seed.c \
|
||||
tls_level.c \
|
||||
tls_proxy_clnt.c tls_proxy_print.c tls_proxy_scan.c
|
||||
OBJS = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o \
|
||||
OBJS = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \
|
||||
tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \
|
||||
tls_rsa.o tls_verify.o tls_certkey.o tls_session.o \
|
||||
tls_client.o tls_server.o tls_scache.o tls_mgr.o tls_seed.o \
|
||||
@ -139,6 +139,19 @@ tls_dh.o: ../../include/vstream.h
|
||||
tls_dh.o: ../../include/vstring.h
|
||||
tls_dh.o: tls.h
|
||||
tls_dh.o: tls_dh.c
|
||||
tls_fprint.o: ../../include/argv.h
|
||||
tls_fprint.o: ../../include/mail_params.h
|
||||
tls_fprint.o: ../../include/msg.h
|
||||
tls_fprint.o: ../../include/mymalloc.h
|
||||
tls_fprint.o: ../../include/name_code.h
|
||||
tls_fprint.o: ../../include/name_mask.h
|
||||
tls_fprint.o: ../../include/stringops.h
|
||||
tls_fprint.o: ../../include/sys_defs.h
|
||||
tls_fprint.o: ../../include/vbuf.h
|
||||
tls_fprint.o: ../../include/vstream.h
|
||||
tls_fprint.o: ../../include/vstring.h
|
||||
tls_fprint.o: tls.h
|
||||
tls_fprint.o: tls_fprint.c
|
||||
tls_level.o: ../../include/argv.h
|
||||
tls_level.o: ../../include/name_code.h
|
||||
tls_level.o: ../../include/name_mask.h
|
||||
@ -320,7 +333,6 @@ tls_stream.o: ../../include/vstring.h
|
||||
tls_stream.o: tls.h
|
||||
tls_stream.o: tls_stream.c
|
||||
tls_verify.o: ../../include/argv.h
|
||||
tls_verify.o: ../../include/mail_params.h
|
||||
tls_verify.o: ../../include/msg.h
|
||||
tls_verify.o: ../../include/mymalloc.h
|
||||
tls_verify.o: ../../include/name_code.h
|
||||
|
@ -29,9 +29,10 @@
|
||||
#define TLS_LEV_NONE 0 /* plain-text only */
|
||||
#define TLS_LEV_MAY 1 /* wildcard */
|
||||
#define TLS_LEV_ENCRYPT 2 /* encrypted connection */
|
||||
#define TLS_LEV_FPRINT 3 /* "peer" CA-less verification */
|
||||
#define TLS_LEV_VERIFY 4 /* certificate verified */
|
||||
#define TLS_LEV_SECURE 5 /* "secure" verification */
|
||||
#define TLS_LEV_DANE 3 /* "peer" CA-less verification */
|
||||
#define TLS_LEV_FPRINT 4 /* "peer" CA-less verification */
|
||||
#define TLS_LEV_VERIFY 5 /* certificate verified */
|
||||
#define TLS_LEV_SECURE 6 /* "secure" verification */
|
||||
|
||||
extern const NAME_CODE tls_level_table[];
|
||||
|
||||
@ -97,8 +98,8 @@ typedef struct {
|
||||
int log_mask; /* What to log */
|
||||
int session_reused; /* this session was reused */
|
||||
int am_server; /* Are we an SSL server or client? */
|
||||
const char *mdalg; /* default message digest algorithm */
|
||||
/* Built-in vs external SSL_accept/read/write/shutdown support. */
|
||||
char *fpt_dgst; /* Certificate fingerprint digest */
|
||||
VSTREAM *stream; /* Blocking-mode SMTP session */
|
||||
} TLS_SESS_STATE;
|
||||
|
||||
@ -234,7 +235,7 @@ typedef struct {
|
||||
const char *eckey_file;
|
||||
const char *CAfile;
|
||||
const char *CApath;
|
||||
const char *fpt_dgst; /* Fingerprint digest algorithm */
|
||||
const char *mdalg; /* default message digest algorithm */
|
||||
} TLS_CLIENT_INIT_PROPS;
|
||||
|
||||
typedef struct {
|
||||
@ -246,11 +247,12 @@ typedef struct {
|
||||
const char *host; /* MX hostname */
|
||||
const char *namaddr; /* nam[addr] for logging */
|
||||
const char *serverid; /* Session cache key */
|
||||
const char *helo; /* Server name from EHLO response */
|
||||
const char *protocols; /* Enabled protocols */
|
||||
const char *cipher_grade; /* Minimum cipher grade */
|
||||
const char *cipher_exclusions; /* Ciphers to exclude */
|
||||
const ARGV *matchargv; /* Cert match patterns */
|
||||
const char *fpt_dgst; /* Fingerprint digest algorithm */
|
||||
const char *mdalg; /* default message digest algorithm */
|
||||
} TLS_CLIENT_START_PROPS;
|
||||
|
||||
extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *);
|
||||
@ -267,11 +269,11 @@ extern TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *);
|
||||
((props)->a12), ((props)->a13), (props)))
|
||||
|
||||
#define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
|
||||
a10, a11, a12, a13) \
|
||||
a10, a11, a12, a13, a14) \
|
||||
tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \
|
||||
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
|
||||
((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
|
||||
((props)->a12), ((props)->a13), (props)))
|
||||
((props)->a12), ((props)->a13), ((props)->a14), (props)))
|
||||
|
||||
/*
|
||||
* tls_server.c
|
||||
@ -296,7 +298,7 @@ typedef struct {
|
||||
const char *dh1024_param_file;
|
||||
const char *dh512_param_file;
|
||||
int ask_ccert;
|
||||
const char *fpt_dgst; /* Fingerprint digest algorithm */
|
||||
const char *mdalg; /* default message digest algorithm */
|
||||
} TLS_SERVER_INIT_PROPS;
|
||||
|
||||
typedef struct {
|
||||
@ -309,7 +311,7 @@ typedef struct {
|
||||
const char *namaddr; /* Client nam[addr] for logging */
|
||||
const char *cipher_grade;
|
||||
const char *cipher_exclusions;
|
||||
const char *fpt_dgst; /* Fingerprint digest algorithm */
|
||||
const char *mdalg; /* default message digest algorithm */
|
||||
} TLS_SERVER_START_PROPS;
|
||||
|
||||
extern TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *);
|
||||
@ -397,9 +399,15 @@ extern RSA *tls_tmp_rsa_cb(SSL *, int, int);
|
||||
extern char *tls_peer_CN(X509 *, const TLS_SESS_STATE *);
|
||||
extern char *tls_issuer_CN(X509 *, const TLS_SESS_STATE *);
|
||||
extern const char *tls_dns_name(const GENERAL_NAME *, const TLS_SESS_STATE *);
|
||||
extern int tls_verify_certificate_callback(int, X509_STORE_CTX *);
|
||||
|
||||
/*
|
||||
* tls_fprint.c
|
||||
*/
|
||||
extern char *tls_fingerprint(X509 *, const char *);
|
||||
extern char *tls_pkey_fprint(X509 *, const char *);
|
||||
extern int tls_verify_certificate_callback(int, X509_STORE_CTX *);
|
||||
extern char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *, long,
|
||||
const char *);
|
||||
|
||||
/*
|
||||
* tls_certkey.c
|
||||
@ -423,6 +431,7 @@ extern long tls_bug_bits(void);
|
||||
extern void tls_print_errors(void);
|
||||
extern void tls_info_callback(const SSL *, int, int);
|
||||
extern long tls_bio_dump_cb(BIO *, int, const char *, int, long, long);
|
||||
extern int tls_validate_digest(const char *);
|
||||
|
||||
/*
|
||||
* tls_seed.c
|
||||
|
@ -168,7 +168,7 @@ static SSL_SESSION *load_clnt_session(TLS_SESS_STATE *TLScontext)
|
||||
* Prepare the query.
|
||||
*/
|
||||
if (TLScontext->log_mask & TLS_LOG_CACHE)
|
||||
/* serverid already contains namaddrport information */
|
||||
/* serverid contains transport:addr:port information */
|
||||
msg_info("looking for session %s in %s cache",
|
||||
TLScontext->serverid, TLScontext->cache_type);
|
||||
|
||||
@ -190,7 +190,7 @@ static SSL_SESSION *load_clnt_session(TLS_SESS_STATE *TLScontext)
|
||||
session = tls_session_activate(STR(session_data), LEN(session_data));
|
||||
if (session) {
|
||||
if (TLScontext->log_mask & TLS_LOG_CACHE)
|
||||
/* serverid already contains namaddrport information */
|
||||
/* serverid contains transport:addr:port information */
|
||||
msg_info("reloaded session %s from %s cache",
|
||||
TLScontext->serverid, TLScontext->cache_type);
|
||||
}
|
||||
@ -230,7 +230,7 @@ static int new_client_session_cb(SSL *ssl, SSL_SESSION *session)
|
||||
myname);
|
||||
|
||||
if (TLScontext->log_mask & TLS_LOG_CACHE)
|
||||
/* serverid already contains namaddrport information */
|
||||
/* serverid contains transport:addr:port information */
|
||||
msg_info("save session %s to %s cache",
|
||||
TLScontext->serverid, TLScontext->cache_type);
|
||||
|
||||
@ -278,7 +278,7 @@ static void uncache_session(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext)
|
||||
return;
|
||||
|
||||
if (TLScontext->log_mask & TLS_LOG_CACHE)
|
||||
/* serverid already contains namaddrport information */
|
||||
/* serverid contains transport:addr:port information */
|
||||
msg_info("remove session %s from client cache", TLScontext->serverid);
|
||||
|
||||
tls_mgr_delete(TLScontext->cache_type, TLScontext->serverid);
|
||||
@ -292,8 +292,6 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
|
||||
int cachable;
|
||||
SSL_CTX *client_ctx;
|
||||
TLS_APPL_STATE *app_ctx;
|
||||
const EVP_MD *md_alg;
|
||||
unsigned int md_len;
|
||||
int log_mask;
|
||||
|
||||
/*
|
||||
@ -339,18 +337,8 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
|
||||
* If the administrator specifies an unsupported digest algorithm, fail
|
||||
* now, rather than in the middle of a TLS handshake.
|
||||
*/
|
||||
if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) {
|
||||
msg_warn("Digest algorithm \"%s\" not found: disabling TLS support",
|
||||
props->fpt_dgst);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check: Newer shared libraries may use larger digests.
|
||||
*/
|
||||
if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) {
|
||||
msg_warn("Digest algorithm \"%s\" output size %u too large:"
|
||||
" disabling TLS support", props->fpt_dgst, md_len);
|
||||
if (!tls_validate_digest(props->mdalg)) {
|
||||
msg_warn("disabling TLS support");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -732,8 +720,8 @@ static void verify_extract_print(TLS_SESS_STATE *TLScontext, X509 *peercert,
|
||||
char **cpp;
|
||||
|
||||
/* Non-null by contract */
|
||||
TLScontext->peer_fingerprint = tls_fingerprint(peercert, props->fpt_dgst);
|
||||
TLScontext->peer_pkey_fprint = tls_pkey_fprint(peercert, props->fpt_dgst);
|
||||
TLScontext->peer_fingerprint = tls_fingerprint(peercert, props->mdalg);
|
||||
TLScontext->peer_pkey_fprint = tls_pkey_fprint(peercert, props->mdalg);
|
||||
|
||||
/*
|
||||
* Compare the fingerprint against each acceptable value, ignoring
|
||||
@ -765,7 +753,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
X509 *peercert;
|
||||
TLS_SESS_STATE *TLScontext;
|
||||
TLS_APPL_STATE *app_ctx = props->ctx;
|
||||
VSTRING *myserverid;
|
||||
char *myserverid;
|
||||
int log_mask = app_ctx->log_mask;
|
||||
|
||||
/*
|
||||
@ -781,19 +769,8 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
/*
|
||||
* First make sure we have valid protocol and cipher parameters
|
||||
*
|
||||
* The cipherlist will be applied to the global SSL context, where it can be
|
||||
* repeatedly reset if necessary, but the protocol restrictions will be
|
||||
* is applied to the SSL connection, because protocol restrictions in the
|
||||
* global context cannot be cleared.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OpenSSL will ignore cached sessions that use the wrong protocol. So we
|
||||
* do not need to filter out cached sessions with the "wrong" protocol,
|
||||
* rather OpenSSL will simply negotiate a new session.
|
||||
*
|
||||
* Still, we salt the session lookup key with the protocol list, so that
|
||||
* sessions found in the cache are always acceptable.
|
||||
* Per-session protocol restrictions must be applied to the SSL connection,
|
||||
* as restrictions in the global context cannot be cleared.
|
||||
*/
|
||||
protomask = tls_protocol_mask(props->protocols);
|
||||
if (protomask == TLS_PROTOCOL_INVALID) {
|
||||
@ -802,35 +779,39 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
props->namaddr, props->protocols);
|
||||
return (0);
|
||||
}
|
||||
myserverid = vstring_alloc(100);
|
||||
vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask);
|
||||
|
||||
/*
|
||||
* Per session cipher selection for sessions with mandatory encryption
|
||||
*
|
||||
* The cipherlist is applied to the global SSL context, since it is likely
|
||||
* to stay the same between connections, so we make use of a 1-element
|
||||
* cache to return the same result for identical inputs.
|
||||
*/
|
||||
cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade,
|
||||
props->cipher_exclusions);
|
||||
if (cipher_list == 0) {
|
||||
msg_warn("%s: %s: aborting TLS session",
|
||||
props->namaddr, vstring_str(app_ctx->why));
|
||||
return (0);
|
||||
}
|
||||
if (log_mask & TLS_LOG_VERBOSE)
|
||||
msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list);
|
||||
|
||||
/*
|
||||
* OpenSSL will ignore cached sessions that use the wrong protocol. So we
|
||||
* do not need to filter out cached sessions with the "wrong" protocol,
|
||||
* rather OpenSSL will simply negotiate a new session.
|
||||
*
|
||||
* We salt the session lookup key with the protocol list, so that sessions
|
||||
* found in the cache are plausibly acceptable.
|
||||
*
|
||||
* By the time a TLS client is negotiating ciphers it has already offered to
|
||||
* re-use a session, it is too late to renege on the offer. So we must
|
||||
* not attempt to re-use sessions whose ciphers are too weak. We salt the
|
||||
* session lookup key with the cipher list, so that sessions found in the
|
||||
* cache are always acceptable.
|
||||
*/
|
||||
cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade,
|
||||
props->cipher_exclusions);
|
||||
if (cipher_list == 0) {
|
||||
msg_warn("%s: %s: aborting TLS session",
|
||||
props->namaddr, vstring_str(app_ctx->why));
|
||||
vstring_free(myserverid);
|
||||
return (0);
|
||||
}
|
||||
if (log_mask & TLS_LOG_VERBOSE)
|
||||
msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list);
|
||||
vstring_sprintf_append(myserverid, "&c=%s", cipher_list);
|
||||
|
||||
/*
|
||||
* Finally, salt the session key with the OpenSSL library version,
|
||||
* (run-time, rather than compile-time, just in case that matters).
|
||||
*/
|
||||
vstring_sprintf_append(myserverid, "&l=%ld", (long) SSLeay());
|
||||
myserverid = tls_serverid_digest(props, protomask, cipher_list);
|
||||
|
||||
/*
|
||||
* Allocate a new TLScontext for the new connection and get an SSL
|
||||
@ -843,8 +824,9 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
TLScontext = tls_alloc_sess_context(log_mask, props->namaddr);
|
||||
TLScontext->cache_type = app_ctx->cache_type;
|
||||
|
||||
TLScontext->serverid = vstring_export(myserverid);
|
||||
TLScontext->serverid = myserverid;
|
||||
TLScontext->stream = props->stream;
|
||||
TLScontext->mdalg = props->mdalg;
|
||||
|
||||
if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
|
||||
msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
|
||||
|
250
postfix/src/tls/tls_fprint.c
Normal file
250
postfix/src/tls/tls_fprint.c
Normal file
@ -0,0 +1,250 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* tls_fprint 3
|
||||
/* SUMMARY
|
||||
/* Digests fingerprints and all that.
|
||||
/* SYNOPSIS
|
||||
/* #include <tls.h>
|
||||
/*
|
||||
/* char *tls_serverid_digest(props, protomask, ciphers);
|
||||
/* const TLS_CLIENT_START_PROPS *props;
|
||||
/* long protomask;
|
||||
/* const char *ciphers;
|
||||
/*
|
||||
/* char *tls_fingerprint(peercert, mdalg)
|
||||
/* X509 *peercert;
|
||||
/* const char *mdalg;
|
||||
/*
|
||||
/* char *tls_pkey_fprint(peercert, mdalg)
|
||||
/* X509 *peercert;
|
||||
/* const char *mdalg;
|
||||
/* DESCRIPTION
|
||||
/* tls_fingerprint() returns a fingerprint of the the given
|
||||
/* certificate using the requested message digest. Panics if the
|
||||
/* (previously verified) digest algorithm is not found. The return
|
||||
/* value is dynamically allocated with mymalloc(), and the caller
|
||||
/* must eventually free it with myfree().
|
||||
/*
|
||||
/* tls_pkey_fprint() returns a public-key fingerprint; in all
|
||||
/* other respects the function behaves as tls_fingerprint().
|
||||
/* The var_tls_bc_pkey_fprint variable enables an incorrect
|
||||
/* algorithm that was used in Postfix versions 2.9.[0-5].
|
||||
/*
|
||||
/* tls_serverid_digest() suffixes props->serverid computed by the SMTP
|
||||
/* client with a digest of additional parameters needed to ensure
|
||||
/* that re-used sessions are more likely to be reused and will satisfy
|
||||
/* all protocol and security requirements. The caller should pass
|
||||
/* the result to myfree().
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP peercert
|
||||
/* Server or client X.509 certificate.
|
||||
/* .IP mdalg
|
||||
/* Name of a message digest algorithm suitable for computing secure
|
||||
/* (1st pre-image resistant) message digests of certificates. For now,
|
||||
/* md5, sha1, or member of SHA-2 family if supported by OpenSSL.
|
||||
/* .IP props
|
||||
/* The client start properties for the session, which include the
|
||||
/* initial serverid from the SMTP client.
|
||||
/* .IP protomask
|
||||
/* The mask of protocol exclusions.
|
||||
/* .IP ciphers
|
||||
/* The SSL client cipherlist.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* This software is free. You can do with it whatever you want.
|
||||
/* The original author kindly requests that you acknowledge
|
||||
/* the use of his software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Viktor Dukhovni
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef USE_TLS
|
||||
#include <string.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <mymalloc.h>
|
||||
#include <stringops.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_params.h>
|
||||
|
||||
/* TLS library. */
|
||||
|
||||
#define TLS_INTERNAL
|
||||
#include <tls.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
static const char hexcodes[] = "0123456789ABCDEF";
|
||||
|
||||
#define chknonzero(ret) (ok &= ((ret) ? 1 : 0))
|
||||
#define digestpl(p, l) chknonzero(EVP_DigestUpdate(mdctx, (char *)(p), (l)))
|
||||
#define digestptr(p) digestpl((p), sizeof(*(p)))
|
||||
#define digeststr(s) digestpl((s), strlen(s)+1)
|
||||
|
||||
/* tls_serverid_digest - suffix props->serverid with parameter digest */
|
||||
|
||||
char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
|
||||
const char *ciphers)
|
||||
{
|
||||
EVP_MD_CTX *mdctx;
|
||||
const EVP_MD *md;
|
||||
const char *mdalg;
|
||||
unsigned char md_buf[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_len;
|
||||
int ok = 1;
|
||||
int i;
|
||||
long sslversion;
|
||||
VSTRING *result;
|
||||
|
||||
/*
|
||||
* Try to use sha256: our serverid choice should be strong enough to
|
||||
* resist 2nd-preimage attacks with a difficulty comparable to that of
|
||||
* DANE TLSA digests. Failing that, we compute serverid digests with the
|
||||
* default digest, but DANE requires sha256 and sha512, so if we must
|
||||
* fall back to our default digest, DANE support won't be available. We
|
||||
* panic if the fallback algorithm is not available, as it was verified
|
||||
* available in tls_client_init() and must not simply vanish.
|
||||
*/
|
||||
if ((md = EVP_get_digestbyname(mdalg = "sha256")) == 0
|
||||
&& (md = EVP_get_digestbyname(mdalg = props->mdalg)) == 0)
|
||||
msg_panic("digest algorithm \"%s\" not found", mdalg);
|
||||
|
||||
/* Salt the session lookup key with the OpenSSL runtime version. */
|
||||
sslversion = SSLeay();
|
||||
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
chknonzero(EVP_DigestInit_ex(mdctx, md, NULL));
|
||||
digeststr(props->helo ? props->helo : "");
|
||||
digestptr(&sslversion);
|
||||
digestptr(&protomask);
|
||||
digeststr(ciphers);
|
||||
chknonzero(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
if (!ok)
|
||||
msg_fatal("error computing %s message digest", mdalg);
|
||||
|
||||
/* Check for OpenSSL contract violation */
|
||||
if (md_len > EVP_MAX_MD_SIZE)
|
||||
msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len);
|
||||
|
||||
/* Append the digest to the serverid */
|
||||
result = vstring_alloc(strlen(props->serverid) + 1 + 2 * md_len);
|
||||
vstring_strcpy(result, props->serverid);
|
||||
VSTRING_ADDCH(result, ':');
|
||||
for (i = 0; i < md_len; i++) {
|
||||
VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0xf0) >> 4U]);
|
||||
VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0x0f)]);
|
||||
}
|
||||
VSTRING_TERMINATE(result);
|
||||
return (vstring_export(result));
|
||||
}
|
||||
|
||||
/* tls_fprint - compute and encode digest of DER-encoded object */
|
||||
|
||||
static char *tls_fprint(const char *buf, int len, const char *mdalg)
|
||||
{
|
||||
EVP_MD_CTX *mdctx;
|
||||
const EVP_MD *md;
|
||||
unsigned char md_buf[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_len;
|
||||
int i;
|
||||
int ok = 1;
|
||||
char *result = 0;
|
||||
|
||||
/* Previously available in "init" routine. */
|
||||
if ((md = EVP_get_digestbyname(mdalg)) == 0)
|
||||
msg_panic("digest algorithm \"%s\" not found", mdalg);
|
||||
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
chknonzero(EVP_DigestInit_ex(mdctx, md, NULL));
|
||||
digestpl(buf, len);
|
||||
chknonzero(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
if (!ok)
|
||||
msg_fatal("error computing %s message digest", mdalg);
|
||||
|
||||
/* Check for OpenSSL contract violation */
|
||||
if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
|
||||
msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len);
|
||||
|
||||
result = mymalloc(md_len * 3);
|
||||
for (i = 0; i < md_len; i++) {
|
||||
result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
|
||||
result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
|
||||
result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* tls_fingerprint - extract certificate fingerprint */
|
||||
|
||||
char *tls_fingerprint(X509 *peercert, const char *mdalg)
|
||||
{
|
||||
int len;
|
||||
char *buf;
|
||||
char *buf2;
|
||||
char *result;
|
||||
|
||||
len = i2d_X509(peercert, NULL);
|
||||
buf2 = buf = mymalloc(len);
|
||||
i2d_X509(peercert, (unsigned char **) &buf2);
|
||||
if (buf2 - buf != len)
|
||||
msg_panic("i2d_X509 invalid result length");
|
||||
|
||||
result = tls_fprint(buf, len, mdalg);
|
||||
myfree(buf);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* tls_pkey_fprint - extract public key fingerprint from certificate */
|
||||
|
||||
char *tls_pkey_fprint(X509 *peercert, const char *mdalg)
|
||||
{
|
||||
if (var_tls_bc_pkey_fprint) {
|
||||
const char *myname = "tls_pkey_fprint";
|
||||
ASN1_BIT_STRING *key;
|
||||
char *result;
|
||||
|
||||
key = X509_get0_pubkey_bitstr(peercert);
|
||||
if (key == 0)
|
||||
msg_fatal("%s: error extracting legacy public-key fingerprint: %m",
|
||||
myname);
|
||||
|
||||
result = tls_fprint((char *) key->data, key->length, mdalg);
|
||||
return (result);
|
||||
} else {
|
||||
int len;
|
||||
char *buf;
|
||||
char *buf2;
|
||||
char *result;
|
||||
|
||||
len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), NULL);
|
||||
buf2 = buf = mymalloc(len);
|
||||
i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **) &buf2);
|
||||
if (buf2 - buf != len)
|
||||
msg_panic("i2d_X509_PUBKEY invalid result length");
|
||||
|
||||
result = tls_fprint(buf, len, mdalg);
|
||||
myfree(buf);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -66,6 +66,9 @@ const NAME_CODE tls_level_table[] = {
|
||||
"none", TLS_LEV_NONE,
|
||||
"may", TLS_LEV_MAY,
|
||||
"encrypt", TLS_LEV_ENCRYPT,
|
||||
#if 0 /* Not yet */
|
||||
"dane", TLS_LEV_DANE,
|
||||
#endif
|
||||
"fingerprint", TLS_LEV_FPRINT,
|
||||
"verify", TLS_LEV_VERIFY,
|
||||
"secure", TLS_LEV_SECURE,
|
||||
|
@ -72,6 +72,9 @@
|
||||
/* int tls_log_mask(log_param, log_level)
|
||||
/* const char *log_param;
|
||||
/* const char *log_level;
|
||||
/*
|
||||
/* int tls_validate_digest(dgst)
|
||||
/* const char *dgst;
|
||||
/* DESCRIPTION
|
||||
/* This module implements routines that support the TLS client
|
||||
/* and server internals.
|
||||
@ -136,6 +139,9 @@
|
||||
/* tls_log_mask() converts a TLS log_level value from string
|
||||
/* to mask. The main.cf parameter name is passed along for
|
||||
/* diagnostics.
|
||||
/*
|
||||
/* tls_validate_digest() returns non-zero if the named digest
|
||||
/* is usable and zero otherwise.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
@ -740,7 +746,7 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
|
||||
TLScontext->cipher_name = 0;
|
||||
TLScontext->log_mask = log_mask;
|
||||
TLScontext->namaddr = lowercase(mystrdup(namaddr));
|
||||
TLScontext->fpt_dgst = 0;
|
||||
TLScontext->mdalg = 0; /* Alias for props->mdalg */
|
||||
|
||||
return (TLScontext);
|
||||
}
|
||||
@ -771,8 +777,6 @@ void tls_free_context(TLS_SESS_STATE *TLScontext)
|
||||
myfree(TLScontext->peer_fingerprint);
|
||||
if (TLScontext->peer_pkey_fprint)
|
||||
myfree(TLScontext->peer_pkey_fprint);
|
||||
if (TLScontext->fpt_dgst)
|
||||
myfree(TLScontext->fpt_dgst);
|
||||
|
||||
myfree((char *) TLScontext);
|
||||
}
|
||||
@ -1054,6 +1058,31 @@ long tls_bio_dump_cb(BIO *bio, int cmd, const char *argp, int argi,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int tls_validate_digest(const char *dgst)
|
||||
{
|
||||
const EVP_MD *md_alg;
|
||||
unsigned int md_len;
|
||||
|
||||
/*
|
||||
* If the administrator specifies an unsupported digest algorithm, fail
|
||||
* now, rather than in the middle of a TLS handshake.
|
||||
*/
|
||||
if ((md_alg = EVP_get_digestbyname(dgst)) == 0) {
|
||||
msg_warn("Digest algorithm \"%s\" not found", dgst);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check: Newer shared libraries may use larger digests.
|
||||
*/
|
||||
if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) {
|
||||
msg_warn("Digest algorithm \"%s\" output size %u too large",
|
||||
dgst, md_len);
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
|
@ -286,8 +286,6 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
|
||||
int cachable;
|
||||
int protomask;
|
||||
TLS_APPL_STATE *app_ctx;
|
||||
const EVP_MD *md_alg;
|
||||
unsigned int md_len;
|
||||
int log_mask;
|
||||
|
||||
/*
|
||||
@ -344,18 +342,8 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
|
||||
* If the administrator specifies an unsupported digest algorithm, fail
|
||||
* now, rather than in the middle of a TLS handshake.
|
||||
*/
|
||||
if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) {
|
||||
msg_warn("Digest algorithm \"%s\" not found: disabling TLS support",
|
||||
props->fpt_dgst);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check: Newer shared libraries may use larger digests.
|
||||
*/
|
||||
if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) {
|
||||
msg_warn("Digest algorithm \"%s\" output size %u too large:"
|
||||
" disabling TLS support", props->fpt_dgst, md_len);
|
||||
if (!tls_validate_digest(props->mdalg)) {
|
||||
msg_warn("disabling TLS support");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -643,9 +631,8 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
|
||||
|
||||
TLScontext->serverid = mystrdup(props->serverid);
|
||||
TLScontext->am_server = 1;
|
||||
|
||||
TLScontext->fpt_dgst = mystrdup(props->fpt_dgst);
|
||||
TLScontext->stream = props->stream;
|
||||
TLScontext->mdalg = props->mdalg;
|
||||
|
||||
ERR_clear_error();
|
||||
if ((TLScontext->con = (SSL *) SSL_new(app_ctx->ssl_ctx)) == 0) {
|
||||
@ -777,10 +764,8 @@ TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext)
|
||||
}
|
||||
TLScontext->peer_CN = tls_peer_CN(peer, TLScontext);
|
||||
TLScontext->issuer_CN = tls_issuer_CN(peer, TLScontext);
|
||||
TLScontext->peer_fingerprint =
|
||||
tls_fingerprint(peer, TLScontext->fpt_dgst);
|
||||
TLScontext->peer_pkey_fprint =
|
||||
tls_pkey_fprint(peer, TLScontext->fpt_dgst);
|
||||
TLScontext->peer_fingerprint = tls_fingerprint(peer, TLScontext->mdalg);
|
||||
TLScontext->peer_pkey_fprint = tls_pkey_fprint(peer, TLScontext->mdalg);
|
||||
|
||||
if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) {
|
||||
msg_info("%s: subject_CN=%s, issuer=%s, fingerprint=%s"
|
||||
@ -795,6 +780,7 @@ TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext)
|
||||
TLScontext->peer_CN = mystrdup("");
|
||||
TLScontext->issuer_CN = mystrdup("");
|
||||
TLScontext->peer_fingerprint = mystrdup("");
|
||||
TLScontext->peer_pkey_fprint = mystrdup("");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -19,13 +19,6 @@
|
||||
/* const GENERAL_NAME *gn;
|
||||
/* TLS_SESS_STATE *TLScontext;
|
||||
/*
|
||||
/* char *tls_fingerprint(peercert, dgst)
|
||||
/* X509 *peercert;
|
||||
/* const char *dgst;
|
||||
/*
|
||||
/* char *tls_pkey_fprint(peercert, dgst)
|
||||
/* X509 *peercert;
|
||||
/* const char *dgst;
|
||||
/*
|
||||
/* int tls_verify_certificate_callback(ok, ctx)
|
||||
/* int ok;
|
||||
@ -48,17 +41,6 @@
|
||||
/* are found, a null string is returned instead. Further sanity
|
||||
/* checks may be added if the need arises.
|
||||
/*
|
||||
/* tls_fingerprint() returns a fingerprint of the the given
|
||||
/* certificate using the requested message digest. Panics if the
|
||||
/* (previously verified) digest algorithm is not found. The return
|
||||
/* value is dynamically allocated with mymalloc(), and the caller
|
||||
/* must eventually free it with myfree().
|
||||
/*
|
||||
/* tls_pkey_fprint() returns a public-key fingerprint; in all
|
||||
/* other respects the function behaves as tls_fingerprint().
|
||||
/* The var_tls_bc_pkey_fprint variable enables an incorrect
|
||||
/* algorithm that was used in Postfix versions 2.9.[0-5].
|
||||
/*
|
||||
/* tls_verify_callback() is called several times (directly or
|
||||
/* indirectly) from crypto/x509/x509_vfy.c. It is called as
|
||||
/* a final check, and if it returns "0", the handshake is
|
||||
@ -99,10 +81,6 @@
|
||||
/* to be decoded and checked for validity.
|
||||
/* .IP peercert
|
||||
/* Server or client X.509 certificate.
|
||||
/* .IP dgst
|
||||
/* Name of a message digest algorithm suitable for computing secure
|
||||
/* (1st pre-image resistant) message digests of certificates. For now,
|
||||
/* md5, sha1, or member of SHA-2 family if supported by OpenSSL.
|
||||
/* .IP TLScontext
|
||||
/* Server or client context for warning messages.
|
||||
/* DIAGNOSTICS
|
||||
@ -149,19 +127,11 @@
|
||||
#include <mymalloc.h>
|
||||
#include <stringops.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_params.h>
|
||||
|
||||
/* TLS library. */
|
||||
|
||||
#define TLS_INTERNAL
|
||||
#include <tls.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
static const char hexcodes[] = "0123456789ABCDEF";
|
||||
|
||||
/* tls_verify_certificate_callback - verify peer certificate info */
|
||||
|
||||
int tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
|
||||
@ -503,96 +473,4 @@ char *tls_issuer_CN(X509 *peer, const TLS_SESS_STATE *TLScontext)
|
||||
return (cn ? cn : mystrdup(""));
|
||||
}
|
||||
|
||||
/* tls_fprint - compute and encode digest of DER-encoded object */
|
||||
|
||||
static char *tls_fprint(const char *buf, int len, const char *dgst)
|
||||
{
|
||||
const char *myname = "tls_fprint";
|
||||
EVP_MD_CTX *mdctx;
|
||||
const EVP_MD *md_alg;
|
||||
unsigned char md_buf[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_len;
|
||||
int i;
|
||||
char *result = 0;
|
||||
|
||||
/* Previously available in "init" routine. */
|
||||
if ((md_alg = EVP_get_digestbyname(dgst)) == 0)
|
||||
msg_panic("%s: digest algorithm \"%s\" not found", myname, dgst);
|
||||
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
if (EVP_DigestInit_ex(mdctx, md_alg, NULL) == 0
|
||||
|| EVP_DigestUpdate(mdctx, buf, len) == 0
|
||||
|| EVP_DigestFinal_ex(mdctx, md_buf, &md_len) == 0)
|
||||
msg_fatal("%s: error computing %s message digest", myname, dgst);
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
|
||||
/* Check for OpenSSL contract violation */
|
||||
if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
|
||||
msg_panic("%s: unexpectedly large %s digest size: %u",
|
||||
myname, dgst, md_len);
|
||||
|
||||
result = mymalloc(md_len * 3);
|
||||
for (i = 0; i < md_len; i++) {
|
||||
result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
|
||||
result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
|
||||
result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* tls_fingerprint - extract certificate fingerprint */
|
||||
|
||||
char *tls_fingerprint(X509 *peercert, const char *dgst)
|
||||
{
|
||||
int len;
|
||||
char *buf;
|
||||
char *buf2;
|
||||
char *result;
|
||||
|
||||
len = i2d_X509(peercert, NULL);
|
||||
buf2 = buf = mymalloc(len);
|
||||
i2d_X509(peercert, (unsigned char **) &buf2);
|
||||
if (buf2 - buf != len)
|
||||
msg_panic("i2d_X509 invalid result length");
|
||||
|
||||
result = tls_fprint(buf, len, dgst);
|
||||
myfree(buf);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* tls_pkey_fprint - extract public key fingerprint from certificate */
|
||||
|
||||
char *tls_pkey_fprint(X509 *peercert, const char *dgst)
|
||||
{
|
||||
if (var_tls_bc_pkey_fprint) {
|
||||
const char *myname = "tls_pkey_fprint";
|
||||
ASN1_BIT_STRING *key;
|
||||
char *result;
|
||||
|
||||
key = X509_get0_pubkey_bitstr(peercert);
|
||||
if (key == 0)
|
||||
msg_fatal("%s: error extracting legacy public-key fingerprint: %m",
|
||||
myname);
|
||||
|
||||
result = tls_fprint((char *) key->data, key->length, dgst);
|
||||
return (result);
|
||||
} else {
|
||||
int len;
|
||||
char *buf;
|
||||
char *buf2;
|
||||
char *result;
|
||||
|
||||
len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), NULL);
|
||||
buf2 = buf = mymalloc(len);
|
||||
i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **) &buf2);
|
||||
if (buf2 - buf != len)
|
||||
msg_panic("i2d_X509_PUBKEY invalid result length");
|
||||
|
||||
result = tls_fprint(buf, len, dgst);
|
||||
myfree(buf);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -698,7 +698,7 @@ static void tlsp_start_tls(TLSP_STATE *state)
|
||||
namaddr = state->remote_endpt,
|
||||
cipher_grade = cipher_grade,
|
||||
cipher_exclusions = STR(cipher_exclusions),
|
||||
fpt_dgst = var_tlsp_tls_fpt_dgst);
|
||||
mdalg = var_tlsp_tls_fpt_dgst);
|
||||
|
||||
if (state->tls_context == 0) {
|
||||
tlsp_state_free(state);
|
||||
@ -993,7 +993,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
|
||||
var_tlsp_tls_mand_proto :
|
||||
var_tlsp_tls_proto,
|
||||
ask_ccert = ask_client_cert,
|
||||
fpt_dgst = var_tlsp_tls_fpt_dgst);
|
||||
mdalg = var_tlsp_tls_fpt_dgst);
|
||||
else
|
||||
msg_warn("No server certs available. TLS can't be enabled");
|
||||
|
||||
|
@ -18,7 +18,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
|
||||
mymalloc.c myrand.c mystrtok.c name_code.c name_mask.c netstring.c \
|
||||
neuter.c non_blocking.c nvtable.c open_as.c open_limit.c open_lock.c \
|
||||
peekfd.c percentm.c posix_signals.c printable.c rand_sleep.c \
|
||||
read_wait.c readable.c readlline.c ring.c safe_getenv.c safe_open.c \
|
||||
readlline.c ring.c safe_getenv.c safe_open.c \
|
||||
sane_accept.c sane_connect.c sane_link.c sane_rename.c \
|
||||
sane_socketpair.c sane_time.c scan_dir.c set_eugid.c set_ugid.c \
|
||||
sigdelay.c skipblanks.c sock_addr.c spawn_command.c split_at.c \
|
||||
@ -28,14 +28,15 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
|
||||
translit.c trimblanks.c unescape.c unix_connect.c unix_listen.c \
|
||||
unix_recv_fd.c unix_send_fd.c unix_trigger.c unsafe.c uppercase.c \
|
||||
username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \
|
||||
vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
|
||||
write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \
|
||||
vstream_popen.c vstring.c vstring_vstream.c watchdog.c \
|
||||
write_buf.c sane_basename.c format_tv.c allspace.c \
|
||||
allascii.c load_file.c killme_after.c vstream_tweak.c \
|
||||
pass_trigger.c edit_file.c inet_windowsize.c \
|
||||
unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
|
||||
ip_match.c nbbio.c base32_code.c dict_test.c \
|
||||
dict_fail.c msg_rate_delay.c dict_surrogate.c warn_stat.c \
|
||||
dict_sockmap.c line_number.c recv_pass_attr.c pass_accept.c
|
||||
dict_sockmap.c line_number.c recv_pass_attr.c pass_accept.c \
|
||||
poll_fd.c
|
||||
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
|
||||
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
|
||||
@ -55,7 +56,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
mymalloc.o myrand.o mystrtok.o name_code.o name_mask.o netstring.o \
|
||||
neuter.o non_blocking.o nvtable.o open_as.o open_limit.o open_lock.o \
|
||||
peekfd.o percentm.o posix_signals.o printable.o rand_sleep.o \
|
||||
read_wait.o readable.o readlline.o ring.o safe_getenv.o safe_open.o \
|
||||
readlline.o ring.o safe_getenv.o safe_open.o \
|
||||
sane_accept.o sane_connect.o sane_link.o sane_rename.o \
|
||||
sane_socketpair.o sane_time.o scan_dir.o set_eugid.o set_ugid.o \
|
||||
sigdelay.o skipblanks.o sock_addr.o spawn_command.o split_at.o \
|
||||
@ -65,14 +66,15 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
translit.o trimblanks.o unescape.o unix_connect.o unix_listen.o \
|
||||
unix_recv_fd.o unix_send_fd.o unix_trigger.o unsafe.o uppercase.o \
|
||||
username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \
|
||||
vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
|
||||
write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \
|
||||
vstream_popen.o vstring.o vstring_vstream.o watchdog.o \
|
||||
write_buf.o sane_basename.o format_tv.o allspace.o \
|
||||
allascii.o load_file.o killme_after.o vstream_tweak.o \
|
||||
pass_trigger.o edit_file.o inet_windowsize.o \
|
||||
unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
|
||||
ip_match.o nbbio.o base32_code.o dict_test.o \
|
||||
dict_fail.o msg_rate_delay.o dict_surrogate.o warn_stat.o \
|
||||
dict_sockmap.o line_number.o recv_pass_attr.o pass_accept.o
|
||||
dict_sockmap.o line_number.o recv_pass_attr.o pass_accept.o \
|
||||
poll_fd.o
|
||||
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
|
||||
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
|
||||
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
|
||||
@ -1644,6 +1646,10 @@ percentm.o: percentm.h
|
||||
percentm.o: sys_defs.h
|
||||
percentm.o: vbuf.h
|
||||
percentm.o: vstring.h
|
||||
poll_fd.o: iostuff.h
|
||||
poll_fd.o: msg.h
|
||||
poll_fd.o: poll_fd.c
|
||||
poll_fd.o: sys_defs.h
|
||||
posix_signals.o: posix_signals.c
|
||||
posix_signals.o: posix_signals.h
|
||||
posix_signals.o: sys_defs.h
|
||||
@ -1657,14 +1663,6 @@ rand_sleep.o: msg.h
|
||||
rand_sleep.o: myrand.h
|
||||
rand_sleep.o: rand_sleep.c
|
||||
rand_sleep.o: sys_defs.h
|
||||
read_wait.o: iostuff.h
|
||||
read_wait.o: msg.h
|
||||
read_wait.o: read_wait.c
|
||||
read_wait.o: sys_defs.h
|
||||
readable.o: iostuff.h
|
||||
readable.o: msg.h
|
||||
readable.o: readable.c
|
||||
readable.o: sys_defs.h
|
||||
readlline.o: msg.h
|
||||
readlline.o: readlline.c
|
||||
readlline.o: readlline.h
|
||||
@ -1981,15 +1979,7 @@ watchdog.o: posix_signals.h
|
||||
watchdog.o: sys_defs.h
|
||||
watchdog.o: watchdog.c
|
||||
watchdog.o: watchdog.h
|
||||
writable.o: iostuff.h
|
||||
writable.o: msg.h
|
||||
writable.o: sys_defs.h
|
||||
writable.o: writable.c
|
||||
write_buf.o: iostuff.h
|
||||
write_buf.o: msg.h
|
||||
write_buf.o: sys_defs.h
|
||||
write_buf.o: write_buf.c
|
||||
write_wait.o: iostuff.h
|
||||
write_wait.o: msg.h
|
||||
write_wait.o: sys_defs.h
|
||||
write_wait.o: write_wait.c
|
||||
|
@ -16,13 +16,10 @@
|
||||
extern int non_blocking(int, int);
|
||||
extern int close_on_exec(int, int);
|
||||
extern int open_limit(int);
|
||||
extern int readable(int);
|
||||
extern int writable(int);
|
||||
extern int poll_fd(int, int, int, int);
|
||||
extern off_t get_file_limit(void);
|
||||
extern void set_file_limit(off_t);
|
||||
extern ssize_t peekfd(int);
|
||||
extern int read_wait(int, int);
|
||||
extern int write_wait(int, int);
|
||||
extern ssize_t write_buf(int, const char *, ssize_t, int);
|
||||
extern ssize_t timed_read(int, void *, size_t, int, void *);
|
||||
extern ssize_t timed_write(int, void *, size_t, int, void *);
|
||||
@ -36,9 +33,18 @@ extern int unix_send_fd(int, int);
|
||||
extern ssize_t dummy_read(int, void *, size_t, int, void *);
|
||||
extern ssize_t dummy_write(int, void *, size_t, int, void *);
|
||||
|
||||
#define readable(fd) poll_fd((fd), POLL_FD_READ, 0, 1)
|
||||
#define writable(fd) poll_fd((fd), POLL_FD_WRITE, 0, 1)
|
||||
|
||||
#define read_wait(fd, time_limit) poll_fd((fd), POLL_FD_READ, (time_limit), 0)
|
||||
#define write_wait(fd, time_limit) poll_fd((fd), POLL_FD_WRITE, (time_limit), 0)
|
||||
|
||||
extern int inet_windowsize;
|
||||
extern void set_inet_windowsize(int, int);
|
||||
|
||||
#define POLL_FD_READ 0
|
||||
#define POLL_FD_WRITE 1
|
||||
|
||||
#define BLOCKING 0
|
||||
#define NON_BLOCKING 1
|
||||
|
||||
|
268
postfix/src/util/poll_fd.c
Normal file
268
postfix/src/util/poll_fd.c
Normal file
@ -0,0 +1,268 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* poll_fd 3
|
||||
/* SUMMARY
|
||||
/* wait until file descriptor becomes readable or writable
|
||||
/* SYNOPSIS
|
||||
/* #include <iostuff.h>
|
||||
/*
|
||||
/* int readable(fd)
|
||||
/* int fd;
|
||||
/*
|
||||
/* int writable(fd)
|
||||
/* int fd;
|
||||
/*
|
||||
/* int read_wait(fd, timeout)
|
||||
/* int fd;
|
||||
/* int timeout
|
||||
/*
|
||||
/* int write_wait(fd, timeout)
|
||||
/* int fd;
|
||||
/* int timeout
|
||||
/*
|
||||
/* int poll_fd(fd, request, time_limit, success_val)
|
||||
/* int fd;
|
||||
/* int request;
|
||||
/* int time_limit;
|
||||
/* int success_val;
|
||||
/* DESCRIPTION
|
||||
/* The functions in this module are macros that provide a
|
||||
/* convenient interface to poll_fd().
|
||||
/*
|
||||
/* readable() asks the kernel if the specified file descriptor
|
||||
/* is readable, i.e. a read operation would not block.
|
||||
/*
|
||||
/* writable() asks the kernel if the specified file descriptor
|
||||
/* is writable, i.e. a write operation would not block.
|
||||
/*
|
||||
/* read_wait() waits until the specified file descriptor becomes
|
||||
/* readable, or until the time limit is reached.
|
||||
/*
|
||||
/* write_wait() waits until the specified file descriptor
|
||||
/* becomes writable, or until the time limit is reached.
|
||||
/*
|
||||
/* poll_fd() waits until the specified file descriptor becomes
|
||||
/* readable or writable, or until the time limit is reached.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP fd
|
||||
/* File descriptor. With implementations based on select(), a
|
||||
/* best effort is made to handle descriptors >=FD_SETSIZE.
|
||||
/* .IP request
|
||||
/* POLL_FD_READ (wait until readable) or POLL_FD_WRITE (wait
|
||||
/* until writable).
|
||||
/* .IP time_limit
|
||||
/* A positive value specifies a time limit in seconds. A zero
|
||||
/* value effects a poll (return immediately). A negative value
|
||||
/* means wait until the requested POLL_FD_READ or POLL_FD_WRITE
|
||||
/* condition becomes true.
|
||||
/* .IP success_val
|
||||
/* Result value when the requested POLL_FD_READ or POLL_FD_WRITE
|
||||
/* condition is true.
|
||||
/* DIAGNOSTICS
|
||||
/* Panic: interface violation. All system call errors are fatal
|
||||
/* unless specified otherwise.
|
||||
/*
|
||||
/* readable() and writable() return 1 when the requested
|
||||
/* condition is true, zero when it is false. They never return
|
||||
/* an error indication.
|
||||
/*
|
||||
/* read_wait() and write_wait() return zero when successful,
|
||||
/* -1 with errno set to ETIMEDOUT when the time limit was
|
||||
/* reached.
|
||||
/*
|
||||
/* poll_fd() returns -1 with errno set to ETIMEDOUT when the
|
||||
/* time limit was reached, success_val if the requested
|
||||
/* POLL_FD_READ or POLL_FD_WRITE condition is true, and returns
|
||||
/* zero otherwise.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_SYSV_POLL
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <iostuff.h>
|
||||
|
||||
/*
|
||||
* Use select() only.
|
||||
*/
|
||||
#ifdef USE_BSD_SELECT
|
||||
#define poll_fd_bsd poll_fd
|
||||
#undef USE_SYSV_POLL
|
||||
#undef USE_SYSV_POLL_WITH_SELECT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use poll() only.
|
||||
*/
|
||||
#ifdef USE_SYSV_POLL
|
||||
#define poll_fd_sysv poll_fd
|
||||
#undef USE_SYSV_POLL_WITH_SELECT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use poll() with fall-back to select(). MacOSX needs this for devices.
|
||||
*/
|
||||
#ifdef USE_SYSV_POLL_WITH_SELECT
|
||||
#define poll_fd_sysv poll_fd
|
||||
#define USE_SYSV_POLL
|
||||
#define USE_BSD_SELECT
|
||||
int poll_fd_bsd(int, int, int, int);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
#if !defined(USE_BSD_SELECT) && !defined(USE_SYSV_POLL)
|
||||
#error "specify USE_BSD_SELECT, USE_SYSV_POLL or USE_SYSV_POLL_WITH_SELECT"
|
||||
#endif
|
||||
|
||||
#ifdef USE_BSD_SELECT
|
||||
|
||||
/* poll_fd_bsd - block with time_limit until file descriptor is ready */
|
||||
|
||||
int poll_fd_bsd(int fd, int request, int time_limit, int success_val)
|
||||
{
|
||||
fd_set req_fds;
|
||||
fd_set *read_fds;
|
||||
fd_set *write_fds;
|
||||
fd_set except_fds;
|
||||
struct timeval tv;
|
||||
struct timeval *tp;
|
||||
int temp_fd = -1;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (FD_SETSIZE <= fd) {
|
||||
if ((temp_fd = dup(fd)) < 0 || temp_fd >= FD_SETSIZE)
|
||||
msg_fatal("descriptor %d does not fit FD_SETSIZE %d", fd, FD_SETSIZE);
|
||||
fd = temp_fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use select() so we do not depend on alarm() and on signal() handlers.
|
||||
* Restart the select when interrupted by some signal. Some select()
|
||||
* implementations reduce the time to wait when interrupted, which is
|
||||
* exactly what we want.
|
||||
*/
|
||||
FD_ZERO(&req_fds);
|
||||
FD_SET(fd, &req_fds);
|
||||
except_fds = req_fds;
|
||||
if (request == POLL_FD_READ) {
|
||||
read_fds = &req_fds;
|
||||
write_fds = 0;
|
||||
} else if (request == POLL_FD_WRITE) {
|
||||
read_fds = 0;
|
||||
write_fds = &req_fds;
|
||||
} else {
|
||||
msg_panic("poll_fd: bad request %d", request);
|
||||
}
|
||||
|
||||
if (time_limit >= 0) {
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = time_limit;
|
||||
tp = &tv;
|
||||
} else {
|
||||
tp = 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
switch (select(fd + 1, read_fds, write_fds, &except_fds, tp)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("select: %m");
|
||||
continue;
|
||||
case 0:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
if (time_limit == 0) {
|
||||
return (0);
|
||||
} else {
|
||||
errno = ETIMEDOUT;
|
||||
return (-1);
|
||||
}
|
||||
default:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
return (success_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYSV_POLL
|
||||
|
||||
/* poll_fd_sysv - block with time_limit until file descriptor is ready */
|
||||
|
||||
int poll_fd_sysv(int fd, int request, int time_limit, int success_val)
|
||||
{
|
||||
struct pollfd pollfd;
|
||||
|
||||
/*
|
||||
* System-V poll() is optimal for polling a few descriptors.
|
||||
*/
|
||||
#define WAIT_FOR_EVENT (-1)
|
||||
|
||||
pollfd.fd = fd;
|
||||
if (request == POLL_FD_READ)
|
||||
pollfd.events = POLLIN;
|
||||
else if (request == POLL_FD_WRITE)
|
||||
pollfd.events = POLLOUT;
|
||||
else
|
||||
msg_panic("poll_fd: bad request %d", request);
|
||||
|
||||
for (;;) {
|
||||
switch (poll(&pollfd, 1, time_limit < 0 ?
|
||||
WAIT_FOR_EVENT : time_limit * 1000)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
#ifdef USE_SYSV_POLL_WITH_SELECT
|
||||
return (poll_fd_bsd(fd, request, time_limit, success_val));
|
||||
#else
|
||||
msg_fatal("poll: %m");
|
||||
#endif
|
||||
continue;
|
||||
case 0:
|
||||
if (time_limit == 0) {
|
||||
return (0);
|
||||
} else {
|
||||
errno = ETIMEDOUT;
|
||||
return (-1);
|
||||
}
|
||||
default:
|
||||
if (pollfd.revents & POLLNVAL)
|
||||
msg_fatal("poll: %m");
|
||||
return (success_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,146 +0,0 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* read_wait 3
|
||||
/* SUMMARY
|
||||
/* wait until descriptor becomes readable
|
||||
/* SYNOPSIS
|
||||
/* #include <iostuff.h>
|
||||
/*
|
||||
/* int read_wait(fd, timeout)
|
||||
/* int fd;
|
||||
/* int timeout;
|
||||
/* DESCRIPTION
|
||||
/* read_wait() blocks the current process until the specified file
|
||||
/* descriptor becomes readable, or until the deadline is exceeded.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP fd
|
||||
/* File descriptor. With implementations based on select(),
|
||||
/* a best effort is made to handle descriptors >=FD_SETSIZE.
|
||||
/* .IP timeout
|
||||
/* If positive, deadline in seconds. A zero value effects a poll.
|
||||
/* A negative value means wait until something happens.
|
||||
/* DIAGNOSTICS
|
||||
/* Panic: interface violation. All system call errors are fatal.
|
||||
/*
|
||||
/* A zero result means success. When the specified deadline is
|
||||
/* exceeded, read_wait() returns -1 and sets errno to ETIMEDOUT.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_SYSV_POLL
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <iostuff.h>
|
||||
|
||||
/* read_wait - block with timeout until file descriptor is readable */
|
||||
|
||||
int read_wait(int fd, int timeout)
|
||||
{
|
||||
#if defined(NO_SYSV_POLL)
|
||||
fd_set read_fds;
|
||||
fd_set except_fds;
|
||||
struct timeval tv;
|
||||
struct timeval *tp;
|
||||
int temp_fd = -1;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (FD_SETSIZE <= fd) {
|
||||
if ((temp_fd = dup(fd)) < 0 || temp_fd >= FD_SETSIZE)
|
||||
msg_fatal("descriptor %d does not fit FD_SETSIZE %d", fd, FD_SETSIZE);
|
||||
fd = temp_fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use select() so we do not depend on alarm() and on signal() handlers.
|
||||
* Restart the select when interrupted by some signal. Some select()
|
||||
* implementations reduce the time to wait when interrupted, which is
|
||||
* exactly what we want.
|
||||
*/
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(fd, &read_fds);
|
||||
FD_ZERO(&except_fds);
|
||||
FD_SET(fd, &except_fds);
|
||||
if (timeout >= 0) {
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = timeout;
|
||||
tp = &tv;
|
||||
} else {
|
||||
tp = 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
switch (select(fd + 1, &read_fds, (fd_set *) 0, &except_fds, tp)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("select: %m");
|
||||
continue;
|
||||
case 0:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
errno = ETIMEDOUT;
|
||||
return (-1);
|
||||
default:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#elif defined(USE_SYSV_POLL)
|
||||
|
||||
/*
|
||||
* System-V poll() is optimal for polling a few descriptors.
|
||||
*/
|
||||
struct pollfd pollfd;
|
||||
|
||||
#define WAIT_FOR_EVENT (-1)
|
||||
|
||||
pollfd.fd = fd;
|
||||
pollfd.events = POLLIN;
|
||||
for (;;) {
|
||||
switch (poll(&pollfd, 1, timeout < 0 ?
|
||||
WAIT_FOR_EVENT : timeout * 1000)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("poll: %m");
|
||||
continue;
|
||||
case 0:
|
||||
errno = ETIMEDOUT;
|
||||
return (-1);
|
||||
default:
|
||||
if (pollfd.revents & POLLNVAL)
|
||||
msg_fatal("poll: %m");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "define USE_SYSV_POLL or NO_SYSV_POLL"
|
||||
#endif
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* readable 3
|
||||
/* SUMMARY
|
||||
/* test if descriptor is readable
|
||||
/* SYNOPSIS
|
||||
/* #include <iostuff.h>
|
||||
/*
|
||||
/* int readable(fd)
|
||||
/* int fd;
|
||||
/* DESCRIPTION
|
||||
/* readable() asks the kernel if the specified file descriptor
|
||||
/* is readable, i.e. a read operation would not block.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP fd
|
||||
/* File descriptor. With implementations based on select(),
|
||||
/* a best effort is made to handle descriptors >=FD_SETSIZE.
|
||||
/* DIAGNOSTICS
|
||||
/* All system call errors are fatal.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_SYSV_POLL
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <iostuff.h>
|
||||
|
||||
/* readable - see if file descriptor is readable */
|
||||
|
||||
int readable(int fd)
|
||||
{
|
||||
#if defined(NO_SYSV_POLL)
|
||||
struct timeval tv;
|
||||
fd_set read_fds;
|
||||
fd_set except_fds;
|
||||
int temp_fd = -1;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (fd >= FD_SETSIZE) {
|
||||
if ((temp_fd = dup(fd)) < 0 || temp_fd >= FD_SETSIZE)
|
||||
msg_fatal("fd %d does not fit in FD_SETSIZE", fd);
|
||||
fd = temp_fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(fd, &read_fds);
|
||||
FD_ZERO(&except_fds);
|
||||
FD_SET(fd, &except_fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
/*
|
||||
* Loop until we have an authoritative answer.
|
||||
*/
|
||||
for (;;) {
|
||||
switch (select(fd + 1, &read_fds, (fd_set *) 0, &except_fds, &tv)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("select: %m");
|
||||
continue;
|
||||
default:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
return (FD_ISSET(fd, &read_fds));
|
||||
case 0:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#elif defined(USE_SYSV_POLL)
|
||||
|
||||
/*
|
||||
* System-V poll() is optimal for polling a few descriptors.
|
||||
*/
|
||||
struct pollfd pollfd;
|
||||
|
||||
#define DONT_WAIT_FOR_EVENT 0
|
||||
|
||||
pollfd.fd = fd;
|
||||
pollfd.events = POLLIN;
|
||||
for (;;) {
|
||||
switch (poll(&pollfd, 1, DONT_WAIT_FOR_EVENT)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("poll: %m");
|
||||
continue;
|
||||
case 0:
|
||||
return (0);
|
||||
default:
|
||||
if (pollfd.revents & POLLNVAL)
|
||||
msg_fatal("poll: %m");
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "define USE_SYSV_POLL or NO_SYSV_POLL"
|
||||
#endif
|
||||
}
|
@ -254,7 +254,7 @@
|
||||
#define SOCKOPT_SIZE socklen_t
|
||||
#ifndef NO_KQUEUE
|
||||
# define EVENTS_STYLE EVENTS_STYLE_KQUEUE
|
||||
# define NO_SYSV_POLL
|
||||
# define USE_SYSV_POLL_WITH_SELECT
|
||||
#endif
|
||||
#ifndef NO_POSIX_GETPW_R
|
||||
# define HAVE_POSIX_GETPW_R
|
||||
@ -1374,16 +1374,15 @@ extern int inet_pton(int, const char *, void *);
|
||||
#if !defined(EVENTS_STYLE)
|
||||
#define EVENTS_STYLE EVENTS_STYLE_SELECT
|
||||
#endif
|
||||
#if !defined(USE_SYSV_POLL) && !defined(USE_SYSV_POLL_WITH_SELECT)
|
||||
#define USE_BSD_SELECT
|
||||
#endif
|
||||
|
||||
#define EVENTS_STYLE_SELECT 1 /* Traditional BSD select */
|
||||
#define EVENTS_STYLE_KQUEUE 2 /* FreeBSD kqueue */
|
||||
#define EVENTS_STYLE_DEVPOLL 3 /* Solaris /dev/poll */
|
||||
#define EVENTS_STYLE_EPOLL 4 /* Linux epoll */
|
||||
|
||||
#if !defined(USE_SYSV_POLL) && !defined(NO_SYSV_POLL) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
|
||||
#error "need USE_SYSV_POLL or NO_SYSV_POLL with EVENTS_STYLE != EVENTS_STYLE_SELECT"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The Postfix 2.9 post-install workaround assumes that the inet_protocols
|
||||
* default value is "ipv4" when Postfix is compiled without IPv6 support.
|
||||
|
@ -1,130 +0,0 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* writable 3
|
||||
/* SUMMARY
|
||||
/* test if descriptor is writable
|
||||
/* SYNOPSIS
|
||||
/* #include <iostuff.h>
|
||||
/*
|
||||
/* int writable(fd)
|
||||
/* int fd;
|
||||
/* DESCRIPTION
|
||||
/* writable() asks the kernel if the specified file descriptor
|
||||
/* is writable, i.e. a write operation would not block.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP fd
|
||||
/* File descriptor. With implementations based on select(),
|
||||
/* a best effort is made to handle descriptors >=FD_SETSIZE.
|
||||
/* DIAGNOSTICS
|
||||
/* All system call errors are fatal.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_SYSV_POLL
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <iostuff.h>
|
||||
|
||||
/* writable - see if file descriptor is writable */
|
||||
|
||||
int writable(int fd)
|
||||
{
|
||||
#if defined(NO_SYSV_POLL)
|
||||
struct timeval tv;
|
||||
fd_set write_fds;
|
||||
fd_set except_fds;
|
||||
int temp_fd = -1;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (fd >= FD_SETSIZE) {
|
||||
if ((temp_fd = dup(fd)) < 0 || temp_fd >= FD_SETSIZE)
|
||||
msg_fatal("fd %d does not fit in FD_SETSIZE", fd);
|
||||
fd = temp_fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
FD_ZERO(&write_fds);
|
||||
FD_SET(fd, &write_fds);
|
||||
FD_ZERO(&except_fds);
|
||||
FD_SET(fd, &except_fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
/*
|
||||
* Loop until we have an authoritative answer.
|
||||
*/
|
||||
for (;;) {
|
||||
switch (select(fd + 1, (fd_set *) 0, &write_fds, &except_fds, &tv)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("select: %m");
|
||||
continue;
|
||||
default:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
return (FD_ISSET(fd, &write_fds));
|
||||
case 0:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#elif defined(USE_SYSV_POLL)
|
||||
|
||||
/*
|
||||
* System-V poll() is optimal for polling a few descriptors.
|
||||
*/
|
||||
struct pollfd pollfd;
|
||||
|
||||
#define DONT_WAIT_FOR_EVENT 0
|
||||
|
||||
pollfd.fd = fd;
|
||||
pollfd.events = POLLOUT;
|
||||
for (;;) {
|
||||
switch (poll(&pollfd, 1, DONT_WAIT_FOR_EVENT)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("poll: %m");
|
||||
continue;
|
||||
case 0:
|
||||
return (0);
|
||||
default:
|
||||
if (pollfd.revents & POLLNVAL)
|
||||
msg_fatal("poll: %m");
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "define USE_SYSV_POLL or NO_SYSV_POLL"
|
||||
#endif
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* write_wait 3
|
||||
/* SUMMARY
|
||||
/* wait until descriptor becomes writable
|
||||
/* SYNOPSIS
|
||||
/* #include <iostuff.h>
|
||||
/*
|
||||
/* int write_wait(fd, timeout)
|
||||
/* int fd;
|
||||
/* int timeout;
|
||||
/* DESCRIPTION
|
||||
/* write_wait() blocks the current process until the specified file
|
||||
/* descriptor becomes writable, or until the deadline is exceeded.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP fd
|
||||
/* File descriptor. With implementations based on select(),
|
||||
/* a best effort is made to handle descriptors >=FD_SETSIZE.
|
||||
/* .IP timeout
|
||||
/* If positive, deadline in seconds. A zero value effects a poll.
|
||||
/* A negative value means wait until something happens.
|
||||
/* DIAGNOSTICS
|
||||
/* Panic: interface violation. All system call errors are fatal.
|
||||
/*
|
||||
/* A zero result means success. When the specified deadline is
|
||||
/* exceeded, write_wait() returns -1 and sets errno to ETIMEDOUT.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_SYSV_POLL
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <iostuff.h>
|
||||
|
||||
/* write_wait - block with timeout until file descriptor is writable */
|
||||
|
||||
int write_wait(int fd, int timeout)
|
||||
{
|
||||
#if defined(NO_SYSV_POLL)
|
||||
fd_set write_fds;
|
||||
fd_set except_fds;
|
||||
struct timeval tv;
|
||||
struct timeval *tp;
|
||||
int temp_fd = -1;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (FD_SETSIZE <= fd) {
|
||||
if ((temp_fd = dup(fd)) < 0 || temp_fd >= FD_SETSIZE)
|
||||
msg_fatal("descriptor %d does not fit FD_SETSIZE %d", fd, FD_SETSIZE);
|
||||
fd = temp_fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard the write() with select() so we do not depend on alarm() and on
|
||||
* signal() handlers. Restart the select when interrupted by some signal.
|
||||
* Some select() implementations may reduce the time to wait when
|
||||
* interrupted, which is exactly what we want.
|
||||
*/
|
||||
FD_ZERO(&write_fds);
|
||||
FD_SET(fd, &write_fds);
|
||||
FD_ZERO(&except_fds);
|
||||
FD_SET(fd, &except_fds);
|
||||
if (timeout >= 0) {
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = timeout;
|
||||
tp = &tv;
|
||||
} else {
|
||||
tp = 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
switch (select(fd + 1, (fd_set *) 0, &write_fds, &except_fds, tp)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("select: %m");
|
||||
continue;
|
||||
case 0:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
errno = ETIMEDOUT;
|
||||
return (-1);
|
||||
default:
|
||||
if (temp_fd != -1)
|
||||
(void) close(temp_fd);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#elif defined(USE_SYSV_POLL)
|
||||
|
||||
/*
|
||||
* System-V poll() is optimal for polling a few descriptors.
|
||||
*/
|
||||
struct pollfd pollfd;
|
||||
|
||||
#define WAIT_FOR_EVENT (-1)
|
||||
|
||||
pollfd.fd = fd;
|
||||
pollfd.events = POLLOUT;
|
||||
for (;;) {
|
||||
switch (poll(&pollfd, 1, timeout < 0 ?
|
||||
WAIT_FOR_EVENT : timeout * 1000)) {
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
msg_fatal("poll: %m");
|
||||
continue;
|
||||
case 0:
|
||||
errno = ETIMEDOUT;
|
||||
return (-1);
|
||||
default:
|
||||
if (pollfd.revents & POLLNVAL)
|
||||
msg_fatal("poll: %m");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "define USE_SYSV_POLL or NO_SYSV_POLL"
|
||||
#endif
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user