/* ==================================================================== * 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 apache@apache.org. * * 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 * . * * 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_dbi * * Paul Querna * * based on mod_authn_mysql * * redchip cvs: $Id: mod_authn_dbi.c,v 1.93.2.3 2003/03/24 22:53:06 chip Exp $ */ #define MOD_AUTHN_DBI_VERSION "0.0.4" #define APR_WANT_STRFUNC #include "apr_want.h" #include "apr_strings.h" #include "apr_md5.h" /* for apr_password_validate */ #include "apr_reslist.h" #include "apr_thread_mutex.h" /* to block MySQL on dbi_connect */ #include "apr_hash.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" /* for ap_hook_(check_user_id | auth_checker)*/ #include "mod_auth.h" #include "util_md5.h" /* for ap_md5 */ #include #ifndef DBI_NOT_THREAD_SAFE #define DBI_NOT_THREAD_SAFE (1) #endif #ifdef DBI_NOT_THREAD_SAFE static apr_thread_mutex_t *dbi_lock = NULL; #endif #define DFLT_DBI_NAME "AuthDB" #define DFLT_DBI_HOST "localhost" #define DFLT_DBI_DRIVER "mysql" #define DFLT_DBI_USER "root" #define DFLT_DBI_PASS NULL #define DFLT_DBI_TABLE "Users" #define DFLT_USERNAME_FIELD "Username" #define DFLT_PASSWORD_FIELD "Password" #define DFLT_ACTIVE_FIELD NULL #define DFLT_CONN_MIN (1) #define DFLT_CONN_SOFT (5) #define DFLT_CONN_MAX (25) #define DFLT_CONN_TTL (600) #ifndef DBI_HARD_MAX_CONNS #define DBI_HARD_MAX_CONNS (255) #endif static int dbi_conn_count = 0; static apr_hash_t *authn_dbi_config; typedef struct dbi_dconfig { const char *id; } dbi_dconfig; typedef struct dbi_config_rec_struct { const char *dbi_name; const char *dbi_user; const char *dbi_pass; const char *dbi_driver; const char *dbi_host; const char *dbi_table; const char *username_field; const char *password_field; const char *isactive_field; int conn_min; int conn_soft; int conn_max; int conn_ttl; } dbi_config_rec; typedef struct dbi_config_struct { const char name; apr_reslist_t *pool; dbi_config_rec rec; } dbi_config; typedef struct dbi_rest_struct { dbi_conn *conn; } dbi_rest; static apr_status_t safe_dbi_new_conn(void **resource, void *params, apr_pool_t *r) { apr_status_t rv = APR_SUCCESS; dbi_config_rec *conf = params; int err_num = 0; const char *err_str; const char *host = conf->dbi_host; const char *driver = conf->dbi_driver; const char *name = conf->dbi_name; const char *user = conf->dbi_user; const char *pwd = conf->dbi_pass; dbi_rest *myres; dbi_conn_count++; if(DBI_HARD_MAX_CONNS > dbi_conn_count) { ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Creating New DBI Server Connection"); myres = apr_palloc(r, sizeof(*myres)); myres->conn = dbi_conn_new(driver); if(myres->conn == NULL) { ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, r, "[mod_authn_dbi.c] DBI Connection Failed. dbi_conn_new returned NULL. Insufficient memory or invalid DBD?"); rv = !APR_SUCCESS; /* * modules/ssl/ssl_engine_log.c:103 * said this was okay. so i do it. */ exit(1); } else { dbi_conn_set_option(myres->conn, "host", host); dbi_conn_set_option(myres->conn, "username", user); dbi_conn_set_option(myres->conn, "password", pwd); dbi_conn_set_option(myres->conn, "dbname", name); #if DBI_NOT_THREAD_SAFE if(strcmp(driver, "mysql")) { apr_thread_mutex_lock(dbi_lock); } #endif if(dbi_conn_connect(myres->conn) != 0) { err_num = dbi_conn_error(myres->conn, &err_str); /* Connetion Failed */ ap_log_perror(APLOG_MARK, APLOG_ERR, 0, r, "[mod_authn_dbi.c] DBI Connection to %s://%s@%s/%s Failed. Error: (%d) %s", driver,user, host, name, err_num, err_str); rv = !APR_SUCCESS; } else { ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Connection was created sucessfully"); } #if DBI_NOT_THREAD_SAFE if(strcmp(driver, "mysql")) { apr_thread_mutex_unlock(dbi_lock); } #endif } *resource = myres; } else { /* Error -- we have too many TOTAL DBI Connections. Maybe a Evil User trying to hurt our system? */ ap_log_perror(APLOG_MARK, APLOG_ERR, 0, r, "[mod_authn_dbi.c] DBI Connection Failed. Hard Max Limit of %d Connections has been reached", DBI_HARD_MAX_CONNS); /* we didn't create a new connection! */ dbi_conn_count--; rv = !APR_SUCCESS; } return rv; } static apr_status_t safe_dbi_kill_conn(void *resource, void *params, apr_pool_t *pool) { dbi_config_rec *conf = params; dbi_rest *res = resource; ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, pool, "[mod_authn_dbi.c] Disconnecting from Server"); dbi_conn_close(res->conn); dbi_conn_count--; return APR_SUCCESS; } static apr_status_t *create_new_conf ( const char *conn_id , apr_pool_t *p) { dbi_config *conf; conf = (dbi_config *) apr_pcalloc(p, sizeof(dbi_config)); conf->rec.dbi_name = DFLT_DBI_NAME; conf->rec.dbi_driver = DFLT_DBI_DRIVER; conf->rec.dbi_host = DFLT_DBI_HOST; conf->rec.dbi_user = DFLT_DBI_USER; conf->rec.dbi_pass = DFLT_DBI_PASS; conf->rec.dbi_table = DFLT_DBI_TABLE; conf->rec.username_field = DFLT_USERNAME_FIELD; conf->rec.password_field = DFLT_PASSWORD_FIELD; conf->rec.isactive_field = DFLT_ACTIVE_FIELD; conf->rec.conn_min = DFLT_CONN_MIN; conf->rec.conn_soft = DFLT_CONN_SOFT; conf->rec.conn_max = DFLT_CONN_MAX; conf->rec.conn_ttl = DFLT_CONN_TTL; apr_hash_set(authn_dbi_config, conn_id, APR_HASH_KEY_STRING, conf); ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, p, "[mod_authn_dbi.c] Creating Config for %s", conn_id); return APR_SUCCESS; } static const char *set_dbi_driver(cmd_parms *cmd, void *config, const char *conn_id, const char *db_dbd) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.dbi_driver = db_dbd; return NULL; } static const char *set_dbi_host(cmd_parms *cmd, void *config, const char *conn_id, const char *db_host) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.dbi_host = db_host; return NULL; } static const char *set_dbi_user(cmd_parms *cmd, void *config, const char *conn_id, const char *db_user) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.dbi_user = db_user; return NULL; } static const char *set_dbi_pass(cmd_parms *cmd, void *config, const char *conn_id, const char *db_pass) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.dbi_pass = db_pass; return NULL; } static const char *set_dbi_name(cmd_parms *cmd, void *config, const char *conn_id, const char *db_name) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.dbi_name = db_name; return NULL; } static const char *set_dbi_table(cmd_parms *cmd, void *config, const char *conn_id, const char *table) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.dbi_table = table; return NULL; } static const char *set_dbi_username_field(cmd_parms *cmd, void *config, const char *conn_id, const char *field) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.username_field = field; return NULL; } static const char *set_dbi_password_field(cmd_parms *cmd, void *config, const char *conn_id, const char *field) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.password_field = field; return NULL; } static const char *set_dbi_isactive_field(cmd_parms *cmd, void *config, const char *conn_id, const char *field) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.isactive_field = field; return NULL; } static const char *set_dbi_conn_min(cmd_parms *cmd, void *config, const char *conn_id, const char *field) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.conn_min = atoi(field); return NULL; } static const char *set_dbi_conn_soft(cmd_parms *cmd, void *config, const char *conn_id, const char *field) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.conn_soft = atoi(field); return NULL; } static const char *set_dbi_conn_max(cmd_parms *cmd, void *config, const char *conn_id, const char *field) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.conn_max = atoi(field); return NULL; } static const char *set_dbi_conn_ttl(cmd_parms *cmd, void *config, const char *conn_id, const char *field) { dbi_config *temp; temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); if(temp == NULL){ /* no such server yet... */ create_new_conf(conn_id, cmd->pool); temp = apr_hash_get(authn_dbi_config, conn_id, APR_HASH_KEY_STRING); } temp->rec.conn_ttl = atoi(field); return NULL; } static const char *set_ddbi_conn(cmd_parms *cmd, void *config, const char *field) { ((dbi_dconfig *) config)->id = field; return NULL; } static const command_rec authn_dbi_cmds[] = { /* global config items */ AP_INIT_TAKE2("AuthnDbiDriver", set_dbi_driver, NULL, RSRC_CONF, "The DBI Driver"), AP_INIT_TAKE2("AuthnDbiHost", set_dbi_host, NULL, RSRC_CONF, "The host for the database connection"), AP_INIT_TAKE2("AuthnDbiUsername", set_dbi_user, NULL, RSRC_CONF, "The username for the database connection"), AP_INIT_TAKE2("AuthnDbiPassword", set_dbi_pass, NULL, RSRC_CONF, "The password for the database connection"), AP_INIT_TAKE2("AuthnDbiName", set_dbi_name, NULL, RSRC_CONF, "The name of the database containing the tables"), AP_INIT_TAKE2("AuthnDbiTable", set_dbi_table, NULL, RSRC_CONF, "The name of the table containing the usernames and password hashes"), AP_INIT_TAKE2("AuthnDbiUsernameField", set_dbi_username_field, NULL, RSRC_CONF, "The table field that contains the username"), AP_INIT_TAKE2("AuthnDbiPasswordField", set_dbi_password_field, NULL, RSRC_CONF, "The table field that contains the password"), AP_INIT_TAKE2("AuthnDbiIsActiveField", set_dbi_isactive_field, NULL, RSRC_CONF, "The table field that contains the username"), AP_INIT_TAKE2("AuthnDbiConnMin", set_dbi_conn_min, NULL, RSRC_CONF, "The Minimum Number of Database Connections"), AP_INIT_TAKE2("AuthnDbiConnSoftMax", set_dbi_conn_soft, NULL, RSRC_CONF, "The Soft Maximum Number of Database Connections"), AP_INIT_TAKE2("AuthnDbiConnHardMax", set_dbi_conn_max, NULL, RSRC_CONF, "The Hard Maximum Number of Database Connections"), AP_INIT_TAKE2("AuthnDbiConnTTL", set_dbi_conn_ttl, NULL, RSRC_CONF, "The Database Pool Time To Live for Each Connection."), /* per auth section */ AP_INIT_TAKE1("AuthnDbiServerConfig", set_ddbi_conn, NULL, OR_AUTHCFG, "The name of the database containing the tables"), NULL }; module AP_MODULE_DECLARE_DATA authn_dbi_module; static void *create_authn_dbi_dir_config(apr_pool_t *p, char *d) { dbi_dconfig *conf; if (d == NULL) { return NULL; } conf = (dbi_dconfig *) apr_pcalloc(p, sizeof(dbi_dconfig)); if (conf) { conf->id = NULL; } return conf; } static void *create_authn_dbi_config(apr_pool_t *p, server_rec *s) { /* TODO: fix this.... this is very bad... */ return NULL; } static apr_status_t safe_dbi_rel_server(apr_reslist_t *dbi_pool, dbi_rest *server, request_rec *r) { apr_status_t rv; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Returning Server Connection to DBI Pool"); rv = apr_reslist_release(dbi_pool, (void**)server); return rv; } static int safe_dbi_query(dbi_rest *mydbi_res, dbi_result *res, request_rec *r, char *query) { int err_num = 0; const char *err_str; int error = 1; *res = (dbi_result)dbi_conn_query(mydbi_res->conn, query); /* logging complete sql queries is bad. I personaly * uncomment this for some debuging... but even * APLOG_DEBUG isn't good for this. */ //ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, // "[mod_authn_dbi.c] SQL Query: %s", query); if(res == NULL){ err_num = dbi_conn_error(mydbi_res->conn, &err_str); ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "[mod_authn_dbi.c] SQL Query Failed. DBI said: (%d) %s", err_num, err_str); } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Query Result is good."); error = 0; } return error; } static authn_status check_dbi_pw(request_rec *r, const char *user, const char *password) { authn_status ARV = AUTH_DENIED; dbi_config *conf; dbi_dconfig *dconf = ap_get_module_config(r->per_dir_config, &authn_dbi_module); char* dbi_pass; char* query; dbi_result result; dbi_rest *dbi_res; char *esc_user; conf = apr_hash_get(authn_dbi_config, dconf->id, APR_HASH_KEY_STRING); if(conf == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "[mod_authn_dbi.c] - Server Config for \"%s\" was not found", dconf->id); return ARV; } esc_user = malloc(strlen(user)+1); strcpy(esc_user, user); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Attempting to Acquire DBI Connection"); apr_reslist_acquire(conf->pool, (void **)&dbi_res); dbi_driver_quote_string(dbi_conn_get_driver(dbi_res->conn), &esc_user); /* make the query to get the user's password */ if (conf->rec.isactive_field) { query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s=%s AND %s!=0 LIMIT 0,1", conf->rec.password_field, conf->rec.dbi_table, conf->rec.username_field, esc_user, conf->rec.isactive_field); } else { query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s=%s LIMIT 0,1", conf->rec.password_field, conf->rec.dbi_table, conf->rec.username_field, esc_user); } /* perform the query */ if (safe_dbi_query(dbi_res, &result, r, query) == 0){ /* store the query result */ if (dbi_result_next_row(result) && dbi_result_get_numrows(result) == 1) { dbi_pass = dbi_result_get_string_copy(result, conf->rec.password_field); if (strcmp(dbi_pass,password) != 0) { ARV = AUTH_DENIED; } else { ARV = AUTH_GRANTED; } } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] %d row(s) was not returned by dbi_result_get_numrows(result)", dbi_result_get_numrows(result)); } } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Query Failed!"); } free(esc_user); dbi_result_free(result); safe_dbi_rel_server(conf->pool, dbi_res, r); return ARV; } static authn_status get_dbi_realm_hash(request_rec *r, const char *user, const char *realm, char **rethash) { dbi_config *conf; authn_status ARV = AUTH_DENIED; dbi_dconfig *dconf = ap_get_module_config(r->per_dir_config, &authn_dbi_module); char* dbi_hash; char* dbi_pass; char* query; dbi_result result; dbi_rest *dbi_res; char *esc_user; conf = apr_hash_get(authn_dbi_config, dconf->id, APR_HASH_KEY_STRING); if(conf == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "[mod_authn_dbi.c] - Server Config for \"%s\" was not found", dconf->id); return ARV; } esc_user = malloc(strlen(user)+1); strcpy(esc_user, user); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Attempting to Acquire DBI Connection"); apr_reslist_acquire(conf->pool, (void **)&dbi_res); dbi_driver_quote_string(dbi_conn_get_driver(dbi_res->conn), &esc_user); /* make the query to get the user's password */ if (conf->rec.isactive_field) { query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s=%s AND %s!=0 LIMIT 0,1", conf->rec.password_field, conf->rec.dbi_table, conf->rec.username_field, esc_user, conf->rec.isactive_field); } else { query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s=%s LIMIT 0,1", conf->rec.password_field, conf->rec.dbi_table, conf->rec.username_field, esc_user); } /* perform the query */ if (safe_dbi_query(dbi_res, &result, r, query) == 0){ /* store the query result */ if (dbi_result_next_row(result) && dbi_result_get_numrows(result) == 1) { dbi_pass = dbi_result_get_string_copy(result, conf->rec.password_field); dbi_hash = (char *) ap_md5(r->pool, (const unsigned char*)apr_pstrcat(r->pool, user, ":", realm, ":", dbi_pass,NULL)); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Query Good. Returning Hash: MD5(%s:%s:%s) = %s", user, realm, dbi_pass, dbi_hash ); *rethash = dbi_hash; ARV = AUTH_USER_FOUND; } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] %d row(s) was not returned by dbi_result_get_numrows(result)", dbi_result_get_numrows(result)); } } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[mod_authn_dbi.c] Query Failed!"); } free(esc_user); dbi_result_free(result); safe_dbi_rel_server(conf->pool, dbi_res, r); return ARV; } static const authn_provider authn_dbi_provider = { &check_dbi_pw, &get_dbi_realm_hash }; static apr_status_t init_authn_dbi_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp){ apr_status_t rv = APR_SUCCESS; /* create our globalish config var */ authn_dbi_config = apr_hash_make(pconf); return rv; } static apr_status_t kill_dbi(void *p) { apr_status_t rv = APR_SUCCESS; apr_hash_index_t *idx; char *key; dbi_config *val; apr_ssize_t len; for (idx = apr_hash_first((apr_pool_t *)p, authn_dbi_config); idx; idx = apr_hash_next(idx)) { apr_hash_this(idx, (void*) &key, &len, (void*) &val); apr_reslist_destroy(val->pool); } dbi_shutdown(); #if DBI_NOT_THREAD_SAFE rv = apr_thread_mutex_destroy(dbi_lock); #endif return rv; } static apr_status_t init_authn_dbi(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s){ apr_status_t rv = APR_SUCCESS; void *data; apr_hash_index_t *idx; char *key; dbi_config *val; apr_ssize_t len; const char *userdata_key = "mod_authn_dbi_init"; dbi_config *conf = ap_get_module_config(s->module_config, &authn_dbi_module); 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_dbi.c] Running DBI init Code"); #if DBI_NOT_THREAD_SAFE rv = apr_thread_mutex_create(&dbi_lock, APR_LOCK_DEFAULT, p); ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, p, "[mod_authn_dbi.c] DBI is running in Non-Thread Safe Mode"); if(rv != APR_SUCCESS) { ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, p, "[mod_authn_dbi.c] - Failed Creating DBI thread Mutex! apr_thread_mutex_create returned: \"%d\" ", rv); return rv; } #endif dbi_initialize(NULL); /* loop the hashed config stuff... */ for (idx = apr_hash_first(p, authn_dbi_config); idx; idx = apr_hash_next(idx)) { apr_hash_this(idx, (void*) &key, &len, (void*) &val); apr_reslist_create(&val->pool, val->rec.conn_min, /* hard minimum */ val->rec.conn_soft, /* soft maximum */ val->rec.conn_max, /* hard maximum */ val->rec.conn_ttl, /* Time to live -- dbi server might override/disconnect! */ safe_dbi_new_conn, /* Make a New Connection */ safe_dbi_kill_conn, /* Kill Old Connection */ (void *) &val->rec, p); apr_hash_set(authn_dbi_config, key, APR_HASH_KEY_STRING, val); } apr_pool_cleanup_register(p, p, kill_dbi, apr_pool_cleanup_null); return rv; } static void register_hooks(apr_pool_t *p) { ap_hook_pre_config(init_authn_dbi_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(init_authn_dbi, NULL, NULL, APR_HOOK_MIDDLE); ap_register_provider(p, AUTHN_PROVIDER_GROUP, "dbi", "0", &authn_dbi_provider); } module AP_MODULE_DECLARE_DATA authn_dbi_module = { STANDARD20_MODULE_STUFF, create_authn_dbi_dir_config , /* dir config creater */ NULL, /* dir merger --- default is to override */ create_authn_dbi_config, /* server config creator */ NULL, /* merge server config */ authn_dbi_cmds, /* command apr_table_t */ register_hooks /* register hooks */ };