Main Page | Modules | Namespace List | Class List | Directories | File List | Class Members | File Members | Related Pages | Examples

mod_authn_dbd.c

Go to the documentation of this file.
00001 /* Licensed to the Apache Software Foundation (ASF) under one or more
00002  * contributor license agreements.  See the NOTICE file distributed with
00003  * this work for additional information regarding copyright ownership.
00004  * The ASF licenses this file to You under the Apache License, Version 2.0
00005  * (the "License"); you may not use this file except in compliance with
00006  * the License.  You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "ap_provider.h"
00018 #include "httpd.h"
00019 #include "http_config.h"
00020 #include "http_log.h"
00021 #include "apr_lib.h"
00022 #include "apr_dbd.h"
00023 #include "mod_dbd.h"
00024 #include "apr_strings.h"
00025 #include "mod_auth.h"
00026 #include "apr_md5.h"
00027 #include "apu_version.h"
00028 
00029 module AP_MODULE_DECLARE_DATA authn_dbd_module;
00030 
00031 typedef struct {
00032     const char *user;
00033     const char *realm;
00034 } authn_dbd_conf;
00035 typedef struct {
00036     const char *label;
00037     const char *query;
00038 } authn_dbd_rec;
00039 
00040 /* optional function - look it up once in post_config */
00041 static ap_dbd_t *(*authn_dbd_acquire_fn)(request_rec*) = NULL;
00042 static void (*authn_dbd_prepare_fn)(server_rec*, const char*, const char*) = NULL;
00043 
00044 static void *authn_dbd_cr_conf(apr_pool_t *pool, char *dummy)
00045 {
00046     authn_dbd_conf *ret = apr_pcalloc(pool, sizeof(authn_dbd_conf));
00047     return ret;
00048 }
00049 static void *authn_dbd_merge_conf(apr_pool_t *pool, void *BASE, void *ADD)
00050 {
00051     authn_dbd_conf *add = ADD;
00052     authn_dbd_conf *base = BASE;
00053     authn_dbd_conf *ret = apr_palloc(pool, sizeof(authn_dbd_conf));
00054     ret->user = (add->user == NULL) ? base->user : add->user;
00055     ret->realm = (add->realm == NULL) ? base->realm : add->realm;
00056     return ret;
00057 }
00058 static const char *authn_dbd_prepare(cmd_parms *cmd, void *cfg, const char *query)
00059 {
00060     static unsigned int label_num = 0;
00061     char *label;
00062 
00063     if (authn_dbd_prepare_fn == NULL) {
00064         authn_dbd_prepare_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_prepare);
00065         if (authn_dbd_prepare_fn == NULL) {
00066             return "You must load mod_dbd to enable AuthDBD functions";
00067         }
00068         authn_dbd_acquire_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire);
00069     }
00070     label = apr_psprintf(cmd->pool, "authn_dbd_%d", ++label_num);
00071 
00072     authn_dbd_prepare_fn(cmd->server, query, label);
00073 
00074     /* save the label here for our own use */
00075     return ap_set_string_slot(cmd, cfg, label);
00076 }
00077 static const command_rec authn_dbd_cmds[] =
00078 {
00079     AP_INIT_TAKE1("AuthDBDUserPWQuery", authn_dbd_prepare,
00080                   (void *)APR_OFFSETOF(authn_dbd_conf, user), ACCESS_CONF,
00081                   "Query used to fetch password for user"),
00082     AP_INIT_TAKE1("AuthDBDUserRealmQuery", authn_dbd_prepare,
00083                   (void *)APR_OFFSETOF(authn_dbd_conf, realm), ACCESS_CONF,
00084                   "Query used to fetch password for user+realm"),
00085     {NULL}
00086 };
00087 static authn_status authn_dbd_password(request_rec *r, const char *user,
00088                                        const char *password)
00089 {
00090     apr_status_t rv;
00091     const char *dbd_password = NULL;
00092     apr_dbd_prepared_t *statement;
00093     apr_dbd_results_t *res = NULL;
00094     apr_dbd_row_t *row = NULL;
00095 
00096     authn_dbd_conf *conf = ap_get_module_config(r->per_dir_config,
00097                                                 &authn_dbd_module);
00098     ap_dbd_t *dbd = authn_dbd_acquire_fn(r);
00099     if (dbd == NULL) {
00100         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00101                       "Error looking up %s in database", user);
00102         return AUTH_GENERAL_ERROR;
00103     }
00104 
00105     if (conf->user == NULL) {
00106         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "No AuthDBDUserPWQuery has been specified.");
00107         return AUTH_GENERAL_ERROR;
00108     }
00109 
00110     statement = apr_hash_get(dbd->prepared, conf->user, APR_HASH_KEY_STRING);
00111     if (statement == NULL) {
00112         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "A prepared statement could not be found for AuthDBDUserPWQuery, key '%s'.", conf->user);
00113         return AUTH_GENERAL_ERROR;
00114     }
00115     if (apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, statement,
00116                               0, user, NULL) != 0) {
00117         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00118                       "Error looking up %s in database", user);
00119         return AUTH_GENERAL_ERROR;
00120     }
00121     for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1);
00122          rv != -1;
00123          rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) {
00124         if (rv != 0) {
00125             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
00126                       "Error looking up %s in database", user);
00127             return AUTH_GENERAL_ERROR;
00128         }
00129         if (dbd_password == NULL) {
00130             dbd_password = apr_dbd_get_entry(dbd->driver, row, 0);
00131 
00132 #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
00133             /* add the rest of the columns to the environment */
00134             int i = 1;
00135             const char *name;
00136             for (name = apr_dbd_get_name(dbd->driver, res, i);
00137                  name != NULL;
00138                  name = apr_dbd_get_name(dbd->driver, res, i)) {
00139 
00140                 char *str = apr_pstrcat(r->pool, AUTHN_PREFIX,
00141                                         name,
00142                                         NULL);
00143                 int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */
00144                 while (str[j]) {
00145                     if (!apr_isalnum(str[j])) {
00146                         str[j] = '_';
00147                     }
00148                     else {
00149                         str[j] = apr_toupper(str[j]);
00150                     }
00151                     j++;
00152                 }
00153                 apr_table_set(r->subprocess_env, str,
00154                               apr_dbd_get_entry(dbd->driver, row, i));
00155                 i++;
00156             }
00157 #endif
00158         }
00159         /* we can't break out here or row won't get cleaned up */
00160     }
00161 
00162     if (!dbd_password) {
00163         return AUTH_USER_NOT_FOUND;
00164     }
00165 
00166     rv = apr_password_validate(password, dbd_password);
00167 
00168     if (rv != APR_SUCCESS) {
00169         return AUTH_DENIED;
00170     }
00171 
00172     return AUTH_GRANTED;
00173 }
00174 static authn_status authn_dbd_realm(request_rec *r, const char *user,
00175                                     const char *realm, char **rethash)
00176 {
00177     apr_status_t rv;
00178     const char *dbd_hash = NULL;
00179     apr_dbd_prepared_t *statement;
00180     apr_dbd_results_t *res = NULL;
00181     apr_dbd_row_t *row = NULL;
00182 
00183     authn_dbd_conf *conf = ap_get_module_config(r->per_dir_config,
00184                                                 &authn_dbd_module);
00185     ap_dbd_t *dbd = authn_dbd_acquire_fn(r);
00186     if (dbd == NULL) {
00187         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00188                       "Error looking up %s in database", user);
00189         return AUTH_GENERAL_ERROR;
00190     }
00191     if (conf->realm == NULL) {
00192         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "No AuthDBDUserRealmQuery has been specified.");
00193         return AUTH_GENERAL_ERROR;
00194     }
00195     statement = apr_hash_get(dbd->prepared, conf->realm, APR_HASH_KEY_STRING);
00196     if (statement == NULL) {
00197         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "A prepared statement could not be found for AuthDBDUserRealmQuery, key '%s'.", conf->realm);
00198         return AUTH_GENERAL_ERROR;
00199     }
00200     if (apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, statement,
00201                               0, user, realm, NULL) != 0) {
00202         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00203                       "Error looking up %s:%s in database", user, realm);
00204         return AUTH_GENERAL_ERROR;
00205     }
00206     for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1);
00207          rv != -1;
00208          rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) {
00209         if (rv != 0) {
00210             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
00211                       "Error looking up %s in database", user);
00212             return AUTH_GENERAL_ERROR;
00213         }
00214         if (dbd_hash == NULL) {
00215             dbd_hash = apr_dbd_get_entry(dbd->driver, row, 0);
00216 
00217 #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
00218             /* add the rest of the columns to the environment */
00219             int i = 1;
00220             const char *name;
00221             for (name = apr_dbd_get_name(dbd->driver, res, i);
00222                  name != NULL;
00223                  name = apr_dbd_get_name(dbd->driver, res, i)) {
00224 
00225                 char *str = apr_pstrcat(r->pool, AUTHN_PREFIX,
00226                                         name,
00227                                         NULL);
00228                 int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */
00229                 while (str[j]) {
00230                     if (!apr_isalnum(str[j])) {
00231                         str[j] = '_';
00232                     }
00233                     else {
00234                         str[j] = apr_toupper(str[j]);
00235                     }
00236                     j++;
00237                 }
00238                 apr_table_set(r->subprocess_env, str,
00239                               apr_dbd_get_entry(dbd->driver, row, i));
00240                 i++;
00241             }
00242 #endif
00243         }
00244         /* we can't break out here or row won't get cleaned up */
00245     }
00246 
00247     if (!dbd_hash) {
00248         return AUTH_USER_NOT_FOUND;
00249     }
00250 
00251     *rethash = apr_pstrdup(r->pool, dbd_hash);
00252     return AUTH_USER_FOUND;
00253 }
00254 static void authn_dbd_hooks(apr_pool_t *p)
00255 {
00256     static const authn_provider authn_dbd_provider = {
00257         &authn_dbd_password,
00258         &authn_dbd_realm
00259     };
00260 
00261     ap_register_provider(p, AUTHN_PROVIDER_GROUP, "dbd", "0", &authn_dbd_provider);
00262 }
00263 module AP_MODULE_DECLARE_DATA authn_dbd_module =
00264 {
00265     STANDARD20_MODULE_STUFF,
00266     authn_dbd_cr_conf,
00267     authn_dbd_merge_conf,
00268     NULL,
00269     NULL,
00270     authn_dbd_cmds,
00271     authn_dbd_hooks
00272 };

© sourcejam.com 2005-2008