Update of /cvsroot/mod-auth/mod_authn_cache/src
In directory sc8-pr-cvs1:/tmp/cvs-serv4746/mod_authn_cache/src
Added Files:
Makefile.am mod_authn_cache.c util_authn_cache.c
util_authn_cache.h util_authn_cache_mgr.c
Log Message:
add initial mod_authn_cache
--- NEW FILE: Makefile.am ---
CLEANFILES = .libs/libmod_authn_cache *~
libmod_authn_cache_la_SOURCES = mod_authn_cache.c
lib_LTLIBRARIES = libmod_authn_cache.la
make_so:
@if test ! -L mod_authn_cache.so ; then ln -s .libs/libmod_authn_cache.so mod_authn_cache.so ; fi
install:
$(INSTALL) -m 644 .libs/libmod_authn_cache.so $(LIBEXECDIR)/mod_authn_cache.so
@echo ""
@echo ""
@echo "***********************************************"
@echo ""
@echo " Please read the documentation at "
@echo " http://mod-auth.sourceforge.net/docs/ for "
@echo " details on configuration of this module "
@echo ""
@echo "***********************************************"
@echo ""
--- NEW FILE: mod_authn_cache.c ---
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact ap...@ap....
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
/*
* mod_authn_cache
*
* Paul Querna
*/
#include "apr_lib.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
#include "apr_strings.h"
#include "apr_md5.h"
#include "apr_sha1.h"
#include "apr_reslist.h"
#include "apr_thread_mutex.h"
#include "apr_hash.h"
#include "apr_shm.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
#include "mod_auth.h"
#include "util_md5.h"
#if !APR_HAS_SHARED_MEMORY
#error Shared Memory is required to use authn_cache
#endif
#include "util_authn_cache.h"
#define DFLT_TIMEOUT 300 // 5 minutes
enum
{
CONF_CACHE_HANDLER,
CONF_CACHE_TIMEOUT,
CONF_CACHE_TYPE,
};
typedef struct {
char *handler;
char *type_path;
int type;
apr_interval_time_t timeout;
authn_provider_list *providers;
util_cache_state_t *cache;
} cache_config_rec;
enum
{
CT_SHMEM,
CT_FILE,
};
static void *create_authn_cache_config(apr_pool_t * p, char *d)
{
cache_config_rec *conf;
conf = (cache_config_rec *) apr_pcalloc(p, sizeof(cache_config_rec));
if (conf == NULL) {
return NULL;
}
conf->handler = NULL;
conf->type = CT_FILE;
conf->type_path = NULL;
conf->timeout = apr_time_from_sec(DFLT_TIMEOUT);
conf->cache = (util_cache_state_t *)apr_pcalloc(p, sizeof(util_cache_state_t));
conf->cache->pool = p;
return conf;
}
static const char *set_cache_switch_conf(cmd_parms * cmd, void *config, const char *value)
{
apr_ssize_t pos = (apr_ssize_t) cmd->info;
cache_config_rec *temp = (cache_config_rec*)config;
switch (pos) {
case CONF_CACHE_HANDLER:
temp->handler = (char *)value;
break;
case CONF_CACHE_TIMEOUT:
temp->timeout = apr_time_from_sec(atoi(value));
break;
case CONF_CACHE_TYPE:
break;
default:
// unknown config directive?
break;
}
return NULL;
}
static const char *add_authn_provider(cmd_parms *cmd, void *config,
const char *arg)
{
cache_config_rec *conf = (cache_config_rec*)config;
authn_provider_list *newp;
const char *provider_name;
if (strcasecmp(arg, "cache") == 0) {
/* hey, recursively cache`ing auth requests is bad.. mmmmkay? */
return NULL;
}
provider_name = apr_pstrdup(cmd->pool, arg);
newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list));
newp->provider_name = provider_name;
/* lookup and cache the actual provider now */
newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
newp->provider_name, "0");
if (newp->provider == NULL) {
/* by the time they use it, the provider should be loaded and
registered with us. */
return apr_psprintf(cmd->pool,
"Unknown Authn provider: %s",
newp->provider_name);
}
if (!newp->provider->check_password) {
/* if it doesn't provide the appropriate function, reject it */
return apr_psprintf(cmd->pool,
"The '%s' Authn provider doesn't support "
"Basic Authentication", provider_name);
}
/* Add it to the list now. */
if (!conf->providers) {
conf->providers = newp;
}
else {
authn_provider_list *last = conf->providers;
while (last->next) {
last = last->next;
}
last->next = newp;
}
return NULL;
}
static const command_rec authn_cache_cmds[] = {
/* per auth section */
AP_INIT_TAKE1("AuthnCacheProvider", add_authn_provider, (void *) CONF_CACHE_HANDLER, OR_AUTHCFG,
"The name of the configuration to use for this section"),
AP_INIT_TAKE1("AuthnCacheTimeout", set_cache_switch_conf, (void *) CONF_CACHE_TIMEOUT, OR_AUTHCFG,
"Time for Auth Tokens to Timeout"),
AP_INIT_TAKE1("AuthnCacheType", set_cache_switch_conf, (void *) CONF_CACHE_TYPE, OR_AUTHCFG,
"Type of storage for authen tokens"),
{NULL}
};
module AP_MODULE_DECLARE_DATA authn_cache_module;
static authn_status check_cache_pw(request_rec * r, const char *user,
const char *password)
{
authn_status auth_result;
util_authn_any_node_t newnode;
util_authn_any_node_t *node;
util_authn_vhost_node_t *curl;
util_authn_vhost_node_t curnode;
authn_provider_list *current_provider;
cache_config_rec *conf = ap_get_module_config(r->per_dir_config,
&authn_cache_module);
AUTHN_CACHE_WRLOCK();
curnode.vhost = apr_pstrdup(conf->cache->pool, r->server->server_hostname);
curl = util_authn_cache_fetch(util_authn_cache, &curnode);
if (curl == NULL) {
curl = util_authn_create_caches(conf->cache, curnode.vhost);
}
AUTHN_CACHE_UNLOCK();
AUTHN_CACHE_WRLOCK();
newnode.username = user;
newnode.realm = ap_auth_name(r);
node = util_authn_cache_fetch(curl->auth_cache, &newnode);
if (node != NULL) {
AUTHN_CACHE_UNLOCK();
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"used cached auth!");
return AUTH_GRANTED;
}
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"NOT used cached auth!");
return AUTH_GRANTED;
AUTHN_CACHE_UNLOCK();
current_provider = conf->providers;
do {
const authn_provider *provider;
if (!current_provider) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"No Cache Authn provider configured");
auth_result = AUTH_GENERAL_ERROR;
break;
}
else {
provider = current_provider->provider;
}
if(!provider->check_password) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The '%s' Cache Authn provider doesn't support Basic Authentication", current_provider->provider_name);
auth_result = AUTH_GENERAL_ERROR;
break;
}
auth_result = provider->check_password(r, user, password);
/* Something occured. Stop checking. */
if (auth_result != AUTH_USER_NOT_FOUND) {
if(auth_result == AUTH_GRANTED)
{
// add to cache
AUTHN_CACHE_RDLOCK();
newnode.username = user;
newnode.realm = ap_auth_name(r);
util_authn_cache_insert(curl->auth_cache, &newnode);
AUTHN_CACHE_UNLOCK();
}
break;
}
/* If we're not really configured for providers, stop now. */
if (!conf->providers) {
break;
}
current_provider = current_provider->next;
} while (current_provider);
return auth_result;
}
static authn_status get_cache_realm_hash(request_rec * r, const char *user,
const char *realm, char **rethash)
{
authn_status auth_result;
util_authn_any_node_t newnode;
authn_provider_list *current_provider;
cache_config_rec *conf = ap_get_module_config(r->per_dir_config,
&authn_cache_module);
current_provider = conf->providers;
do {
const authn_provider *provider;
if (!current_provider) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"No Cache Authn provider configured");
auth_result = AUTH_GENERAL_ERROR;
break;
}
else {
provider = current_provider->provider;
}
if(!provider->check_password) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The '%s' Cache Authn provider doesn't support Digest Authentication", current_provider->provider_name);
auth_result = AUTH_GENERAL_ERROR;
break;
}
/* We expect the password to be md5 hash of user:realm:password */
auth_result = provider->get_realm_hash(r, user, realm,
rethash);
/* Something occured. Stop checking. */
if (auth_result != AUTH_USER_NOT_FOUND) {
if(auth_result == AUTH_GRANTED)
{
// add to cache
AUTHN_CACHE_RDLOCK();
newnode.username = (char *)user;
newnode.realm = (char *)ap_auth_name(r);
util_authn_cache_insert(util_authn_cache, &newnode);
AUTHN_CACHE_UNLOCK();
}
break;
}
/* If we're not really configured for providers, stop now. */
if (!conf->providers) {
break;
}
current_provider = current_provider->next;
} while (current_provider);
return auth_result;
}
static apr_status_t init_authn_cache_config(apr_pool_t * pconf,
apr_pool_t * plog,
apr_pool_t * ptemp)
{
apr_status_t rv = APR_SUCCESS;
return rv;
}
static apr_status_t init_authn_cache(apr_pool_t * p, apr_pool_t * plog,
apr_pool_t * ptemp, server_rec * s)
{
apr_status_t rv = APR_SUCCESS;
void *data;
const char *userdata_key = "mod_authn_cache_init";
apr_pool_userdata_get(&data, userdata_key, s->process->pool);
if (!data) {
apr_pool_userdata_set((const void *) 1, userdata_key,
apr_pool_cleanup_null, s->process->pool);
return OK;
}
ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, p,
"[mod_authn_cache.c] Running Cache init Code");
AUTHN_CACHE_LOCK_CREATE(p);
apr_status_t result = util_authn_cache_init(p, 10000);
return rv;
}
static const authn_provider authn_cache_provider = {
&check_cache_pw,
&get_cache_realm_hash
};
static void register_hooks(apr_pool_t * p)
{
ap_hook_pre_config(init_authn_cache_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(init_authn_cache, NULL, NULL, APR_HOOK_MIDDLE);
ap_register_provider(p, AUTHN_PROVIDER_GROUP, "cache", "0",
&authn_cache_provider);
}
module AP_MODULE_DECLARE_DATA authn_cache_module = {
STANDARD20_MODULE_STUFF,
create_authn_cache_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config creator */
NULL, /* merge server config */
authn_cache_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
--- NEW FILE: util_authn_cache.c ---
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact ap...@ap....
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
* util_authn_cache.c: Authen cache things
*
* Original code from auth_ldap module for Apache v1.3:
* Copyright 1998, 1999 Enbridge Pipelines Inc.
* Copyright 1999-2001 Dave Carrigan
*/
#include "util_authn_cache.h"
#define MODAUTHN_SHMEM_CACHE "/tmp/mod_authn_cache"
/* ------------------------------------------------------------------ */
unsigned long util_authn_any_hash(void *n)
{
util_authn_any_node_t *node = (util_authn_any_node_t *)n;
return util_authn_hash_string(2, node->username, node->realm);
}
int util_authn_any_compare(void *a, void *b)
{
util_authn_any_node_t *na = (util_authn_any_node_t *)a;
util_authn_any_node_t *nb = (util_authn_any_node_t *)b;
return( strcmp(na->username, nb->username) == 0 && strcmp(na->realm, nb->realm) == 0 );
}
void *util_authn_any_copy(void *c)
{
util_authn_any_node_t *n = (util_authn_any_node_t *)c;
util_authn_any_node_t *node = (util_authn_any_node_t *)util_authn_alloc(sizeof(util_authn_any_node_t));
if (node) {
if (
!(node->username = util_authn_strdup(n->username)) ||
!(node->realm = util_authn_strdup(n->realm))
) {
util_authn_any_free((void*)node);
return NULL;
}
return node;
}
else {
return NULL;
}
}
void util_authn_any_free(void *n)
{
util_authn_any_node_t *node = (util_authn_any_node_t *)n;
util_authn_free(node->username);
util_authn_free(node->realm);
util_authn_free(node);
}
/* ------------------------------------------------------------------ */
unsigned long util_authn_vhost_hash(void *n)
{
util_authn_vhost_node_t *node = (util_authn_vhost_node_t *)n;
return util_authn_hash_string(1, node->vhost);
}
int util_authn_vhost_compare(void *a, void *b)
{
util_authn_vhost_node_t *na = (util_authn_vhost_node_t *)a;
util_authn_vhost_node_t *nb = (util_authn_vhost_node_t *)b;
return( strcmp(na->vhost, nb->vhost) == 0);
}
void *util_authn_vhost_copy(void *c)
{
util_authn_vhost_node_t *n = (util_authn_vhost_node_t *)c;
util_authn_vhost_node_t *node = (util_authn_vhost_node_t *)util_authn_alloc(sizeof(util_authn_vhost_node_t));
if (node) {
if (
!(node->vhost = util_authn_strdup(n->vhost))
) {
util_authn_vhost_free((void*)node);
return NULL;
}
return node;
}
else {
return NULL;
}
}
void util_authn_vhost_free(void *n)
{
util_authn_vhost_node_t *node = (util_authn_vhost_node_t *)n;
util_authn_free(node->vhost);
util_authn_free(node);
}
/* ------------------------------------------------------------------ */
apr_status_t util_authn_cache_child_kill(void *data);
apr_status_t util_authn_cache_module_kill(void *data);
apr_status_t util_authn_cache_module_kill(void *data)
{
#if APR_HAS_SHARED_MEMORY
if (util_authn_shm != NULL) {
apr_status_t result = apr_shm_destroy(util_authn_shm);
util_authn_shm = NULL;
return result;
}
#endif
util_authn_destroy_cache(util_authn_cache);
return APR_SUCCESS;
}
apr_status_t util_authn_cache_init(apr_pool_t *pool, apr_size_t reqsize)
{
#if APR_HAS_SHARED_MEMORY
apr_status_t result;
result = apr_shm_create(&util_authn_shm, reqsize, MODAUTHN_SHMEM_CACHE, pool);
if (result == EEXIST) {
/*
* The cache could have already been created (i.e. we may be a child process). See
* if we can attach to the existing shared memory
*/
result = apr_shm_attach(&util_authn_shm, MODAUTHN_SHMEM_CACHE, pool);
}
if (result != APR_SUCCESS) {
return result;
}
/* This will create a rmm "handler" to get into the shared memory area */
apr_rmm_init(&util_authn_rmm, NULL,
(void *)apr_shm_baseaddr_get(util_authn_shm), reqsize, pool);
#endif
apr_pool_cleanup_register(pool, NULL, util_authn_cache_module_kill, apr_pool_cleanup_null);
util_authn_cache = util_authn_create_cache(50,
util_authn_vhost_hash,
util_authn_vhost_compare,
util_authn_vhost_copy,
util_authn_vhost_free);
return APR_SUCCESS;
}
--- NEW FILE: util_authn_cache.h ---
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact ap...@ap....
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
#ifndef APU_AUTHN_CACHE_H
#define APU_AUTHN_CACHE_H
/*
* This switches AUTHN support on or off.
*/
/*
* AUTHN Cache Manager
*/
#include "apr_shm.h"
#include "apr_rmm.h"
#include "apr_time.h"
typedef struct util_cache_state_t {
apr_pool_t *pool; /* pool from which this state is allocated */
#if APR_HAS_THREADS
apr_thread_mutex_t *mutex; /* mutex lock for the connection list */
#endif
apr_size_t cache_bytes; /* Size (in bytes) of shared memory cache */
} util_cache_state_t;
typedef struct util_cache_node_t {
void *payload; /* Pointer to the payload */
apr_time_t add_time; /* Time node was added to cache */
struct util_cache_node_t *next;
} util_cache_node_t;
typedef struct util_authn_cache_t {
unsigned long size; /* Size of cache array */
unsigned long maxentries; /* Maximum number of cache entries */
unsigned long numentries; /* Current number of cache entries */
unsigned long fullmark; /* Used to keep track of when cache becomes 3/4 full */
apr_time_t marktime; /* Time that the cache became 3/4 full */
unsigned long (*hash)(void *); /* Func to hash the payload */
int (*compare)(void *, void *); /* Func to compare two payloads */
void * (*copy)(void *); /* Func to alloc mem and copy payload to new mem */
void (*free)(void *); /* Func to free mem used by the payload */
util_cache_node_t **nodes;
unsigned long numpurges; /* No. of times the cache has been purged */
double avg_purgetime; /* Average time to purge the cache */
apr_time_t last_purge; /* Time of the last purge */
unsigned long npurged; /* Number of elements purged in last purge. This is not
obvious: it won't be 3/4 the size of the cache if
there were a lot of expired entries. */
unsigned long fetches; /* Number of fetches */
unsigned long hits; /* Number of cache hits */
unsigned long inserts; /* Number of inserts */
unsigned long removes; /* Number of removes */
} util_authn_cache_t;
#if APR_HAS_SHARED_MEMORY
apr_shm_t *util_authn_shm;
apr_rmm_t *util_authn_rmm;
#endif
util_authn_cache_t *util_authn_cache;
#if APR_HAS_THREADS
apr_thread_rwlock_t *util_authn_cache_lock;
#define AUTHN_CACHE_LOCK_CREATE(p) \
if (!util_authn_cache_lock) apr_thread_rwlock_create(&util_authn_cache_lock, p)
#define AUTHN_CACHE_WRLOCK() \
apr_thread_rwlock_wrlock(util_authn_cache_lock)
#define AUTHN_CACHE_UNLOCK() \
apr_thread_rwlock_unlock(util_authn_cache_lock)
#define AUTHN_CACHE_RDLOCK() \
apr_thread_rwlock_rdlock(util_authn_cache_lock)
#else
#define AUTHN_CACHE_LOCK_CREATE(p)
#define AUTHN_CACHE_WRLOCK()
#define AUTHN_CACHE_UNLOCK()
#define AUTHN_CACHE_RDLOCK()
#endif
#ifndef WIN32
#define ALD_MM_FILE_MODE ( S_IRUSR|S_IWUSR )
#else
#define ALD_MM_FILE_MODE ( _S_IREAD|_S_IWRITE )
#endif
/*
* AUTHN Cache
*/
typedef struct util_authn_vhost_node_t {
const char *vhost;
util_cache_node_t *auth_cache;
} util_authn_vhost_node_t;
typedef struct util_authn_any_node_t {
const char *username;
const char *realm;
const char *rethash;
} util_authn_any_node_t;
/*
* Function prototypes for AUTHN cache
*/
/* util_authn_cache.c */
unsigned long util_authn_any_hash(void *n);
int util_authn_any_compare(void *a, void *b);
void *util_authn_any_copy(void *c);
void util_authn_any_free(void *n);
unsigned long util_authn_vhost_hash(void *n);
int util_authn_vhost_compare(void *a, void *b);
void *util_authn_vhost_copy(void *c);
void util_authn_vhost_free(void *n);
/* util_authn_cache_mgr.c */
void util_authn_free(const void *ptr);
void *util_authn_alloc(unsigned long size);
const char *util_authn_strdup(const char *s);
unsigned long util_authn_hash_string(int nstr, ...);
void util_authn_cache_purge(util_authn_cache_t *cache);
util_authn_vhost_node_t *util_authn_create_caches(util_cache_state_t *s, const char *vhost);
util_authn_cache_t *util_authn_create_cache(unsigned long maxentries,
unsigned long (*hashfunc)(void *),
int (*comparefunc)(void *, void *),
void * (*copyfunc)(void *),
void (*freefunc)(void *));
void util_authn_destroy_cache(util_authn_cache_t *cache);
void *util_authn_cache_fetch(util_authn_cache_t *cache, void *payload);
void util_authn_cache_insert(util_authn_cache_t *cache, void *payload);
void util_authn_cache_remove(util_authn_cache_t *cache, void *payload);
#endif /* APU_AUTHN_CACHE_H */
--- NEW FILE: util_authn_cache_mgr.c ---
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact ap...@ap....
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
* util_authn_cache_mgr.c: AUTHN cache manager things
*
* Original code from auth_ldap module for Apache v1.3:
* Copyright 1998, 1999 Enbridge Pipelines Inc.
* Copyright 1999-2001 Dave Carrigan
*/
#include "util_authn_cache.h"
#include <apr_strings.h>
/* only here until strdup is gone */
#include <string.h>
/* here till malloc is gone */
#include <stdlib.h>
static const unsigned long primes[] =
{
11,
19,
37,
73,
109,
163,
251,
367,
557,
823,
1237,
1861,
2777,
4177,
6247,
9371,
14057,
21089,
31627,
47431,
71143,
106721,
160073,
240101,
360163,
540217,
810343,
1215497,
1823231,
2734867,
4102283,
6153409,
9230113,
13845163,
0
};
void util_authn_free(const void *ptr)
{
#if APR_HAS_SHARED_MEMORY
if (util_authn_shm) {
if (ptr)
apr_rmm_free(util_authn_rmm, apr_rmm_offset_get(util_authn_rmm, (void *)ptr));
} else {
if (ptr)
free((void *)ptr);
}
#else
if (ptr)
free((void *)ptr);
#endif
}
void *util_authn_alloc(unsigned long size)
{
if (0 == size)
return NULL;
#if APR_HAS_SHARED_MEMORY
if (util_authn_shm) {
return (void *)apr_rmm_addr_get(util_authn_rmm, apr_rmm_calloc(util_authn_rmm, size));
} else {
return (void *)calloc(sizeof(char), size);
}
#else
return (void *)calloc(sizeof(char), size);
#endif
}
const char *util_authn_strdup(const char *s)
{
#if APR_HAS_SHARED_MEMORY
if (util_authn_shm) {
char *buf = (char *)apr_rmm_addr_get(util_authn_rmm, apr_rmm_calloc(util_authn_rmm, strlen(s)+1));
if (buf) {
strcpy(buf, s);
return buf;
}
else {
return NULL;
}
} else {
return strdup(s);
}
#else
return strdup(s);
#endif
}
/*
* Computes the hash on a set of strings. The first argument is the number
* of strings to hash, the rest of the args are strings.
* Algorithm taken from glibc.
*/
unsigned long util_authn_hash_string(int nstr, ...)
{
int i;
va_list args;
unsigned long h=0, g;
char *str, *p;
va_start(args, nstr);
for (i=0; i < nstr; ++i) {
str = va_arg(args, char *);
for (p = str; *p; ++p) {
h = ( h << 4 ) + *p;
if ( ( g = h & 0xf0000000 ) ) {
h = h ^ (g >> 24);
h = h ^ g;
}
}
}
va_end(args);
return h;
}
/*
Purges a cache that has gotten full. We keep track of the time that we
added the entry that made the cache 3/4 full, then delete all entries
that were added before that time. It's pretty simplistic, but time to
purge is only O(n), which is more important.
*/
void util_authn_cache_purge(util_authn_cache_t *cache)
{
unsigned long i;
util_cache_node_t *p, *q;
apr_time_t t;
if (!cache)
return;
cache->last_purge = apr_time_now();
cache->npurged = 0;
cache->numpurges++;
for (i=0; i < cache->size; ++i) {
p = cache->nodes[i];
while (p != NULL) {
if (p->add_time < cache->marktime) {
q = p->next;
(*cache->free)(p->payload);
util_authn_free(p);
cache->numentries--;
cache->npurged++;
p = q;
}
else {
p = p->next;
}
}
}
t = apr_time_now();
cache->avg_purgetime =
((t - cache->last_purge) + (cache->avg_purgetime * (cache->numpurges-1))) /
cache->numpurges;
}
/*
* create caches
*/
util_authn_vhost_node_t *util_authn_create_caches(util_cache_state_t *st, const char *vhost)
{
util_authn_vhost_node_t *curl = NULL;
util_authn_cache_t *auth_cache;
auth_cache = util_authn_create_cache(1000,
util_authn_any_hash,
util_authn_any_compare,
util_authn_any_copy,
util_authn_any_free);
if (auth_cache) {
curl = (util_authn_vhost_node_t *)apr_pcalloc(st->pool, sizeof(util_authn_vhost_node_t));
curl->vhost = vhost;
curl->auth_cache = (util_authn_cache_t*) auth_cache;
util_authn_cache_insert(util_authn_cache, curl);
}
return curl;
}
util_authn_cache_t *util_authn_create_cache(unsigned long maxentries,
unsigned long (*hashfunc)(void *),
int (*comparefunc)(void *, void *),
void * (*copyfunc)(void *),
void (*freefunc)(void *))
{
util_authn_cache_t *cache;
unsigned long i;
if (maxentries <= 0)
return NULL;
cache = (util_authn_cache_t *)util_authn_alloc(sizeof(util_authn_cache_t));
if (!cache)
return NULL;
cache->maxentries = maxentries;
cache->numentries = 0;
cache->size = maxentries / 3;
if (cache->size < 64) cache->size = 64;
for (i = 0; primes[i] && primes[i] < cache->size; ++i) ;
cache->size = primes[i]? primes[i] : primes[i-1];
cache->nodes = (util_cache_node_t **)util_authn_alloc(cache->size * sizeof(util_cache_node_t *));
if (!cache->nodes) {
util_authn_free(cache);
return NULL;
}
for (i=0; i < cache->size; ++i)
cache->nodes[i] = NULL;
cache->hash = hashfunc;
cache->compare = comparefunc;
cache->copy = copyfunc;
cache->free = freefunc;
cache->fullmark = cache->maxentries / 4 * 3;
cache->marktime = 0;
cache->avg_purgetime = 0.0;
cache->numpurges = 0;
cache->last_purge = 0;
cache->npurged = 0;
cache->fetches = 0;
cache->hits = 0;
cache->inserts = 0;
cache->removes = 0;
return cache;
}
void util_authn_destroy_cache(util_authn_cache_t *cache)
{
unsigned long i;
util_cache_node_t *p, *q;
if (cache == NULL)
return;
for (i = 0; i < cache->size; ++i) {
p = cache->nodes[i];
q = NULL;
while (p != NULL) {
q = p->next;
(*cache->free)(p->payload);
util_authn_free(p);
p = q;
}
}
util_authn_free(cache->nodes);
util_authn_free(cache);
}
void *util_authn_cache_fetch(util_authn_cache_t *cache, void *payload)
{
int hashval;
util_cache_node_t *p;
if (cache == NULL)
return NULL;
cache->fetches++;
hashval = (*cache->hash)(payload) % cache->size;
for (p = cache->nodes[hashval];
p && !(*cache->compare)(p->payload, payload);
p = p->next) ;
if (p != NULL) {
cache->hits++;
return p->payload;
}
else {
return NULL;
}
}
/*
* Insert an item into the cache.
* *** Does not catch duplicates!!! ***
*/
void util_authn_cache_insert(util_authn_cache_t *cache, void *payload)
{
int hashval;
util_cache_node_t *node;
if (cache == NULL || payload == NULL)
return;
cache->inserts++;
hashval = (*cache->hash)(payload) % cache->size;
node = (util_cache_node_t *)util_authn_alloc(sizeof(util_cache_node_t));
node->add_time = apr_time_now();
node->payload = (*cache->copy)(payload);
node->next = cache->nodes[hashval];
cache->nodes[hashval] = node;
if (++cache->numentries == cache->fullmark)
cache->marktime=apr_time_now();
if (cache->numentries >= cache->maxentries)
util_authn_cache_purge(cache);
}
void util_authn_cache_remove(util_authn_cache_t *cache, void *payload)
{
int hashval;
util_cache_node_t *p, *q;
if (cache == NULL)
return;
cache->removes++;
hashval = (*cache->hash)(payload) % cache->size;
for (p = cache->nodes[hashval], q=NULL;
p && !(*cache->compare)(p->payload, payload);
p = p->next) {
q = p;
}
/* If p is null, it means that we couldn't find the node, so just return */
if (p == NULL)
return;
if (q == NULL) {
/* We found the node, and it's the first in the list */
cache->nodes[hashval] = p->next;
}
else {
/* We found the node and it's not the first in the list */
q->next = p->next;
}
(*cache->free)(p->payload);
util_authn_free(p);
cache->numentries--;
}
|