source: mod_gnutls/src/gnutls_cache.c @ 8e33f2d

debian/masterdebian/stretch-backportsjessie-backportsmsvaproxy-ticketupstream
Last change on this file since 8e33f2d was c301152, checked in by Paul Querna <chip@…>, 15 years ago
  • move hooks to gnutls_hooks.c
  • use 'mgs_' as the prefix for all symbols, instead of mixed prefixes.
  • Property mode set to 100644
File size: 15.2 KB
RevLine 
[fcb122d]1/**
2 *  Copyright 2004-2005 Paul Querna
[0b3bc05]3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 *
16 */
17
18#include "mod_gnutls.h"
[6e0bfd6]19
20#if HAVE_APR_MEMCACHE
21#include "apr_memcache.h"
22#endif
23
[fcb122d]24#include "apr_dbm.h"
25
[a66e147]26#include "ap_mpm.h"
[0b3bc05]27
[fcb122d]28#include <unistd.h>
29#include <sys/types.h>
30
31#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
32#include "unixd.h"
33#endif
34
[42307a9]35
[6e0bfd6]36#define MC_TAG "mod_gnutls:"
37#define MC_TAG_LEN \
38    (sizeof(MC_TAG))
39#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
40
41static char *gnutls_session_id2sz(unsigned char *id, int idlen,
[42307a9]42                               char *str, int strsize)
[6e0bfd6]43{
44    char *cp;
45    int n;
46 
47    cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN);
48    for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
49        apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
50        cp += 2;
51    }
52    *cp = '\0';
53    return str;
54}
55
[c301152]56char *mgs_session_id2sz(unsigned char *id, int idlen,
[42307a9]57                               char *str, int strsize)
58{
59    char *cp;
60    int n;
61   
62    cp = str;
63    for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
64        apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
65        cp += 2;
66    }
67    *cp = '\0';
68    return str;
69}
70
[6e0bfd6]71
72#if HAVE_APR_MEMCACHE
73
[0b3bc05]74/**
75 * GnuTLS Session Cache using libmemcached
76 *
77 */
78
[a66e147]79/* The underlying apr_memcache system is thread safe... woohoo */
80static apr_memcache_t* mc;
81
[46b85d8]82static int mc_cache_child_init(apr_pool_t *p, server_rec *s, 
[c301152]83                                mgs_srvconf_rec *sc)
[32f2e60]84{
[a66e147]85    apr_status_t rv = APR_SUCCESS;
86    int thread_limit = 0;
87    int nservers = 0;
88    char* cache_config;
89    char* split;
90    char* tok;
91
92    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
93
94    /* Find all the servers in the first run to get a total count */
95    cache_config = apr_pstrdup(p, sc->cache_config);
96    split = apr_strtok(cache_config, " ", &tok);
97    while (split) {
98        nservers++;
99        split = apr_strtok(NULL," ", &tok);
100    }
101
102    rv = apr_memcache_create(p, nservers, 0, &mc);
103    if (rv != APR_SUCCESS) {
104        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
105                        "[gnutls_cache] Failed to create Memcache Object of '%d' size.", 
106                         nservers);
107        return rv;
108    }
109
110    /* Now add each server to the memcache */
111    cache_config = apr_pstrdup(p, sc->cache_config);
112    split = apr_strtok(cache_config, " ", &tok);
113    while (split) {
114        apr_memcache_server_t* st;
115        char* host_str;
[95ca7c0]116        char* scope_id;
117        apr_port_t port;
[a66e147]118
[95ca7c0]119        rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p);
[42307a9]120        if (rv != APR_SUCCESS) {
[95ca7c0]121            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
122                         "[gnutls_cache] Failed to Parse Server: '%s'", split);
123            return rv;
124        }
125
[42307a9]126        if (host_str == NULL) {
[95ca7c0]127            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
128                         "[gnutls_cache] Failed to Parse Server, "
129                         "no hostname specified: '%s'", split);
130            return rv;
[a66e147]131        }
[95ca7c0]132
133        if (port == 0) {
134            port = 11211; /* default port */
[a66e147]135        }
136
137        /* Should Max Conns be (thread_limit / nservers) ? */
138        rv = apr_memcache_server_create(p,
139                                        host_str, port,
140                                        0,
141                                        1,
142                                        thread_limit, 
143                                        600,
144                                        &st);
[42307a9]145        if (rv != APR_SUCCESS) {
[a66e147]146            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
147                         "[gnutls_cache] Failed to Create Server: %s:%d", 
148                         host_str, port);
149            return rv;
150        }
151
152        rv = apr_memcache_add_server(mc, st);
[42307a9]153        if (rv != APR_SUCCESS) {
[a66e147]154            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
155                         "[gnutls_cache] Failed to Add Server: %s:%d", 
156                         host_str, port);
157            return rv;
158        }
159
160        split = apr_strtok(NULL," ", &tok);
161    }
162    return rv;
[32f2e60]163}
[a66e147]164
[6e0bfd6]165static int mc_cache_store(void* baton, gnutls_datum_t key, 
166                          gnutls_datum_t data)
[32f2e60]167{
[a66e147]168    apr_status_t rv = APR_SUCCESS;
[c301152]169    mgs_handle_t *ctxt = baton;
[a66e147]170    char buf[STR_SESSION_LEN];
171    char* strkey = NULL;
172    apr_uint32_t timeout;
173
174    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
175    if(!strkey)
176        return -1;
177
[42307a9]178    timeout = apr_time_sec(ctxt->sc->cache_timeout);
[a66e147]179
[42307a9]180    rv = apr_memcache_set(mc, strkey, data.data, data.size, timeout, 0);
[a66e147]181
[42307a9]182    if (rv != APR_SUCCESS) {
[a66e147]183        ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
184                     ctxt->c->base_server,
185                     "[gnutls_cache] error setting key '%s' "
186                     "with %d bytes of data", strkey, data.size);
187        return -1;
188    }
189
190    return 0;
191}
192
[6e0bfd6]193static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
[a66e147]194{
195    apr_status_t rv = APR_SUCCESS;
[c301152]196    mgs_handle_t *ctxt = baton;
[a66e147]197    char buf[STR_SESSION_LEN];
198    char* strkey = NULL;
199    char* value;
200    apr_size_t value_len;
201    gnutls_datum_t data = { NULL, 0 };
202
203    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
[42307a9]204    if (!strkey) {
[a66e147]205        return data;
206    }
207
208    rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
209                           &value, &value_len, NULL);
210
[42307a9]211    if (rv != APR_SUCCESS) {
[316bd8c]212#if MOD_GNUTLS_DEBUG
[a66e147]213        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
214                     ctxt->c->base_server,
215                     "[gnutls_cache] error fetching key '%s' ",
216                     strkey);
[316bd8c]217#endif
[a66e147]218        data.size = 0;
219        data.data = NULL;
220        return data;
221    }
222
[6e0bfd6]223    /* TODO: Eliminate this memcpy. gnutls-- */
[a66e147]224    data.data = gnutls_malloc(value_len);
225    if (data.data == NULL)
226        return data;
227
228    data.size = value_len;
229    memcpy(data.data, value, value_len);
230
231    return data;
[32f2e60]232}
233
[6e0bfd6]234static int mc_cache_delete(void* baton, gnutls_datum_t key)
[32f2e60]235{
[a66e147]236    apr_status_t rv = APR_SUCCESS;
[c301152]237    mgs_handle_t *ctxt = baton;
[a66e147]238    char buf[STR_SESSION_LEN];
239    char* strkey = NULL;
240
241    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
242    if(!strkey)
243        return -1;
244
245    rv = apr_memcache_delete(mc, strkey, 0);
246
[42307a9]247    if (rv != APR_SUCCESS) {
[a66e147]248        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
249                     ctxt->c->base_server,
250                     "[gnutls_cache] error deleting key '%s' ",
251                      strkey);
252        return -1;
253    }
254
255    return 0;
[32f2e60]256}
257
[6e0bfd6]258#endif /* have_apr_memcache */
259
[fcb122d]260#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
261
[c301152]262static int dbm_cache_expire(mgs_handle_t *ctxt)
[fcb122d]263{
264    apr_status_t rv;
265    apr_dbm_t *dbm;
[42307a9]266    apr_datum_t *keylist;
267    apr_datum_t dbmkey;
268    apr_datum_t dbmval;
269    apr_time_t ex;
270    apr_time_t dtime;
271    apr_pool_t* spool;
272    int i = 0;
273    int keyidx = 0;
274    int should_delete = 0;
275
276    apr_pool_create(&spool, ctxt->c->pool);
277    ex = apr_time_now();
278   
279    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, APR_DBM_READONLY,
280                      SSL_DBM_FILE_MODE, spool);
[fcb122d]281    if (rv != APR_SUCCESS) {
282        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
283                     ctxt->c->base_server,
[42307a9]284                     "[gnutls_cache] error opening cache searcher '%s'",
[fcb122d]285                     ctxt->sc->cache_config);
286        return -1;
287    }
[42307a9]288
289#define KEYMAX 128
290
291    keylist = apr_palloc(spool, sizeof(dbmkey)*KEYMAX);
292
293    apr_dbm_firstkey(dbm, &dbmkey);
294    while (dbmkey.dptr != NULL) {
295        apr_dbm_fetch(dbm, dbmkey, &dbmval);
296        if (dbmval.dptr != NULL) {
297            if (dbmval.dsize >= sizeof(apr_time_t)) {
298                memcpy(&dtime, dbmval.dptr, sizeof(apr_time_t));
299                if (dtime < ex) {
300                    should_delete = 1;
301                }
302            }
303            else {
304                should_delete = 1;
305            }
306           
307            if (should_delete == 1) {
308                should_delete = 0;
309                keylist[keyidx].dptr = apr_palloc(spool, dbmkey.dsize) ;
310                memcpy(keylist[keyidx].dptr, dbmkey.dptr, dbmkey.dsize);
311                keylist[keyidx].dsize = dbmkey.dsize;
312                keyidx++;
313                if (keyidx == KEYMAX) {
314                    break;
315                }
316            }
317           
318        }
319        apr_dbm_nextkey(dbm, &dbmkey);
320    }
[fcb122d]321    apr_dbm_close(dbm);
322
[42307a9]323    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
324                  APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, spool);
325    if (rv != APR_SUCCESS) {
326        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
327                 ctxt->c->base_server,
328                 "[gnutls_cache] error opening cache writer '%s'",
329                 ctxt->sc->cache_config);
330        return -1;
331    }
332
333    for (i = 0; i < keyidx; i++) {
334        apr_dbm_delete(dbm, keylist[i]);
335    }
336
337    apr_dbm_close(dbm);
338    apr_pool_destroy(spool);
339   
[fcb122d]340    return 0;
341}
342
343static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
344{
345    gnutls_datum_t data = { NULL, 0 };
346    apr_dbm_t *dbm;
347    apr_datum_t dbmkey;
348    apr_datum_t dbmval;
[c301152]349    mgs_handle_t *ctxt = baton;
[fcb122d]350    apr_status_t rv;
351
352    dbmkey.dptr  = key.data;
353    dbmkey.dsize = key.size;
354
[42307a9]355    dbm_cache_expire(ctxt);
356
[fcb122d]357    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
358                      APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
359    if (rv != APR_SUCCESS) {
360        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
361                     ctxt->c->base_server,
362                     "[gnutls_cache] error opening cache '%s'",
363                     ctxt->sc->cache_config);
364        return data;
365    }
366
367    rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
[42307a9]368   
[fcb122d]369    if (rv != APR_SUCCESS) {
370        apr_dbm_close(dbm);
371        return data;
372    }
373
374    if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(apr_time_t)) {
375        apr_dbm_close(dbm);
376        return data;
377    }
[42307a9]378    apr_dbm_close(dbm);
[fcb122d]379
380    data.size = dbmval.dsize - sizeof(apr_time_t);
[42307a9]381
382    data.data = gnutls_malloc(data.size);
383    if (data.data == NULL) {
384        return data;
385    }
386   
[fcb122d]387    memcpy(data.data, dbmval.dptr+sizeof(apr_time_t), data.size);
388
389    return data;
390}
391
392static int dbm_cache_store(void* baton, gnutls_datum_t key, 
393                          gnutls_datum_t data)
394{
395    apr_dbm_t *dbm;
396    apr_datum_t dbmkey;
397    apr_datum_t dbmval;
[c301152]398    mgs_handle_t *ctxt = baton;
[fcb122d]399    apr_status_t rv;
[42307a9]400    apr_time_t expiry;
[fcb122d]401   
402    dbmkey.dptr  = (char *)key.data;
403    dbmkey.dsize = key.size;
404
405    /* create DBM value */
[42307a9]406    dbmval.dsize = data.size + sizeof(apr_time_t);
407    dbmval.dptr  = (char *)malloc(dbmval.dsize);
408
409    expiry = apr_time_now() + ctxt->sc->cache_timeout;
[fcb122d]410
[42307a9]411    memcpy((char *)dbmval.dptr, &expiry, sizeof(apr_time_t));
[fcb122d]412    memcpy((char *)dbmval.dptr+sizeof(apr_time_t),
413           data.data, data.size);
414
[42307a9]415    dbm_cache_expire(ctxt);
416
[fcb122d]417    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
418                      APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
419    if (rv != APR_SUCCESS) {
420        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
421                     ctxt->c->base_server,
422                     "[gnutls_cache] error opening cache '%s'",
423                     ctxt->sc->cache_config);
424        free(dbmval.dptr);       
425        return -1;
426    }
427
428    rv = apr_dbm_store(dbm, dbmkey, dbmval);
[42307a9]429   
[fcb122d]430    if (rv != APR_SUCCESS) {
431        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
432                     ctxt->c->base_server,
433                     "[gnutls_cache] error storing in cache '%s'",
434                     ctxt->sc->cache_config);
435        apr_dbm_close(dbm);
436        free(dbmval.dptr);
437        return -1;
438    }
439
440    apr_dbm_close(dbm);
441
442    free(dbmval.dptr);
443   
444    return 0;
445}
446
447static int dbm_cache_delete(void* baton, gnutls_datum_t key)
448{
449    apr_dbm_t *dbm;
450    apr_datum_t dbmkey;
[c301152]451    mgs_handle_t *ctxt = baton;
[fcb122d]452    apr_status_t rv;
453   
454    dbmkey.dptr  = (char *)key.data;
455    dbmkey.dsize = key.size;
456
[42307a9]457    dbm_cache_expire(ctxt);
458   
[fcb122d]459    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
460                      APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
461    if (rv != APR_SUCCESS) {
462        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
463                     ctxt->c->base_server,
464                     "[gnutls_cache] error opening cache '%s'",
465                     ctxt->sc->cache_config);
466        return -1;
467    }
468
469    rv = apr_dbm_delete(dbm, dbmkey);
470
471    if (rv != APR_SUCCESS) {
472        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
473                     ctxt->c->base_server,
[42307a9]474                     "[gnutls_cache] error deleting from cache '%s'",
[fcb122d]475                     ctxt->sc->cache_config);
476        apr_dbm_close(dbm);
477        return -1;
478    }
479
480    apr_dbm_close(dbm);
481
482    return 0;
483}
484
[42307a9]485static int dbm_cache_post_config(apr_pool_t *p, server_rec *s, 
[c301152]486                                mgs_srvconf_rec *sc)
[fcb122d]487{
488    apr_status_t rv;
489    apr_dbm_t *dbm;
490    const char* path1;
491    const char* path2;
492
493    rv = apr_dbm_open(&dbm, sc->cache_config, APR_DBM_RWCREATE, 
494                      SSL_DBM_FILE_MODE, p);
495
496    if (rv != APR_SUCCESS) {
497        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
498                     "GnuTLS: Cannot create DBM Cache at `%s'", 
499                     sc->cache_config);
500        return rv; 
501    }
502
503    apr_dbm_close(dbm);
504
505    apr_dbm_get_usednames(p, sc->cache_config, &path1, &path2);
506
507    /* The Following Code takes logic directly from mod_ssl's DBM Cache */ 
508#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
509    /* Running as Root */
510    if (geteuid() == 0)  {
511        chown(path1, unixd_config.user_id, -1);
512        if (path2 != NULL) { 
513            chown(path2, unixd_config.user_id, -1);
514        }
515    }
516#endif
517
518    return rv;
519}
520
[c301152]521int mgs_cache_post_config(apr_pool_t *p, server_rec *s, 
522                                 mgs_srvconf_rec *sc)
[fcb122d]523{
[c301152]524    if (sc->cache_type == mgs_cache_dbm) {
[42307a9]525        return dbm_cache_post_config(p, s, sc);
[fcb122d]526    }
527    return 0;
528}
529
[c301152]530int mgs_cache_child_init(apr_pool_t *p, server_rec *s, 
531                                mgs_srvconf_rec *sc)
[6e0bfd6]532{
[c301152]533    if (sc->cache_type == mgs_cache_dbm) {
[fcb122d]534        return 0;
535    }
[6e0bfd6]536#if HAVE_APR_MEMCACHE
[c301152]537    else if (sc->cache_type == mgs_cache_memcache) { 
[fcb122d]538        return mc_cache_child_init(p, s, sc);
539    }
[6e0bfd6]540#endif
[fcb122d]541    return 0;
[6e0bfd6]542}
543
[fcb122d]544 #include <assert.h>
545
[c301152]546int mgs_cache_session_init(mgs_handle_t *ctxt)
[32f2e60]547{
[c301152]548    if (ctxt->sc->cache_type == mgs_cache_dbm) {
[fcb122d]549        gnutls_db_set_retrieve_function(ctxt->session, dbm_cache_fetch);
550        gnutls_db_set_remove_function(ctxt->session, dbm_cache_delete);
551        gnutls_db_set_store_function(ctxt->session, dbm_cache_store);
552        gnutls_db_set_ptr(ctxt->session, ctxt);
553    }
[6e0bfd6]554#if HAVE_APR_MEMCACHE
[c301152]555    else if (ctxt->sc->cache_type == mgs_cache_memcache) { 
[fcb122d]556        gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch);
557        gnutls_db_set_remove_function(ctxt->session, mc_cache_delete);
558        gnutls_db_set_store_function(ctxt->session, mc_cache_store);
559        gnutls_db_set_ptr(ctxt->session, ctxt);
560    }
[6e0bfd6]561#endif
[42307a9]562
[a66e147]563    return 0;
[32f2e60]564}
Note: See TracBrowser for help on using the repository browser.