From: Wietse Venema Date: Fri, 4 Mar 2005 05:00:00 +0000 (-0500) Subject: postfix-2.2.0-RC2 X-Git-Tag: v2.2.0-RC2^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6ff927dbfb1734e46c51e7146b3aa37a80876073;p=thirdparty%2Fpostfix.git postfix-2.2.0-RC2 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 02f7b445b..bd7e14502 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -10405,154 +10405,43 @@ Apologies for any names omitted. 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. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 54ba7b6ce..a973f43e0 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -21,8 +21,8 @@ the following sections of this document. 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 @@ -75,8 +75,8 @@ the Postfix/TLS patch. [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 ---------------------------- @@ -116,15 +116,6 @@ Postfix/TLS patch by Lutz Jaenicke. TLS support is not compiled 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. @@ -150,6 +141,15 @@ 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 -------------------------------------------- diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index 272d98661..517277974 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -582,11 +582,24 @@ debugger_command = 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 +# " where 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 # diff --git a/postfix/src/discard/discard.c b/postfix/src/discard/discard.c index 09b562745..235367f06 100644 --- a/postfix/src/discard/discard.c +++ b/postfix/src/discard/discard.c @@ -115,6 +115,7 @@ #include #include #include +#include /* Single server skeleton. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 111660d3c..5ba0f7925 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,14 +20,14 @@ * 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; diff --git a/postfix/src/master/master_vars.c b/postfix/src/master/master_vars.c index 53b37220b..33869b8c8 100644 --- a/postfix/src/master/master_vars.c +++ b/postfix/src/master/master_vars.c @@ -25,6 +25,7 @@ /* System library. */ #include +#include #include /* Utility library. */ diff --git a/postfix/src/postdrop/postdrop.c b/postfix/src/postdrop/postdrop.c index 13e3b8057..d5cf5fa0a 100644 --- a/postfix/src/postdrop/postdrop.c +++ b/postfix/src/postdrop/postdrop.c @@ -152,7 +152,7 @@ /* * 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, diff --git a/postfix/src/postqueue/postqueue.c b/postfix/src/postqueue/postqueue.c index 200079ea2..6f6ae1d90 100644 --- a/postfix/src/postqueue/postqueue.c +++ b/postfix/src/postqueue/postqueue.c @@ -222,8 +222,8 @@ /* * 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, diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index b36aa904c..d4d8645fc 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -447,7 +447,7 @@ typedef struct SM_STATE { /* * 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, diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 53d918656..2aa7a363c 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -173,6 +173,7 @@ typedef struct SMTP_SESSION { 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 */ diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 964fd5773..ebbe53f1a 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -219,6 +219,8 @@ char *xfer_request[SMTP_STATE_LAST] = { "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) @@ -245,7 +247,6 @@ 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 @@ -361,9 +362,22 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) * 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) { @@ -396,16 +410,8 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) 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) @@ -554,6 +560,7 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) 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 @@ -580,13 +587,26 @@ static int smtp_start_tls(SMTP_STATE *state, int misc_flags) * 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")); @@ -741,10 +761,10 @@ static void smtp_header_rewrite(void *context, int header_class, 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) { diff --git a/postfix/src/smtp/smtp_sasl_proto.c b/postfix/src/smtp/smtp_sasl_proto.c index e2a35e0e6..4dcd20b05 100644 --- a/postfix/src/smtp/smtp_sasl_proto.c +++ b/postfix/src/smtp/smtp_sasl_proto.c @@ -98,8 +98,8 @@ static const char *smtp_sasl_compat_mechs(const char *words) 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); diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 75e7b6dcf..64cb7f273 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -96,6 +96,7 @@ #include #include #include +#include #ifdef STRCASECMP_IN_STRINGS_H #include @@ -118,6 +119,7 @@ /* Application-specific. */ #include "smtp.h" +#include "smtp_sasl.h" #define STR(x) vstring_str(x) @@ -211,6 +213,7 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest, session->host = mystrdup(host); session->addr = mystrdup(addr); session->namaddr = concatenate(host, "[", addr, "]", (char *) 0); + session->helo = 0; session->port = port; session->features = 0; @@ -298,6 +301,8 @@ void smtp_session_free(SMTP_SESSION *session) myfree(session->host); myfree(session->addr); myfree(session->namaddr); + if (session->helo) + myfree(session->helo); vstring_free(session->buffer); vstring_free(session->scratch); diff --git a/postfix/src/smtpd/smtpd_sasl_glue.c b/postfix/src/smtpd/smtpd_sasl_glue.c index b3c3587cc..63f3d8183 100644 --- a/postfix/src/smtpd/smtpd_sasl_glue.c +++ b/postfix/src/smtpd/smtpd_sasl_glue.c @@ -93,6 +93,7 @@ #include #include #include +#include /* Global library. */ diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index a2ce27139..a6514d776 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -52,6 +52,7 @@ typedef struct { 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]; @@ -67,6 +68,18 @@ typedef struct { #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; @@ -88,7 +101,8 @@ extern const tls_info_t tls_info_zero; */ 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)) @@ -183,7 +197,6 @@ extern int tls_set_my_certificate_key_info(SSL_CTX *, const char *, * 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); diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index 95002bda2..a47e322da 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -9,13 +9,15 @@ /* 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) @@ -36,6 +38,9 @@ /* 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 @@ -144,12 +149,10 @@ static int client_verify_callback(int ok, X509_STORE_CTX *ctx) /* 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; @@ -158,7 +161,6 @@ static SSL_SESSION *load_clnt_session(const char *hostname, /* * 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) @@ -174,97 +176,34 @@ static SSL_SESSION *load_clnt_session(const char *hostname, 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 @@ -295,7 +234,7 @@ static int new_client_session_cb(SSL *ssl, SSL_SESSION *session) */ 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)); @@ -304,6 +243,7 @@ static int new_client_session_cb(SSL *ssl, SSL_SESSION *session) */ if (session_data) vstring_free(session_data); + SSL_SESSION_free(session); /* 200502 */ return (1); } @@ -479,19 +419,6 @@ SSL_CTX *tls_client_init(int unused_verifydepth) 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); } @@ -500,14 +427,15 @@ SSL_CTX *tls_client_init(int unused_verifydepth) * 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; @@ -526,24 +454,24 @@ TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream, int timeout */ #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); } @@ -574,7 +502,7 @@ TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream, int timeout 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; @@ -587,7 +515,7 @@ TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream, int timeout * 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 */ @@ -661,7 +589,7 @@ TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream, int timeout } 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)) diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c index 2828f3008..03976abc7 100644 --- a/postfix/src/tls/tls_misc.c +++ b/postfix/src/tls/tls_misc.c @@ -82,7 +82,6 @@ * 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 */ diff --git a/postfix/src/tls/tls_server.c b/postfix/src/tls/tls_server.c index 5b8efba5d..d71955eab 100644 --- a/postfix/src/tls/tls_server.c +++ b/postfix/src/tls/tls_server.c @@ -191,28 +191,6 @@ static SSL_SESSION *get_server_session_cb(SSL *unused_ssl, 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) @@ -243,6 +221,7 @@ 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); } @@ -425,6 +404,13 @@ SSL_CTX *tls_server_init(int unused_verifydepth, int askcert) /* * 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) { @@ -432,7 +418,6 @@ SSL_CTX *tls_server_init(int unused_verifydepth, int askcert) 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); } /* @@ -474,14 +459,13 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream, * 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; @@ -490,14 +474,14 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream, 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); } @@ -528,7 +512,7 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream, msg_info("Could not obtain BIO_pair"); tls_print_errors(); SSL_free(TLScontext->con); - myfree((char *) TLScontext); + FREE_TLS_CONTEXT(TLScontext); return (0); } @@ -577,7 +561,7 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream, 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 */ @@ -622,7 +606,6 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream, 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, @@ -672,7 +655,7 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream, 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); } } diff --git a/postfix/src/tls/tls_session.c b/postfix/src/tls/tls_session.c index 1c319dd21..8ffe56923 100644 --- a/postfix/src/tls/tls_session.c +++ b/postfix/src/tls/tls_session.c @@ -113,7 +113,7 @@ void tls_session_stop(SSL_CTX *ctx, VSTREAM *stream, int timeout, 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));