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#include "apr_strings.h" 18#include "apr_md5.h" /* for apr_password_validate */ 19 20#include "ap_config.h" 21#include "ap_provider.h" 22#include "httpd.h" 23#include "http_config.h" 24#include "http_core.h" 25#include "http_log.h" 26#include "http_protocol.h" 27#include "http_request.h" 28 29#include "mod_auth.h" 30 31typedef struct { 32 char *pwfile; 33} authn_file_config_rec; 34 35static APR_OPTIONAL_FN_TYPE(ap_authn_cache_store) *authn_cache_store = NULL; 36#define AUTHN_CACHE_STORE(r,user,realm,data) \ 37 if (authn_cache_store != NULL) \ 38 authn_cache_store((r), "file", (user), (realm), (data)) 39 40static void *create_authn_file_dir_config(apr_pool_t *p, char *d) 41{ 42 authn_file_config_rec *conf = apr_palloc(p, sizeof(*conf)); 43 44 conf->pwfile = NULL; /* just to illustrate the default really */ 45 return conf; 46} 47 48static const command_rec authn_file_cmds[] = 49{ 50 AP_INIT_TAKE1("AuthUserFile", ap_set_file_slot, 51 (void *)APR_OFFSETOF(authn_file_config_rec, pwfile), 52 OR_AUTHCFG, "text file containing user IDs and passwords"), 53 {NULL} 54}; 55 56module AP_MODULE_DECLARE_DATA authn_file_module; 57 58static authn_status check_password(request_rec *r, const char *user, 59 const char *password) 60{ 61 authn_file_config_rec *conf = ap_get_module_config(r->per_dir_config, 62 &authn_file_module); 63 ap_configfile_t *f; 64 char l[MAX_STRING_LEN]; 65 apr_status_t status; 66 char *file_password = NULL; 67 68 if (!conf->pwfile) { 69 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01619) 70 "AuthUserFile not specified in the configuration"); 71 return AUTH_GENERAL_ERROR; 72 } 73 74 status = ap_pcfg_openfile(&f, r->pool, conf->pwfile); 75 76 if (status != APR_SUCCESS) { 77 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01620) 78 "Could not open password file: %s", conf->pwfile); 79 return AUTH_GENERAL_ERROR; 80 } 81 82 while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { 83 const char *rpw, *w; 84 85 /* Skip # or blank lines. */ 86 if ((l[0] == '#') || (!l[0])) { 87 continue; 88 } 89 90 rpw = l; 91 w = ap_getword(r->pool, &rpw, ':'); 92 93 if (!strcmp(user, w)) { 94 file_password = ap_getword(r->pool, &rpw, ':'); 95 break; 96 } 97 } 98 ap_cfg_closefile(f); 99 100 if (!file_password) { 101 return AUTH_USER_NOT_FOUND; 102 } 103 AUTHN_CACHE_STORE(r, user, NULL, file_password); 104 105 status = apr_password_validate(password, file_password); 106 if (status != APR_SUCCESS) { 107 return AUTH_DENIED; 108 } 109 110 return AUTH_GRANTED; 111} 112 113static authn_status get_realm_hash(request_rec *r, const char *user, 114 const char *realm, char **rethash) 115{ 116 authn_file_config_rec *conf = ap_get_module_config(r->per_dir_config, 117 &authn_file_module); 118 ap_configfile_t *f; 119 char l[MAX_STRING_LEN]; 120 apr_status_t status; 121 char *file_hash = NULL; 122 123 if (!conf->pwfile) { 124 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01621) 125 "AuthUserFile not specified in the configuration"); 126 return AUTH_GENERAL_ERROR; 127 } 128 129 status = ap_pcfg_openfile(&f, r->pool, conf->pwfile); 130 131 if (status != APR_SUCCESS) { 132 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01622) 133 "Could not open password file: %s", conf->pwfile); 134 return AUTH_GENERAL_ERROR; 135 } 136 137 while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { 138 const char *rpw, *w, *x; 139 140 /* Skip # or blank lines. */ 141 if ((l[0] == '#') || (!l[0])) { 142 continue; 143 } 144 145 rpw = l; 146 w = ap_getword(r->pool, &rpw, ':'); 147 x = ap_getword(r->pool, &rpw, ':'); 148 149 if (x && w && !strcmp(user, w) && !strcmp(realm, x)) { 150 /* Remember that this is a md5 hash of user:realm:password. */ 151 file_hash = ap_getword(r->pool, &rpw, ':'); 152 break; 153 } 154 } 155 ap_cfg_closefile(f); 156 157 if (!file_hash) { 158 return AUTH_USER_NOT_FOUND; 159 } 160 161 *rethash = file_hash; 162 AUTHN_CACHE_STORE(r, user, realm, file_hash); 163 164 return AUTH_USER_FOUND; 165} 166 167static const authn_provider authn_file_provider = 168{ 169 &check_password, 170 &get_realm_hash, 171}; 172 173static void opt_retr(void) 174{ 175 authn_cache_store = APR_RETRIEVE_OPTIONAL_FN(ap_authn_cache_store); 176} 177static void register_hooks(apr_pool_t *p) 178{ 179 ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "file", 180 AUTHN_PROVIDER_VERSION, 181 &authn_file_provider, AP_AUTH_INTERNAL_PER_CONF); 182 ap_hook_optional_fn_retrieve(opt_retr, NULL, NULL, APR_HOOK_MIDDLE); 183} 184 185AP_DECLARE_MODULE(authn_file) = 186{ 187 STANDARD20_MODULE_STUFF, 188 create_authn_file_dir_config, /* dir config creater */ 189 NULL, /* dir merger --- default is to override */ 190 NULL, /* server config */ 191 NULL, /* merge server config */ 192 authn_file_cmds, /* command apr_table_t */ 193 register_hooks /* register hooks */ 194}; 195