mirror of
https://github.com/apache/httpd.git
synced 2025-06-01 23:21:45 +03:00
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@546708 13f79535-47bb-0310-9956-ffa450edef68
307 lines
8.4 KiB
C
307 lines
8.4 KiB
C
/* 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.. */
|
|
static apr_memcache_t *memctxt;
|
|
|
|
#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
|
|
|
|
|
|
void ssl_scache_mc_init(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;
|
|
SSLModConfigRec *mc = myModConfig(s);
|
|
|
|
ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
|
|
|
|
if (mc->szSessionCacheDataFile == NULL) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSLSessionCache required");
|
|
ssl_die();
|
|
}
|
|
|
|
/* Find all the servers in the first run to get a total count */
|
|
cache_config = apr_pstrdup(p, mc->szSessionCacheDataFile);
|
|
split = apr_strtok(cache_config, ",", &tok);
|
|
while (split) {
|
|
nservers++;
|
|
split = apr_strtok(NULL,",", &tok);
|
|
}
|
|
|
|
rv = apr_memcache_create(p, nservers, 0, &memctxt);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
|
|
"SSLSessionCache: Failed to create Memcache Object of '%d' size.",
|
|
nservers);
|
|
ssl_die();
|
|
}
|
|
|
|
/* Now add each server to the memcache */
|
|
cache_config = apr_pstrdup(p, mc->szSessionCacheDataFile);
|
|
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);
|
|
ssl_die();
|
|
}
|
|
|
|
if (host_str == NULL) {
|
|
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
|
|
"SSLSessionCache: Failed to Parse Server, "
|
|
"no hostname specified: '%s'", split);
|
|
ssl_die();
|
|
}
|
|
|
|
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);
|
|
ssl_die();
|
|
}
|
|
|
|
rv = apr_memcache_add_server(memctxt, st);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
|
|
"SSLSessionCache: Failed to Add Server: %s:%d",
|
|
host_str, port);
|
|
ssl_die();
|
|
}
|
|
|
|
split = apr_strtok(NULL,",", &tok);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void ssl_scache_mc_kill(server_rec *s)
|
|
{
|
|
|
|
}
|
|
|
|
static char *mc_session_id2sz(unsigned char *id, 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, 2, "%02X", id[n]);
|
|
cp += 2;
|
|
}
|
|
|
|
*cp = '\0';
|
|
|
|
return str;
|
|
}
|
|
|
|
BOOL ssl_scache_mc_store(server_rec *s, UCHAR *id, int idlen,
|
|
time_t timeout, SSL_SESSION *pSession)
|
|
{
|
|
char buf[MC_KEY_LEN];
|
|
char *strkey = NULL;
|
|
UCHAR ucaData[SSL_SESSION_MAX_DER];
|
|
UCHAR *ucp;
|
|
int nData;
|
|
apr_status_t rv;
|
|
|
|
/* streamline session data */
|
|
if ((nData = i2d_SSL_SESSION(pSession, NULL)) > sizeof(ucaData)) {
|
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
|
"scache_mc: streamline session data size too large: %d > "
|
|
"%" APR_SIZE_T_FMT,
|
|
nData, sizeof(ucaData));
|
|
return FALSE;
|
|
}
|
|
|
|
ucp = ucaData;
|
|
i2d_SSL_SESSION(pSession, &ucp);
|
|
|
|
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 FALSE;
|
|
}
|
|
|
|
rv = apr_memcache_set(memctxt, 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 FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
SSL_SESSION *ssl_scache_mc_retrieve(server_rec *s, UCHAR *id, int idlen,
|
|
apr_pool_t *p)
|
|
{
|
|
SSL_SESSION *pSession;
|
|
MODSSL_D2I_SSL_SESSION_CONST unsigned char *pder;
|
|
apr_size_t der_len;
|
|
SSLModConfigRec *mc = myModConfig(s);
|
|
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 NULL;
|
|
}
|
|
|
|
rv = apr_memcache_getp(memctxt, p, strkey,
|
|
(char**)&pder, &der_len, NULL);
|
|
|
|
if (rv == APR_NOTFOUND) {
|
|
/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
|
"scache_mc: 'get_session' MISS"); */
|
|
return NULL;
|
|
}
|
|
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
|
|
"scache_mc: 'get_session' FAIL");
|
|
return NULL;
|
|
}
|
|
|
|
if (der_len > SSL_SESSION_MAX_DER) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
|
|
"scache_mc: 'get_session' OVERFLOW");
|
|
return NULL;
|
|
}
|
|
|
|
pSession = d2i_SSL_SESSION(NULL, &pder, der_len);
|
|
|
|
if (!pSession) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
|
|
"scache_mc: 'get_session' CORRUPT");
|
|
return NULL;
|
|
}
|
|
|
|
/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
|
"scache_mc: 'get_session' HIT"); */
|
|
|
|
return pSession;
|
|
}
|
|
|
|
void ssl_scache_mc_remove(server_rec *s, UCHAR *id, int idlen)
|
|
{
|
|
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(memctxt, strkey, 0);
|
|
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
|
|
"scache_mc: error deleting key '%s' ",
|
|
strkey);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void ssl_scache_mc_status(request_rec *r, int flags, apr_pool_t *pool)
|
|
{
|
|
/* SSLModConfigRec *mc = myModConfig(r->server); */
|
|
/* TODO: Make a mod_status handler. meh. */
|
|
}
|
|
|
|
#endif
|