source: mod_gnutls/src/gnutls_cache.c @ c39ae1a

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

Initialize OCSP timeouts with an "unset" value

The configuration merge function used the default timeout to check if
an OCSP related timeout has been set in a virtual host
configuration. This would work most of the time, but break in the
corner case of the global configuration setting a non-default timeout
and a virtual host configuration restoring the default. In this
situation the merge would handle the value from the virtual host
configuration as unset and copy the global timeout.

The problem is solved by initializing the timeouts using the new macro
MGS_TIMEOUT_UNSET. Timeouts as used in the mod_gnutls configuration
cannot be negative, so there is ample room for explicitly unset
values. MGS_TIMEOUT_UNSET is also used for the session cache timeout
instead of hard coded -1.

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