diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c')
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c new file mode 100644 index 00000000..10ab9c89 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c @@ -0,0 +1,462 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_scache_dbm.c + * Session Cache via DBM + */ + +#include "mod_ssl.h" + +void ssl_scache_dbm_init(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_status_t rv; + + /* for the DBM we need the data file */ + if (mc->szSessionCacheDataFile == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "SSLSessionCache required"); + ssl_die(); + } + + /* open it once to create it and to make sure it _can_ be created */ + ssl_mutex_on(s); + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot create SSLSessionCache DBM file `%s'", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return; + } + apr_dbm_close(dbm); + +#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) + /* + * We have to make sure the Apache child processes have access to + * the DBM file. But because there are brain-dead platforms where we + * cannot exactly determine the suffixes we try all possibilities. + */ + if (geteuid() == 0 /* is superuser */) { + chown(mc->szSessionCacheDataFile, unixd_config.user_id, -1 /* no gid change */); + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL), + unixd_config.user_id, -1) == -1) { + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL), + unixd_config.user_id, -1) == -1) + chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL), + unixd_config.user_id, -1); + } + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL), + unixd_config.user_id, -1) == -1) { + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL), + unixd_config.user_id, -1) == -1) + chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL), + unixd_config.user_id, -1); + } + } +#endif + ssl_mutex_off(s); + ssl_scache_dbm_expire(s); + return; +} + +void ssl_scache_dbm_kill(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_pool_t *p; + + apr_pool_sub_make(&p, mc->pPool, NULL); + if (p != NULL) { + /* the correct way */ + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL)); + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL)); + /* the additional ways to be sure */ + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL)); + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL)); + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL)); + unlink(mc->szSessionCacheDataFile); + apr_pool_destroy(p); + } + return; +} + +BOOL ssl_scache_dbm_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + UCHAR ucaData[SSL_SESSION_MAX_DER]; + int nData; + UCHAR *ucp; + apr_status_t rv; + + /* streamline session data */ + if ((nData = i2d_SSL_SESSION(sess, NULL)) > sizeof(ucaData)) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "streamline session data size too large: %d > %d", + nData, sizeof(ucaData)); + return FALSE; + } + ucp = ucaData; + i2d_SSL_SESSION(sess, &ucp); + + /* be careful: do not try to store too much bytes in a DBM file! */ +#ifdef PAIRMAX + if ((idlen + nData) >= PAIRMAX) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "data size too large for DBM session cache: %d >= %d", + (idlen + nData), PAIRMAX); + return FALSE; + } +#else + if ((idlen + nData) >= 950 /* at least less than approx. 1KB */) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "data size too large for DBM session cache: %d >= %d", + (idlen + nData), 950); + return FALSE; + } +#endif + + /* create DBM key */ + dbmkey.dptr = (char *)id; + dbmkey.dsize = idlen; + + /* create DBM value */ + dbmval.dsize = sizeof(time_t) + nData; + dbmval.dptr = (char *)malloc(dbmval.dsize); + if (dbmval.dptr == NULL) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "malloc error creating DBM value"); + return FALSE; + } + memcpy((char *)dbmval.dptr, &expiry, sizeof(time_t)); + memcpy((char *)dbmval.dptr+sizeof(time_t), ucaData, nData); + + /* and store it to the DBM file */ + ssl_mutex_on(s); + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for writing " + "(store)", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + free(dbmval.dptr); + return FALSE; + } + if ((rv = apr_dbm_store(dbm, dbmkey, dbmval)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot store SSL session to DBM file `%s'", + mc->szSessionCacheDataFile); + apr_dbm_close(dbm); + ssl_mutex_off(s); + free(dbmval.dptr); + return FALSE; + } + apr_dbm_close(dbm); + ssl_mutex_off(s); + + /* free temporary buffers */ + free(dbmval.dptr); + + /* allow the regular expiring to occur */ + ssl_scache_dbm_expire(s); + + return TRUE; +} + +SSL_SESSION *ssl_scache_dbm_retrieve(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + SSL_SESSION *sess = NULL; + MODSSL_D2I_SSL_SESSION_CONST unsigned char *ucpData; + int nData; + time_t expiry; + time_t now; + apr_status_t rc; + + /* allow the regular expiring to occur */ + ssl_scache_dbm_expire(s); + + /* create DBM key and values */ + dbmkey.dptr = (char *)id; + dbmkey.dsize = idlen; + + /* and fetch it from the DBM file + * XXX: Should we open the dbm against r->pool so the cleanup will + * do the apr_dbm_close? This would make the code a bit cleaner. + */ + ssl_mutex_on(s); + if ((rc = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, + "Cannot open SSLSessionCache DBM file `%s' for reading " + "(fetch)", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return NULL; + } + rc = apr_dbm_fetch(dbm, dbmkey, &dbmval); + if (rc != APR_SUCCESS) { + apr_dbm_close(dbm); + ssl_mutex_off(s); + return NULL; + } + if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(time_t)) { + apr_dbm_close(dbm); + ssl_mutex_off(s); + return NULL; + } + + /* parse resulting data */ + nData = dbmval.dsize-sizeof(time_t); + ucpData = malloc(nData); + if (ucpData == NULL) { + apr_dbm_close(dbm); + ssl_mutex_off(s); + return NULL; + } + /* Cast needed, ucpData may be const */ + memcpy((unsigned char *)ucpData, + (char *)dbmval.dptr + sizeof(time_t), nData); + memcpy(&expiry, dbmval.dptr, sizeof(time_t)); + + apr_dbm_close(dbm); + ssl_mutex_off(s); + + /* make sure the stuff is still not expired */ + now = time(NULL); + if (expiry <= now) { + ssl_scache_dbm_remove(s, id, idlen); + return NULL; + } + + /* unstreamed SSL_SESSION */ + sess = d2i_SSL_SESSION(NULL, &ucpData, nData); + + return sess; +} + +void ssl_scache_dbm_remove(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_status_t rv; + + /* create DBM key and values */ + dbmkey.dptr = (char *)id; + dbmkey.dsize = idlen; + + /* and delete it from the DBM file */ + ssl_mutex_on(s); + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for writing " + "(delete)", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return; + } + apr_dbm_delete(dbm, dbmkey); + apr_dbm_close(dbm); + ssl_mutex_off(s); + + return; +} + +void ssl_scache_dbm_expire(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + SSLSrvConfigRec *sc = mySrvConfig(s); + static time_t tLast = 0; + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + apr_pool_t *p; + time_t tExpiresAt; + int nElements = 0; + int nDeleted = 0; + int bDelete; + apr_datum_t *keylist; + int keyidx; + int i; + time_t tNow; + apr_status_t rv; + + /* + * make sure the expiration for still not-accessed session + * cache entries is done only from time to time + */ + tNow = time(NULL); + if (tNow < tLast+sc->session_cache_timeout) + return; + tLast = tNow; + + /* + * Here we have to be very carefully: Not all DBM libraries are + * smart enough to allow one to iterate over the elements and at the + * same time delete expired ones. Some of them get totally crazy + * while others have no problems. So we have to do it the slower but + * more safe way: we first iterate over all elements and remember + * those which have to be expired. Then in a second pass we delete + * all those expired elements. Additionally we reopen the DBM file + * to be really safe in state. + */ + +#define KEYMAX 1024 + + ssl_mutex_on(s); + for (;;) { + /* allocate the key array in a memory sub pool */ + apr_pool_sub_make(&p, mc->pPool, NULL); + if (p == NULL) + break; + if ((keylist = apr_palloc(p, sizeof(dbmkey)*KEYMAX)) == NULL) { + apr_pool_destroy(p); + break; + } + + /* pass 1: scan DBM database */ + keyidx = 0; + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE,SSL_DBM_FILE_MODE, + p)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for " + "scanning", + mc->szSessionCacheDataFile); + apr_pool_destroy(p); + break; + } + apr_dbm_firstkey(dbm, &dbmkey); + while (dbmkey.dptr != NULL) { + nElements++; + bDelete = FALSE; + apr_dbm_fetch(dbm, dbmkey, &dbmval); + if (dbmval.dsize <= sizeof(time_t) || dbmval.dptr == NULL) + bDelete = TRUE; + else { + memcpy(&tExpiresAt, dbmval.dptr, sizeof(time_t)); + if (tExpiresAt <= tNow) + bDelete = TRUE; + } + if (bDelete) { + if ((keylist[keyidx].dptr = apr_palloc(p, dbmkey.dsize)) != NULL) { + memcpy(keylist[keyidx].dptr, dbmkey.dptr, dbmkey.dsize); + keylist[keyidx].dsize = dbmkey.dsize; + keyidx++; + if (keyidx == KEYMAX) + break; + } + } + apr_dbm_nextkey(dbm, &dbmkey); + } + apr_dbm_close(dbm); + + /* pass 2: delete expired elements */ + if (apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE,SSL_DBM_FILE_MODE, p) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot re-open SSLSessionCache DBM file `%s' for " + "expiring", + mc->szSessionCacheDataFile); + apr_pool_destroy(p); + break; + } + for (i = 0; i < keyidx; i++) { + apr_dbm_delete(dbm, keylist[i]); + nDeleted++; + } + apr_dbm_close(dbm); + + /* destroy temporary pool */ + apr_pool_destroy(p); + + if (keyidx < KEYMAX) + break; + } + ssl_mutex_off(s); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Inter-Process Session Cache (DBM) Expiry: " + "old: %d, new: %d, removed: %d", + nElements, nElements-nDeleted, nDeleted); + return; +} + +void ssl_scache_dbm_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + int nElem; + int nSize; + int nAverage; + apr_status_t rv; + + nElem = 0; + nSize = 0; + ssl_mutex_on(s); + /* + * XXX - Check what pool is to be used - TBD + */ + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, + mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for status " + "retrival", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return; + } + /* + * XXX - Check the return value of apr_dbm_firstkey, apr_dbm_fetch - TBD + */ + apr_dbm_firstkey(dbm, &dbmkey); + for ( ; dbmkey.dptr != NULL; apr_dbm_nextkey(dbm, &dbmkey)) { + apr_dbm_fetch(dbm, dbmkey, &dbmval); + if (dbmval.dptr == NULL) + continue; + nElem += 1; + nSize += dbmval.dsize; + } + apr_dbm_close(dbm); + ssl_mutex_off(s); + if (nSize > 0 && nElem > 0) + nAverage = nSize / nElem; + else + nAverage = 0; + func(apr_psprintf(p, "cache type: <b>DBM</b>, maximum size: <b>unlimited</b><br>"), arg); + func(apr_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg); + func(apr_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg); + return; +} + |