/* ====================================================================
* 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 */
};