source: mod_gnutls/src/gnutls_cache.c @ ac3f500

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

Compatibility code for GnuTLS version < 3.4

  • gnutls_memset() is not available.
  • GNUTLS_MAX_SESSION_ID_SIZE is undefined. GNUTLS_MAX_SESSION_ID serves the same purpose, but the name is less intuitive.
  • Property mode set to 100644
File size: 22.7 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
48#if HAVE_APR_MEMCACHE
49#include "apr_memcache.h"
50#endif
51
52#include "apr_dbm.h"
53#include <apr_escape.h>
54
55#include "ap_mpm.h"
56#include <util_mutex.h>
57
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
65/* default cache timeout */
66#define MGS_DEFAULT_CACHE_TIMEOUT 300
67
68/* it seems the default has some strange errors. Use SDBM
69 */
70#define MC_TAG "mod_gnutls:"
71/* two characters per byte, plus one more for '\0' */
72#if GNUTLS_VERSION_NUMBER >= 0x030400
73#define GNUTLS_SESSION_ID_STRING_LEN ((GNUTLS_MAX_SESSION_ID_SIZE * 2) + 1)
74#else
75#define GNUTLS_SESSION_ID_STRING_LEN ((GNUTLS_MAX_SESSION_ID * 2) + 1)
76#endif
77
78#if MODULE_MAGIC_NUMBER_MAJOR < 20081201
79#define ap_unixd_config unixd_config
80#endif
81
82#ifdef APLOG_USE_MODULE
83APLOG_USE_MODULE(gnutls);
84#endif
85
86/* Name the Session ID as:
87 * server:port.SessionID
88 * to disallow resuming sessions on different servers
89 */
90static int mgs_session_id2dbm(conn_rec *c, unsigned char *id, int idlen,
91                              gnutls_datum_t *dbmkey)
92{
93    char sz[GNUTLS_SESSION_ID_STRING_LEN];
94    apr_status_t rv = apr_escape_hex(sz, id, idlen, 0, NULL);
95    if (rv != APR_SUCCESS)
96        return -1;
97
98    char *newkey = apr_psprintf(c->pool, "%s:%d.%s",
99                                c->base_server->server_hostname,
100                                c->base_server->port, sz);
101    dbmkey->size = strlen(newkey);
102    /* signedness does not matter for arbitrary bits */
103    dbmkey->data = (unsigned char*) newkey;
104    return 0;
105}
106
107/* The OPENSSL_TIME_FORMAT macro and mgs_time2sz() serve to print time
108 * in a format compatible with OpenSSL's ASN1_TIME_print()
109 * function. */
110
111#define OPENSSL_TIME_FORMAT "%b %d %k:%M:%S %Y %Z"
112
113char *mgs_time2sz(time_t in_time, char *str, int strsize)
114{
115    apr_time_exp_t vtm;
116    apr_size_t ret_size;
117    apr_time_t t;
118
119
120    apr_time_ansi_put(&t, in_time);
121    apr_time_exp_gmt(&vtm, t);
122    apr_strftime(str, &ret_size, strsize - 1, OPENSSL_TIME_FORMAT, &vtm);
123
124    return str;
125}
126
127#if HAVE_APR_MEMCACHE
128
129/* Name the Session ID as:
130 * server:port.SessionID
131 * to disallow resuming sessions on different servers
132 */
133static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen)
134{
135    char sz[GNUTLS_SESSION_ID_STRING_LEN];
136    apr_status_t rv = apr_escape_hex(sz, id, idlen, 0, NULL);
137    if (rv != APR_SUCCESS)
138        return NULL;
139
140    return apr_psprintf(c->pool, MC_TAG "%s:%d.%s",
141            c->base_server->server_hostname,
142            c->base_server->port, sz);
143}
144
145/**
146 * GnuTLS Session Cache using libmemcached
147 *
148 */
149
150/* The underlying apr_memcache system is thread safe... woohoo */
151static apr_memcache_t *mc;
152
153static int mc_cache_child_init(apr_pool_t * p, server_rec * s,
154        mgs_srvconf_rec * sc) {
155    apr_status_t rv = APR_SUCCESS;
156    int thread_limit = 0;
157    int nservers = 0;
158    char *cache_config;
159    char *split;
160    char *tok;
161
162    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
163
164    /* Find all the servers in the first run to get a total count */
165    cache_config = apr_pstrdup(p, sc->cache_config);
166    split = apr_strtok(cache_config, " ", &tok);
167    while (split) {
168        nservers++;
169        split = apr_strtok(NULL, " ", &tok);
170    }
171
172    rv = apr_memcache_create(p, nservers, 0, &mc);
173    if (rv != APR_SUCCESS) {
174        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
175                "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
176                nservers);
177        return rv;
178    }
179
180    /* Now add each server to the memcache */
181    cache_config = apr_pstrdup(p, sc->cache_config);
182    split = apr_strtok(cache_config, " ", &tok);
183    while (split) {
184        apr_memcache_server_t *st;
185        char *host_str;
186        char *scope_id;
187        apr_port_t port;
188
189        rv = apr_parse_addr_port(&host_str, &scope_id, &port,
190                split, p);
191        if (rv != APR_SUCCESS) {
192            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
193                    "[gnutls_cache] Failed to Parse Server: '%s'",
194                    split);
195            return rv;
196        }
197
198        if (host_str == NULL) {
199            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
200                    "[gnutls_cache] 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                    "[gnutls_cache] 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                    "[gnutls_cache] 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                     "[gnutls_cache] error setting key '%s' "
244                     "with %d bytes of data", 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                      "[gnutls_cache] 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                "[gnutls_cache] 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                "[gnutls_cache] 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            "[gnutls_cache] 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_DEBUG, 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_DEBUG, 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_DEBUG, 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                "[gnutls_cache] 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                "[gnutls_cache] 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 == -1)
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.