source: mod_gnutls/src/gnutls_cache.c @ c34a68b

asynciodebian/masterproxy-ticket
Last change on this file since c34a68b was c34a68b, checked in by Fiona Klute <fiona.klute@…>, 3 years ago

dbm_cache_fetch: Prepare for signature without connection context

Minimizing references to the connection context and collecting them
all at the top will make the signature change easier.

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