source: mod_gnutls/src/gnutls_cache.c @ aa68232

debian/masterdebian/stretch-backportsupstream
Last change on this file since aa68232 was aa68232, checked in by Thomas Klute <thomas2.klute@…>, 4 years ago

Move global cache mutex into the private cache struct

  • Property mode set to 100644
File size: 22.4 KB
RevLine 
[fcb122d]1/**
2 *  Copyright 2004-2005 Paul Querna
[e183628]3 *  Copyright 2008 Nikos Mavrogiannopoulos
4 *  Copyright 2011 Dash Shendy
[8913410]5 *  Copyright 2015-2016 Thomas Klute
[0b3bc05]6 *
7 *  Licensed under the Apache License, Version 2.0 (the "License");
8 *  you may not use this file except in compliance with the License.
9 *  You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 *  Unless required by applicable law or agreed to in writing, software
14 *  distributed under the License is distributed on an "AS IS" BASIS,
15 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 *  See the License for the specific language governing permissions and
17 *  limitations under the License.
18 *
19 */
20
[3e22b82]21/***
22 * The signatures of the (dbm|mc)_cache_...() functions may be a bit
23 * confusing: "store" and "expire" take a server_rec, "fetch" an
24 * mgs_handle_t, and "delete" the void* required for a
25 * gnutls_db_remove_func. The first two have matching ..._session
26 * functions to fit their respective GnuTLS session cache signatures.
27 *
28 * This is because "store", "expire" (dbm only), and "fetch" are also
29 * needed for the OCSP cache. Their ..._session variants have been
30 * created to take care of the session cache specific parts, mainly
31 * calculating the DB key from the session ID. They have to match the
32 * appropriate GnuTLS DB function signatures.
33 *
34 * Additionally, there are the mc_cache_(store|fetch)_generic()
35 * functions. They exist because memcached requires string keys while
36 * DBM accepts binary keys, and provide wrappers to turn binary keys
37 * into hex strings with a "mod_gnutls:" prefix.
38 *
39 * To update cached OCSP responses independent of client connections,
40 * "store" and "expire" have to work without a connection context. On
41 * the other hand "fetch" does not need to do that, because cached
42 * OCSP responses will be retrieved for use in client connections.
43 ***/
44
[04e6e65]45#include "gnutls_cache.h"
[0b3bc05]46#include "mod_gnutls.h"
[6e0bfd6]47
48#if HAVE_APR_MEMCACHE
49#include "apr_memcache.h"
50#endif
51
[fcb122d]52#include "apr_dbm.h"
[f450ac9]53#include <apr_escape.h>
[fcb122d]54
[a66e147]55#include "ap_mpm.h"
[c005645]56#include <util_mutex.h>
[0b3bc05]57
[fcb122d]58#include <unistd.h>
59#include <sys/types.h>
60
61#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
62#include "unixd.h"
63#endif
64
[c005645]65/* default cache timeout */
66#define MGS_DEFAULT_CACHE_TIMEOUT 300
67
[671b64f]68/* it seems the default has some strange errors. Use SDBM
[03a9a6b]69 */
[6e0bfd6]70#define MC_TAG "mod_gnutls:"
[f450ac9]71/* two characters per byte, plus one more for '\0' */
72#define GNUTLS_SESSION_ID_STRING_LEN ((GNUTLS_MAX_SESSION_ID_SIZE * 2) + 1)
[6e0bfd6]73
[7e67487]74#if MODULE_MAGIC_NUMBER_MAJOR < 20081201
75#define ap_unixd_config unixd_config
76#endif
77
[55dc3f0]78#ifdef APLOG_USE_MODULE
79APLOG_USE_MODULE(gnutls);
80#endif
81
[c055502]82/* Name the Session ID as:
[c223c85]83 * server:port.SessionID
[c055502]84 * to disallow resuming sessions on different servers
85 */
[2f932fa]86static int mgs_session_id2dbm(conn_rec *c, unsigned char *id, int idlen,
87                              gnutls_datum_t *dbmkey)
88{
[f450ac9]89    char sz[GNUTLS_SESSION_ID_STRING_LEN];
90    apr_status_t rv = apr_escape_hex(sz, id, idlen, 0, NULL);
91    if (rv != APR_SUCCESS)
[e183628]92        return -1;
93
[2f932fa]94    char *newkey = apr_psprintf(c->pool, "%s:%d.%s",
95                                c->base_server->server_hostname,
96                                c->base_server->port, sz);
97    dbmkey->size = strlen(newkey);
98    /* signedness does not matter for arbitrary bits */
99    dbmkey->data = (unsigned char*) newkey;
[e183628]100    return 0;
[c055502]101}
[7bebb42]102
103#define CTIME "%b %d %k:%M:%S %Y %Z"
[e02dd8c]104
[e183628]105char *mgs_time2sz(time_t in_time, char *str, int strsize) {
106    apr_time_exp_t vtm;
107    apr_size_t ret_size;
108    apr_time_t t;
[e02dd8c]109
110
[e183628]111    apr_time_ansi_put(&t, in_time);
112    apr_time_exp_gmt(&vtm, t);
113    apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm);
114
115    return str;
[7bebb42]116}
[6e0bfd6]117
[c055502]118#if HAVE_APR_MEMCACHE
[e183628]119
[c055502]120/* Name the Session ID as:
[c223c85]121 * server:port.SessionID
[c055502]122 * to disallow resuming sessions on different servers
123 */
[f450ac9]124static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen)
125{
126    char sz[GNUTLS_SESSION_ID_STRING_LEN];
127    apr_status_t rv = apr_escape_hex(sz, id, idlen, 0, NULL);
128    if (rv != APR_SUCCESS)
[e183628]129        return NULL;
130
131    return apr_psprintf(c->pool, MC_TAG "%s:%d.%s",
132            c->base_server->server_hostname,
133            c->base_server->port, sz);
[42307a9]134}
135
[0b3bc05]136/**
137 * GnuTLS Session Cache using libmemcached
138 *
139 */
140
[a66e147]141/* The underlying apr_memcache system is thread safe... woohoo */
[e02dd8c]142static apr_memcache_t *mc;
[a66e147]143
[e02dd8c]144static int mc_cache_child_init(apr_pool_t * p, server_rec * s,
[e183628]145        mgs_srvconf_rec * sc) {
146    apr_status_t rv = APR_SUCCESS;
147    int thread_limit = 0;
148    int nservers = 0;
149    char *cache_config;
150    char *split;
151    char *tok;
152
153    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
154
155    /* Find all the servers in the first run to get a total count */
156    cache_config = apr_pstrdup(p, sc->cache_config);
157    split = apr_strtok(cache_config, " ", &tok);
158    while (split) {
159        nservers++;
160        split = apr_strtok(NULL, " ", &tok);
161    }
162
163    rv = apr_memcache_create(p, nservers, 0, &mc);
164    if (rv != APR_SUCCESS) {
165        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
166                "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
167                nservers);
168        return rv;
169    }
170
171    /* Now add each server to the memcache */
172    cache_config = apr_pstrdup(p, sc->cache_config);
173    split = apr_strtok(cache_config, " ", &tok);
174    while (split) {
175        apr_memcache_server_t *st;
176        char *host_str;
177        char *scope_id;
178        apr_port_t port;
179
180        rv = apr_parse_addr_port(&host_str, &scope_id, &port,
181                split, p);
182        if (rv != APR_SUCCESS) {
183            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
184                    "[gnutls_cache] Failed to Parse Server: '%s'",
185                    split);
186            return rv;
187        }
188
189        if (host_str == NULL) {
190            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
191                    "[gnutls_cache] Failed to Parse Server, "
192                    "no hostname specified: '%s'", split);
193            return rv;
194        }
195
196        if (port == 0) {
197            port = 11211; /* default port */
198        }
199
200        /* Should Max Conns be (thread_limit / nservers) ? */
201        rv = apr_memcache_server_create(p,
202                host_str, port,
203                0,
204                1, thread_limit, 600, &st);
205        if (rv != APR_SUCCESS) {
206            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
207                    "[gnutls_cache] Failed to Create Server: %s:%d",
208                    host_str, port);
209            return rv;
210        }
211
212        rv = apr_memcache_add_server(mc, st);
213        if (rv != APR_SUCCESS) {
214            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
215                    "[gnutls_cache] Failed to Add Server: %s:%d",
216                    host_str, port);
217            return rv;
218        }
219
220        split = apr_strtok(NULL, " ", &tok);
221    }
222    return rv;
[32f2e60]223}
[a66e147]224
[3e22b82]225static int mc_cache_store(server_rec *s, const char *key,
226                          gnutls_datum_t data, apr_uint32_t timeout)
227{
228    apr_status_t rv = apr_memcache_set(mc, key, (char *) data.data,
229                                       data.size, timeout, 0);
[e183628]230
[3e22b82]231    if (rv != APR_SUCCESS)
232    {
233        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
234                     "[gnutls_cache] error setting key '%s' "
235                     "with %d bytes of data", key, data.size);
[e183628]236        return -1;
[3e22b82]237    }
[e183628]238
[3e22b82]239    return 0;
240}
[e183628]241
[e809fb3]242static int mc_cache_store_generic(server_rec *s, gnutls_datum_t key,
243                                  gnutls_datum_t data, apr_time_t expiry)
[3e22b82]244{
245    apr_uint32_t timeout = apr_time_sec(expiry - apr_time_now());
[e183628]246
[3e22b82]247    apr_pool_t *p;
248    apr_pool_create(&p, NULL);
249
250    const char *hex = apr_pescape_hex(p, key.data, key.size, 1);
251    if (hex == NULL)
252    {
253        apr_pool_destroy(p);
[e183628]254        return -1;
255    }
256
[3e22b82]257    const char *strkey = apr_psprintf(p, MC_TAG "%s", hex);
258
259    int ret = mc_cache_store(s, strkey, data, timeout);
260
261    apr_pool_destroy(p);
262    return ret;
[a66e147]263}
264
[3e22b82]265static int mc_cache_store_session(void *baton, gnutls_datum_t key,
266                                  gnutls_datum_t data)
267{
[e183628]268    mgs_handle_t *ctxt = baton;
[3e22b82]269
270    const char *strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
271    if (!strkey)
272        return -1;
273
274    apr_uint32_t timeout = apr_time_sec(ctxt->sc->cache_timeout);
275
276    return mc_cache_store(ctxt->c->base_server, strkey, data, timeout);
277}
278
279static gnutls_datum_t mc_cache_fetch(conn_rec *c, const char *key)
280{
281    apr_status_t rv = APR_SUCCESS;
[e183628]282    char *value;
283    apr_size_t value_len;
284    gnutls_datum_t data = {NULL, 0};
[e02dd8c]285
[3e22b82]286    rv = apr_memcache_getp(mc, c->pool, key, &value, &value_len, NULL);
[e02dd8c]287
[3e22b82]288    if (rv != APR_SUCCESS)
289    {
[316bd8c]290#if MOD_GNUTLS_DEBUG
[3e22b82]291        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
292                      "[gnutls_cache] error fetching key '%s' ",
293                      key);
[316bd8c]294#endif
[e183628]295        return data;
296    }
[a66e147]297
[e183628]298    /* TODO: Eliminate this memcpy. gnutls-- */
299    data.data = gnutls_malloc(value_len);
300    if (data.data == NULL)
301        return data;
[a66e147]302
[e183628]303    data.size = value_len;
304    memcpy(data.data, value, value_len);
[a66e147]305
[e183628]306    return data;
[32f2e60]307}
308
[e809fb3]309static gnutls_datum_t mc_cache_fetch_generic(mgs_handle_t *ctxt,
310                                             gnutls_datum_t key)
[3e22b82]311{
312    gnutls_datum_t data = {NULL, 0};
313    const char *hex = apr_pescape_hex(ctxt->c->pool, key.data, key.size, 1);
314    if (hex == NULL)
315        return data;
316
317    const char *strkey = apr_psprintf(ctxt->c->pool, MC_TAG "%s", hex);
318    return mc_cache_fetch(ctxt->c, strkey);
319}
320
321static gnutls_datum_t mc_cache_fetch_session(void *baton, gnutls_datum_t key)
322{
323    mgs_handle_t *ctxt = baton;
324    gnutls_datum_t data = {NULL, 0};
325
326    const char *strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
327    if (!strkey)
328        return data;
329
330    return mc_cache_fetch(ctxt->c, strkey);
331}
332
[e183628]333static int mc_cache_delete(void *baton, gnutls_datum_t key) {
334    apr_status_t rv = APR_SUCCESS;
335    mgs_handle_t *ctxt = baton;
336    char *strkey = NULL;
[a66e147]337
[e183628]338    strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
339    if (!strkey)
340        return -1;
[a66e147]341
[e183628]342    rv = apr_memcache_delete(mc, strkey, 0);
[a66e147]343
[e183628]344    if (rv != APR_SUCCESS) {
345        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
346                ctxt->c->base_server,
347                "[gnutls_cache] error deleting key '%s' ",
348                strkey);
349        return -1;
350    }
[a66e147]351
[e183628]352    return 0;
[32f2e60]353}
354
[410d216]355#endif  /* have_apr_memcache */
[6e0bfd6]356
[410d216]357static const char *db_type(mgs_srvconf_rec * sc) {
[e183628]358    if (sc->cache_type == mgs_cache_gdbm)
359        return "gdbm";
360    else
361        return "db";
[771ca63]362}
363
[fcb122d]364#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
365
[f785704]366static void dbm_cache_expire(server_rec *s)
367{
368    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
369        ap_get_module_config(s->module_config, &gnutls_module);
370
[e183628]371    apr_status_t rv;
372    apr_dbm_t *dbm;
373    apr_datum_t dbmkey;
374    apr_datum_t dbmval;
375    apr_time_t dtime;
376    apr_pool_t *spool;
377    int total, deleted;
378
[f785704]379    apr_time_t now = apr_time_now();
[e183628]380
[f785704]381    if (now - sc->last_cache_check < (sc->cache_timeout) / 2)
[e183628]382        return;
383
[f785704]384    sc->last_cache_check = now;
[e183628]385
[f785704]386    apr_pool_create(&spool, NULL);
[e183628]387
388    total = 0;
389    deleted = 0;
390
[aa68232]391    apr_global_mutex_lock(sc->cache->mutex);
[c005645]392
[f785704]393    rv = apr_dbm_open_ex(&dbm, db_type(sc),
394            sc->cache_config, APR_DBM_RWCREATE,
[e183628]395            SSL_DBM_FILE_MODE, spool);
396    if (rv != APR_SUCCESS) {
[f785704]397        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s,
[c005645]398                "[gnutls_cache] error opening cache '%s'",
[f785704]399                sc->cache_config);
[aa68232]400        apr_global_mutex_unlock(sc->cache->mutex);
[e183628]401        apr_pool_destroy(spool);
402        return;
403    }
404
405    apr_dbm_firstkey(dbm, &dbmkey);
406    while (dbmkey.dptr != NULL) {
407        apr_dbm_fetch(dbm, dbmkey, &dbmval);
408        if (dbmval.dptr != NULL
409                && dbmval.dsize >= sizeof (apr_time_t)) {
410            memcpy(&dtime, dbmval.dptr, sizeof (apr_time_t));
411
412            if (now >= dtime) {
413                apr_dbm_delete(dbm, dbmkey);
414                deleted++;
415            }
416            apr_dbm_freedatum(dbm, dbmval);
417        } else {
418            apr_dbm_delete(dbm, dbmkey);
419            deleted++;
420        }
421        total++;
422        apr_dbm_nextkey(dbm, &dbmkey);
423    }
424    apr_dbm_close(dbm);
425
[aa68232]426    rv = apr_global_mutex_unlock(sc->cache->mutex);
[c005645]427
[f785704]428    ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
[e183628]429            "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d",
[f785704]430            sc->cache_config, deleted, total - deleted);
[e183628]431
432    apr_pool_destroy(spool);
433
434    return;
[fcb122d]435}
436
[e809fb3]437static gnutls_datum_t dbm_cache_fetch(mgs_handle_t *ctxt, gnutls_datum_t key)
[15245bf]438{
[e183628]439    gnutls_datum_t data = {NULL, 0};
440    apr_dbm_t *dbm;
[2f932fa]441    apr_datum_t dbmkey = {(char*) key.data, key.size};
[e183628]442    apr_datum_t dbmval;
[d18afb8]443    apr_time_t expiry = 0;
[e183628]444    apr_status_t rv;
445
[c55902b]446    /* check if it is time for cache expiration */
447    dbm_cache_expire(ctxt->c->base_server);
448
[aa68232]449    apr_global_mutex_lock(ctxt->sc->cache->mutex);
[c005645]450
[e183628]451    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
452            ctxt->sc->cache_config, APR_DBM_READONLY,
453            SSL_DBM_FILE_MODE, ctxt->c->pool);
454    if (rv != APR_SUCCESS) {
[15245bf]455        ap_log_cerror(APLOG_MARK, APLOG_NOTICE, rv, ctxt->c,
456                      "error opening cache '%s'",
457                      ctxt->sc->cache_config);
[aa68232]458        apr_global_mutex_unlock(ctxt->sc->cache->mutex);
[e183628]459        return data;
460    }
461
[2f932fa]462    rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
[e183628]463
[c55902b]464    if (rv != APR_SUCCESS)
465        goto close_db;
[e183628]466
[c55902b]467    if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t))
468        goto cleanup;
[e183628]469
470    data.size = dbmval.dsize - sizeof (apr_time_t);
[d18afb8]471    /* get data expiration tag */
472    expiry = *((apr_time_t *) dbmval.dptr);
[e183628]473
474    data.data = gnutls_malloc(data.size);
[c55902b]475    if (data.data == NULL)
476        goto cleanup;
[e183628]477
[15245bf]478    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, ctxt->c,
479                  "fetched %ld bytes from cache",
480                  dbmval.dsize);
481
[e183628]482    memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size);
483
[c55902b]484 cleanup:
[e183628]485    apr_dbm_freedatum(dbm, dbmval);
[c55902b]486 close_db:
[e183628]487    apr_dbm_close(dbm);
[aa68232]488    apr_global_mutex_unlock(ctxt->sc->cache->mutex);
[e183628]489
[d18afb8]490    /* cache entry might have expired since last cache cleanup */
491    if (expiry != 0 && expiry < apr_time_now())
492    {
493        gnutls_free(data.data);
494        data.data = NULL;
495        data.size = 0;
496        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
497                      "dropped expired cache data");
498    }
499
[e183628]500    return data;
[fcb122d]501}
502
[2f932fa]503static gnutls_datum_t dbm_cache_fetch_session(void *baton, gnutls_datum_t key)
[15245bf]504{
505    gnutls_datum_t data = {NULL, 0};
[2f932fa]506    gnutls_datum_t dbmkey;
[15245bf]507    mgs_handle_t *ctxt = baton;
508
509    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
510        return data;
511
512    return dbm_cache_fetch(ctxt, dbmkey);
513}
514
[e809fb3]515static int dbm_cache_store(server_rec *s, gnutls_datum_t key,
516                           gnutls_datum_t data, apr_time_t expiry)
[ae08186]517{
[1d1361f]518    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
519        ap_get_module_config(s->module_config, &gnutls_module);
520
[e183628]521    apr_dbm_t *dbm;
[2f932fa]522    apr_datum_t dbmkey = {(char*) key.data, key.size};
[e183628]523    apr_datum_t dbmval;
524    apr_status_t rv;
525    apr_pool_t *spool;
526
[c55902b]527    /* check if it is time for cache expiration */
[1d1361f]528    dbm_cache_expire(s);
[e183628]529
[1d1361f]530    apr_pool_create(&spool, NULL);
[e183628]531
532    /* create DBM value */
533    dbmval.dsize = data.size + sizeof (apr_time_t);
534    dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize);
535
[ae08186]536    /* prepend expiration time */
[e183628]537    memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t));
538    memcpy((char *) dbmval.dptr + sizeof (apr_time_t),
539            data.data, data.size);
540
[aa68232]541    apr_global_mutex_lock(sc->cache->mutex);
[c005645]542
[1d1361f]543    rv = apr_dbm_open_ex(&dbm, db_type(sc),
544                         sc->cache_config, APR_DBM_RWCREATE,
545                         SSL_DBM_FILE_MODE, spool);
546    if (rv != APR_SUCCESS)
547    {
548        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s,
549                     "error opening cache '%s'",
550                     sc->cache_config);
[aa68232]551        apr_global_mutex_unlock(sc->cache->mutex);
[e183628]552        apr_pool_destroy(spool);
553        return -1;
554    }
555
[2f932fa]556    rv = apr_dbm_store(dbm, dbmkey, dbmval);
[1d1361f]557    if (rv != APR_SUCCESS)
558    {
559        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
560                     "error storing in cache '%s'",
561                     sc->cache_config);
[e183628]562        apr_dbm_close(dbm);
[aa68232]563        apr_global_mutex_unlock(sc->cache->mutex);
[e183628]564        apr_pool_destroy(spool);
565        return -1;
566    }
567
[c005645]568    apr_dbm_close(dbm);
[aa68232]569    apr_global_mutex_unlock(sc->cache->mutex);
[c005645]570
[1d1361f]571    ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
572                 "stored %ld bytes of data (%ld byte key) in cache '%s'",
[2f932fa]573                 dbmval.dsize, dbmkey.dsize, sc->cache_config);
[1d1361f]574
[e183628]575    apr_pool_destroy(spool);
576
577    return 0;
[fcb122d]578}
579
[ae08186]580static int dbm_cache_store_session(void *baton, gnutls_datum_t key,
581                                   gnutls_datum_t data)
582{
583    mgs_handle_t *ctxt = baton;
[2f932fa]584    gnutls_datum_t dbmkey;
[ae08186]585
586    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
587        return -1;
588
589    apr_time_t expiry = apr_time_now() + ctxt->sc->cache_timeout;
590
[1d1361f]591    return dbm_cache_store(ctxt->c->base_server, dbmkey, data, expiry);
[ae08186]592}
593
[c55902b]594static int dbm_cache_delete(void *baton, gnutls_datum_t key)
595{
[e183628]596    apr_dbm_t *dbm;
[2f932fa]597    gnutls_datum_t tmpkey;
[e183628]598    mgs_handle_t *ctxt = baton;
599    apr_status_t rv;
600
[2f932fa]601    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &tmpkey) < 0)
[e183628]602        return -1;
[2f932fa]603    apr_datum_t dbmkey = {(char*) tmpkey.data, tmpkey.size};
[e183628]604
[aa68232]605    apr_global_mutex_lock(ctxt->sc->cache->mutex);
[c005645]606
[e183628]607    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
608            ctxt->sc->cache_config, APR_DBM_RWCREATE,
609            SSL_DBM_FILE_MODE, ctxt->c->pool);
610    if (rv != APR_SUCCESS) {
611        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
612                ctxt->c->base_server,
613                "[gnutls_cache] error opening cache '%s'",
614                ctxt->sc->cache_config);
[aa68232]615        apr_global_mutex_unlock(ctxt->sc->cache->mutex);
[e183628]616        return -1;
617    }
618
619    rv = apr_dbm_delete(dbm, dbmkey);
620
621    if (rv != APR_SUCCESS) {
622        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
623                ctxt->c->base_server,
624                "[gnutls_cache] error deleting from cache '%s'",
625                ctxt->sc->cache_config);
626        apr_dbm_close(dbm);
[aa68232]627        apr_global_mutex_unlock(ctxt->sc->cache->mutex);
[e183628]628        return -1;
629    }
630
631    apr_dbm_close(dbm);
[aa68232]632    apr_global_mutex_unlock(ctxt->sc->cache->mutex);
[e183628]633
634    return 0;
[fcb122d]635}
636
[e02dd8c]637static int dbm_cache_post_config(apr_pool_t * p, server_rec * s,
[e183628]638        mgs_srvconf_rec * sc) {
639    apr_status_t rv;
640    apr_dbm_t *dbm;
641    const char *path1;
642    const char *path2;
[fcb122d]643
[e183628]644    rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config,
645            APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p);
[fcb122d]646
[e183628]647    if (rv != APR_SUCCESS) {
648        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
649                "GnuTLS: Cannot create DBM Cache at `%s'",
650                sc->cache_config);
651        return rv;
652    }
[fcb122d]653
[e183628]654    apr_dbm_close(dbm);
[fcb122d]655
[e183628]656    apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1,
657            &path2);
[fcb122d]658
[e183628]659    /* The Following Code takes logic directly from mod_ssl's DBM Cache */
[fcb122d]660#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
[e183628]661    /* Running as Root */
662    if (path1 && geteuid() == 0) {
[422f5b7]663        if (0 != chown(path1, ap_unixd_config.user_id, -1))
664            ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s,
665                         "GnuTLS: could not chown cache path1 `%s' to uid %d (errno: %d)",
666                         path1, ap_unixd_config.user_id, errno);
[e183628]667        if (path2 != NULL) {
[422f5b7]668            if (0 != chown(path2, ap_unixd_config.user_id, -1))
669                ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s,
670                             "GnuTLS: could not chown cache path2 `%s' to uid %d (errno: %d)",
671                             path2, ap_unixd_config.user_id, errno);
[e183628]672        }
673    }
[fcb122d]674#endif
675
[e183628]676    return rv;
[fcb122d]677}
678
[e02dd8c]679int mgs_cache_post_config(apr_pool_t * p, server_rec * s,
[e183628]680        mgs_srvconf_rec * sc) {
[040387c]681
682    /* if GnuTLSCache was never explicitly set: */
683    if (sc->cache_type == mgs_cache_unset)
684        sc->cache_type = mgs_cache_none;
685    /* if GnuTLSCacheTimeout was never explicitly set: */
[671b64f]686    if (sc->cache_timeout == -1)
[c005645]687        sc->cache_timeout = apr_time_from_sec(MGS_DEFAULT_CACHE_TIMEOUT);
688
689    /* initialize mutex only once */
[aa68232]690    if (sc->cache == NULL)
[c005645]691    {
[aa68232]692        sc->cache = apr_palloc(p, sizeof(struct mgs_cache));
693        apr_status_t rv = ap_global_mutex_create(&sc->cache->mutex, NULL,
[c005645]694                                                 MGS_CACHE_MUTEX_NAME,
695                                                 NULL, s, p, 0);
696        if (rv != APR_SUCCESS)
697            return rv;
698    }
[040387c]699
[e809fb3]700    if (sc->cache_type == mgs_cache_dbm || sc->cache_type == mgs_cache_gdbm)
701    {
702        sc->cache->store = dbm_cache_store;
703        sc->cache->fetch = dbm_cache_fetch;
[e183628]704        return dbm_cache_post_config(p, s, sc);
705    }
[e809fb3]706#if HAVE_APR_MEMCACHE
707    else if (sc->cache_type == mgs_cache_memcache)
708    {
709        sc->cache->store = mc_cache_store_generic;
710        sc->cache->fetch = mc_cache_fetch_generic;
711    }
712#endif
[c005645]713
714    return APR_SUCCESS;
[fcb122d]715}
716
[e765670]717int mgs_cache_child_init(apr_pool_t * p,
718                         server_rec * s,
719                         mgs_srvconf_rec * sc)
720{
[aa68232]721    /* reinit cache mutex */
722    const char *lockfile = apr_global_mutex_lockfile(sc->cache->mutex);
723    apr_status_t rv = apr_global_mutex_child_init(&sc->cache->mutex,
724                                                  lockfile, p);
725    if (rv != APR_SUCCESS)
726        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
727                     "Failed to reinit mutex '%s'", MGS_CACHE_MUTEX_NAME);
728
[e183628]729    if (sc->cache_type == mgs_cache_dbm
730            || sc->cache_type == mgs_cache_gdbm) {
731        return 0;
732    }
[6e0bfd6]733#if HAVE_APR_MEMCACHE
[e183628]734    else if (sc->cache_type == mgs_cache_memcache) {
735        return mc_cache_child_init(p, s, sc);
736    }
[6e0bfd6]737#endif
[e183628]738    return 0;
[6e0bfd6]739}
740
[e02dd8c]741#include <assert.h>
[fcb122d]742
[e183628]743int mgs_cache_session_init(mgs_handle_t * ctxt) {
744    if (ctxt->sc->cache_type == mgs_cache_dbm
745            || ctxt->sc->cache_type == mgs_cache_gdbm) {
746        gnutls_db_set_retrieve_function(ctxt->session,
[15245bf]747                dbm_cache_fetch_session);
[e183628]748        gnutls_db_set_remove_function(ctxt->session,
749                dbm_cache_delete);
750        gnutls_db_set_store_function(ctxt->session,
[ae08186]751                dbm_cache_store_session);
[e183628]752        gnutls_db_set_ptr(ctxt->session, ctxt);
753    }
[6e0bfd6]754#if HAVE_APR_MEMCACHE
[e183628]755    else if (ctxt->sc->cache_type == mgs_cache_memcache) {
756        gnutls_db_set_retrieve_function(ctxt->session,
[3e22b82]757                mc_cache_fetch_session);
[e183628]758        gnutls_db_set_remove_function(ctxt->session,
759                mc_cache_delete);
760        gnutls_db_set_store_function(ctxt->session,
[3e22b82]761                mc_cache_store_session);
[e183628]762        gnutls_db_set_ptr(ctxt->session, ctxt);
763    }
[6e0bfd6]764#endif
[42307a9]765
[e183628]766    return 0;
[32f2e60]767}
Note: See TracBrowser for help on using the repository browser.