diff options
Diffstat (limited to 'modules/aaa/mod_authn_dbm.c')
-rw-r--r-- | modules/aaa/mod_authn_dbm.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/modules/aaa/mod_authn_dbm.c b/modules/aaa/mod_authn_dbm.c new file mode 100644 index 0000000..9f47350 --- /dev/null +++ b/modules/aaa/mod_authn_dbm.c @@ -0,0 +1,231 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * http_auth: authentication + * + * Rob McCool & Brian Behlendorf. + * + * Adapted to Apache by rst. + * + */ + +#define APR_WANT_STRFUNC +#include "apr_want.h" +#include "apr_strings.h" +#include "apr_dbm.h" +#include "apr_md5.h" /* for apr_password_validate */ + +#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 "apr_version.h" +#if !APR_VERSION_AT_LEAST(2,0,0) +#include "apu_version.h" +#endif + +static APR_OPTIONAL_FN_TYPE(ap_authn_cache_store) *authn_cache_store = NULL; +#define AUTHN_CACHE_STORE(r,user,realm,data) \ + if (authn_cache_store != NULL) \ + authn_cache_store((r), "dbm", (user), (realm), (data)) + +typedef struct { + const char *pwfile; + const char *dbmtype; +} authn_dbm_config_rec; + +static void *create_authn_dbm_dir_config(apr_pool_t *p, char *d) +{ + authn_dbm_config_rec *conf = apr_palloc(p, sizeof(*conf)); + + conf->pwfile = NULL; + conf->dbmtype = "default"; + + return conf; +} + +static const command_rec authn_dbm_cmds[] = +{ + AP_INIT_TAKE1("AuthDBMUserFile", ap_set_file_slot, + (void *)APR_OFFSETOF(authn_dbm_config_rec, pwfile), + OR_AUTHCFG, "dbm database file containing user IDs and passwords"), + AP_INIT_TAKE1("AuthDBMType", ap_set_string_slot, + (void *)APR_OFFSETOF(authn_dbm_config_rec, dbmtype), + OR_AUTHCFG, "what type of DBM file the user file is"), + {NULL} +}; + +module AP_MODULE_DECLARE_DATA authn_dbm_module; + +static apr_status_t fetch_dbm_value(request_rec *r, const char *dbmtype, + const char *dbmfile, + const char *user, char **value) +{ +#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) + const apr_dbm_driver_t *driver; + const apu_err_t *err; +#endif + apr_dbm_t *f; + apr_datum_t key, val; + apr_status_t rv; + +#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) + rv = apr_dbm_get_driver(&driver, dbmtype, &err, r->pool); + + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10284) + "could not load '%s' dbm library: %s", + err->reason, err->msg); + return rv; + } + + rv = apr_dbm_open2(&f, driver, dbmfile, APR_DBM_READONLY, + APR_OS_DEFAULT, r->pool); +#else + rv = apr_dbm_open_ex(&f, dbmtype, dbmfile, APR_DBM_READONLY, + APR_OS_DEFAULT, r->pool); +#endif + + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10285) + "could not open dbm (type %s) file: %s", + dbmtype, dbmfile); + return rv; + } + + key.dptr = (char*)user; +#ifndef NETSCAPE_DBM_COMPAT + key.dsize = strlen(key.dptr); +#else + key.dsize = strlen(key.dptr) + 1; +#endif + + *value = NULL; + + if (apr_dbm_fetch(f, key, &val) == APR_SUCCESS && val.dptr) { + *value = apr_pstrmemdup(r->pool, val.dptr, val.dsize); + } + + apr_dbm_close(f); + + /* NOT FOUND is not an error case; this is indicated by a NULL result. + * Treat all NULL lookup/error results as success for the simple case + * of auth credential lookup, these are DECLINED in both cases. + */ + return APR_SUCCESS; +} + +static authn_status check_dbm_pw(request_rec *r, const char *user, + const char *password) +{ + authn_dbm_config_rec *conf = ap_get_module_config(r->per_dir_config, + &authn_dbm_module); + apr_status_t rv; + char *dbm_password; + char *colon_pw; + + rv = fetch_dbm_value(r, conf->dbmtype, conf->pwfile, user, &dbm_password); + + if (rv != APR_SUCCESS) { + return AUTH_GENERAL_ERROR; + } + + if (!dbm_password) { + return AUTH_USER_NOT_FOUND; + } + + colon_pw = ap_strchr(dbm_password, ':'); + if (colon_pw) { + *colon_pw = '\0'; + } + AUTHN_CACHE_STORE(r, user, NULL, dbm_password); + + rv = apr_password_validate(password, dbm_password); + + if (rv != APR_SUCCESS) { + return AUTH_DENIED; + } + + return AUTH_GRANTED; +} + +static authn_status get_dbm_realm_hash(request_rec *r, const char *user, + const char *realm, char **rethash) +{ + authn_dbm_config_rec *conf = ap_get_module_config(r->per_dir_config, + &authn_dbm_module); + apr_status_t rv; + char *dbm_hash; + char *colon_hash; + + rv = fetch_dbm_value(r, conf->dbmtype, conf->pwfile, + apr_pstrcat(r->pool, user, ":", realm, NULL), + &dbm_hash); + + if (rv != APR_SUCCESS) { + return AUTH_GENERAL_ERROR; + } + + if (!dbm_hash) { + return AUTH_USER_NOT_FOUND; + } + + colon_hash = ap_strchr(dbm_hash, ':'); + if (colon_hash) { + *colon_hash = '\0'; + } + + *rethash = dbm_hash; + AUTHN_CACHE_STORE(r, user, realm, dbm_hash); + + return AUTH_USER_FOUND; +} + +static const authn_provider authn_dbm_provider = +{ + &check_dbm_pw, + &get_dbm_realm_hash, +}; + +static void opt_retr(void) +{ + authn_cache_store = APR_RETRIEVE_OPTIONAL_FN(ap_authn_cache_store); +} +static void register_hooks(apr_pool_t *p) +{ + ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "dbm", + AUTHN_PROVIDER_VERSION, + &authn_dbm_provider, AP_AUTH_INTERNAL_PER_CONF); + ap_hook_optional_fn_retrieve(opt_retr, NULL, NULL, APR_HOOK_MIDDLE); +} + +AP_DECLARE_MODULE(authn_dbm) = +{ + STANDARD20_MODULE_STUFF, + create_authn_dbm_dir_config, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + NULL, /* server config */ + NULL, /* merge server config */ + authn_dbm_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; |