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
42 static 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
47 typedef struct {
48 const char *pwfile;
49 const char *dbmtype;
50 } authn_dbm_config_rec;
51
create_authn_dbm_dir_config(apr_pool_t * p,char * d)52 static 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
set_dbm_type(cmd_parms * cmd,void * dir_config,const char * arg)62 static 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
72 static 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
83 module AP_MODULE_DECLARE_DATA authn_dbm_module;
84
fetch_dbm_value(const char * dbmtype,const char * dbmfile,const char * user,char ** value,apr_pool_t * pool)85 static 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
check_dbm_pw(request_rec * r,const char * user,const char * password)118 static 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
get_dbm_realm_hash(request_rec * r,const char * user,const char * realm,char ** rethash)156 static 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
191 static const authn_provider authn_dbm_provider =
192 {
193 &check_dbm_pw,
194 &get_dbm_realm_hash,
195 };
196
opt_retr(void)197 static void opt_retr(void)
198 {
199 authn_cache_store = APR_RETRIEVE_OPTIONAL_FN(ap_authn_cache_store);
200 }
register_hooks(apr_pool_t * p)201 static 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
209 AP_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