FROM: or CC: by From: or Cc:. Files: cleanup/cleanup_message.c,
smtp/smtp_proto.c.
-Open problems:
+20050228
+
+ Cleanup/portability: missing #includes and bad prototypes.
+ Matthias Andree, Carsten Hoeger, and others.
+
+20050302
+
+ Workaround: make TLS session caching work with perverse
+ sites that have multiple servers per hostname or even
+ multiple servers per IP address, but no shared TLS session
+ cache. The SMTP client TLS session cache is now indexed by
+ (server hostname, server address, server port, server helo
+ hostname). After an idea by Victor Duchovni. Files:
+ smtp/smtp_proto.c, tls/tls_client.c.
+
+20050303
+
+ Bugfix (bug inherited from Postfix/TLS patch): a rare 9kbyte
+ memory leak when in-memory TLS session information expires;
+ found by setting the expiry time shorter than the time to
+ deliver one or two messages with a very slow machine. This
+ was due to a missing SSL_SESSION_free() call in the "new
+ session" call-back routines. Found by Victor Duchovni.
+ Files: tls/tls_client.c, tls/tls_server.c.
+
+ Workaround: OpenSSL is overly agressive when purging a
+ not-yet expired entry from a full in-memory cache: it also
+ purges the entry from the on-disk server session cache.
+ Workaround is to let only the tlsmgr purge entries from the
+ on-disk server session cache. Found by Victor Duchovni.
+ File: tls/tls_server.c.
+
+20050304
+
+ Postfix releases are now signed with Wietse's new PGP key.
+ The old key was getting a bit short for today's standards.
+ The new public key can be found on the Postfix download
+ webpage. As proof of authenticity the new PGP key is signed
+ with Wietse's old PGP key.
- Med: disable header address rewriting after XCLIENT?
- Introduce a better concept of original submission?
-
- Low: 9kbyte memory leak when expired in-memory session
- information is removed by SSL_CTX_flush_sessions(); found
- by setting the expiry time shorter than the time to deliver
- one or two messages. Postfix processes are short-lived,
- and the occurrance of this leak is rare enough that it is
- a low priority.
-
- Low: configurable order of local(8) delivery methods.
-
- Med: local and remote source port and IP address for smtpd
- policy hook.
-
- Med: smtp_connect_timeout_budget (default: 3x smtp_connect_timeout)
- to limit the total time spent trying to connect.
-
- Med: transform IPv4-in-IPv6 address literals to IPv4 form
- when comparing against local IP addresses?
-
- Med: transform IPv4-in-IPv6 address literals to IPv4 form
- when eliminating MX mailer loops?
-
- Med: Postfix requires [] around IPv6 address information
- in match lists such as mynetworks, debug_peer_list etc.,
- but the [] must not be specified in access(5) maps. Other
- places don't care. For now, this gotcha is documented in
- IPV6_README and in postconf(5) with each feature that may
- use IPv6 address information. The general recommendation
- is not to use [] unless absolutely necessary.
-
- Med: the partial address matching of IPv6 addresses in
- access(5) maps is a bit lame: it repeatedly truncates the
- last ":octetpair" from the printable address representation
- until a match is found or until truncation is no longer
- possible. Since one or more ":" are usually omitted from
- the printable IPv6 address representation, this does not
- really try all the possibilities that one might expect to
- be tried. For now, this gotcha is documented in access(5).
-
- Med: the TLS certificate verification depth parameters
- never worked.
-
- Med: eliminate the tls_info data structure.
-
- Low: reject HELO with any domain name or IP address that
- this MTA is the final destination for.
-
- Low: should the Delivered-To: test in local(8) be configurable?
-
- Low: make mail_addr_find() lookup configurable.
-
- Low: update events.c so that 1-second timer requests do
- not suffer from rounding errors. This is needed for 1-second
- SMTP session caching time limits. A 1-second interval would
- become arbitrarily short when an event is scheduled just
- before the current second rolls over.
-
- Low: per-sender resolver personalities?
-
- Low: configurable internal/system locking method.
-
- Low: make sure CCARGS -I options come at the end.
-
- Low: add INSTALL section for pre-existing Postfix systems.
-
- Low: add INSTALL section for pre-existing RPM Postfixes.
-
- Low: disallow smtpd_recipient_limit < 100 (the RFC minimum).
-
- Low: noise filter: allow smtp(8) to retry immediately if
- all MXes return a quick ECONNRESET or 4xx reply during the
- initial handshake.
-
- Low: make post-install a "postfix-only script" so it can
- take data from the environment instead of main.cf.
-
- Low: randomize deferred mail backoff.
-
- Med: separate ulimit for delivery to command?
-
- Med: option to open queue file early, after MAIL FROM.
-
- Low: log xdelay (esp. for SMTP and delivery to command).
-
- Med: silly queue file bit so that the queue manager doesn't
- skip files when fast flush is requested while a queue scan
- is in progress. The bit is set by the flush server and is
- reset when the mail is deferred, so that it survives queue
- manager restart.
-
- Med: postsuper -r should do something with recipients in
- bounce logfiles.
-
- Low: postsuper re-run after renaming files, but only a
- limited number of times.
-
- Low: smtp-source may block when sending large test messages.
-
- Med: make qmgr recipient bounce/defer activity asynchronous
- or add a multi-recipient operation that reduces overhead.
- One possibility is to pass delivery requests to a retry(8)
- delivery agent which is error(8) in disguise, and which
- calls defer_append() instead of bounce_append().
-
- Low: postmap/postalias should not try to open a bogus file
- when given an unsupported dictionary type.
-
- Med: find a way to log the sender address when MAIL FROM
- is rejected due to lack of disk space.
-
- Low: revise other local delivery agent duplicate filters.
-
- Low: all table lookups should consistently use internalized
- (unquoted) or externalized (quoted) forms as lookup keys.
- smtpd, qmgr, local, etc. use unquoted address forms as
- keys. cleanup uses quoted forms.
-
- Low: have a configurable list of errno values for mailbox
- or maildir delivery that result in deferral rather than
- bouncing mail.
-
- Low: after reorganizing configuration parameters, add flags
- to all parameters whose value can be read from file.
-
- Medium: need in-process caching for map lookups. LDAP
- servers seem to need this in particular. Need a way to
- expire cached results that are too old.
-
- Low: generic showq protocol, to allow for more intelligent
- processing than just mailq. Maybe marry this with postsuper.
-
- Low: default domain for appending to unqualified recipients,
- so that unqualified names can be delivered locally.
-
- Low: The $process_id_directory setting is not used anywhere
- in Postfix. Problem reported by Michael Smith, texas.net.
- This should be documented, or better, the code should warn
- about attempts to set read-only parameters.
-
- Low: postconf -e edits parameters that postconf won't list.
-
- Low: while converting 8bit text to quoted-printable, perhaps
- use =46rom to avoid having to produce >From when delivering
- to mailbox.
-
- virtual_mailbox_path expression like forward_path, so that
- people can specify prefix and suffix.
from third-party patches.
- SMTP client-side connection reuse. This can dramatically speed
-up deliveries to high-volume destinations that have good and
-non-responding mail servers.
+up deliveries to high-volume destinations that have some servers
+that respond, and some non-responding mail servers.
- By default, message header address rewriting is now disabled for
SMTP mail from other systems. Thus, spam from poorly written
[Feature 20040919] The upgrade procedure adds the discard service
to the master.cf file.
-[Feature 20040720] The upgrade procedure adds the scache (connection
-cache) service to the master.cf file.
+[Feature 20040720] The upgrade procedure adds the scache (shared
+connection cache) service to the master.cf file.
Major changes - IPv6 support
----------------------------
in by default. For more information about Postfix 2.2 TLS support,
see the TLS_README document.
-[Feature 20050209] The Postfix SMTP server policy delegation protocol
-now supplies TLS client certificate information after successful
-verification. The new policy delegation protocol attribute names
-are ccert_subject, ccert_issuer and ccert_fingerprint.
-
-[Feature 20050208] New "check_ccert_maps maptype:mapname" feature
-to enforce access control based on hexadecimal client certificate
-fingerprints.
-
[Incompat 20041210] Postfix version 2.2 TLS support differs from
the Postfix/TLS patch by Lutz Jaenicke in a few minor ways.
(PRNG) pool, and in order to access the TLS session cache databases.
Such a protocol cannot be run across fifos.
+[Feature 20050209] The Postfix SMTP server policy delegation protocol
+now supplies TLS client certificate information after successful
+verification. The new policy delegation protocol attribute names
+are ccert_subject, ccert_issuer and ccert_fingerprint.
+
+[Feature 20050208] New "check_ccert_maps maptype:mapname" feature
+to enforce access control based on hexadecimal client certificate
+fingerprints.
+
Major changes - SMTP client connection cache
--------------------------------------------
PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
xxgdb $daemon_directory/$process_name $process_id & sleep 5
-# If you don't have X installed on the Postfix machine, try:
+# If you can't use X, use this to capture the call stack when a
+# daemon crashes. The result is in a file in the configuration
+# directory, and is named after the process name and the process ID.
+#
# debugger_command =
# PATH=/bin:/usr/bin:/usr/local/bin; export PATH; (echo cont;
# echo where) | gdb $daemon_directory/$process_name $process_id 2>&1
# >$config_directory/$process_name.$process_id.log & sleep 5
+#
+# Another possibility is to run gdb under a detached screen session.
+# To attach to the screen sesssion, su root and run "screen -r
+# <id_string>" where <id_string> uniquely matches one of the detached
+# sessions (from "screen -list").
+#
+# debugger_command =
+# PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH; screen
+# -dmS $process_name gdb $daemon_directory/$process_name
+# $process_id & sleep 1
# INSTALL-TIME CONFIGURATION INFORMATION
#
#include <bounce.h>
#include <deliver_completed.h>
#include <flush_clnt.h>
+#include <sent.h>
/* Single server skeleton. */
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
-#define MAIL_RELEASE_DATE "20050227"
+#define MAIL_RELEASE_DATE "20050304"
#define MAIL_VERSION_NUMBER "2.2"
#define VAR_MAIL_VERSION "mail_version"
#ifdef SNAPSHOT
#define DEF_MAIL_VERSION MAIL_VERSION_NUMBER "-" MAIL_RELEASE_DATE
#else
-#define DEF_MAIL_VERSION MAIL_VERSION_NUMBER "-RC1"
+#define DEF_MAIL_VERSION MAIL_VERSION_NUMBER "-RC2"
#endif
extern char *var_mail_version;
/* System library. */
#include <sys_defs.h>
+#include <string.h>
#include <unistd.h>
/* Utility library. */
/*
* Local mail submission access list.
*/
-static char *var_submit_acl;
+char *var_submit_acl;
static CONFIG_STR_TABLE str_table[] = {
VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0,
/*
* Queue manipulation access lists.
*/
-static char *var_flush_acl;
-static char *var_showq_acl;
+char *var_flush_acl;
+char *var_showq_acl;
static CONFIG_STR_TABLE str_table[] = {
VAR_FLUSH_ACL, DEF_FLUSH_ACL, &var_flush_acl, 0, 0,
/*
* Mail submission ACL
*/
-static char *var_submit_acl;
+char *var_submit_acl;
static CONFIG_STR_TABLE str_table[] = {
VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0,
char *host; /* mail exchanger */
char *addr; /* mail exchanger */
char *namaddr; /* mail exchanger */
+ char *helo; /* helo response */
unsigned port; /* network byte order */
VSTRING *buffer; /* I/O buffer */
"QUIT command",
};
+static int smtp_start_tls(SMTP_STATE *, int);
+
/* smtp_helo - perform initial handshake with SMTP server */
int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags)
int discard_mask;
#ifdef USE_TLS
- static int smtp_start_tls(SMTP_STATE *, int);
int saved_features = session->features;
#endif
* MicroSoft implemented AUTH based on an old draft.
*/
lines = resp->str;
- while ((words = mystrtok(&lines, "\n")) != 0) {
+ for (n = 0; (words = mystrtok(&lines, "\n")) != 0; /* see below */ ) {
if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) {
- if (strcasecmp(word, "8BITMIME") == 0) {
+ if (n == 0) {
+ if (session->helo != 0)
+ myfree(session->helo);
+ session->helo = lowercase(mystrdup(word));
+ if (strcasecmp(word, var_myhostname) == 0
+ && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) != 0) {
+ msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
+ session->namaddr, var_myhostname);
+ return (smtp_site_fail(state,
+ (session->features & SMTP_FEATURE_BEST_MX) ? 550 : 450,
+ "mail for %s loops back to myself",
+ request->nexthop));
+ }
+ } else if (strcasecmp(word, "8BITMIME") == 0) {
if ((discard_mask & EHLO_MASK_8BITMIME) == 0)
session->features |= SMTP_FEATURE_8BITMIME;
} else if (strcasecmp(word, "PIPELINING") == 0) {
if ((discard_mask & EHLO_MASK_AUTH) == 0)
smtp_sasl_helo_auth(session, words);
#endif
- } else if (strcasecmp(word, var_myhostname) == 0) {
- if (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) {
- msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
- session->namaddr, var_myhostname);
- return (smtp_site_fail(state,
- (session->features & SMTP_FEATURE_BEST_MX) ? 550 : 450,
- "mail for %s loops back to myself",
- request->nexthop));
- }
}
+ n++;
}
}
if (msg_verbose)
static int smtp_start_tls(SMTP_STATE *state, int misc_flags)
{
SMTP_SESSION *session = state->session;
+ VSTRING *serverid;
/*
* Turn off SMTP connection caching. When the TLS handshake succeeds, we
* follow below AFTER the tls_client_start() call. These tests should be
* done inside tls_client_start() or its call-backs, to keep the SMTP
* client code clean (as it is in the SMTP server).
+ *
+ * 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
+ * use TLS session caching???
*/
+ serverid = vstring_alloc(10);
+ vstring_sprintf(serverid, "%s:%s:%u",
+ session->host, session->addr,
+ ntohs(session->port));
+ if (session->helo && strcasecmp(session->host, session->helo) != 0)
+ vstring_sprintf_append(serverid, ":%s", session->helo);
session->tls_context =
tls_client_start(smtp_tls_ctx, session->stream,
var_smtp_starttls_tmout,
session->tls_enforce_peername,
session->host,
+ lowercase(vstring_str(serverid)),
&(session->tls_info));
+ vstring_free(serverid);
if (session->tls_context == 0)
return (smtp_site_fail(state, 450,
"Cannot start TLS: handshake failure"));
char *end_line;
/*
- * Rewrite primary header addresses that match the smtp_generic_maps.
- * The cleanup server already enforces that all headers have proper
- * lengths and that all addresses are in proper form, so we don't have to
- * repeat that.
+ * Rewrite primary header addresses that match the smtp_generic_maps. The
+ * cleanup server already enforces that all headers have proper lengths
+ * and that all addresses are in proper form, so we don't have to repeat
+ * that.
*/
if (header_info && header_class == MIME_HDR_PRIMARY
&& (header_info->flags & (HDR_OPT_SENDER | HDR_OPT_RECIP)) != 0) {
save_mech = mech_list = mystrdup(words);
- while (mech = mystrtok(&mech_list, " \t")) {
- if (string_list_match(smtp_sasl_mechs, mech)) {
+ while ((mech = mystrtok(&mech_list, " \t")) != 0) {
+ if (string_list_match(smtp_sasl_mechs, mech)) {
if (VSTRING_LEN(buf) > 0)
VSTRING_ADDCH(buf, ' ');
vstring_strcat(buf, mech);
#include <sys_defs.h>
#include <stdlib.h>
#include <string.h>
+#include <netinet/in.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
/* Application-specific. */
#include "smtp.h"
+#include "smtp_sasl.h"
#define STR(x) vstring_str(x)
session->host = mystrdup(host);
session->addr = mystrdup(addr);
session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
+ session->helo = 0;
session->port = port;
session->features = 0;
myfree(session->host);
myfree(session->addr);
myfree(session->namaddr);
+ if (session->helo)
+ myfree(session->helo);
vstring_free(session->buffer);
vstring_free(session->scratch);
#include <mymalloc.h>
#include <namadr_list.h>
#include <name_mask.h>
+#include <stringops.h>
/* Global library. */
SSL *con;
BIO *internal_bio; /* postfix/TLS side of pair */
BIO *network_bio; /* network side of pair */
+ char *serverid; /* unique server identifier */
char peer_subject[CCERT_BUFSIZ];
char peer_issuer[CCERT_BUFSIZ];
char peer_CN[CCERT_BUFSIZ];
#define TLS_BIO_BUFSIZE 8192
+#define NEW_TLS_CONTEXT(p) do { \
+ p = (TLScontext_t *) mymalloc(sizeof(*p)); \
+ memset((char *) p, 0, sizeof(*p)); \
+ p->serverid = 0; \
+ } while (0)
+
+#define FREE_TLS_CONTEXT(p) do { \
+ if ((p)->serverid) \
+ myfree((p)->serverid); \
+ myfree((char *) (p)); \
+ } while (0)
+
typedef struct {
int peer_verified;
int hostname_matched;
*/
extern SSL_CTX *tls_client_init(int);
extern TLScontext_t *tls_client_start(SSL_CTX *, VSTREAM *, int, int,
- const char *, tls_info_t *);
+ const char *, const char *,
+ tls_info_t *);
#define tls_client_stop(ctx , stream, timeout, failure, tls_info) \
tls_session_stop((ctx), (stream), (timeout), (failure), (tls_info))
* tls_misc.c
*/
extern int TLScontext_index;
-extern int TLSpeername_index;
extern void tls_print_errors(void);
extern void tls_info_callback(const SSL *, int, int);
/* SSL_CTX *tls_client_init(verifydepth)
/* int verifydepth; /* unused */
/*
-/* TLScontext_t *tls_client_start(client_ctx, stream, timeout, peername,
-/* peeraddr, tls_info)
+/* TLScontext_t *tls_client_start(client_ctx, stream, timeout,
+/* enforce_peername, peername,
+/* serverid, tls_info)
/* SSL_CTX *client_ctx;
/* VSTREAM *stream;
/* int timeout;
+/* int enforce_peername;
/* const char *peername;
-/* const char *peeraddr;
+/* const char *serverid;
/* tls_info_t *tls_info;
/*
/* void tls_client_stop(client_ctx, stream, failure, tls_info)
/* passed as argument. We expect that network buffers are flushed and the
/* TLS handshake can begin immediately. Information about the peer
/* is stored into the tls_info structure passed as argument.
+/* The serverid argument specifies a string that hopefully
+/* uniquely identifies a server. It is used as the client
+/* session cache lookup key.
/*
/* tls_client_stop() sends the "close notify" alert via
/* SSL_shutdown() to the peer and resets all connection specific
/* load_clnt_session - load session from client cache (non-callback) */
-static SSL_SESSION *load_clnt_session(const char *hostname,
+static SSL_SESSION *load_clnt_session(const char *cache_id,
int enforce_peername)
{
SSL_SESSION *session = 0;
- char *cache_id;
- VSTRING *cache_id_buffer;
VSTRING *session_data = vstring_alloc(2048);
int flags = 0;
/*
* Prepare the query.
*/
- cache_id = lowercase(mystrdup(hostname));
if (var_smtp_tls_loglevel >= 3)
msg_info("looking for session %s in client cache", cache_id);
if (enforce_peername)
if (session) {
if (var_smtp_tls_loglevel >= 3)
msg_info("reloaded session %s from client cache", cache_id);
- cache_id_buffer =
- (VSTRING *) SSL_SESSION_get_ex_data(session, TLSpeername_index);
- vstring_strcpy(cache_id_buffer, cache_id);
}
}
/*
* Clean up.
*/
- myfree(cache_id);
vstring_free(session_data);
return (session);
}
- /*
- * The client session cache is indexed by peer name, not by session id. The
- * following routines maintain string storage for the peer name in an
- * SSL_SESSION object. We use VSTRING buffers so that we don't have to worry
- * about hostname length problems.
- */
-
-/* new_cache_id_func - create space for peer name in SSL_SESSION object */
-
-static int new_cache_id_func(void *unused_parent, void *unused_ptr,
- CRYPTO_EX_DATA *ad, int idx,
- long unused_argl, void *unused_argp)
-{
- VSTRING *cache_id_buffer;
-
- cache_id_buffer = vstring_alloc(32);
- return (CRYPTO_set_ex_data(ad, idx, (void *) cache_id_buffer));
-}
-
-/* free_cache_id_func - destroy space for peer name in SSL_SESSION object */
-
-static void free_cache_id_func(void *unused_parent, void *unused_ptr,
- CRYPTO_EX_DATA *ad, int idx,
- long unused_argl, void *unused_argp)
-{
- VSTRING *cache_id_buffer;
-
- cache_id_buffer = (VSTRING *) CRYPTO_get_ex_data(ad, idx);
- vstring_free(cache_id_buffer);
-}
-
-/* dup_cache_id_func - duplicate peer name when SSL_SESSION is duplicated */
-
-static int dup_cache_id_func(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
- void *unused_from_d, int idx, long unused_argl, void *unused_argp)
-{
- const char *myname = "dup_cache_id_func";
- VSTRING *old_cache_id_buffer;
- VSTRING *new_cache_id_buffer;
-
- old_cache_id_buffer = (VSTRING *) CRYPTO_get_ex_data(from, idx);
- if (old_cache_id_buffer == 0) {
- msg_warn("%s: cannot get old SSL_SESSION peer name buffer", myname);
- return (0);
- }
- new_cache_id_buffer = (VSTRING *) CRYPTO_get_ex_data(to, idx);
- if (new_cache_id_buffer == 0) {
- msg_warn("%s: cannot get new SSL_SESSION peer name buffer", myname);
- return (0);
- }
- vstring_strcpy(new_cache_id_buffer, STR(old_cache_id_buffer));
- return (1);
-}
-
/* new_client_session_cb - name new session and save it to client cache */
static int new_client_session_cb(SSL *ssl, SSL_SESSION *session)
{
TLScontext_t *TLScontext;
VSTRING *session_data;
- VSTRING *cache_id_buffer;
+ const char *cache_id;
int flags = 0;
/*
- * Attach the cache ID string to the session object. Don't worry about
- * the length; that is the concern of the code that updates the session
- * cache.
+ * Look up the cache ID string for this session object.
*/
- cache_id_buffer =
- (VSTRING *) SSL_SESSION_get_ex_data(session, TLSpeername_index);
TLScontext = SSL_get_ex_data(ssl, TLScontext_index);
- vstring_strcpy(cache_id_buffer, TLScontext->peername_save);
- lowercase(STR(cache_id_buffer)); /* just in case */
+ cache_id = TLScontext->serverid;
if (var_smtp_tls_loglevel >= 3)
- msg_info("save session %s to client cache", STR(cache_id_buffer));
+ msg_info("save session %s to client cache", cache_id);
/*
* Remember whether peername matching was enforced when the session was
*/
session_data = tls_session_passivate(session);
if (session_data)
- tls_mgr_update(tls_client_cache, STR(cache_id_buffer),
+ tls_mgr_update(tls_client_cache, cache_id,
OPENSSL_VERSION_NUMBER, flags,
STR(session_data), LEN(session_data));
*/
if (session_data)
vstring_free(session_data);
+ SSL_SESSION_free(session); /* 200502 */
return (1);
}
if (TLScontext_index < 0)
TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index",
NULL, NULL, NULL);
-
- /*
- * Create a global index so that we can attach peer name information to
- * SSL_SESSION objects; the client session cache manager uses this to
- * generate cache ID strings.
- */
- if (TLSpeername_index < 0)
- TLSpeername_index = SSL_SESSION_get_ex_new_index(0,
- "TLSpeername ex_data index",
- new_cache_id_func,
- dup_cache_id_func,
- free_cache_id_func);
-
return (client_ctx);
}
* buffers are flushed and the "220 Ready to start TLS" was received by us,
* so that we can immediately start the TLS handshake process.
*/
-TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream, int timeout,
+TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream,
+ int timeout,
int enforce_peername,
const char *peername,
+ const char *serverid,
tls_info_t *tls_info)
{
int sts;
- SSL_SESSION *session,
- *old_session;
+ SSL_SESSION *session, *old_session;
SSL_CIPHER *cipher;
X509 *peer;
int verify_flags;
*/
#define PEERNAME_SIZE sizeof(TLScontext->peername_save)
- TLScontext = (TLScontext_t *) mymalloc(sizeof(TLScontext_t));
- memset((char *) TLScontext, 0, sizeof(*TLScontext));
+ NEW_TLS_CONTEXT(TLScontext);
TLScontext->log_level = var_smtp_tls_loglevel;
strncpy(TLScontext->peername_save, peername, PEERNAME_SIZE - 1);
TLScontext->peername_save[PEERNAME_SIZE - 1] = 0;
(void) lowercase(TLScontext->peername_save);
+ TLScontext->serverid = mystrdup(serverid);
if ((TLScontext->con = (SSL *) SSL_new(client_ctx)) == NULL) {
msg_info("Could not allocate 'TLScontext->con' with SSL_new()");
tls_print_errors();
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
msg_info("Could not set application data for 'TLScontext->con'");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
msg_info("Could not obtain BIO_pair");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
old_session = NULL;
* will be reused.
*/
if (tls_client_cache) {
- old_session = load_clnt_session(peername, enforce_peername);
+ old_session = load_clnt_session(serverid, enforce_peername);
if (old_session) {
SSL_set_session(TLScontext->con, old_session);
SSL_SESSION_free(old_session); /* 200411 */
}
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio); /* 200411 */
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
if (var_smtp_tls_loglevel >= 3 && SSL_session_reused(TLScontext->con))
* so that it can be accessed by call-back routines.
*/
int TLScontext_index = -1;
-int TLSpeername_index = -1;
/* tls_print_errors - print and clear the error stack */
return (session);
}
-/* remove_server_session_cb - callback to remove session from server cache */
-
-static void remove_server_session_cb(SSL_CTX *unused_ctx, SSL_SESSION *session)
-{
- VSTRING *cache_id;
-
- /*
- * Encode the session ID.
- */
- cache_id =
- MAKE_SERVER_CACHE_ID(session->session_id, session->session_id_length);
- if (var_smtpd_tls_loglevel >= 3)
- msg_info("remove session %s from server cache", STR(cache_id));
-
- /*
- * Delete the session from cache.
- */
- tls_mgr_delete(tls_server_cache, STR(cache_id));
-
- vstring_free(cache_id);
-}
-
/* new_server_session_cb - callback to save session to server cache */
static int new_server_session_cb(SSL *unused_ssl, SSL_SESSION *session)
if (session_data)
vstring_free(session_data);
vstring_free(cache_id);
+ SSL_SESSION_free(session); /* 200502 */
return (1);
}
/*
* The session cache is implemented by the tlsmgr(8) server.
+ *
+ * XXX 200502 Surprise: when OpenSSL purges an entry from the in-memory
+ * cache, it also attempts to purge the entry from the on-disk cache.
+ * This is undesirable, especially when we set the in-memory cache size
+ * to 1. For this reason we don't allow OpenSSL to purge on-disk cache
+ * entries, and leave it up to the tlsmgr process instead. Found by
+ * Victor Duchovni.
*/
if (tls_mgr_policy(&cache_types) == TLS_MGR_STAT_OK
&& (tls_server_cache = (cache_types & TLS_MGR_SCACHE_SERVER)) != 0) {
SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR);
SSL_CTX_sess_set_get_cb(server_ctx, get_server_session_cb);
SSL_CTX_sess_set_new_cb(server_ctx, new_server_session_cb);
- SSL_CTX_sess_set_remove_cb(server_ctx, remove_server_session_cb);
}
/*
* Allocate a new TLScontext for the new connection and get an SSL
* structure. Add the location of TLScontext to the SSL to later retrieve
* the information inside the tls_verify_certificate_callback().
- *
+ *
* XXX Need a dedicated procedure for consistent initialization of all the
* fields in this structure.
*/
#define PEERNAME_SIZE sizeof(TLScontext->peername_save)
- TLScontext = (TLScontext_t *) mymalloc(sizeof(TLScontext_t));
- memset((char *) TLScontext, 0, sizeof(*TLScontext));
+ NEW_TLS_CONTEXT(TLScontext);
TLScontext->log_level = var_smtpd_tls_loglevel;
strncpy(TLScontext->peername_save, peername, PEERNAME_SIZE - 1);
TLScontext->peername_save[PEERNAME_SIZE - 1] = 0;
if ((TLScontext->con = (SSL *) SSL_new(server_ctx)) == NULL) {
msg_info("Could not allocate 'TLScontext->con' with SSL_new()");
tls_print_errors();
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
msg_info("Could not set application data for 'TLScontext->con'");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
msg_info("Could not obtain BIO_pair");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
tls_print_errors();
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio); /* 200411 */
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
/* Only loglevel==4 dumps everything */
msg_info("fingerprint=%s", TLScontext->fingerprint);
tls_info->peer_fingerprint = TLScontext->fingerprint;
}
-
TLScontext->peer_CN[0] = '\0';
if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
NID_commonName, TLScontext->peer_CN,
SSL_CTX_remove_session(server_ctx, session);
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio); /* 200411 */
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
}
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
tls_stream_stop(stream);
SSL_CTX_flush_sessions(ctx, time(NULL));