BOOL ssl_scache_shmht_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) { SSLModConfigRec *mc = myModConfig(); void *vp; UCHAR ucaData[SSL_SESSION_MAX_DER]; int nData; UCHAR *ucp; /* streamline session data */ if ((nData = i2d_SSL_SESSION(sess, NULL)) > sizeof(ucaData)) return FALSE; ucp = ucaData; i2d_SSL_SESSION(sess, &ucp); ssl_mutex_on(s); if (table_insert_kd(mc->tSessionCacheDataTable, id, idlen, NULL, sizeof(time_t)+nData, NULL, &vp, 1) != TABLE_ERROR_NONE) { ssl_mutex_off(s); return FALSE; } memcpy(vp, &expiry, sizeof(time_t)); memcpy((char *)vp+sizeof(time_t), ucaData, nData); ssl_mutex_off(s); /* allow the regular expiring to occur */ ssl_scache_shmht_expire(s); return TRUE; }
/* _________________________________________________________________ ** ** SSL Extension to mod_status ** _________________________________________________________________ */ static int ssl_ext_status_hook(request_rec *r, int flags) { SSLModConfigRec *mc = myModConfig(r->server); if (mc == NULL || flags & AP_STATUS_SHORT || mc->sesscache == NULL) return OK; ap_rputs("<hr>\n", r); ap_rputs("<table cellspacing=0 cellpadding=0>\n", r); ap_rputs("<tr><td bgcolor=\"#000000\">\n", r); ap_rputs("<b><font color=\"#ffffff\" face=\"Arial,Helvetica\">SSL/TLS Session Cache Status:</font></b>\r", r); ap_rputs("</td></tr>\n", r); ap_rputs("<tr><td bgcolor=\"#ffffff\">\n", r); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(r->server); } mc->sesscache->status(mc->sesscache_context, r, flags); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(r->server); } ap_rputs("</td></tr>\n", r); ap_rputs("</table>\n", r); return OK; }
SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); unsigned char dest[SSL_SESSION_MAX_DER]; unsigned int destlen = SSL_SESSION_MAX_DER; const unsigned char *ptr; apr_status_t rv; if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(s); } rv = mc->sesscache->retrieve(mc->sesscache_context, s, id, idlen, dest, &destlen, p); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(s); } if (rv != APR_SUCCESS) { return NULL; } ptr = dest; return d2i_SSL_SESSION(NULL, &ptr, destlen); }
BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, apr_time_t expiry, SSL_SESSION *sess, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); unsigned char encoded[SSL_SESSION_MAX_DER], *ptr; unsigned int len; apr_status_t rv; /* Serialise the session. */ len = i2d_SSL_SESSION(sess, NULL); if (len > sizeof encoded) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01875) "session is too big (%u bytes)", len); return FALSE; } ptr = encoded; len = i2d_SSL_SESSION(sess, &ptr); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(s); } rv = mc->sesscache->store(mc->sesscache_context, s, id, idlen, expiry, encoded, len, p); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(s); } return rv == APR_SUCCESS ? TRUE : FALSE; }
void ssl_scache_shmht_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg) { SSLModConfigRec *mc = myModConfig(); void *vpKey; void *vpData; int nKey; int nData; int nElem; int nSize; int nAverage; nElem = 0; nSize = 0; ssl_mutex_on(s); if (table_first(mc->tSessionCacheDataTable, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { do { if (vpKey == NULL || vpData == NULL) continue; nElem += 1; nSize += nData; } while (table_next(mc->tSessionCacheDataTable, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE); } ssl_mutex_off(s); if (nSize > 0 && nElem > 0) nAverage = nSize / nElem; else nAverage = 0; func(ap_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg); func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg); func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg); return; }
SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); SSL_SESSION *pSession = NULL; SHMCBHeader *header = mc->tSessionCacheDataTable; SHMCBSubcache *subcache = SHMCB_MASK(header, id); ssl_mutex_on(s); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "ssl_scache_shmcb_retrieve (0x%02x -> subcache %d)", SHMCB_MASK_DBG(header, id)); if (idlen < 4) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " "(%u bytes)", idlen); goto done; } /* Get the session corresponding to the session_id or NULL if it doesn't * exist (or is flagged as "removed"). */ pSession = shmcb_subcache_retrieve(s, header, subcache, id, idlen); if (pSession) header->stat_retrieves_hit++; else header->stat_retrieves_miss++; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "leaving ssl_scache_shmcb_retrieve successfully"); done: ssl_mutex_off(s); return pSession; }
SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(); void *vp; SSL_SESSION *sess = NULL; UCHAR *ucpData; int nData; time_t expiry; time_t now; int n; /* allow the regular expiring to occur */ ssl_scache_shmht_expire(s); /* lookup key in table */ ssl_mutex_on(s); if (table_retrieve(mc->tSessionCacheDataTable, id, idlen, &vp, &n) != TABLE_ERROR_NONE) { ssl_mutex_off(s); return NULL; } /* copy over the information to the SCI */ nData = n-sizeof(time_t); ucpData = (UCHAR *)malloc(nData); if (ucpData == NULL) { ssl_mutex_off(s); return NULL; } memcpy(&expiry, vp, sizeof(time_t)); memcpy(ucpData, (char *)vp+sizeof(time_t), nData); ssl_mutex_off(s); /* make sure the stuff is still not expired */ now = time(NULL); if (expiry <= now) { ssl_scache_shmht_remove(s, id, idlen); return NULL; } /* unstreamed SSL_SESSION */ sess = d2i_SSL_SESSION(NULL, &ucpData, nData); return sess; }
void ssl_scache_shmht_expire(server_rec *s) { SSLModConfigRec *mc = myModConfig(); SSLSrvConfigRec *sc = mySrvConfig(s); static time_t tLast = 0; table_linear_t iterator; time_t tExpiresAt; void *vpKey; void *vpKeyThis; void *vpData; int nKey; int nKeyThis; int nData; int nElements = 0; int nDeleted = 0; int bDelete; int rc; time_t tNow; /* * 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->nSessionCacheTimeout) return; tLast = tNow; ssl_mutex_on(s); if (table_first_r(mc->tSessionCacheDataTable, &iterator, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { do { bDelete = FALSE; nElements++; if (nData < sizeof(time_t) || vpData == NULL) bDelete = TRUE; else { memcpy(&tExpiresAt, vpData, sizeof(time_t)); if (tExpiresAt <= tNow) bDelete = TRUE; } vpKeyThis = vpKey; nKeyThis = nKey; rc = table_next_r(mc->tSessionCacheDataTable, &iterator, &vpKey, &nKey, &vpData, &nData); if (bDelete) { table_delete(mc->tSessionCacheDataTable, vpKeyThis, nKeyThis, NULL, NULL); nDeleted++; } } while (rc == TABLE_ERROR_NONE); } ssl_mutex_off(s); ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache (SHMHT) Expiry: " "old: %d, new: %d, removed: %d", nElements, nElements-nDeleted, nDeleted); return; }
void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(); /* remove value under key in table */ ssl_mutex_on(s); table_delete(mc->tSessionCacheDataTable, id, idlen, NULL, NULL); ssl_mutex_off(s); return; }
void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_on(s); } mc->sesscache->remove(mc->sesscache_context, s, id, idlen, p); if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { ssl_mutex_off(s); } }
BOOL ssl_scache_shmcb_store(server_rec *s, UCHAR *id, int idlen, time_t timeout, SSL_SESSION * pSession) { SSLModConfigRec *mc = myModConfig(s); BOOL to_return = FALSE; unsigned char encoded[SSL_SESSION_MAX_DER]; unsigned char *ptr_encoded; unsigned int len_encoded; SHMCBHeader *header = mc->tSessionCacheDataTable; SHMCBSubcache *subcache = SHMCB_MASK(header, id); ssl_mutex_on(s); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "ssl_scache_shmcb_store (0x%02x -> subcache %d)", SHMCB_MASK_DBG(header, id)); if (idlen < 4) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " "(%u bytes)", idlen); goto done; } /* Serialise the session. */ len_encoded = i2d_SSL_SESSION(pSession, NULL); if (len_encoded > SSL_SESSION_MAX_DER) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "session is too big (%u bytes)", len_encoded); goto done; } ptr_encoded = encoded; len_encoded = i2d_SSL_SESSION(pSession, &ptr_encoded); if (!shmcb_subcache_store(s, header, subcache, encoded, len_encoded, id, timeout)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "can't store a session!"); goto done; } header->stat_stores++; to_return = TRUE; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "leaving ssl_scache_shmcb_store successfully"); done: ssl_mutex_off(s); return to_return; }
void ssl_scache_shmcb_remove(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); SHMCBHeader *header = mc->tSessionCacheDataTable; SHMCBSubcache *subcache = SHMCB_MASK(header, id); ssl_mutex_on(s); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "ssl_scache_shmcb_remove (0x%02x -> subcache %d)", SHMCB_MASK_DBG(header, id)); if (idlen < 4) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " "(%u bytes)", idlen); goto done; } if (shmcb_subcache_remove(s, header, subcache, id, idlen)) header->stat_removes_hit++; else header->stat_removes_miss++; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "leaving ssl_scache_shmcb_remove successfully"); done: ssl_mutex_off(s); }
void ssl_scache_shmcb_status(request_rec *r, int flags, apr_pool_t *p) { server_rec *s = r->server; SSLModConfigRec *mc = myModConfig(s); void *shm_segment = apr_shm_baseaddr_get(mc->pSessionCacheDataMM); SHMCBHeader *header = shm_segment; unsigned int loop, total = 0, cache_total = 0, non_empty_subcaches = 0; time_t idx_expiry, min_expiry = 0, max_expiry = 0, average_expiry = 0; time_t now = time(NULL); double expiry_total = 0; int index_pct, cache_pct; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "inside shmcb_status"); /* Perform the iteration inside the mutex to avoid corruption or invalid * pointer arithmetic. The rest of our logic uses read-only header data so * doesn't need the lock. */ ssl_mutex_on(s); /* Iterate over the subcaches */ for (loop = 0; loop < header->subcache_num; loop++) { SHMCBSubcache *subcache = SHMCB_SUBCACHE(header, loop); shmcb_subcache_expire(s, header, subcache); total += subcache->idx_used; cache_total += subcache->data_used; if (subcache->idx_used) { SHMCBIndex *idx = SHMCB_INDEX(subcache, subcache->idx_pos); non_empty_subcaches++; idx_expiry = idx->expires; expiry_total += (double)idx_expiry; max_expiry = ((idx_expiry > max_expiry) ? idx_expiry : max_expiry); if (!min_expiry) min_expiry = idx_expiry; else min_expiry = ((idx_expiry < min_expiry) ? idx_expiry : min_expiry); } } ssl_mutex_off(s); index_pct = (100 * total) / (header->index_num * header->subcache_num); cache_pct = (100 * cache_total) / (header->subcache_data_size * header->subcache_num); /* Generate HTML */ ap_rprintf(r, "cache type: <b>SHMCB</b>, shared memory: <b>%d</b> " "bytes, current sessions: <b>%d</b><br>", mc->nSessionCacheDataSize, total); ap_rprintf(r, "subcaches: <b>%d</b>, indexes per subcache: <b>%d</b><br>", header->subcache_num, header->index_num); if (non_empty_subcaches) { average_expiry = (time_t)(expiry_total / (double)non_empty_subcaches); ap_rprintf(r, "time left on oldest entries' SSL sessions: "); if (now < average_expiry) ap_rprintf(r, "avg: <b>%d</b> seconds, (range: %d...%d)<br>", (int)(average_expiry - now), (int)(min_expiry - now), (int)(max_expiry - now)); else ap_rprintf(r, "expiry_threshold: <b>Calculation error!</b><br>"); } ap_rprintf(r, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b><br>", index_pct, cache_pct); ap_rprintf(r, "total sessions stored since starting: <b>%lu</b><br>", header->stat_stores); ap_rprintf(r, "total sessions expired since starting: <b>%lu</b><br>", header->stat_expiries); ap_rprintf(r, "total (pre-expiry) sessions scrolled out of the cache: " "<b>%lu</b><br>", header->stat_scrolled); ap_rprintf(r, "total retrieves since starting: <b>%lu</b> hit, " "<b>%lu</b> miss<br>", header->stat_retrieves_hit, header->stat_retrieves_miss); ap_rprintf(r, "total removes since starting: <b>%lu</b> hit, " "<b>%lu</b> miss<br>", header->stat_removes_hit, header->stat_removes_miss); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "leaving shmcb_status"); }