1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* 18 * http_auth: authentication 19 * 20 * Rob McCool & Brian Behlendorf. 21 * 22 * Adapted to Apache by rst. 23 * 24 */ 25 26#define APR_WANT_STRFUNC 27#include "apr_want.h" 28#include "apr_strings.h" 29#include "apr_dbm.h" 30#include "apr_md5.h" /* for apr_password_validate */ 31 32#include "ap_provider.h" 33#include "httpd.h" 34#include "http_config.h" 35#include "http_core.h" 36#include "http_log.h" 37#include "http_protocol.h" 38#include "http_request.h" /* for ap_hook_(check_user_id | auth_checker)*/ 39 40#include "mod_auth.h" 41 42static APR_OPTIONAL_FN_TYPE(ap_authn_cache_store) *authn_cache_store = NULL; 43#define AUTHN_CACHE_STORE(r,user,realm,data) \ 44 if (authn_cache_store != NULL) \ 45 authn_cache_store((r), "dbm", (user), (realm), (data)) 46 47typedef struct { 48 const char *pwfile; 49 const char *dbmtype; 50} authn_dbm_config_rec; 51 52static void *create_authn_dbm_dir_config(apr_pool_t *p, char *d) 53{ 54 authn_dbm_config_rec *conf = apr_palloc(p, sizeof(*conf)); 55 56 conf->pwfile = NULL; 57 conf->dbmtype = "default"; 58 59 return conf; 60} 61 62static const char *set_dbm_type(cmd_parms *cmd, 63 void *dir_config, 64 const char *arg) 65{ 66 authn_dbm_config_rec *conf = dir_config; 67 68 conf->dbmtype = apr_pstrdup(cmd->pool, arg); 69 return NULL; 70} 71 72static const command_rec authn_dbm_cmds[] = 73{ 74 AP_INIT_TAKE1("AuthDBMUserFile", ap_set_file_slot, 75 (void *)APR_OFFSETOF(authn_dbm_config_rec, pwfile), 76 OR_AUTHCFG, "dbm database file containing user IDs and passwords"), 77 AP_INIT_TAKE1("AuthDBMType", set_dbm_type, 78 NULL, 79 OR_AUTHCFG, "what type of DBM file the user file is"), 80 {NULL} 81}; 82 83module AP_MODULE_DECLARE_DATA authn_dbm_module; 84 85static apr_status_t fetch_dbm_value(const char *dbmtype, const char *dbmfile, 86 const char *user, char **value, 87 apr_pool_t *pool) 88{ 89 apr_dbm_t *f; 90 apr_datum_t key, val; 91 apr_status_t rv; 92 93 rv = apr_dbm_open_ex(&f, dbmtype, dbmfile, APR_DBM_READONLY, 94 APR_OS_DEFAULT, pool); 95 96 if (rv != APR_SUCCESS) { 97 return rv; 98 } 99 100 key.dptr = (char*)user; 101#ifndef NETSCAPE_DBM_COMPAT 102 key.dsize = strlen(key.dptr); 103#else 104 key.dsize = strlen(key.dptr) + 1; 105#endif 106 107 *value = NULL; 108 109 if (apr_dbm_fetch(f, key, &val) == APR_SUCCESS && val.dptr) { 110 *value = apr_pstrmemdup(pool, val.dptr, val.dsize); 111 } 112 113 apr_dbm_close(f); 114 115 return rv; 116} 117 118static authn_status check_dbm_pw(request_rec *r, const char *user, 119 const char *password) 120{ 121 authn_dbm_config_rec *conf = ap_get_module_config(r->per_dir_config, 122 &authn_dbm_module); 123 apr_status_t rv; 124 char *dbm_password; 125 char *colon_pw; 126 127 rv = fetch_dbm_value(conf->dbmtype, conf->pwfile, user, &dbm_password, 128 r->pool); 129 130 if (rv != APR_SUCCESS) { 131 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01754) 132 "could not open dbm (type %s) auth file: %s", 133 conf->dbmtype, conf->pwfile); 134 return AUTH_GENERAL_ERROR; 135 } 136 137 if (!dbm_password) { 138 return AUTH_USER_NOT_FOUND; 139 } 140 141 colon_pw = ap_strchr(dbm_password, ':'); 142 if (colon_pw) { 143 *colon_pw = '\0'; 144 } 145 AUTHN_CACHE_STORE(r, user, NULL, dbm_password); 146 147 rv = apr_password_validate(password, dbm_password); 148 149 if (rv != APR_SUCCESS) { 150 return AUTH_DENIED; 151 } 152 153 return AUTH_GRANTED; 154} 155 156static authn_status get_dbm_realm_hash(request_rec *r, const char *user, 157 const char *realm, char **rethash) 158{ 159 authn_dbm_config_rec *conf = ap_get_module_config(r->per_dir_config, 160 &authn_dbm_module); 161 apr_status_t rv; 162 char *dbm_hash; 163 char *colon_hash; 164 165 rv = fetch_dbm_value(conf->dbmtype, conf->pwfile, 166 apr_pstrcat(r->pool, user, ":", realm, NULL), 167 &dbm_hash, r->pool); 168 169 if (rv != APR_SUCCESS) { 170 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01755) 171 "Could not open dbm (type %s) hash file: %s", 172 conf->dbmtype, conf->pwfile); 173 return AUTH_GENERAL_ERROR; 174 } 175 176 if (!dbm_hash) { 177 return AUTH_USER_NOT_FOUND; 178 } 179 180 colon_hash = ap_strchr(dbm_hash, ':'); 181 if (colon_hash) { 182 *colon_hash = '\0'; 183 } 184 185 *rethash = dbm_hash; 186 AUTHN_CACHE_STORE(r, user, realm, dbm_hash); 187 188 return AUTH_USER_FOUND; 189} 190 191static const authn_provider authn_dbm_provider = 192{ 193 &check_dbm_pw, 194 &get_dbm_realm_hash, 195}; 196 197static void opt_retr(void) 198{ 199 authn_cache_store = APR_RETRIEVE_OPTIONAL_FN(ap_authn_cache_store); 200} 201static void register_hooks(apr_pool_t *p) 202{ 203 ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "dbm", 204 AUTHN_PROVIDER_VERSION, 205 &authn_dbm_provider, AP_AUTH_INTERNAL_PER_CONF); 206 ap_hook_optional_fn_retrieve(opt_retr, NULL, NULL, APR_HOOK_MIDDLE); 207} 208 209AP_DECLARE_MODULE(authn_dbm) = 210{ 211 STANDARD20_MODULE_STUFF, 212 create_authn_dbm_dir_config, /* dir config creater */ 213 NULL, /* dir merger --- default is to override */ 214 NULL, /* server config */ 215 NULL, /* merge server config */ 216 authn_dbm_cmds, /* command apr_table_t */ 217 register_hooks /* register hooks */ 218}; 219