diff options
-rw-r--r-- | modules/ssl/config.m4 | 128 | ||||
-rw-r--r-- | modules/ssl/mod_ssl.c | 30 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_config.c | 8 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_mutex.c | 4 | ||||
-rw-r--r-- | modules/ssl/ssl_private.h | 93 | ||||
-rw-r--r-- | modules/ssl/ssl_scache.c | 4 | ||||
-rw-r--r-- | modules/ssl/ssl_scache_dbm.c | 465 | ||||
-rw-r--r-- | modules/ssl/ssl_scache_dc.c | 188 | ||||
-rw-r--r-- | modules/ssl/ssl_scache_memcache.c | 306 | ||||
-rw-r--r-- | modules/ssl/ssl_scache_shmcb.c | 833 |
10 files changed, 11 insertions, 2048 deletions
diff --git a/modules/ssl/config.m4 b/modules/ssl/config.m4 index f95e1d4b27..841dbf1f61 100644 --- a/modules/ssl/config.m4 +++ b/modules/ssl/config.m4 @@ -13,128 +13,6 @@ dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. -AC_DEFUN([CHECK_DISTCACHE], [ - AC_MSG_CHECKING(whether Distcache is required) - ap_ssltk_dc="no" - tmp_nomessage="" - tmp_forced="no" - AC_ARG_ENABLE(distcache, - APACHE_HELP_STRING(--enable-distcache,Select distcache support in mod_ssl), - ap_ssltk_dc="$enableval" - tmp_nomessage="" - tmp_forced="yes" - if test "x$ap_ssltk_dc" = "x"; then - ap_ssltk_dc="yes" - dnl our "error"s become "tests revealed that..." - tmp_forced="no" - fi - if test "$ap_ssltk_dc" != "yes" -a "$ap_ssltk_dc" != "no"; then - tmp_nomessage="--enable-distcache had illegal syntax - disabling" - ap_ssltk_dc="no" - fi) - if test "$tmp_forced" = "no"; then - AC_MSG_RESULT($ap_ssltk_dc (default)) - else - AC_MSG_RESULT($ap_ssltk_dc (specified)) - fi - if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno" -a "x$tmp_nomessage" != "x"; then - AC_MSG_ERROR(distcache support failed: $tmp_nomessage) - fi - if test "$ap_ssltk_dc" = "yes"; then - AC_CHECK_HEADER( - [distcache/dc_client.h], - [], - [tmp_nomessage="can't include distcache headers" - ap_ssltk_dc="no"]) - if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno"; then - AC_MSG_ERROR(distcache support failed: $tmp_nomessage) - fi - fi - if test "$ap_ssltk_dc" = "yes"; then - AC_MSG_CHECKING(for Distcache version) - AC_TRY_COMPILE( -[#include <distcache/dc_client.h>], -[#if DISTCACHE_CLIENT_API != 0x0001 -#error "distcache API version is unrecognised" -#endif], -[], -[tmp_nomessage="distcache has an unsupported API version" -ap_ssltk_dc="no"]) - AC_MSG_RESULT($ap_ssltk_dc) - if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno"; then - AC_MSG_ERROR(distcache support failed: $tmp_nomessage) - fi - fi - if test "$ap_ssltk_dc" = "yes"; then - AC_MSG_CHECKING(for Distcache libraries) - save_libs=$LIBS - LIBS="$LIBS -ldistcache -lnal" - AC_TRY_LINK( - [#include <distcache/dc_client.h>], - [DC_CTX *foo = DC_CTX_new((const char *)0,0);], - [], - [tmp_no_message="failed to link with distcache libraries" - ap_ssltk_dc="no"]) - LIBS=$save_libs - AC_MSG_RESULT($ap_ssltk_dc) - if test "$tmp_forced" = "yes" -a "x$ap_ssltk_dc" = "xno"; then - AC_MSG_ERROR(distcache support failed: $tmp_nomessage) - else - APR_ADDTO(MOD_SSL_LDADD, [-ldistcache -lnal]) - AC_DEFINE(HAVE_DISTCACHE, 1, [Define if distcache support is enabled]) - fi - fi -]) - - - -AC_DEFUN([CHECK_SSL_MEMCACHE], [ - AC_MSG_CHECKING(for ssl session caching in memcache) - ap_ssltk_mc="no" - tmp_nomessage="" - tmp_forced="no" - AC_ARG_ENABLE(ssl-memcache, - APACHE_HELP_STRING(--enable-ssl-memcache,Select memcache support in mod_ssl), - ap_ssltk_mc="$enableval" - tmp_nomessage="" - tmp_forced="yes" - if test "x$ap_ssltk_mc" = "x"; then - ap_ssltk_mc="yes" - dnl our "error"s become "tests revealed that..." - tmp_forced="no" - fi - if test "$ap_ssltk_mc" != "yes" -a "$ap_ssltk_mc" != "no"; then - tmp_nomessage="--enable-ssl-cache-memcache had illegal syntax - disabling" - ap_ssltk_mc="no" - fi) - if test "$tmp_forced" = "no"; then - AC_MSG_RESULT($ap_ssltk_mc (default)) - else - AC_MSG_RESULT($ap_ssltk_mc (specified)) - fi - if test "$tmp_forced" = "yes" -a "x$ap_ssltk_mc" = "xno" -a "x$tmp_nomessage" != "x"; then - AC_MSG_ERROR(ssl memcache support failed: $tmp_nomessage) - fi - if test "$ap_ssltk_mc" = "yes"; then - save_cpp=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $APR_INCLUDES $APU_INCLUDES" - AC_CHECK_HEADER( - [apr_memcache.h], - [], - [tmp_nomessage="can't include apr_memcache headers" - ap_ssltk_mc="no"]) - - CPPFLAGS=$save_cpp - - if test "$tmp_forced" = "yes" -a "x$ap_ssltk_mc" = "xno"; then - AC_MSG_ERROR(ssl memcache support failed: $tmp_nomessage) - fi - fi - if test "$ap_ssltk_mc" = "yes"; then - AC_DEFINE(HAVE_SSL_CACHE_MEMCACHE, 1, [Define if ssl-memcache support is enabled]) - fi -]) - AC_DEFUN([CHECK_OCSP], [ AC_CHECK_HEADERS(openssl/ocsp.h, [AC_DEFINE([HAVE_OCSP], 1, [Define if OCSP is supported by OpenSSL])] @@ -162,10 +40,6 @@ ssl_expr_eval.lo dnl ssl_expr_parse.lo dnl ssl_expr_scan.lo dnl ssl_scache.lo dnl -ssl_scache_dbm.lo dnl -ssl_scache_shmcb.lo dnl -ssl_scache_dc.lo dnl -ssl_scache_memcache.lo dnl ssl_util.lo dnl ssl_util_ssl.lo dnl ssl_engine_ocsp.lo dnl @@ -175,8 +49,6 @@ dnl # hook module into the Autoconf mechanism (--enable-ssl option) APACHE_MODULE(ssl, [SSL/TLS support (mod_ssl)], $ssl_objs, , no, [ APACHE_CHECK_SSL_TOOLKIT APR_SETVAR(MOD_SSL_LDADD, [\$(SSL_LIBS)]) - CHECK_DISTCACHE - CHECK_SSL_MEMCACHE CHECK_OCSP if test "x$enable_ssl" = "xshared"; then # The only symbol which needs to be exported is the module diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 379c827471..43d031d884 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -454,34 +454,6 @@ static int ssl_hook_pre_connection(conn_rec *c, void *csd) return ssl_init_ssl_connection(c, NULL); } -/* Register all session cache providers. */ -static void modssl_register_scache(apr_pool_t *p) -{ - /* shmcb is a cache of many names. */ - ap_register_provider(p, MODSSL_SESSCACHE_PROVIDER_GROUP, "shmcb", - MODSSL_SESSCACHE_PROVIDER_VERSION, - &modssl_sesscache_shmcb); - ap_register_provider(p, MODSSL_SESSCACHE_PROVIDER_GROUP, "shmht", - MODSSL_SESSCACHE_PROVIDER_VERSION, - &modssl_sesscache_shmcb); - ap_register_provider(p, MODSSL_SESSCACHE_PROVIDER_GROUP, "shm", - MODSSL_SESSCACHE_PROVIDER_VERSION, - &modssl_sesscache_shmcb); - ap_register_provider(p, MODSSL_SESSCACHE_PROVIDER_GROUP, "dbm", - MODSSL_SESSCACHE_PROVIDER_VERSION, - &modssl_sesscache_dbm); -#ifdef HAVE_DISTCACHE - ap_register_provider(p, MODSSL_SESSCACHE_PROVIDER_GROUP, "dc", - MODSSL_SESSCACHE_PROVIDER_VERSION, - &modssl_sesscache_dc); -#endif -#ifdef HAVE_SSL_CACHE_MEMCACHE - ap_register_provider(p, MODSSL_SESSCACHE_PROVIDER_GROUP, "mc", - MODSSL_SESSCACHE_PROVIDER_VERSION, - &modssl_sesscache_mc); -#endif -} - /* * the module registration phase */ @@ -512,8 +484,6 @@ static void ssl_register_hooks(apr_pool_t *p) ssl_var_register(p); - modssl_register_scache(p); - APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); } diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 18acb83c77..1a9ed212eb 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -985,9 +985,9 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, char *name = apr_pstrmemdup(cmd->pool, arg, sep - arg); /* Find the provider of given name. */ - mc->sesscache = ap_lookup_provider(MODSSL_SESSCACHE_PROVIDER_GROUP, + mc->sesscache = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP, name, - MODSSL_SESSCACHE_PROVIDER_VERSION); + AP_SOCACHE_PROVIDER_VERSION); if (mc->sesscache) { /* Cache found; create it, passing anything beyond the colon. */ mc->sesscache_mode = enabled_flags; @@ -1001,8 +1001,8 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, /* Build a comma-separated list of all registered provider * names: */ name_list = ap_list_provider_names(cmd->pool, - MODSSL_SESSCACHE_PROVIDER_GROUP, - MODSSL_SESSCACHE_PROVIDER_VERSION); + AP_SOCACHE_PROVIDER_GROUP, + AP_SOCACHE_PROVIDER_VERSION); all_names = apr_array_pstrcat(cmd->pool, name_list, ','); err = apr_psprintf(cmd->pool, "'%s' session cache not supported " diff --git a/modules/ssl/ssl_engine_mutex.c b/modules/ssl/ssl_engine_mutex.c index 649c324311..533a25289d 100644 --- a/modules/ssl/ssl_engine_mutex.c +++ b/modules/ssl/ssl_engine_mutex.c @@ -43,7 +43,7 @@ int ssl_mutex_init(server_rec *s, apr_pool_t *p) * the provider used is not internally multi-process/thread * safe. */ if (!mc->sesscache - || (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) == 0) { + || (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) == 0) { return TRUE; } @@ -88,7 +88,7 @@ int ssl_mutex_reinit(server_rec *s, apr_pool_t *p) apr_status_t rv; if (mc->nMutexMode == SSL_MUTEXMODE_NONE || !mc->sesscache - || (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) == 0) { + || (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) == 0) { return TRUE; } diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index a28471403a..1bbbcb2ab9 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -48,11 +48,9 @@ #include "apr_lib.h" #include "apr_fnmatch.h" #include "apr_strings.h" -#include "apr_dbm.h" -#include "apr_rmm.h" -#include "apr_shm.h" #include "apr_global_mutex.h" #include "apr_optional.h" +#include "ap_socache.h" #define MOD_SSL_VERSION AP_SERVER_BASEREVISION @@ -159,25 +157,6 @@ typedef enum { #define SSL_MM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) /** - * Support for DBM library - */ -#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) - -#if !defined(SSL_DBM_FILE_SUFFIX_DIR) && !defined(SSL_DBM_FILE_SUFFIX_PAG) -#if defined(DBM_SUFFIX) -#define SSL_DBM_FILE_SUFFIX_DIR DBM_SUFFIX -#define SSL_DBM_FILE_SUFFIX_PAG DBM_SUFFIX -#elif defined(__FreeBSD__) || (defined(DB_LOCK) && defined(DB_SHMEM)) -#define SSL_DBM_FILE_SUFFIX_DIR ".db" -#define SSL_DBM_FILE_SUFFIX_PAG ".db" -#else -#define SSL_DBM_FILE_SUFFIX_DIR ".dir" -#define SSL_DBM_FILE_SUFFIX_PAG ".pag" -#endif -#endif - - -/** * Define the certificate algorithm types */ @@ -351,59 +330,6 @@ typedef struct { int non_ssl_request; } SSLConnRec; -#define MODSSL_SESSCACHE_PROVIDER_GROUP "mod_ssl-sesscache" -#define MODSSL_SESSCACHE_PROVIDER_VERSION "0" - -/* If this flag is set, the store/retrieve/delete/status interfaces of - * the provider are NOT safe to be called concurrently from multiple - * processes or threads, and an external global mutex must be used to - * serialize access to the provider. */ -#define MODSSL_SESSCACHE_FLAG_NOTMPSAFE (0x0001) - -/* Session cache provider vtable. */ -typedef struct { - /* Canonical provider name: */ - const char *name; - - /* Bitmask of MODSSL_SESSCACHE_FLAG_* flags: */ - unsigned int flags; - - /* Create a session cache based on the given configuration string - * ARG. Returns NULL on success, or an error string on failure. - * Pool TMP should be used for any temporary allocations, pool P - * should be used for any allocations lasting as long as the - * lifetime of the return context. - * - * The context pointer returned in *CONTEXT will be passed as the - * first argument to subsequent invocations. */ - const char *(*create)(void **context, const char *arg, - apr_pool_t *tmp, apr_pool_t *p); - /* Initialize the cache. Return APR error code. */ - apr_status_t (*init)(void *context, server_rec *s, apr_pool_t *pool); - /* Destroy a given cache context. */ - void (*destroy)(void *context, server_rec *s); - /* Store an object in the cache. */ - apr_status_t (*store)(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - time_t expiry, - unsigned char *data, unsigned int datalen); - /* Retrieve cached data with key ID of length IDLEN, - * returning TRUE on success or FALSE otherwise. If - * TRUE, the data must be placed in DEST, which has length - * on entry of *DESTLEN. *DESTLEN must be updated to - * equal the length of data written on exit. */ - apr_status_t (*retrieve)(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - unsigned char *dest, unsigned int *destlen, - apr_pool_t *pool); - /* Remove an object from the cache. */ - void (*delete)(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - apr_pool_t *pool); - /* Dump cache status for mod_status output. */ - void (*status)(void *context, request_rec *r, int flags); -} modssl_sesscache_provider; - typedef struct { pid_t pid; apr_pool_t *pPool; @@ -414,8 +340,8 @@ typedef struct { /* The configured provider, and associated private data * structure. */ - const modssl_sesscache_provider *sesscache; - void *sesscache_context; + const ap_socache_provider_t *sesscache; + ap_socache_instance_t *sesscache_context; ssl_mutexmode_t nMutexMode; apr_lockmech_e nMutexMech; @@ -638,17 +564,6 @@ SSL_SESSION *ssl_scache_retrieve(server_rec *, UCHAR *, int, apr_pool_t *); void ssl_scache_remove(server_rec *, UCHAR *, int, apr_pool_t *); -extern const modssl_sesscache_provider modssl_sesscache_shmcb; -extern const modssl_sesscache_provider modssl_sesscache_dbm; - -#ifdef HAVE_DISTCACHE -extern const modssl_sesscache_provider modssl_sesscache_dc; -#endif - -#ifdef HAVE_SSL_CACHE_MEMCACHE -extern const modssl_sesscache_provider modssl_sesscache_mc; -#endif - /** Proxy Support */ int ssl_proxy_enable(conn_rec *c); int ssl_engine_disable(conn_rec *c); @@ -732,8 +647,6 @@ apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer, const cha void ssl_var_log_config_register(apr_pool_t *p); -#define APR_SHM_MAXSIZE (64 * 1024 * 1024) - #ifdef HAVE_OCSP /* Perform OCSP validation of the current cert in the given context. * Returns non-zero on success or zero on failure. On failure, the diff --git a/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c index d096b7b929..120ef0a027 100644 --- a/modules/ssl/ssl_scache.c +++ b/modules/ssl/ssl_scache.c @@ -151,13 +151,13 @@ void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen, { SSLModConfigRec *mc = myModConfig(s); - if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) { + if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(s); } mc->sesscache->delete(mc->sesscache_context, s, id, idlen, p); - if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) { + if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(s); } } diff --git a/modules/ssl/ssl_scache_dbm.c b/modules/ssl/ssl_scache_dbm.c deleted file mode 100644 index bbed2fb89a..0000000000 --- a/modules/ssl/ssl_scache_dbm.c +++ /dev/null @@ -1,465 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* _ _ - * _ __ ___ ___ __| | ___ ___| | mod_ssl - * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL - * | | | | | | (_) | (_| | \__ \__ \ | - * |_| |_| |_|\___/ \__,_|___|___/___/_| - * |_____| - * ssl_scache_dbm.c - * Session Cache via DBM - */ - -#include "ssl_private.h" - -/* Use of the context structure must be thread-safe after the initial - * create/init; callers must hold the mutex. */ -struct context { - const char *data_file; - /* Pool must only be used with the mutex held. */ - apr_pool_t *pool; - time_t last_expiry; -}; - -static void ssl_scache_dbm_expire(struct context *ctx, server_rec *s); - -static void ssl_scache_dbm_remove(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - apr_pool_t *p); - -static const char *ssl_scache_dbm_create(void **context, const char *arg, - apr_pool_t *tmp, apr_pool_t *p) -{ - struct context *ctx; - - *context = ctx = apr_pcalloc(p, sizeof *ctx); - - ctx->data_file = ap_server_root_relative(p, arg); - if (!ctx->data_file) { - return apr_psprintf(tmp, "Invalid cache file path %s", arg); - } - - apr_pool_create(&ctx->pool, p); - - return NULL; -} - -static apr_status_t ssl_scache_dbm_init(void *context, server_rec *s, apr_pool_t *p) -{ - struct context *ctx = context; - apr_dbm_t *dbm; - apr_status_t rv; - - /* for the DBM we need the data file */ - if (ctx->data_file == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "SSLSessionCache required"); - return APR_EINVAL; - } - - /* open it once to create it and to make sure it _can_ be created */ - apr_pool_clear(ctx->pool); - - if ((rv = apr_dbm_open(&dbm, ctx->data_file, - APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctx->pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot create SSLSessionCache DBM file `%s'", - ctx->data_file); - return rv; - } - apr_dbm_close(dbm); - -#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) - /* - * We have to make sure the Apache child processes have access to - * the DBM file. But because there are brain-dead platforms where we - * cannot exactly determine the suffixes we try all possibilities. - */ - if (geteuid() == 0 /* is superuser */) { - chown(ctx->data_file, unixd_config.user_id, -1 /* no gid change */); - if (chown(apr_pstrcat(p, ctx->data_file, SSL_DBM_FILE_SUFFIX_DIR, NULL), - unixd_config.user_id, -1) == -1) { - if (chown(apr_pstrcat(p, ctx->data_file, ".db", NULL), - unixd_config.user_id, -1) == -1) - chown(apr_pstrcat(p, ctx->data_file, ".dir", NULL), - unixd_config.user_id, -1); - } - if (chown(apr_pstrcat(p, ctx->data_file, SSL_DBM_FILE_SUFFIX_PAG, NULL), - unixd_config.user_id, -1) == -1) { - if (chown(apr_pstrcat(p, ctx->data_file, ".db", NULL), - unixd_config.user_id, -1) == -1) - chown(apr_pstrcat(p, ctx->data_file, ".pag", NULL), - unixd_config.user_id, -1); - } - } -#endif - ssl_scache_dbm_expire(ctx, s); - - return APR_SUCCESS; -} - -static void ssl_scache_dbm_kill(void *context, server_rec *s) -{ - struct context *ctx = context; - - /* the correct way */ - unlink(apr_pstrcat(ctx->pool, ctx->data_file, SSL_DBM_FILE_SUFFIX_DIR, NULL)); - unlink(apr_pstrcat(ctx->pool, ctx->data_file, SSL_DBM_FILE_SUFFIX_PAG, NULL)); - /* the additional ways to be sure */ - unlink(apr_pstrcat(ctx->pool, ctx->data_file, ".dir", NULL)); - unlink(apr_pstrcat(ctx->pool, ctx->data_file, ".pag", NULL)); - unlink(apr_pstrcat(ctx->pool, ctx->data_file, ".db", NULL)); - unlink(ctx->data_file); - - return; -} - -static apr_status_t ssl_scache_dbm_store(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - time_t expiry, - unsigned char *ucaData, unsigned int nData) -{ - struct context *ctx = context; - apr_dbm_t *dbm; - apr_datum_t dbmkey; - apr_datum_t dbmval; - apr_status_t rv; - - /* be careful: do not try to store too much bytes in a DBM file! */ -#ifdef PAIRMAX - if ((idlen + nData) >= PAIRMAX) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "data size too large for DBM session cache: %d >= %d", - (idlen + nData), PAIRMAX); - return APR_ENOSPC; - } -#else - if ((idlen + nData) >= 950 /* at least less than approx. 1KB */) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "data size too large for DBM session cache: %d >= %d", - (idlen + nData), 950); - return APR_ENOSPC; - } -#endif - - /* create DBM key */ - dbmkey.dptr = (char *)id; - dbmkey.dsize = idlen; - - /* create DBM value */ - dbmval.dsize = sizeof(time_t) + nData; - dbmval.dptr = (char *)malloc(dbmval.dsize); - if (dbmval.dptr == NULL) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "malloc error creating DBM value"); - return APR_ENOMEM; - } - memcpy((char *)dbmval.dptr, &expiry, sizeof(time_t)); - memcpy((char *)dbmval.dptr+sizeof(time_t), ucaData, nData); - - /* and store it to the DBM file */ - apr_pool_clear(ctx->pool); - - if ((rv = apr_dbm_open(&dbm, ctx->data_file, - APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctx->pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot open SSLSessionCache DBM file `%s' for writing " - "(store)", - ctx->data_file); - free(dbmval.dptr); - return rv; - } - if ((rv = apr_dbm_store(dbm, dbmkey, dbmval)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot store SSL session to DBM file `%s'", - ctx->data_file); - apr_dbm_close(dbm); - free(dbmval.dptr); - return rv; - } - apr_dbm_close(dbm); - - /* free temporary buffers */ - free(dbmval.dptr); - - /* allow the regular expiring to occur */ - ssl_scache_dbm_expire(ctx, s); - - return APR_SUCCESS; -} - -static apr_status_t ssl_scache_dbm_retrieve(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - unsigned char *dest, unsigned int *destlen, - apr_pool_t *p) -{ - struct context *ctx = context; - apr_dbm_t *dbm; - apr_datum_t dbmkey; - apr_datum_t dbmval; - unsigned int nData; - time_t expiry; - time_t now; - apr_status_t rc; - - /* allow the regular expiring to occur */ - ssl_scache_dbm_expire(ctx, s); - - /* create DBM key and values */ - dbmkey.dptr = (char *)id; - dbmkey.dsize = idlen; - - /* and fetch it from the DBM file - * XXX: Should we open the dbm against r->pool so the cleanup will - * do the apr_dbm_close? This would make the code a bit cleaner. - */ - apr_pool_clear(ctx->pool); - if ((rc = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE, - SSL_DBM_FILE_MODE, ctx->pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, - "Cannot open SSLSessionCache DBM file `%s' for reading " - "(fetch)", - ctx->data_file); - return rc; - } - rc = apr_dbm_fetch(dbm, dbmkey, &dbmval); - if (rc != APR_SUCCESS) { - apr_dbm_close(dbm); - return rc; - } - if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(time_t)) { - apr_dbm_close(dbm); - return rc; - } - - /* parse resulting data */ - nData = dbmval.dsize-sizeof(time_t); - if (nData > *destlen) { - apr_dbm_close(dbm); - return APR_ENOSPC; - } - - *destlen = nData; - memcpy(&expiry, dbmval.dptr, sizeof(time_t)); - memcpy(dest, (char *)dbmval.dptr + sizeof(time_t), nData); - - apr_dbm_close(dbm); - - /* make sure the stuff is still not expired */ - now = time(NULL); - if (expiry <= now) { - ssl_scache_dbm_remove(context, s, id, idlen, p); - return APR_EGENERAL; - } - - return APR_SUCCESS; -} - -static void ssl_scache_dbm_remove(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - apr_pool_t *p) -{ - struct context *ctx = context; - apr_dbm_t *dbm; - apr_datum_t dbmkey; - apr_status_t rv; - - /* create DBM key and values */ - dbmkey.dptr = (char *)id; - dbmkey.dsize = idlen; - - /* and delete it from the DBM file */ - apr_pool_clear(ctx->pool); - - if ((rv = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE, - SSL_DBM_FILE_MODE, ctx->pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot open SSLSessionCache DBM file `%s' for writing " - "(delete)", - ctx->data_file); - return; - } - apr_dbm_delete(dbm, dbmkey); - apr_dbm_close(dbm); - - return; -} - -static void ssl_scache_dbm_expire(struct context *ctx, server_rec *s) -{ - SSLSrvConfigRec *sc = mySrvConfig(s); - apr_dbm_t *dbm; - apr_datum_t dbmkey; - apr_datum_t dbmval; - time_t tExpiresAt; - int nElements = 0; - int nDeleted = 0; - int bDelete; - apr_datum_t *keylist; - int keyidx; - int i; - time_t tNow; - apr_status_t rv; - - /* - * make sure the expiration for still not-accessed session - * cache entries is done only from time to time - */ - tNow = time(NULL); - - if (tNow < ctx->last_expiry + sc->session_cache_timeout) { - return; - } - - ctx->last_expiry = tNow; - - /* - * Here we have to be very carefully: Not all DBM libraries are - * smart enough to allow one to iterate over the elements and at the - * same time delete expired ones. Some of them get totally crazy - * while others have no problems. So we have to do it the slower but - * more safe way: we first iterate over all elements and remember - * those which have to be expired. Then in a second pass we delete - * all those expired elements. Additionally we reopen the DBM file - * to be really safe in state. - */ - -#define KEYMAX 1024 - - for (;;) { - /* allocate the key array in a memory sub pool */ - apr_pool_clear(ctx->pool); - - if ((keylist = apr_palloc(ctx->pool, sizeof(dbmkey)*KEYMAX)) == NULL) { - break; - } - - /* pass 1: scan DBM database */ - keyidx = 0; - if ((rv = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE, - SSL_DBM_FILE_MODE, ctx->pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot open SSLSessionCache DBM file `%s' for " - "scanning", - ctx->data_file); - break; - } - apr_dbm_firstkey(dbm, &dbmkey); - while (dbmkey.dptr != NULL) { - nElements++; - bDelete = FALSE; - apr_dbm_fetch(dbm, dbmkey, &dbmval); - if (dbmval.dsize <= sizeof(time_t) || dbmval.dptr == NULL) - bDelete = TRUE; - else { - memcpy(&tExpiresAt, dbmval.dptr, sizeof(time_t)); - if (tExpiresAt <= tNow) - bDelete = TRUE; - } - if (bDelete) { - if ((keylist[keyidx].dptr = apr_pmemdup(ctx->pool, dbmkey.dptr, dbmkey.dsize)) != NULL) { - keylist[keyidx].dsize = dbmkey.dsize; - keyidx++; - if (keyidx == KEYMAX) - break; - } - } - apr_dbm_nextkey(dbm, &dbmkey); - } - apr_dbm_close(dbm); - - /* pass 2: delete expired elements */ - if (apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE, - SSL_DBM_FILE_MODE, ctx->pool) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot re-open SSLSessionCache DBM file `%s' for " - "expiring", - ctx->data_file); - break; - } - for (i = 0; i < keyidx; i++) { - apr_dbm_delete(dbm, keylist[i]); - nDeleted++; - } - apr_dbm_close(dbm); - - if (keyidx < KEYMAX) - break; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Inter-Process Session Cache (DBM) Expiry: " - "old: %d, new: %d, removed: %d", - nElements, nElements-nDeleted, nDeleted); -} - -static void ssl_scache_dbm_status(void *context, request_rec *r, int flags) -{ - struct context *ctx = context; - apr_dbm_t *dbm; - apr_datum_t dbmkey; - apr_datum_t dbmval; - int nElem; - int nSize; - int nAverage; - apr_status_t rv; - - nElem = 0; - nSize = 0; - - apr_pool_clear(ctx->pool); - if ((rv = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE, - SSL_DBM_FILE_MODE, ctx->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "Cannot open SSLSessionCache DBM file `%s' for status " - "retrival", - ctx->data_file); - return; - } - /* - * XXX - Check the return value of apr_dbm_firstkey, apr_dbm_fetch - TBD - */ - apr_dbm_firstkey(dbm, &dbmkey); - for ( ; dbmkey.dptr != NULL; apr_dbm_nextkey(dbm, &dbmkey)) { - apr_dbm_fetch(dbm, dbmkey, &dbmval); - if (dbmval.dptr == NULL) - continue; - nElem += 1; - nSize += dbmval.dsize; - } - apr_dbm_close(dbm); - if (nSize > 0 && nElem > 0) - nAverage = nSize / nElem; - else - nAverage = 0; - ap_rprintf(r, "cache type: <b>DBM</b>, maximum size: <b>unlimited</b><br>"); - ap_rprintf(r, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize); - ap_rprintf(r, "average session size: <b>%d</b> bytes<br>", nAverage); - return; -} - -const modssl_sesscache_provider modssl_sesscache_dbm = { - "dbm", - MODSSL_SESSCACHE_FLAG_NOTMPSAFE, - ssl_scache_dbm_create, - ssl_scache_dbm_init, - ssl_scache_dbm_kill, - ssl_scache_dbm_store, - ssl_scache_dbm_retrieve, - ssl_scache_dbm_remove, - ssl_scache_dbm_status -}; diff --git a/modules/ssl/ssl_scache_dc.c b/modules/ssl/ssl_scache_dc.c deleted file mode 100644 index 086fd41bb9..0000000000 --- a/modules/ssl/ssl_scache_dc.c +++ /dev/null @@ -1,188 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* _ _ - * _ __ ___ ___ __| | ___ ___| | mod_ssl - * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL - * | | | | | | (_) | (_| | \__ \__ \ | - * |_| |_| |_|\___/ \__,_|___|___/___/_| - * |_____| - * ssl_scache_dc.c - * Distributed Session Cache (client support) - */ - -#include "ssl_private.h" - -/* Only build this code if it's enabled at configure-time. */ -#ifdef HAVE_DISTCACHE - -#include "distcache/dc_client.h" - -#if !defined(DISTCACHE_CLIENT_API) || (DISTCACHE_CLIENT_API < 0x0001) -#error "You must compile with a more recent version of the distcache-base package" -#endif - -/* - * This cache implementation allows modssl to access 'distcache' servers (or - * proxies) to facilitate distributed session caching. It is based on code - * released as open source by Cryptographic Appliances Inc, and was developed by - * Geoff Thorpe, Steve Robb, and Chris Zimmerman. - */ - -/* -** -** High-Level "handlers" as per ssl_scache.c -** -*/ - -struct context { - /* Configured target server: */ - const char *target; - /* distcache client context: */ - DC_CTX *dc; -}; - -static const char *ssl_scache_dc_create(void **context, const char *arg, - apr_pool_t *tmp, apr_pool_t *p) -{ - struct context *ctx; - - ctx = *context = apr_palloc(p, sizeof *ctx); - - ctx->target = apr_pstrdup(p, arg); - - return NULL; -} - -static apr_status_t ssl_scache_dc_init(void *context, server_rec *s, apr_pool_t *p) -{ - struct context *ctx = ctx; - -#if 0 - /* If a "persistent connection" mode of operation is preferred, you *must* - * also use the PIDCHECK flag to ensure fork()'d processes don't interlace - * comms on the same connection as each other. */ -#define SESSION_CTX_FLAGS SESSION_CTX_FLAG_PERSISTENT | \ - SESSION_CTX_FLAG_PERSISTENT_PIDCHECK | \ - SESSION_CTX_FLAG_PERSISTENT_RETRY | \ - SESSION_CTX_FLAG_PERSISTENT_LATE -#else - /* This mode of operation will open a temporary connection to the 'target' - * for each cache operation - this makes it safe against fork() - * automatically. This mode is preferred when running a local proxy (over - * unix domain sockets) because overhead is negligable and it reduces the - * performance/stability danger of file-descriptor bloatage. */ -#define SESSION_CTX_FLAGS 0 -#endif - ctx->dc = DC_CTX_new(ctx->target, SESSION_CTX_FLAGS); - if (!ctx->dc) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache failed to obtain context"); - return APR_EGENERAL; - } - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "distributed scache context initialised"); - - return APR_SUCCESS; -} - -static void ssl_scache_dc_kill(void *context, server_rec *s) -{ - struct context *ctx = context; - - if (ctx && ctx->dc) { - DC_CTX_free(ctx->dc); - ctx->dc = NULL; - } -} - -static apr_status_t ssl_scache_dc_store(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - time_t timeout, - unsigned char *der, unsigned int der_len) -{ - struct context *ctx = context; - - /* !@#$%^ - why do we deal with *absolute* time anyway??? */ - timeout -= time(NULL); - /* Send the serialised session to the distributed cache context */ - if (!DC_CTX_add_session(ctx->dc, id, idlen, der, der_len, - (unsigned long)timeout * 1000)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'add_session' failed"); - return APR_EGENERAL; - } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'add_session' successful"); - return APR_SUCCESS; -} - -static apr_status_t ssl_scache_dc_retrieve(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - unsigned char *dest, unsigned int *destlen, - apr_pool_t *p) -{ - unsigned int data_len; - struct context *ctx = context; - - /* Retrieve any corresponding session from the distributed cache context */ - if (!DC_CTX_get_session(ctx->dc, id, idlen, dest, *destlen, &data_len)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' MISS"); - return APR_EGENERAL; - } - if (data_len > *destlen) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'get_session' OVERFLOW"); - return APR_ENOSPC; - } - *destlen = data_len; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "distributed scache 'get_session' HIT"); - return APR_SUCCESS; -} - -static void ssl_scache_dc_remove(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - apr_pool_t *p) -{ - struct context *ctx = context; - - /* Remove any corresponding session from the distributed cache context */ - if (!DC_CTX_remove_session(ctx->dc, id, idlen)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'remove_session' MISS"); - } else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'remove_session' HIT"); - } -} - -static void ssl_scache_dc_status(void *context, request_rec *r, int flags) -{ - struct context *ctx = context; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "distributed scache 'ssl_scache_dc_status'"); - ap_rprintf(r, "cache type: <b>DC (Distributed Cache)</b>, " - " target: <b>%s</b><br>", ctx->target); -} - -const modssl_sesscache_provider modssl_sesscache_dc = { - "distcache", - 0, - ssl_scache_dc_create, - ssl_scache_dc_init, - ssl_scache_dc_kill, - ssl_scache_dc_store, - ssl_scache_dc_retrieve, - ssl_scache_dc_remove, - ssl_scache_dc_status -}; - -#endif - diff --git a/modules/ssl/ssl_scache_memcache.c b/modules/ssl/ssl_scache_memcache.c deleted file mode 100644 index f542e07bfa..0000000000 --- a/modules/ssl/ssl_scache_memcache.c +++ /dev/null @@ -1,306 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -/* _ _ - * _ __ ___ ___ __| | ___ ___| | mod_ssl - * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL - * | | | | | | (_) | (_| | \__ \__ \ | - * |_| |_| |_|\___/ \__,_|___|___/___/_| - * |_____| - * ssl_scache_memcache.c - * Distributed Session Cache on top of memcached - */ - -#include "ssl_private.h" - -#ifdef HAVE_SSL_CACHE_MEMCACHE - -#include "apr_memcache.h" -#include "ap_mpm.h" - -/* - * SSL Session Caching using memcached as a backend. - */ - -/* -** -** High-Level "handlers" as per ssl_scache.c -** -*/ - - -/* The underlying apr_memcache system is thread safe.. */ -#define MC_TAG "mod_ssl:" -#define MC_TAG_LEN \ - (sizeof(MC_TAG)) - -#define MC_KEY_LEN 254 - -#ifndef MC_DEFAULT_SERVER_PORT -#define MC_DEFAULT_SERVER_PORT 11211 -#endif - - -#ifndef MC_DEFAULT_SERVER_MIN -#define MC_DEFAULT_SERVER_MIN 0 -#endif - -#ifndef MC_DEFAULT_SERVER_SMAX -#define MC_DEFAULT_SERVER_SMAX 1 -#endif - -#ifndef MC_DEFAULT_SERVER_TTL -#define MC_DEFAULT_SERVER_TTL 600 -#endif - -struct context { - const char *servers; - apr_memcache_t *mc; -}; - -static const char *ssl_scache_mc_create(void **context, const char *arg, - apr_pool_t *tmp, apr_pool_t *p) -{ - struct context *ctx; - - *context = ctx = apr_palloc(p, sizeof *ctx); - - ctx->servers = apr_pstrdup(p, arg); - - return NULL; -} - -static apr_status_t ssl_scache_mc_init(void *context, server_rec *s, apr_pool_t *p) -{ - apr_status_t rv; - int thread_limit = 0; - int nservers = 0; - char *cache_config; - char *split; - char *tok; - struct context *ctx = context; - - ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); - - /* Find all the servers in the first run to get a total count */ - cache_config = apr_pstrdup(p, ctx->servers); - split = apr_strtok(cache_config, ",", &tok); - while (split) { - nservers++; - split = apr_strtok(NULL,",", &tok); - } - - rv = apr_memcache_create(p, nservers, 0, &ctx->mc); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "SSLSessionCache: Failed to create Memcache Object of '%d' size.", - nservers); - return rv; - } - - /* Now add each server to the memcache */ - cache_config = apr_pstrdup(p, ctx->servers); - split = apr_strtok(cache_config, ",", &tok); - while (split) { - apr_memcache_server_t *st; - char *host_str; - char *scope_id; - apr_port_t port; - - rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "SSLSessionCache: Failed to Parse Server: '%s'", split); - return rv; - } - - if (host_str == NULL) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "SSLSessionCache: Failed to Parse Server, " - "no hostname specified: '%s'", split); - return APR_EINVAL; - } - - if (port == 0) { - port = MC_DEFAULT_SERVER_PORT; - } - - rv = apr_memcache_server_create(p, - host_str, port, - MC_DEFAULT_SERVER_MIN, - MC_DEFAULT_SERVER_SMAX, - thread_limit, - MC_DEFAULT_SERVER_TTL, - &st); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "SSLSessionCache: Failed to Create Server: %s:%d", - host_str, port); - return rv; - } - - rv = apr_memcache_add_server(ctx->mc, st); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "SSLSessionCache: Failed to Add Server: %s:%d", - host_str, port); - return rv; - } - - split = apr_strtok(NULL,",", &tok); - } - - return APR_SUCCESS; -} - -static void ssl_scache_mc_kill(void *context, server_rec *s) -{ - /* noop. */ -} - -static char *mc_session_id2sz(const unsigned char *id, unsigned int idlen, - char *str, int strsize) -{ - char *cp; - int n; - int maxlen = (strsize - MC_TAG_LEN)/2; - - cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN); - for (n = 0; n < idlen && n < maxlen; n++) { - apr_snprintf(cp, 3, "%02X", (unsigned) id[n]); - cp += 2; - } - - *cp = '\0'; - - return str; -} - -static apr_status_t ssl_scache_mc_store(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - time_t timeout, - unsigned char *ucaData, unsigned int nData) -{ - struct context *ctx = context; - char buf[MC_KEY_LEN]; - char *strkey = NULL; - apr_status_t rv; - - strkey = mc_session_id2sz(id, idlen, buf, sizeof(buf)); - if(!strkey) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "scache_mc: Key generation borked."); - return APR_EGENERAL; - } - - rv = apr_memcache_set(ctx->mc, strkey, (char*)ucaData, nData, timeout, 0); - - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "scache_mc: error setting key '%s' " - "with %d bytes of data", strkey, nData); - return rv; - } - - return APR_SUCCESS; -} - -static apr_status_t ssl_scache_mc_retrieve(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - unsigned char *dest, unsigned int *destlen, - apr_pool_t *p) -{ - struct context *ctx = context; - apr_size_t der_len; - char buf[MC_KEY_LEN], *der; - char *strkey = NULL; - apr_status_t rv; - - strkey = mc_session_id2sz(id, idlen, buf, sizeof(buf)); - - if (!strkey) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "scache_mc: Key generation borked."); - return APR_EGENERAL; - } - - /* ### this could do with a subpool, but _getp looks like it will - * eat memory like it's going out of fashion anyway. */ - - rv = apr_memcache_getp(ctx->mc, p, strkey, - &der, &der_len, NULL); - if (rv) { - if (rv != APR_NOTFOUND) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "scache_mc: 'get_session' FAIL"); - } - return rv; - } - else if (der_len > *destlen) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "scache_mc: 'get_session' OVERFLOW"); - return rv; - } - - memcpy(dest, der, der_len); - *destlen = der_len; - - return APR_SUCCESS; -} - -static void ssl_scache_mc_remove(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - apr_pool_t *p) -{ - struct context *ctx = context; - char buf[MC_KEY_LEN]; - char* strkey = NULL; - apr_status_t rv; - - strkey = mc_session_id2sz(id, idlen, buf, sizeof(buf)); - if(!strkey) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "scache_mc: Key generation borked."); - return; - } - - rv = apr_memcache_delete(ctx->mc, strkey, 0); - - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, - "scache_mc: error deleting key '%s' ", - strkey); - return; - } -} - -static void ssl_scache_mc_status(void *context, request_rec *r, int flags) -{ - /* SSLModConfigRec *mc = myModConfig(r->server); */ - /* TODO: Make a mod_status handler. meh. */ -} - -const modssl_sesscache_provider modssl_sesscache_mc = { - "memcache", - 0, - ssl_scache_mc_create, - ssl_scache_mc_init, - ssl_scache_mc_kill, - ssl_scache_mc_store, - ssl_scache_mc_retrieve, - ssl_scache_mc_remove, - ssl_scache_mc_status -}; -#endif diff --git a/modules/ssl/ssl_scache_shmcb.c b/modules/ssl/ssl_scache_shmcb.c deleted file mode 100644 index 6cf5f3fc0f..0000000000 --- a/modules/ssl/ssl_scache_shmcb.c +++ /dev/null @@ -1,833 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* _ _ - * _ __ ___ ___ __| | ___ ___| | mod_ssl - * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL - * | | | | | | (_) | (_| | \__ \__ \ | - * |_| |_| |_|\___/ \__,_|___|___/___/_| - * |_____| - * ssl_scache_shmcb.c - * Session Cache via Shared Memory (Cyclic Buffer Variant) - */ - -#include "ssl_private.h" - -/* - * This shared memory based SSL session cache implementation was - * originally written by Geoff Thorpe <geoff geoffthorpe.net> for C2Net - * Europe as a contribution to Ralf Engelschall's mod_ssl project. - * - * Since rewritten by GT to not use alignment-fudging memcpys and reduce - * complexity. - */ - -/* - * Header structure - the start of the shared-mem segment - */ -typedef struct { - /* Stats for cache operations */ - unsigned long stat_stores; - unsigned long stat_expiries; - unsigned long stat_scrolled; - unsigned long stat_retrieves_hit; - unsigned long stat_retrieves_miss; - unsigned long stat_removes_hit; - unsigned long stat_removes_miss; - /* Number of subcaches */ - unsigned int subcache_num; - /* How many indexes each subcache's queue has */ - unsigned int index_num; - /* How large each subcache is, including the queue and data */ - unsigned int subcache_size; - /* How far into each subcache the data area is (optimisation) */ - unsigned int subcache_data_offset; - /* How large the data area in each subcache is (optimisation) */ - unsigned int subcache_data_size; -} SHMCBHeader; - -/* - * Subcache structure - the start of each subcache, followed by - * indexes then data - */ -typedef struct { - /* The start position and length of the cyclic buffer of indexes */ - unsigned int idx_pos, idx_used; - /* Same for the data area */ - unsigned int data_pos, data_used; -} SHMCBSubcache; - -/* - * Index structure - each subcache has an array of these - */ -typedef struct { - /* absolute time this entry expires */ - time_t expires; - /* location within the subcache's data area */ - unsigned int data_pos; - /* size (most logic ignores this, we keep it only to minimise memcpy) */ - unsigned int data_used; - /* length of the used data which contains the id */ - unsigned int id_len; - /* Used to mark explicitly-removed sessions */ - unsigned char removed; -} SHMCBIndex; - -struct context { - const char *data_file; - apr_size_t shm_size; - apr_shm_t *shm; - SHMCBHeader *header; -}; - -/* The SHM data segment is of fixed size and stores data as follows. - * - * [ SHMCBHeader | Subcaches ] - * - * The SHMCBHeader header structure stores metadata concerning the - * cache and the contained subcaches. - * - * Subcaches is a hash table of header->subcache_num SHMCBSubcache - * structures. The hash table is indexed by SHMCB_MASK(id). Each - * SHMCBSubcache structure has a fixed size (header->subcache_size), - * which is determined at creation time, and looks like the following: - * - * [ SHMCBSubcache | Indexes | Data ] - * - * Each subcache is prefixed by the SHMCBSubcache structure. - * - * The subcache's "Data" segment is a single cyclic data buffer, of - * total size header->subcache_data_size; data inside is referenced - * using byte offsets. The offset marking the beginning of the cyclic - * buffer is subcache->data_pos the buffer's length is - * subcache->data_used. - * - * "Indexes" is an array of header->index_num SHMCBIndex structures, - * which is used as a cyclic queue; subcache->idx_pos gives the array - * index of the first in use, subcache->idx_used gives the number in - * use. Both ->idx_* values have a range of [0, header->index_num) - * - * Each in-use SHMCBIndex structure represents a single SSL session. - * The ID and data segment are stored consecutively in the subcache's - * cyclic data buffer. The "Data" segment can thus be seen to - * look like this, for example - * - * offset: [ 0 1 2 3 4 5 6 ... - * contents:[ ID1 Data1 ID2 Data2 ID3 ... - * - * where the corresponding indices would look like: - * - * idx1 = { data_pos = 0, data_used = 3, id_len = 1, ...} - * idx2 = { data_pos = 3, data_used = 3, id_len = 1, ...} - * ... - */ - -/* This macro takes a pointer to the header and a zero-based index and returns - * a pointer to the corresponding subcache. */ -#define SHMCB_SUBCACHE(pHeader, num) \ - (SHMCBSubcache *)(((unsigned char *)(pHeader)) + \ - sizeof(SHMCBHeader) + \ - (num) * ((pHeader)->subcache_size)) - -/* This macro takes a pointer to the header and a session id and returns a - * pointer to the corresponding subcache. */ -#define SHMCB_MASK(pHeader, id) \ - SHMCB_SUBCACHE((pHeader), *(id) & ((pHeader)->subcache_num - 1)) - -/* This macro takes the same params as the last, generating two outputs for use - * in ap_log_error(...). */ -#define SHMCB_MASK_DBG(pHeader, id) \ - *(id), (*(id) & ((pHeader)->subcache_num - 1)) - -/* This macro takes a pointer to a subcache and a zero-based index and returns - * a pointer to the corresponding SHMCBIndex. */ -#define SHMCB_INDEX(pSubcache, num) \ - ((SHMCBIndex *)(((unsigned char *)pSubcache) + \ - sizeof(SHMCBSubcache)) + num) - -/* This macro takes a pointer to the header and a subcache and returns a - * pointer to the corresponding data area. */ -#define SHMCB_DATA(pHeader, pSubcache) \ - ((unsigned char *)(pSubcache) + (pHeader)->subcache_data_offset) - -/* - * Cyclic functions - assists in "wrap-around"/modulo logic - */ - -/* Addition modulo 'mod' */ -#define SHMCB_CYCLIC_INCREMENT(val,inc,mod) \ - (((val) + (inc)) % (mod)) - -/* Subtraction (or "distance between") modulo 'mod' */ -#define SHMCB_CYCLIC_SPACE(val1,val2,mod) \ - ((val2) >= (val1) ? ((val2) - (val1)) : \ - ((val2) + (mod) - (val1))) - -/* A "normal-to-cyclic" memcpy. */ -static void shmcb_cyclic_ntoc_memcpy(unsigned int buf_size, unsigned char *data, - unsigned int dest_offset, const unsigned char *src, - unsigned int src_len) -{ - if (dest_offset + src_len < buf_size) - /* It be copied all in one go */ - memcpy(data + dest_offset, src, src_len); - else { - /* Copy the two splits */ - memcpy(data + dest_offset, src, buf_size - dest_offset); - memcpy(data, src + buf_size - dest_offset, - src_len + dest_offset - buf_size); - } -} - -/* A "cyclic-to-normal" memcpy. */ -static void shmcb_cyclic_cton_memcpy(unsigned int buf_size, unsigned char *dest, - const unsigned char *data, unsigned int src_offset, - unsigned int src_len) -{ - if (src_offset + src_len < buf_size) - /* It be copied all in one go */ - memcpy(dest, data + src_offset, src_len); - else { - /* Copy the two splits */ - memcpy(dest, data + src_offset, buf_size - src_offset); - memcpy(dest + buf_size - src_offset, data, - src_len + src_offset - buf_size); - } -} - -/* A memcmp against a cyclic data buffer. Compares SRC of length - * SRC_LEN against the contents of cyclic buffer DATA (which is of - * size BUF_SIZE), starting at offset DEST_OFFSET. Got that? Good. */ -static int shmcb_cyclic_memcmp(unsigned int buf_size, unsigned char *data, - unsigned int dest_offset, - const unsigned char *src, - unsigned int src_len) -{ - if (dest_offset + src_len < buf_size) - /* It be compared all in one go */ - return memcmp(data + dest_offset, src, src_len); - else { - /* Compare the two splits */ - int diff; - - diff = memcmp(data + dest_offset, src, buf_size - dest_offset); - if (diff) { - return diff; - } - return memcmp(data, src + buf_size - dest_offset, - src_len + dest_offset - buf_size); - } -} - - -/* Prototypes for low-level subcache operations */ -static void shmcb_subcache_expire(server_rec *, SHMCBHeader *, SHMCBSubcache *); -/* Returns zero on success, non-zero on failure. */ -static int shmcb_subcache_store(server_rec *s, SHMCBHeader *header, - SHMCBSubcache *subcache, - unsigned char *data, unsigned int data_len, - const unsigned char *id, unsigned int id_len, - time_t expiry); -/* Returns zero on success, non-zero on failure. */ -static int shmcb_subcache_retrieve(server_rec *, SHMCBHeader *, SHMCBSubcache *, - const unsigned char *id, unsigned int idlen, - unsigned char *data, unsigned int *datalen); -/* Returns zero on success, non-zero on failure. */ -static int shmcb_subcache_remove(server_rec *, SHMCBHeader *, SHMCBSubcache *, - const unsigned char *, unsigned int); - -/* - * High-Level "handlers" as per ssl_scache.c - * subcache internals are deferred to shmcb_subcache_*** functions lower down - */ - -static const char *ssl_scache_shmcb_create(void **context, const char *arg, - apr_pool_t *tmp, apr_pool_t *p) -{ - struct context *ctx; - char *path, *cp, *cp2; - - /* Allocate the context. */ - *context = ctx = apr_pcalloc(p, sizeof *ctx); - - ctx->data_file = path = ap_server_root_relative(p, arg); - ctx->shm_size = 1024*512; /* 512KB */ - - cp = strchr(path, '('); - if (cp) { - *cp++ = NUL; - - if (!(cp2 = strchr(cp, ')'))) { - return "Invalid argument: no closing parenthesis"; - } - - *cp2 = NUL; - - ctx->shm_size = atoi(cp); - - if (ctx->shm_size < 8192) { - return "Invalid argument: size has to be >= 8192 bytes"; - - } - - if (ctx->shm_size >= APR_SHM_MAXSIZE) { - return apr_psprintf(tmp, - "Invalid argument: size has " - "to be < %d bytes on this platform", - APR_SHM_MAXSIZE); - - } - } - - return NULL; -} - -static apr_status_t ssl_scache_shmcb_init(void *context, server_rec *s, apr_pool_t *p) -{ - void *shm_segment; - apr_size_t shm_segsize; - apr_status_t rv; - SHMCBHeader *header; - unsigned int num_subcache, num_idx, loop; - struct context *ctx = context; - - /* Create shared memory segment */ - if (ctx->data_file == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "SSLSessionCache required"); - return APR_EINVAL; - } - - /* Use anonymous shm by default, fall back on name-based. */ - rv = apr_shm_create(&ctx->shm, ctx->shm_size, NULL, p); - if (APR_STATUS_IS_ENOTIMPL(rv)) { - /* For a name-based segment, remove it first in case of a - * previous unclean shutdown. */ - apr_shm_remove(ctx->data_file, p); - - rv = apr_shm_create(&ctx->shm, ctx->shm_size, ctx->data_file, p); - } - - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "could not allocate shared memory for shmcb " - "session cache"); - return rv; - } - - shm_segment = apr_shm_baseaddr_get(ctx->shm); - shm_segsize = apr_shm_size_get(ctx->shm); - if (shm_segsize < (5 * sizeof(SHMCBHeader))) { - /* the segment is ridiculously small, bail out */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "shared memory segment too small"); - return APR_ENOSPC; - } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "shmcb_init allocated %" APR_SIZE_T_FMT - " bytes of shared memory", - shm_segsize); - /* Discount the header */ - shm_segsize -= sizeof(SHMCBHeader); - /* Select the number of subcaches to create and how many indexes each - * should contain based on the size of the memory (the header has already - * been subtracted). Typical non-client-auth sslv3/tlsv1 sessions are - * around 180 bytes (148 bytes data and 32 bytes for the id), so - * erring to division by 150 helps ensure we would exhaust data - * storage before index storage (except sslv2, where it's - * *slightly* the other way). From there, we select the number of - * subcaches to be a power of two, such that the number of indexes - * per subcache at least twice the number of subcaches. */ - num_idx = (shm_segsize) / 150; - num_subcache = 256; - while ((num_idx / num_subcache) < (2 * num_subcache)) - num_subcache /= 2; - num_idx /= num_subcache; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "for %" APR_SIZE_T_FMT " bytes (%" APR_SIZE_T_FMT - " including header), recommending %u subcaches, " - "%u indexes each", shm_segsize, - shm_segsize + sizeof(SHMCBHeader), num_subcache, num_idx); - if (num_idx < 5) { - /* we're still too small, bail out */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "shared memory segment too small"); - return APR_ENOSPC; - } - /* OK, we're sorted */ - ctx->header = header = shm_segment; - header->stat_stores = 0; - header->stat_expiries = 0; - header->stat_scrolled = 0; - header->stat_retrieves_hit = 0; - header->stat_retrieves_miss = 0; - header->stat_removes_hit = 0; - header->stat_removes_miss = 0; - header->subcache_num = num_subcache; - /* Convert the subcache size (in bytes) to a value that is suitable for - * structure alignment on the host platform, by rounding down if necessary. - * This assumes that sizeof(unsigned long) provides an appropriate - * alignment unit. */ - header->subcache_size = ((size_t)(shm_segsize / num_subcache) & - ~(size_t)(sizeof(unsigned long) - 1)); - header->subcache_data_offset = sizeof(SHMCBSubcache) + - num_idx * sizeof(SHMCBIndex); - header->subcache_data_size = header->subcache_size - - header->subcache_data_offset; - header->index_num = num_idx; - - /* Output trace info */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "shmcb_init_memory choices follow"); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "subcache_num = %u", header->subcache_num); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "subcache_size = %u", header->subcache_size); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "subcache_data_offset = %u", header->subcache_data_offset); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "subcache_data_size = %u", header->subcache_data_size); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "index_num = %u", header->index_num); - /* The header is done, make the caches empty */ - for (loop = 0; loop < header->subcache_num; loop++) { - SHMCBSubcache *subcache = SHMCB_SUBCACHE(header, loop); - subcache->idx_pos = subcache->idx_used = 0; - subcache->data_pos = subcache->data_used = 0; - } - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "Shared memory session cache initialised"); - /* Success ... */ - - return APR_SUCCESS; -} - -static void ssl_scache_shmcb_kill(void *context, server_rec *s) -{ - struct context *ctx = context; - - if (ctx && ctx->shm) { - apr_shm_destroy(ctx->shm); - ctx->shm = NULL; - } -} - -static apr_status_t ssl_scache_shmcb_store(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - time_t timeout, - unsigned char *encoded, - unsigned int len_encoded) -{ - struct context *ctx = context; - SHMCBHeader *header = ctx->header; - SHMCBSubcache *subcache = SHMCB_MASK(header, id); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "ssl_scache_shmcb_store (0x%02x -> subcache %d)", - SHMCB_MASK_DBG(header, id)); - if (idlen < 4) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " - "(%u bytes)", idlen); - return APR_EINVAL; - } - if (shmcb_subcache_store(s, header, subcache, encoded, - len_encoded, id, idlen, timeout)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "can't store a session!"); - return APR_ENOSPC; - } - header->stat_stores++; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "leaving ssl_scache_shmcb_store successfully"); - return APR_SUCCESS; -} - -static apr_status_t ssl_scache_shmcb_retrieve(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - unsigned char *dest, unsigned int *destlen, - apr_pool_t *p) -{ - struct context *ctx = context; - SHMCBHeader *header = ctx->header; - SHMCBSubcache *subcache = SHMCB_MASK(header, id); - int rv; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "ssl_scache_shmcb_retrieve (0x%02x -> subcache %d)", - SHMCB_MASK_DBG(header, id)); - - /* Get the session corresponding to the session_id, if it exists. */ - rv = shmcb_subcache_retrieve(s, header, subcache, id, idlen, - dest, destlen); - if (rv == 0) - header->stat_retrieves_hit++; - else - header->stat_retrieves_miss++; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "leaving ssl_scache_shmcb_retrieve successfully"); - - return rv == 0 ? APR_SUCCESS : APR_EGENERAL; -} - -static void ssl_scache_shmcb_remove(void *context, server_rec *s, - const unsigned char *id, unsigned int idlen, - apr_pool_t *p) -{ - struct context *ctx = context; - SHMCBHeader *header = ctx->header; - SHMCBSubcache *subcache = SHMCB_MASK(header, id); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "ssl_scache_shmcb_remove (0x%02x -> subcache %d)", - SHMCB_MASK_DBG(header, id)); - if (idlen < 4) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " - "(%u bytes)", idlen); - return; - } - if (shmcb_subcache_remove(s, header, subcache, id, idlen)) - header->stat_removes_hit++; - else - header->stat_removes_miss++; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "leaving ssl_scache_shmcb_remove successfully"); -} - -static void ssl_scache_shmcb_status(void *context, request_rec *r, int flags) -{ - server_rec *s = r->server; - struct context *ctx = context; - SHMCBHeader *header = ctx->header; - unsigned int loop, total = 0, cache_total = 0, non_empty_subcaches = 0; - time_t idx_expiry, min_expiry = 0, max_expiry = 0, average_expiry = 0; - time_t now = time(NULL); - double expiry_total = 0; - int index_pct, cache_pct; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "inside shmcb_status"); - /* Perform the iteration inside the mutex to avoid corruption or invalid - * pointer arithmetic. The rest of our logic uses read-only header data so - * doesn't need the lock. */ - /* Iterate over the subcaches */ - for (loop = 0; loop < header->subcache_num; loop++) { - SHMCBSubcache *subcache = SHMCB_SUBCACHE(header, loop); - shmcb_subcache_expire(s, header, subcache); - total += subcache->idx_used; - cache_total += subcache->data_used; - if (subcache->idx_used) { - SHMCBIndex *idx = SHMCB_INDEX(subcache, subcache->idx_pos); - non_empty_subcaches++; - idx_expiry = idx->expires; - expiry_total += (double)idx_expiry; - max_expiry = ((idx_expiry > max_expiry) ? idx_expiry : max_expiry); - if (!min_expiry) - min_expiry = idx_expiry; - else - min_expiry = ((idx_expiry < min_expiry) ? idx_expiry : min_expiry); - } - } - index_pct = (100 * total) / (header->index_num * - header->subcache_num); - cache_pct = (100 * cache_total) / (header->subcache_data_size * - header->subcache_num); - /* Generate HTML */ - ap_rprintf(r, "cache type: <b>SHMCB</b>, shared memory: <b>%" APR_SIZE_T_FMT "</b> " - "bytes, current sessions: <b>%d</b><br>", - ctx->shm_size, total); - ap_rprintf(r, "subcaches: <b>%d</b>, indexes per subcache: <b>%d</b><br>", - header->subcache_num, header->index_num); - if (non_empty_subcaches) { - average_expiry = (time_t)(expiry_total / (double)non_empty_subcaches); - ap_rprintf(r, "time left on oldest entries' SSL sessions: "); - if (now < average_expiry) - ap_rprintf(r, "avg: <b>%d</b> seconds, (range: %d...%d)<br>", - (int)(average_expiry - now), - (int)(min_expiry - now), - (int)(max_expiry - now)); - else - ap_rprintf(r, "expiry_threshold: <b>Calculation error!</b><br>"); - } - - ap_rprintf(r, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b><br>", - index_pct, cache_pct); - ap_rprintf(r, "total sessions stored since starting: <b>%lu</b><br>", - header->stat_stores); - ap_rprintf(r, "total sessions expired since starting: <b>%lu</b><br>", - header->stat_expiries); - ap_rprintf(r, "total (pre-expiry) sessions scrolled out of the cache: " - "<b>%lu</b><br>", header->stat_scrolled); - ap_rprintf(r, "total retrieves since starting: <b>%lu</b> hit, " - "<b>%lu</b> miss<br>", header->stat_retrieves_hit, - header->stat_retrieves_miss); - ap_rprintf(r, "total removes since starting: <b>%lu</b> hit, " - "<b>%lu</b> miss<br>", header->stat_removes_hit, - header->stat_removes_miss); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "leaving shmcb_status"); -} - -/* - * Subcache-level cache operations - */ - -static void shmcb_subcache_expire(server_rec *s, SHMCBHeader *header, - SHMCBSubcache *subcache) -{ - time_t now = time(NULL); - unsigned int loop = 0; - unsigned int new_idx_pos = subcache->idx_pos; - SHMCBIndex *idx = NULL; - - while (loop < subcache->idx_used) { - idx = SHMCB_INDEX(subcache, new_idx_pos); - if (idx->expires > now) - /* it hasn't expired yet, we're done iterating */ - break; - loop++; - new_idx_pos = SHMCB_CYCLIC_INCREMENT(new_idx_pos, 1, header->index_num); - } - if (!loop) - /* Nothing to do */ - return; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "will be expiring %u sessions", loop); - if (loop == subcache->idx_used) { - /* We're expiring everything, piece of cake */ - subcache->idx_used = 0; - subcache->data_used = 0; - } else { - /* There remain other indexes, so we can use idx to adjust 'data' */ - unsigned int diff = SHMCB_CYCLIC_SPACE(subcache->data_pos, - idx->data_pos, - header->subcache_data_size); - /* Adjust the indexes */ - subcache->idx_used -= loop; - subcache->idx_pos = new_idx_pos; - /* Adjust the data area */ - subcache->data_used -= diff; - subcache->data_pos = idx->data_pos; - } - header->stat_expiries += loop; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "we now have %u sessions", subcache->idx_used); -} - -static int shmcb_subcache_store(server_rec *s, SHMCBHeader *header, - SHMCBSubcache *subcache, - unsigned char *data, unsigned int data_len, - const unsigned char *id, unsigned int id_len, - time_t expiry) -{ - unsigned int data_offset, new_idx, id_offset; - SHMCBIndex *idx; - unsigned int total_len = id_len + data_len; - - /* Sanity check the input */ - if (total_len > header->subcache_data_size) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "inserting session larger (%d) than subcache data area (%d)", - total_len, header->subcache_data_size); - return -1; - } - - /* If there are entries to expire, ditch them first. */ - shmcb_subcache_expire(s, header, subcache); - - /* Loop until there is enough space to insert */ - if (header->subcache_data_size - subcache->data_used < total_len - || subcache->idx_used == header->index_num) { - unsigned int loop = 0; - - idx = SHMCB_INDEX(subcache, subcache->idx_pos); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "about to force-expire, subcache: idx_used=%d, " - "data_used=%d", subcache->idx_used, subcache->data_used); - do { - SHMCBIndex *idx2; - - /* Adjust the indexes by one */ - subcache->idx_pos = SHMCB_CYCLIC_INCREMENT(subcache->idx_pos, 1, - header->index_num); - subcache->idx_used--; - if (!subcache->idx_used) { - /* There's nothing left */ - subcache->data_used = 0; - break; - } - /* Adjust the data */ - idx2 = SHMCB_INDEX(subcache, subcache->idx_pos); - subcache->data_used -= SHMCB_CYCLIC_SPACE(idx->data_pos, idx2->data_pos, - header->subcache_data_size); - subcache->data_pos = idx2->data_pos; - /* Stats */ - header->stat_scrolled++; - /* Loop admin */ - idx = idx2; - loop++; - } while (header->subcache_data_size - subcache->data_used < total_len); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "finished force-expire, subcache: idx_used=%d, " - "data_used=%d", subcache->idx_used, subcache->data_used); - } - - /* HERE WE ASSUME THAT THE NEW SESSION SHOULD GO ON THE END! I'M NOT - * CHECKING WHETHER IT SHOULD BE GENUINELY "INSERTED" SOMEWHERE. - * - * We either fix that, or find out at a "higher" (read "mod_ssl") - * level whether it is possible to have distinct session caches for - * any attempted tomfoolery to do with different session timeouts. - * Knowing in advance that we can have a cache-wide constant timeout - * would make this stuff *MUCH* more efficient. Mind you, it's very - * efficient right now because I'm ignoring this problem!!! - */ - /* Insert the id */ - id_offset = SHMCB_CYCLIC_INCREMENT(subcache->data_pos, subcache->data_used, - header->subcache_data_size); - shmcb_cyclic_ntoc_memcpy(header->subcache_data_size, - SHMCB_DATA(header, subcache), id_offset, - id, id_len); - subcache->data_used += id_len; - /* Insert the data */ - data_offset = SHMCB_CYCLIC_INCREMENT(subcache->data_pos, subcache->data_used, - header->subcache_data_size); - shmcb_cyclic_ntoc_memcpy(header->subcache_data_size, - SHMCB_DATA(header, subcache), data_offset, - data, data_len); - subcache->data_used += data_len; - /* Insert the index */ - new_idx = SHMCB_CYCLIC_INCREMENT(subcache->idx_pos, subcache->idx_used, - header->index_num); - idx = SHMCB_INDEX(subcache, new_idx); - idx->expires = expiry; - idx->data_pos = id_offset; - idx->data_used = total_len; - idx->id_len = id_len; - idx->removed = 0; - subcache->idx_used++; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "insert happened at idx=%d, data=(%u:%u)", new_idx, - id_offset, data_offset); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "finished insert, subcache: idx_pos/idx_used=%d/%d, " - "data_pos/data_used=%d/%d", - subcache->idx_pos, subcache->idx_used, - subcache->data_pos, subcache->data_used); - return 0; -} - -static int shmcb_subcache_retrieve(server_rec *s, SHMCBHeader *header, - SHMCBSubcache *subcache, - const unsigned char *id, unsigned int idlen, - unsigned char *dest, unsigned int *destlen) -{ - unsigned int pos; - unsigned int loop = 0; - - /* If there are entries to expire, ditch them first. */ - shmcb_subcache_expire(s, header, subcache); - pos = subcache->idx_pos; - - while (loop < subcache->idx_used) { - SHMCBIndex *idx = SHMCB_INDEX(subcache, pos); - - /* Only consider 'idx' if the id matches, and the "removed" - * flag isn't set; check the data length too to avoid a buffer - * overflow in case of corruption, which should be impossible, - * but it's cheap to be safe. */ - if (!idx->removed - && idx->id_len == idlen && (idx->data_used - idx->id_len) < *destlen - && shmcb_cyclic_memcmp(header->subcache_data_size, - SHMCB_DATA(header, subcache), - idx->data_pos, id, idx->id_len) == 0) { - unsigned int data_offset; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "match at idx=%d, data=%d", pos, idx->data_pos); - - /* Find the offset of the data segment, after the id */ - data_offset = SHMCB_CYCLIC_INCREMENT(idx->data_pos, - idx->id_len, - header->subcache_data_size); - - *destlen = idx->data_used - idx->id_len; - - /* Copy out the data */ - shmcb_cyclic_cton_memcpy(header->subcache_data_size, - dest, SHMCB_DATA(header, subcache), - data_offset, *destlen); - - return 0; - } - /* Increment */ - loop++; - pos = SHMCB_CYCLIC_INCREMENT(pos, 1, header->index_num); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "shmcb_subcache_retrieve found no match"); - return -1; - -} - -static int shmcb_subcache_remove(server_rec *s, SHMCBHeader *header, - SHMCBSubcache *subcache, - const unsigned char *id, unsigned int idlen) -{ - unsigned int pos; - unsigned int loop = 0; - - /* Unlike the others, we don't do an expire-run first. This is to keep - * consistent statistics where a "remove" operation may actually be the - * higher layer spotting an expiry issue prior to us. Our caller is - * handling stats, so a failure return would be inconsistent if the - * intended session was in fact removed by an expiry run. */ - - pos = subcache->idx_pos; - while (loop < subcache->idx_used) { - SHMCBIndex *idx = SHMCB_INDEX(subcache, pos); - - /* Only consider 'idx' if the id matches, and the "removed" - * flag isn't set. */ - if (!idx->removed && idx->id_len == idlen - && shmcb_cyclic_memcmp(header->subcache_data_size, - SHMCB_DATA(header, subcache), - idx->data_pos, id, idx->id_len) == 0) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "possible match at idx=%d, data=%d", pos, idx->data_pos); - /* Found the matching session, remove it quietly. */ - idx->removed = 1; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "shmcb_subcache_remove removing matching session"); - return 0; - } - /* Increment */ - loop++; - pos = SHMCB_CYCLIC_INCREMENT(pos, 1, header->index_num); - } - - return -1; /* failure */ -} - -const modssl_sesscache_provider modssl_sesscache_shmcb = { - "shmcb", - MODSSL_SESSCACHE_FLAG_NOTMPSAFE, - ssl_scache_shmcb_create, - ssl_scache_shmcb_init, - ssl_scache_shmcb_kill, - ssl_scache_shmcb_store, - ssl_scache_shmcb_retrieve, - ssl_scache_shmcb_remove, - ssl_scache_shmcb_status -}; |