source: mod_gnutls/src/gnutls_cache.c @ fcb122d

debian/masterdebian/stretch-backportsjessie-backportsmsvaupstream
Last change on this file since fcb122d was fcb122d, checked in by Paul Querna <chip@…>, 15 years ago

checkpoint the work so far. The DBM cache needs a little more work.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/**
2 *  Copyright 2004-2005 Paul Querna
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"
19
20#if HAVE_APR_MEMCACHE
21#include "apr_memcache.h"
22#endif
23
24#include "apr_dbm.h"
25
26#include "ap_mpm.h"
27
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
35#define GNUTLS_SESSION_ID_STRING_LEN \
36    ((GNUTLS_MAX_SESSION_ID + 1) * 2)
37#define MC_TAG "mod_gnutls:"
38#define MC_TAG_LEN \
39    (sizeof(MC_TAG))
40#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
41
42static char *gnutls_session_id2sz(unsigned char *id, int idlen,
43                        char *str, int strsize)
44{
45    char *cp;
46    int n;
47 
48    cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN);
49    for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
50        apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
51        cp += 2;
52    }
53    *cp = '\0';
54    return str;
55}
56
57
58#if HAVE_APR_MEMCACHE
59
60/**
61 * GnuTLS Session Cache using libmemcached
62 *
63 */
64
65/* The underlying apr_memcache system is thread safe... woohoo */
66static apr_memcache_t* mc;
67
68int mc_cache_child_init(apr_pool_t *p, server_rec *s, 
69                                mod_gnutls_srvconf_rec *sc)
70{
71    apr_status_t rv = APR_SUCCESS;
72    int thread_limit = 0;
73    int nservers = 0;
74    char* cache_config;
75    char* split;
76    char* tok;
77
78    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
79
80    /* Find all the servers in the first run to get a total count */
81    cache_config = apr_pstrdup(p, sc->cache_config);
82    split = apr_strtok(cache_config, " ", &tok);
83    while (split) {
84        nservers++;
85        split = apr_strtok(NULL," ", &tok);
86    }
87
88    rv = apr_memcache_create(p, nservers, 0, &mc);
89    if (rv != APR_SUCCESS) {
90        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
91                        "[gnutls_cache] Failed to create Memcache Object of '%d' size.", 
92                         nservers);
93        return rv;
94    }
95
96    /* Now add each server to the memcache */
97    cache_config = apr_pstrdup(p, sc->cache_config);
98    split = apr_strtok(cache_config, " ", &tok);
99    while (split) {
100        apr_memcache_server_t* st;
101        char* host_str;
102        char* scope_id;
103        apr_port_t port;
104
105        rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p);
106        if(rv != APR_SUCCESS) {
107            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
108                         "[gnutls_cache] Failed to Parse Server: '%s'", split);
109            return rv;
110        }
111
112        if(host_str == NULL) {
113            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
114                         "[gnutls_cache] Failed to Parse Server, "
115                         "no hostname specified: '%s'", split);
116            return rv;
117        }
118
119        if (port == 0) {
120            port = 11211; /* default port */
121        }
122
123        /* Should Max Conns be (thread_limit / nservers) ? */
124        rv = apr_memcache_server_create(p,
125                                        host_str, port,
126                                        0,
127                                        1,
128                                        thread_limit, 
129                                        600,
130                                        &st);
131        if(rv != APR_SUCCESS) {
132            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
133                         "[gnutls_cache] Failed to Create Server: %s:%d", 
134                         host_str, port);
135            return rv;
136        }
137
138        rv = apr_memcache_add_server(mc, st);
139        if(rv != APR_SUCCESS) {
140            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
141                         "[gnutls_cache] Failed to Add Server: %s:%d", 
142                         host_str, port);
143            return rv;
144        }
145
146        split = apr_strtok(NULL," ", &tok);
147    }
148    return rv;
149}
150
151static int mc_cache_store(void* baton, gnutls_datum_t key, 
152                          gnutls_datum_t data)
153{
154    apr_status_t rv = APR_SUCCESS;
155    mod_gnutls_handle_t *ctxt = baton;
156    char buf[STR_SESSION_LEN];
157    char* strkey = NULL;
158    apr_uint32_t timeout;
159
160    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
161    if(!strkey)
162        return -1;
163
164    timeout = ctxt->sc->cache_timeout;
165
166    rv = apr_memcache_set(mc,  strkey, data.data, data.size, timeout, 0);
167
168    if(rv != APR_SUCCESS) {
169        ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
170                     ctxt->c->base_server,
171                     "[gnutls_cache] error setting key '%s' "
172                     "with %d bytes of data", strkey, data.size);
173        return -1;
174    }
175
176    return 0;
177}
178
179static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
180{
181    apr_status_t rv = APR_SUCCESS;
182    mod_gnutls_handle_t *ctxt = baton;
183    char buf[STR_SESSION_LEN];
184    char* strkey = NULL;
185    char* value;
186    apr_size_t value_len;
187    gnutls_datum_t data = { NULL, 0 };
188
189    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
190    if(!strkey) {
191        return data;
192    }
193
194    rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
195                           &value, &value_len, NULL);
196
197    if(rv != APR_SUCCESS) {
198        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
199                     ctxt->c->base_server,
200                     "[gnutls_cache] error fetching key '%s' ",
201                     strkey);
202
203        data.size = 0;
204        data.data = NULL;
205        return data;
206    }
207
208    /* TODO: Eliminate this memcpy. gnutls-- */
209    data.data = gnutls_malloc(value_len);
210    if (data.data == NULL)
211        return data;
212
213    data.size = value_len;
214    memcpy(data.data, value, value_len);
215
216    return data;
217}
218
219static int mc_cache_delete(void* baton, gnutls_datum_t key)
220{
221    apr_status_t rv = APR_SUCCESS;
222    mod_gnutls_handle_t *ctxt = baton;
223    char buf[STR_SESSION_LEN];
224    char* strkey = NULL;
225
226    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
227    if(!strkey)
228        return -1;
229
230    rv = apr_memcache_delete(mc, strkey, 0);
231
232    if(rv != APR_SUCCESS) {
233        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
234                     ctxt->c->base_server,
235                     "[gnutls_cache] error deleting key '%s' ",
236                      strkey);
237        return -1;
238    }
239
240    return 0;
241}
242
243#endif /* have_apr_memcache */
244
245#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
246
247static int dbm_cache_expire(mod_gnutls_handle_t *ctxt)
248{
249    apr_status_t rv;
250    apr_dbm_t *dbm;
251
252    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
253                      APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
254    if (rv != APR_SUCCESS) {
255        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
256                     ctxt->c->base_server,
257                     "[gnutls_cache] error opening cache '%s'",
258                     ctxt->sc->cache_config);
259        return -1;
260    }
261    apr_dbm_close(dbm);
262
263    return 0;
264}
265
266static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
267{
268    gnutls_datum_t data = { NULL, 0 };
269    apr_dbm_t *dbm;
270    apr_datum_t dbmkey;
271    apr_datum_t dbmval;
272    mod_gnutls_handle_t *ctxt = baton;
273    apr_status_t rv;
274
275    dbmkey.dptr  = key.data;
276    dbmkey.dsize = key.size;
277
278    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
279                      APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
280    if (rv != APR_SUCCESS) {
281        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
282                     ctxt->c->base_server,
283                     "[gnutls_cache] error opening cache '%s'",
284                     ctxt->sc->cache_config);
285        return data;
286    }
287
288    rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
289
290    if (rv != APR_SUCCESS) {
291        apr_dbm_close(dbm);
292        return data;
293    }
294
295    if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(apr_time_t)) {
296        apr_dbm_close(dbm);
297        return data;
298    }
299
300    data.data = gnutls_malloc(dbmval.dsize - sizeof(apr_time_t));
301    if (data.data == NULL)
302        return data;
303
304    data.size = dbmval.dsize - sizeof(apr_time_t);
305    memcpy(data.data, dbmval.dptr+sizeof(apr_time_t), data.size);
306
307    apr_dbm_close(dbm);
308    return data;
309}
310
311static int dbm_cache_store(void* baton, gnutls_datum_t key, 
312                          gnutls_datum_t data)
313{
314    apr_dbm_t *dbm;
315    apr_datum_t dbmkey;
316    apr_datum_t dbmval;
317    mod_gnutls_handle_t *ctxt = baton;
318    apr_status_t rv;
319    apr_time_t timeout;
320   
321    dbmkey.dptr  = (char *)key.data;
322    dbmkey.dsize = key.size;
323
324    /* create DBM value */
325    dbmval.dsize = data.size;
326    dbmval.dptr  = (char *)malloc(dbmval.dsize+sizeof(apr_time_t));
327
328    memcpy((char *)dbmval.dptr+sizeof(apr_time_t),
329           data.data, data.size);
330
331    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
332                      APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
333    if (rv != APR_SUCCESS) {
334        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
335                     ctxt->c->base_server,
336                     "[gnutls_cache] error opening cache '%s'",
337                     ctxt->sc->cache_config);
338        free(dbmval.dptr);       
339        return -1;
340    }
341
342    rv = apr_dbm_store(dbm, dbmkey, dbmval);
343
344    if (rv != APR_SUCCESS) {
345        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
346                     ctxt->c->base_server,
347                     "[gnutls_cache] error storing in cache '%s'",
348                     ctxt->sc->cache_config);
349        apr_dbm_close(dbm);
350        free(dbmval.dptr);
351        return -1;
352    }
353
354    apr_dbm_close(dbm);
355
356    free(dbmval.dptr);
357   
358    return 0;
359}
360
361static int dbm_cache_delete(void* baton, gnutls_datum_t key)
362{
363    apr_dbm_t *dbm;
364    apr_datum_t dbmkey;
365    mod_gnutls_handle_t *ctxt = baton;
366    apr_status_t rv;
367   
368    dbmkey.dptr  = (char *)key.data;
369    dbmkey.dsize = key.size;
370
371    rv = apr_dbm_open(&dbm, ctxt->sc->cache_config,
372                      APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool);
373    if (rv != APR_SUCCESS) {
374        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
375                     ctxt->c->base_server,
376                     "[gnutls_cache] error opening cache '%s'",
377                     ctxt->sc->cache_config);
378        return -1;
379    }
380
381    rv = apr_dbm_delete(dbm, dbmkey);
382
383    if (rv != APR_SUCCESS) {
384        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
385                     ctxt->c->base_server,
386                     "[gnutls_cache] error storing in cache '%s'",
387                     ctxt->sc->cache_config);
388        apr_dbm_close(dbm);
389        return -1;
390    }
391
392    apr_dbm_close(dbm);
393
394    return 0;
395}
396
397static int dbm_cache_child_init(apr_pool_t *p, server_rec *s, 
398                                mod_gnutls_srvconf_rec *sc)
399{
400    apr_status_t rv;
401    apr_dbm_t *dbm;
402    const char* path1;
403    const char* path2;
404
405    rv = apr_dbm_open(&dbm, sc->cache_config, APR_DBM_RWCREATE, 
406                      SSL_DBM_FILE_MODE, p);
407
408    if (rv != APR_SUCCESS) {
409        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
410                     "GnuTLS: Cannot create DBM Cache at `%s'", 
411                     sc->cache_config);
412        return rv; 
413    }
414
415    apr_dbm_close(dbm);
416
417    apr_dbm_get_usednames(p, sc->cache_config, &path1, &path2);
418
419    /* The Following Code takes logic directly from mod_ssl's DBM Cache */ 
420#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
421    /* Running as Root */
422    if (geteuid() == 0)  {
423        chown(path1, unixd_config.user_id, -1);
424        if (path2 != NULL) { 
425            chown(path2, unixd_config.user_id, -1);
426        }
427    }
428#endif
429
430    return rv;
431}
432
433int mod_gnutls_cache_post_config(apr_pool_t *p, server_rec *s, 
434                                 mod_gnutls_srvconf_rec *sc)
435{
436    if (sc->cache_type == mod_gnutls_cache_dbm) {
437        return dbm_cache_child_init(p, s, sc);
438    }
439    return 0;
440}
441
442int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s, 
443                                mod_gnutls_srvconf_rec *sc)
444{
445    if (sc->cache_type == mod_gnutls_cache_dbm) {
446        return 0;
447    }
448#if HAVE_APR_MEMCACHE
449    else if (sc->cache_type == mod_gnutls_cache_memcache) { 
450        return mc_cache_child_init(p, s, sc);
451    }
452#endif
453    return 0;
454}
455
456 #include <assert.h>
457
458int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt)
459{
460    printf("Type: %d Params: %s\n",ctxt->sc->cache_type, ctxt->sc->cache_config);
461    if (ctxt->sc->cache_type == mod_gnutls_cache_dbm) {
462        gnutls_db_set_retrieve_function(ctxt->session, dbm_cache_fetch);
463        gnutls_db_set_remove_function(ctxt->session, dbm_cache_delete);
464        gnutls_db_set_store_function(ctxt->session, dbm_cache_store);
465        gnutls_db_set_ptr(ctxt->session, ctxt);
466    }
467#if HAVE_APR_MEMCACHE
468    else if (ctxt->sc->cache_type == mod_gnutls_cache_memcache) { 
469        gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch);
470        gnutls_db_set_remove_function(ctxt->session, mc_cache_delete);
471        gnutls_db_set_store_function(ctxt->session, mc_cache_store);
472        gnutls_db_set_ptr(ctxt->session, ctxt);
473    }
474#endif
475    else {
476        assert(1);
477        /* No Session Cache is Available. Opps. */
478    }
479    return 0;
480}
Note: See TracBrowser for help on using the repository browser.