---
 modules/ssl/mod_ssl.c     |   59 ++++++++++++++++++++++++++++++++++++++--------
 modules/ssl/ssl_private.h |    7 ++++-
 modules/ssl/ssl_util.c    |   51 +++++++++++++++++++++++++++++++++++++--
 3 files changed, 104 insertions(+), 13 deletions(-)

--- a/modules/ssl/mod_ssl.c
+++ b/modules/ssl/mod_ssl.c
@@ -30,9 +30,12 @@
 #include "util_md5.h"
 #include "util_mutex.h"
 #include "ap_provider.h"
+#include "http_config.h"
 
 #include <assert.h>
 
+static int modssl_running_statically = 0;
+
 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, pre_handshake,
                                     (conn_rec *c,SSL *ssl,int is_proxy),
                                     (c,ssl,is_proxy), OK, DECLINED);
@@ -297,22 +300,47 @@
 /*
  *  the various processing hooks
  */
+static int modssl_is_prelinked(void)
+{
+	apr_size_t i = 0;
+	const module *mod;
+	while ((mod = ap_prelinked_modules[i++])) {
+		if (strcmp(mod->name, "mod_ssl.c") == 0) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
 static apr_status_t ssl_cleanup_pre_config(void *data)
 {
     /*
      * Try to kill the internals of the SSL library.
      */
-    /* Corresponds to OPENSSL_load_builtin_modules():
-     * XXX: borrowed from apps.h, but why not CONF_modules_free()
-     * which also invokes CONF_modules_finish()?
-     */
-    CONF_modules_unload(1);
+#ifdef HAVE_FIPS
+	FIPS_mode_set(0);
+#endif
+	/* Corresponds to OBJ_create()s */
+	OBJ_cleanup();
+	/* Corresponds to OPENSSL_load_builtin_modules() */
+	CONF_modules_free();
     /* Corresponds to SSL_library_init: */
     EVP_cleanup();
 #if HAVE_ENGINE_LOAD_BUILTIN_ENGINES
     ENGINE_cleanup();
 #endif
-    ERR_remove_state(0);
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+	SSL_COMP_free_compression_methods();
+#endif
+
+	/* Usually needed per thread, but this parent process is single-threaded */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
+	ERR_remove_thread_state(NULL);
+#else
+	ERR_remove_state(0);
+#endif
+#endif
 
     /* Don't call ERR_free_strings in earlier versions, ERR_load_*_strings only
      * actually loaded the error strings once per process due to static
@@ -321,11 +349,14 @@
     ERR_free_strings();
 #endif
 
-    /* Also don't call CRYPTO_cleanup_all_ex_data here; any registered
-     * ex_data indices may have been cached in static variables in
-     * OpenSSL; removing them may cause havoc.  Notably, with OpenSSL
+    /* Also don't call CRYPTO_cleanup_all_ex_data when linked statically here;
+     * any registered ex_data indices may have been cached in static variables
+     * in OpenSSL; removing them may cause havoc.  Notably, with OpenSSL
      * versions >= 0.9.8f, COMP_CTX cleanups would not be run, which
      * could result in a per-connection memory leak (!). */
+	if (!modssl_running_statically) {
+		CRYPTO_cleanup_all_ex_data();
+	}
 
     /*
      * TODO: determine somewhere we can safely shove out diagnostics
@@ -339,6 +370,13 @@
                                apr_pool_t *plog,
                                apr_pool_t *ptemp)
 {
+	modssl_running_statically = modssl_is_prelinked();
+
+	/* Some OpenSSL internals are allocated per-thread, make sure they
+	 * are associated to the/our same thread-id until cleaned up.
+	 */
+	ssl_util_thread_id_setup(pconf);
+
     /* We must register the library in full, to ensure our configuration
      * code can successfully test the SSL environment.
      */
@@ -357,6 +395,9 @@
                          "SRVName otherName form");
     }
 
+	/* Start w/o errors (e.g. OBJ_txt2nid() above) */
+	ERR_clear_error();
+
     /*
      * Let us cleanup the ssl library when the module is unloaded
      */
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -882,7 +882,12 @@
 char        *ssl_util_readfilter(server_rec *, apr_pool_t *, const char *,
                                  const char * const *);
 BOOL         ssl_util_path_check(ssl_pathcheck_t, const char *, apr_pool_t *);
-void         ssl_util_thread_setup(apr_pool_t *);
+#if APR_HAS_THREADS
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+void		 ssl_util_thread_setup(apr_pool_t *);
+#endif
+void         ssl_util_thread_id_setup(apr_pool_t *);
+#endif
 int          ssl_init_ssl_connection(conn_rec *c, request_rec *r);
 
 BOOL         ssl_util_vhost_matches(const char *servername, server_rec *s);
--- a/modules/ssl/ssl_util.c
+++ b/modules/ssl/ssl_util.c
@@ -247,6 +247,7 @@
 }
 
 #if APR_HAS_THREADS
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 /*
  * To ensure thread-safetyness in OpenSSL - work in progress
  */
@@ -362,6 +363,33 @@
     apr_pool_destroy(l->pool);
 }
 
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+
+static void ssl_util_thr_id(CRYPTO_THREADID *id)
+{
+    /* OpenSSL needs this to return an unsigned long.  On OS/390, the pthread
+     * id is a structure twice that big.  Use the TCB pointer instead as a
+     * unique unsigned long.
+     */
+#ifdef __MVS__
+    struct PSA {
+        char unmapped[540]; /* PSATOLD is at offset 540 in the PSA */
+        unsigned long PSATOLD;
+    } *psaptr = 0; /* PSA is at address 0 */
+
+    CRYPTO_THREADID_set_numeric(id, psaptr->PSATOLD);
+#else
+    CRYPTO_THREADID_set_numeric(id, (unsigned long) apr_os_thread_current());
+#endif
+}
+static apr_status_t ssl_util_thr_id_cleanup(void *old)
+{
+	CRYPTO_THREADID_set_callback(old);
+	return APR_SUCCESS;
+}
+
+#else
+
 static unsigned long ssl_util_thr_id(void)
 {
     /* OpenSSL needs this to return an unsigned long.  On OS/390, the pthread
@@ -380,10 +408,17 @@
 #endif
 }
 
+static apr_status_t ssl_util_thr_id_cleanup(void *old)
+{
+    CRYPTO_set_id_callback(old);
+    return APR_SUCCESS;
+}
+
+#endif
+
 static apr_status_t ssl_util_thread_cleanup(void *data)
 {
     CRYPTO_set_locking_callback(NULL);
-    CRYPTO_set_id_callback(NULL);
 
     CRYPTO_set_dynlock_create_callback(NULL);
     CRYPTO_set_dynlock_lock_callback(NULL);
@@ -407,8 +442,6 @@
         apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
     }
 
-    CRYPTO_set_id_callback(ssl_util_thr_id);
-
     CRYPTO_set_locking_callback(ssl_util_thr_lock);
 
     /* Set up dynamic locking scaffolding for OpenSSL to use at its
@@ -422,4 +455,16 @@
     apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
                                        apr_pool_cleanup_null);
 }
+
+void ssl_util_thread_id_setup(apr_pool_t *p)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+	CRYPTO_THREADID_set_callback(ssl_util_thr_id);
+#else
+	CRYPTO_set_id_callback(ssl_util_thr_id);
 #endif
+	apr_pool_cleanup_register(p, NULL, ssl_util_thr_id_cleanup,
+									   apr_pool_cleanup_null);
+}
+#endif /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */
+#endif /* #if APR_HAS_THREADS */
