source: mod_gnutls/src/gnutls_cache.c @ 04addef

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

Clarify the purpose of mgs_time2sz()

I've renamed the CTIME macro to OPENSSL_TIME_FORMAT because its name
is misleading: ctime() uses a different output format.

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