Changeset d8afa3e in mod_gnutls for src/gnutls_cache.c


Ignore:
Timestamp:
Dec 17, 2016, 6:56:34 PM (5 years ago)
Author:
Daniel Kahn Gillmor <dkg@…>
Branches:
debian/master, debian/stretch-backports, upstream
Children:
c598e21, d2b32f1
Parents:
ce12806 (diff), 677754f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

New upstream version 0.8.0

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_cache.c

    rce12806 rd8afa3e  
    1 /**
     1/*
    22 *  Copyright 2004-2005 Paul Querna
    33 *  Copyright 2008 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    5  *  Copyright 2015 Thomas Klute
     5 *  Copyright 2015-2016 Thomas Klute
    66 *
    77 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1616 *  See the License for the specific language governing permissions and
    1717 *  limitations under the License.
    18  *
    1918 */
    2019
     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"
    2147#include "mod_gnutls.h"
     48#include "gnutls_config.h"
    2249
    2350#if HAVE_APR_MEMCACHE
     
    2653
    2754#include "apr_dbm.h"
     55#include <apr_escape.h>
    2856
    2957#include "ap_mpm.h"
     58#include <util_mutex.h>
    3059
    3160#include <unistd.h>
     
    3665#endif
    3766
    38 /* it seems the default has some strange errors. Use SDBM
    39  */
     67/** Default session cache timeout */
     68#define MGS_DEFAULT_CACHE_TIMEOUT 300
     69
     70/** Prefix for keys used with a memcached cache */
    4071#define MC_TAG "mod_gnutls:"
    41 #define MC_TAG_LEN sizeof(MC_TAG)
    42 #define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
     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
    4379
    4480#if MODULE_MAGIC_NUMBER_MAJOR < 20081201
     
    5086#endif
    5187
    52 char *mgs_session_id2sz(unsigned char *id, int idlen,
    53         char *str, int strsize) {
    54     char *cp;
    55     int n;
    56 
    57     cp = str;
    58     for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
    59         apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]);
    60         cp += 2;
    61     }
    62     *cp = '\0';
    63     return str;
    64 }
    65 
    66 /* Name the Session ID as:
    67  * server:port.SessionID
    68  * to disallow resuming sessions on different servers
     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
    6994 */
    70 static int mgs_session_id2dbm(conn_rec * c, unsigned char *id, int idlen,
    71         apr_datum_t * dbmkey) {
    72     char buf[STR_SESSION_LEN];
    73     char *sz;
    74 
    75     sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf));
    76     if (sz == NULL)
    77         return -1;
    78 
    79     dbmkey->dptr =
    80             apr_psprintf(c->pool, "%s:%d.%s",
    81             c->base_server->server_hostname,
    82             c->base_server->port, sz);
    83     dbmkey->dsize = strlen(dbmkey->dptr);
    84 
     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;
    85109    return 0;
    86110}
    87111
    88 #define CTIME "%b %d %k:%M:%S %Y %Z"
    89 
    90 char *mgs_time2sz(time_t in_time, char *str, int strsize) {
     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{
    91119    apr_time_exp_t vtm;
    92120    apr_size_t ret_size;
     
    96124    apr_time_ansi_put(&t, in_time);
    97125    apr_time_exp_gmt(&vtm, t);
    98     apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm);
     126    apr_strftime(str, &ret_size, strsize - 1, OPENSSL_TIME_FORMAT, &vtm);
    99127
    100128    return str;
     
    103131#if HAVE_APR_MEMCACHE
    104132
    105 /* Name the Session ID as:
    106  * server:port.SessionID
    107  * to disallow resuming sessions on different servers
     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
    108139 */
    109 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) {
    110     char buf[STR_SESSION_LEN];
    111     char *sz;
    112 
    113     sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf));
    114     if (sz == NULL)
     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)
    115145        return NULL;
    116146
     
    150180    if (rv != APR_SUCCESS) {
    151181        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    152                 "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
    153                 nservers);
     182                     "Failed to create Memcache object of size '%d'.",
     183                     nservers);
    154184        return rv;
    155185    }
     
    168198        if (rv != APR_SUCCESS) {
    169199            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    170                     "[gnutls_cache] Failed to Parse Server: '%s'",
    171                     split);
     200                         "Failed to parse server: '%s'", split);
    172201            return rv;
    173202        }
     
    175204        if (host_str == NULL) {
    176205            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    177                     "[gnutls_cache] Failed to Parse Server, "
    178                     "no hostname specified: '%s'", split);
     206                         "Failed to parse server, "
     207                         "no hostname specified: '%s'", split);
    179208            return rv;
    180209        }
     
    191220        if (rv != APR_SUCCESS) {
    192221            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    193                     "[gnutls_cache] Failed to Create Server: %s:%d",
    194                     host_str, port);
     222                         "Failed to create server: %s:%d",
     223                         host_str, port);
    195224            return rv;
    196225        }
     
    199228        if (rv != APR_SUCCESS) {
    200229            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    201                     "[gnutls_cache] Failed to Add Server: %s:%d",
    202                     host_str, port);
     230                         "Failed to add server: %s:%d",
     231                         host_str, port);
    203232            return rv;
    204233        }
     
    209238}
    210239
    211 static int mc_cache_store(void *baton, gnutls_datum_t key,
    212         gnutls_datum_t data) {
     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
     294static gnutls_datum_t mc_cache_fetch(conn_rec *c, const char *key)
     295{
    213296    apr_status_t rv = APR_SUCCESS;
    214     mgs_handle_t *ctxt = baton;
    215     char *strkey = NULL;
    216     apr_uint32_t timeout;
    217 
    218     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    219     if (!strkey)
    220         return -1;
    221 
    222     timeout = apr_time_sec(ctxt->sc->cache_timeout);
    223 
    224     rv = apr_memcache_set(mc, strkey, (char *) data.data, data.size, timeout,
    225             0);
    226 
    227     if (rv != APR_SUCCESS) {
    228         ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
    229                 ctxt->c->base_server,
    230                 "[gnutls_cache] error setting key '%s' "
    231                 "with %d bytes of data", strkey, data.size);
    232         return -1;
    233     }
    234 
    235     return 0;
    236 }
    237 
    238 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) {
    239     apr_status_t rv = APR_SUCCESS;
    240     mgs_handle_t *ctxt = baton;
    241     char *strkey = NULL;
    242297    char *value;
    243298    apr_size_t value_len;
    244299    gnutls_datum_t data = {NULL, 0};
    245300
    246     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    247     if (!strkey) {
    248         return data;
    249     }
    250 
    251     rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
    252             &value, &value_len, NULL);
    253 
    254     if (rv != APR_SUCCESS) {
     301    rv = apr_memcache_getp(mc, c->pool, key, &value, &value_len, NULL);
     302
     303    if (rv != APR_SUCCESS)
     304    {
    255305#if MOD_GNUTLS_DEBUG
    256         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    257                 ctxt->c->base_server,
    258                 "[gnutls_cache] error fetching key '%s' ",
    259                 strkey);
    260 #endif
    261         data.size = 0;
    262         data.data = NULL;
     306        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
     307                      "error fetching key '%s'",
     308                      key);
     309#endif
    263310        return data;
    264311    }
     
    275322}
    276323
     324static gnutls_datum_t mc_cache_fetch_generic(mgs_handle_t *ctxt,
     325                                             gnutls_datum_t key)
     326{
     327    gnutls_datum_t data = {NULL, 0};
     328    const char *hex = apr_pescape_hex(ctxt->c->pool, key.data, key.size, 1);
     329    if (hex == NULL)
     330        return data;
     331
     332    const char *strkey = apr_psprintf(ctxt->c->pool, MC_TAG "%s", hex);
     333    return mc_cache_fetch(ctxt->c, strkey);
     334}
     335
     336static gnutls_datum_t mc_cache_fetch_session(void *baton, gnutls_datum_t key)
     337{
     338    mgs_handle_t *ctxt = baton;
     339    gnutls_datum_t data = {NULL, 0};
     340
     341    const char *strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
     342    if (!strkey)
     343        return data;
     344
     345    return mc_cache_fetch(ctxt->c, strkey);
     346}
     347
    277348static int mc_cache_delete(void *baton, gnutls_datum_t key) {
    278349    apr_status_t rv = APR_SUCCESS;
     
    288359    if (rv != APR_SUCCESS) {
    289360        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    290                 ctxt->c->base_server,
    291                 "[gnutls_cache] error deleting key '%s' ",
    292                 strkey);
     361                     ctxt->c->base_server,
     362                     "error deleting key '%s'",
     363                     strkey);
    293364        return -1;
    294365    }
     
    308379#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
    309380
    310 static void dbm_cache_expire(mgs_handle_t * ctxt) {
     381static void dbm_cache_expire(server_rec *s)
     382{
     383    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     384        ap_get_module_config(s->module_config, &gnutls_module);
     385
    311386    apr_status_t rv;
    312387    apr_dbm_t *dbm;
    313388    apr_datum_t dbmkey;
    314389    apr_datum_t dbmval;
    315     apr_time_t now;
    316390    apr_time_t dtime;
    317391    apr_pool_t *spool;
    318392    int total, deleted;
    319393
    320     now = apr_time_now();
    321 
    322     if (now - ctxt->sc->last_cache_check <
    323             (ctxt->sc->cache_timeout) / 2)
     394    apr_time_t now = apr_time_now();
     395
     396    if (now - sc->last_cache_check < (sc->cache_timeout) / 2)
    324397        return;
    325398
    326     ctxt->sc->last_cache_check = now;
    327 
    328     apr_pool_create(&spool, ctxt->c->pool);
     399    sc->last_cache_check = now;
     400
     401    apr_pool_create(&spool, NULL);
    329402
    330403    total = 0;
    331404    deleted = 0;
    332405
    333     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    334             ctxt->sc->cache_config, APR_DBM_RWCREATE,
     406    apr_global_mutex_lock(sc->cache->mutex);
     407
     408    rv = apr_dbm_open_ex(&dbm, db_type(sc),
     409            sc->cache_config, APR_DBM_RWCREATE,
    335410            SSL_DBM_FILE_MODE, spool);
    336411    if (rv != APR_SUCCESS) {
    337         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    338                 ctxt->c->base_server,
    339                 "[gnutls_cache] error opening cache searcher '%s'",
    340                 ctxt->sc->cache_config);
     412        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s,
     413                     "error opening cache '%s'",
     414                     sc->cache_config);
     415        apr_global_mutex_unlock(sc->cache->mutex);
    341416        apr_pool_destroy(spool);
    342417        return;
     
    364439    apr_dbm_close(dbm);
    365440
    366     ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    367             ctxt->c->base_server,
    368             "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d",
    369             ctxt->sc->cache_config, deleted, total - deleted);
     441    rv = apr_global_mutex_unlock(sc->cache->mutex);
     442
     443    ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
     444                 "Cleaned up cache '%s'. Deleted %d and left %d",
     445                 sc->cache_config, deleted, total - deleted);
    370446
    371447    apr_pool_destroy(spool);
     
    374450}
    375451
    376 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) {
     452static gnutls_datum_t dbm_cache_fetch(mgs_handle_t *ctxt, gnutls_datum_t key)
     453{
    377454    gnutls_datum_t data = {NULL, 0};
    378455    apr_dbm_t *dbm;
    379     apr_datum_t dbmkey;
     456    apr_datum_t dbmkey = {(char*) key.data, key.size};
    380457    apr_datum_t dbmval;
    381     mgs_handle_t *ctxt = baton;
     458    apr_time_t expiry = 0;
    382459    apr_status_t rv;
    383460
    384     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    385         return data;
     461    /* check if it is time for cache expiration */
     462    dbm_cache_expire(ctxt->c->base_server);
     463
     464    apr_global_mutex_lock(ctxt->sc->cache->mutex);
    386465
    387466    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
     
    389468            SSL_DBM_FILE_MODE, ctxt->c->pool);
    390469    if (rv != APR_SUCCESS) {
    391         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    392                 ctxt->c->base_server,
    393                 "[gnutls_cache] error opening cache '%s'",
    394                 ctxt->sc->cache_config);
     470        ap_log_cerror(APLOG_MARK, APLOG_NOTICE, rv, ctxt->c,
     471                      "error opening cache '%s'",
     472                      ctxt->sc->cache_config);
     473        apr_global_mutex_unlock(ctxt->sc->cache->mutex);
    395474        return data;
    396475    }
     
    398477    rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
    399478
    400     if (rv != APR_SUCCESS) {
    401         apr_dbm_close(dbm);
     479    if (rv != APR_SUCCESS)
     480        goto close_db;
     481
     482    if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t))
     483        goto cleanup;
     484
     485    data.size = dbmval.dsize - sizeof (apr_time_t);
     486    /* get data expiration tag */
     487    expiry = *((apr_time_t *) dbmval.dptr);
     488
     489    data.data = gnutls_malloc(data.size);
     490    if (data.data == NULL)
     491    {
     492        data.size = 0;
     493        goto cleanup;
     494    }
     495
     496    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, ctxt->c,
     497                  "fetched %ld bytes from cache",
     498                  dbmval.dsize);
     499
     500    memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size);
     501
     502 cleanup:
     503    apr_dbm_freedatum(dbm, dbmval);
     504 close_db:
     505    apr_dbm_close(dbm);
     506    apr_global_mutex_unlock(ctxt->sc->cache->mutex);
     507
     508    /* cache entry might have expired since last cache cleanup */
     509    if (expiry != 0 && expiry < apr_time_now())
     510    {
     511        gnutls_free(data.data);
     512        data.data = NULL;
     513        data.size = 0;
     514        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     515                      "dropped expired cache data");
     516    }
     517
     518    return data;
     519}
     520
     521static gnutls_datum_t dbm_cache_fetch_session(void *baton, gnutls_datum_t key)
     522{
     523    gnutls_datum_t data = {NULL, 0};
     524    gnutls_datum_t dbmkey;
     525    mgs_handle_t *ctxt = baton;
     526
     527    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    402528        return data;
    403     }
    404 
    405     if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t)) {
    406         apr_dbm_freedatum(dbm, dbmval);
    407         apr_dbm_close(dbm);
    408         return data;
    409     }
    410 
    411     data.size = dbmval.dsize - sizeof (apr_time_t);
    412 
    413     data.data = gnutls_malloc(data.size);
    414     if (data.data == NULL) {
    415         apr_dbm_freedatum(dbm, dbmval);
    416         apr_dbm_close(dbm);
    417         return data;
    418     }
    419 
    420     memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size);
    421 
    422     apr_dbm_freedatum(dbm, dbmval);
    423     apr_dbm_close(dbm);
    424 
    425     return data;
    426 }
    427 
    428 static int dbm_cache_store(void *baton, gnutls_datum_t key,
    429         gnutls_datum_t data) {
     529
     530    return dbm_cache_fetch(ctxt, dbmkey);
     531}
     532
     533static int dbm_cache_store(server_rec *s, gnutls_datum_t key,
     534                           gnutls_datum_t data, apr_time_t expiry)
     535{
     536    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     537        ap_get_module_config(s->module_config, &gnutls_module);
     538
    430539    apr_dbm_t *dbm;
    431     apr_datum_t dbmkey;
     540    apr_datum_t dbmkey = {(char*) key.data, key.size};
    432541    apr_datum_t dbmval;
    433     mgs_handle_t *ctxt = baton;
    434542    apr_status_t rv;
    435     apr_time_t expiry;
    436543    apr_pool_t *spool;
    437544
    438     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    439         return -1;
    440 
    441     /* we expire dbm only on every store
    442      */
    443     dbm_cache_expire(ctxt);
    444 
    445     apr_pool_create(&spool, ctxt->c->pool);
     545    /* check if it is time for cache expiration */
     546    dbm_cache_expire(s);
     547
     548    apr_pool_create(&spool, NULL);
    446549
    447550    /* create DBM value */
     
    449552    dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize);
    450553
    451     expiry = apr_time_now() + ctxt->sc->cache_timeout;
    452 
     554    /* prepend expiration time */
    453555    memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t));
    454556    memcpy((char *) dbmval.dptr + sizeof (apr_time_t),
    455557            data.data, data.size);
     558
     559    apr_global_mutex_lock(sc->cache->mutex);
     560
     561    rv = apr_dbm_open_ex(&dbm, db_type(sc),
     562                         sc->cache_config, APR_DBM_RWCREATE,
     563                         SSL_DBM_FILE_MODE, spool);
     564    if (rv != APR_SUCCESS)
     565    {
     566        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s,
     567                     "error opening cache '%s'",
     568                     sc->cache_config);
     569        apr_global_mutex_unlock(sc->cache->mutex);
     570        apr_pool_destroy(spool);
     571        return -1;
     572    }
     573
     574    rv = apr_dbm_store(dbm, dbmkey, dbmval);
     575    if (rv != APR_SUCCESS)
     576    {
     577        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
     578                     "error storing in cache '%s'",
     579                     sc->cache_config);
     580        apr_dbm_close(dbm);
     581        apr_global_mutex_unlock(sc->cache->mutex);
     582        apr_pool_destroy(spool);
     583        return -1;
     584    }
     585
     586    apr_dbm_close(dbm);
     587    apr_global_mutex_unlock(sc->cache->mutex);
     588
     589    ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, s,
     590                 "stored %ld bytes of data (%ld byte key) in cache '%s'",
     591                 dbmval.dsize, dbmkey.dsize, sc->cache_config);
     592
     593    apr_pool_destroy(spool);
     594
     595    return 0;
     596}
     597
     598static int dbm_cache_store_session(void *baton, gnutls_datum_t key,
     599                                   gnutls_datum_t data)
     600{
     601    mgs_handle_t *ctxt = baton;
     602    gnutls_datum_t dbmkey;
     603
     604    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
     605        return -1;
     606
     607    apr_time_t expiry = apr_time_now() + ctxt->sc->cache_timeout;
     608
     609    return dbm_cache_store(ctxt->c->base_server, dbmkey, data, expiry);
     610}
     611
     612static int dbm_cache_delete(void *baton, gnutls_datum_t key)
     613{
     614    apr_dbm_t *dbm;
     615    gnutls_datum_t tmpkey;
     616    mgs_handle_t *ctxt = baton;
     617    apr_status_t rv;
     618
     619    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &tmpkey) < 0)
     620        return -1;
     621    apr_datum_t dbmkey = {(char*) tmpkey.data, tmpkey.size};
     622
     623    apr_global_mutex_lock(ctxt->sc->cache->mutex);
    456624
    457625    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
     
    460628    if (rv != APR_SUCCESS) {
    461629        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    462                 ctxt->c->base_server,
    463                 "[gnutls_cache] error opening cache '%s'",
    464                 ctxt->sc->cache_config);
    465         apr_pool_destroy(spool);
    466         return -1;
    467     }
    468 
    469     rv = apr_dbm_store(dbm, dbmkey, dbmval);
    470 
    471     if (rv != APR_SUCCESS) {
    472         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    473                 ctxt->c->base_server,
    474                 "[gnutls_cache] error storing in cache '%s'",
    475                 ctxt->sc->cache_config);
    476         apr_dbm_close(dbm);
    477         apr_pool_destroy(spool);
    478         return -1;
    479     }
    480 
    481     apr_dbm_close(dbm);
    482 
    483     apr_pool_destroy(spool);
    484 
    485     return 0;
    486 }
    487 
    488 static int dbm_cache_delete(void *baton, gnutls_datum_t key) {
    489     apr_dbm_t *dbm;
    490     apr_datum_t dbmkey;
    491     mgs_handle_t *ctxt = baton;
    492     apr_status_t rv;
    493 
    494     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    495         return -1;
    496 
    497     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    498             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    499             SSL_DBM_FILE_MODE, ctxt->c->pool);
     630                     ctxt->c->base_server,
     631                     "error opening cache '%s'",
     632                     ctxt->sc->cache_config);
     633        apr_global_mutex_unlock(ctxt->sc->cache->mutex);
     634        return -1;
     635    }
     636
     637    rv = apr_dbm_delete(dbm, dbmkey);
     638
    500639    if (rv != APR_SUCCESS) {
    501640        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    502                 ctxt->c->base_server,
    503                 "[gnutls_cache] error opening cache '%s'",
    504                 ctxt->sc->cache_config);
    505         return -1;
    506     }
    507 
    508     rv = apr_dbm_delete(dbm, dbmkey);
    509 
    510     if (rv != APR_SUCCESS) {
    511         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    512                 ctxt->c->base_server,
    513                 "[gnutls_cache] error deleting from cache '%s'",
    514                 ctxt->sc->cache_config);
     641                     ctxt->c->base_server,
     642                     "error deleting from cache '%s'",
     643                     ctxt->sc->cache_config);
    515644        apr_dbm_close(dbm);
     645        apr_global_mutex_unlock(ctxt->sc->cache->mutex);
    516646        return -1;
    517647    }
    518648
    519649    apr_dbm_close(dbm);
     650    apr_global_mutex_unlock(ctxt->sc->cache->mutex);
    520651
    521652    return 0;
     
    571702        sc->cache_type = mgs_cache_none;
    572703    /* if GnuTLSCacheTimeout was never explicitly set: */
    573     if (sc->cache_timeout == -1)
    574         sc->cache_timeout = apr_time_from_sec(300);
    575 
    576     if (sc->cache_type == mgs_cache_dbm
    577             || sc->cache_type == mgs_cache_gdbm) {
     704    if (sc->cache_timeout == MGS_TIMEOUT_UNSET)
     705        sc->cache_timeout = apr_time_from_sec(MGS_DEFAULT_CACHE_TIMEOUT);
     706
     707    /* initialize mutex only once */
     708    if (sc->cache == NULL)
     709    {
     710        sc->cache = apr_palloc(p, sizeof(struct mgs_cache));
     711        apr_status_t rv = ap_global_mutex_create(&sc->cache->mutex, NULL,
     712                                                 MGS_CACHE_MUTEX_NAME,
     713                                                 NULL, s, p, 0);
     714        if (rv != APR_SUCCESS)
     715            return rv;
     716    }
     717
     718    if (sc->cache_type == mgs_cache_dbm || sc->cache_type == mgs_cache_gdbm)
     719    {
     720        sc->cache->store = dbm_cache_store;
     721        sc->cache->fetch = dbm_cache_fetch;
    578722        return dbm_cache_post_config(p, s, sc);
    579723    }
    580     return 0;
    581 }
    582 
    583724#if HAVE_APR_MEMCACHE
     725    else if (sc->cache_type == mgs_cache_memcache)
     726    {
     727        sc->cache->store = mc_cache_store_generic;
     728        sc->cache->fetch = mc_cache_fetch_generic;
     729    }
     730#endif
     731
     732    return APR_SUCCESS;
     733}
     734
    584735int mgs_cache_child_init(apr_pool_t * p,
    585736                         server_rec * s,
    586737                         mgs_srvconf_rec * sc)
    587 #else
    588 int mgs_cache_child_init(apr_pool_t * p __attribute__((unused)),
    589                          server_rec * s __attribute__((unused)),
    590                          mgs_srvconf_rec * sc)
    591 #endif
    592 {
     738{
     739    /* reinit cache mutex */
     740    const char *lockfile = apr_global_mutex_lockfile(sc->cache->mutex);
     741    apr_status_t rv = apr_global_mutex_child_init(&sc->cache->mutex,
     742                                                  lockfile, p);
     743    if (rv != APR_SUCCESS)
     744        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     745                     "Failed to reinit mutex '%s'", MGS_CACHE_MUTEX_NAME);
     746
    593747    if (sc->cache_type == mgs_cache_dbm
    594748            || sc->cache_type == mgs_cache_gdbm) {
     
    609763            || ctxt->sc->cache_type == mgs_cache_gdbm) {
    610764        gnutls_db_set_retrieve_function(ctxt->session,
    611                 dbm_cache_fetch);
     765                dbm_cache_fetch_session);
    612766        gnutls_db_set_remove_function(ctxt->session,
    613767                dbm_cache_delete);
    614768        gnutls_db_set_store_function(ctxt->session,
    615                 dbm_cache_store);
     769                dbm_cache_store_session);
    616770        gnutls_db_set_ptr(ctxt->session, ctxt);
    617771    }
     
    619773    else if (ctxt->sc->cache_type == mgs_cache_memcache) {
    620774        gnutls_db_set_retrieve_function(ctxt->session,
    621                 mc_cache_fetch);
     775                mc_cache_fetch_session);
    622776        gnutls_db_set_remove_function(ctxt->session,
    623777                mc_cache_delete);
    624778        gnutls_db_set_store_function(ctxt->session,
    625                 mc_cache_store);
     779                mc_cache_store_session);
    626780        gnutls_db_set_ptr(ctxt->session, ctxt);
    627781    }
Note: See TracChangeset for help on using the changeset viewer.