/[Apache-SVN]/httpd/httpd/trunk/modules/aaa/mod_authn_dbd.c
ViewVC logotype

Contents of /httpd/httpd/trunk/modules/aaa/mod_authn_dbd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 644525 - (show annotations)
Thu Apr 3 21:51:07 2008 UTC (19 months, 3 weeks ago) by chrisd
File MIME type: text/plain
File size: 10523 byte(s)
Avoid calling access control hooks for internal requests with
configurations which match those of the initial request.  Revert to
the original behaviour (call access control hooks for internal requests
with URIs different from the initial request) if any access control hooks
or providers are not registered as permitting this optimization.
Introduce wrappers for access control hook and provider registration
which can accept additional mode and flag data.

The configuration walk optimizations were originally proposed a while
ago (see http://marc.info/?l=apache-httpd-dev&m=116536713506234&w=2);
they have been used since then in production systems and appear to be
stable and effective.  They permit certain combinations of modules
and clients to function efficiently, especially when a deeply recursive
series of internal requests, such as those generated by certain WebDAV
requests, are all subject to the identical authentication and authorization
directives.

The major change from the original proposal is a cleaner mechanism for
detecting modules which may expect the old behaviour.  This has been
tested successfully with Subversion's mod_authz_svn, which specifically
requires the old behaviour when performing path-based authorization based
against its own private access control configuration files.
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 "ap_provider.h"
18 #include "httpd.h"
19 #include "http_config.h"
20 #include "http_log.h"
21 #include "http_request.h"
22 #include "apr_lib.h"
23 #include "apr_dbd.h"
24 #include "mod_dbd.h"
25 #include "apr_strings.h"
26 #include "mod_auth.h"
27 #include "apr_md5.h"
28 #include "apu_version.h"
29
30 module AP_MODULE_DECLARE_DATA authn_dbd_module;
31
32 typedef struct {
33 const char *user;
34 const char *realm;
35 } authn_dbd_conf;
36 typedef struct {
37 const char *label;
38 const char *query;
39 } authn_dbd_rec;
40
41 /* optional function - look it up once in post_config */
42 static ap_dbd_t *(*authn_dbd_acquire_fn)(request_rec*) = NULL;
43 static void (*authn_dbd_prepare_fn)(server_rec*, const char*, const char*) = NULL;
44
45 static void *authn_dbd_cr_conf(apr_pool_t *pool, char *dummy)
46 {
47 authn_dbd_conf *ret = apr_pcalloc(pool, sizeof(authn_dbd_conf));
48 return ret;
49 }
50 static void *authn_dbd_merge_conf(apr_pool_t *pool, void *BASE, void *ADD)
51 {
52 authn_dbd_conf *add = ADD;
53 authn_dbd_conf *base = BASE;
54 authn_dbd_conf *ret = apr_palloc(pool, sizeof(authn_dbd_conf));
55 ret->user = (add->user == NULL) ? base->user : add->user;
56 ret->realm = (add->realm == NULL) ? base->realm : add->realm;
57 return ret;
58 }
59 static const char *authn_dbd_prepare(cmd_parms *cmd, void *cfg, const char *query)
60 {
61 static unsigned int label_num = 0;
62 char *label;
63
64 if (authn_dbd_prepare_fn == NULL) {
65 authn_dbd_prepare_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_prepare);
66 if (authn_dbd_prepare_fn == NULL) {
67 return "You must load mod_dbd to enable AuthDBD functions";
68 }
69 authn_dbd_acquire_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire);
70 }
71 label = apr_psprintf(cmd->pool, "authn_dbd_%d", ++label_num);
72
73 authn_dbd_prepare_fn(cmd->server, query, label);
74
75 /* save the label here for our own use */
76 return ap_set_string_slot(cmd, cfg, label);
77 }
78 static const command_rec authn_dbd_cmds[] =
79 {
80 AP_INIT_TAKE1("AuthDBDUserPWQuery", authn_dbd_prepare,
81 (void *)APR_OFFSETOF(authn_dbd_conf, user), ACCESS_CONF,
82 "Query used to fetch password for user"),
83 AP_INIT_TAKE1("AuthDBDUserRealmQuery", authn_dbd_prepare,
84 (void *)APR_OFFSETOF(authn_dbd_conf, realm), ACCESS_CONF,
85 "Query used to fetch password for user+realm"),
86 {NULL}
87 };
88 static authn_status authn_dbd_password(request_rec *r, const char *user,
89 const char *password)
90 {
91 apr_status_t rv;
92 const char *dbd_password = NULL;
93 apr_dbd_prepared_t *statement;
94 apr_dbd_results_t *res = NULL;
95 apr_dbd_row_t *row = NULL;
96
97 authn_dbd_conf *conf = ap_get_module_config(r->per_dir_config,
98 &authn_dbd_module);
99 ap_dbd_t *dbd = authn_dbd_acquire_fn(r);
100 if (dbd == NULL) {
101 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
102 "Failed to acquire database connection to look up "
103 "user '%s'", user);
104 return AUTH_GENERAL_ERROR;
105 }
106
107 if (conf->user == NULL) {
108 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
109 "No AuthDBDUserPWQuery has been specified");
110 return AUTH_GENERAL_ERROR;
111 }
112
113 statement = apr_hash_get(dbd->prepared, conf->user, APR_HASH_KEY_STRING);
114 if (statement == NULL) {
115 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
116 "A prepared statement could not be found for "
117 "AuthDBDUserPWQuery with the key '%s'", conf->user);
118 return AUTH_GENERAL_ERROR;
119 }
120 if (apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, statement,
121 0, user, NULL) != 0) {
122 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
123 "Query execution error looking up '%s' "
124 "in database", user);
125 return AUTH_GENERAL_ERROR;
126 }
127 for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1);
128 rv != -1;
129 rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) {
130 if (rv != 0) {
131 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
132 "Error retrieving results while looking up '%s' "
133 "in database", user);
134 return AUTH_GENERAL_ERROR;
135 }
136 if (dbd_password == NULL) {
137 #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
138 /* add the rest of the columns to the environment */
139 int i = 1;
140 const char *name;
141 for (name = apr_dbd_get_name(dbd->driver, res, i);
142 name != NULL;
143 name = apr_dbd_get_name(dbd->driver, res, i)) {
144
145 char *str = apr_pstrcat(r->pool, AUTHN_PREFIX,
146 name,
147 NULL);
148 int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */
149 while (str[j]) {
150 if (!apr_isalnum(str[j])) {
151 str[j] = '_';
152 }
153 else {
154 str[j] = apr_toupper(str[j]);
155 }
156 j++;
157 }
158 apr_table_set(r->subprocess_env, str,
159 apr_dbd_get_entry(dbd->driver, row, i));
160 i++;
161 }
162 #endif
163 dbd_password = apr_dbd_get_entry(dbd->driver, row, 0);
164 }
165 /* we can't break out here or row won't get cleaned up */
166 }
167
168 if (!dbd_password) {
169 return AUTH_USER_NOT_FOUND;
170 }
171
172 rv = apr_password_validate(password, dbd_password);
173
174 if (rv != APR_SUCCESS) {
175 return AUTH_DENIED;
176 }
177
178 return AUTH_GRANTED;
179 }
180 static authn_status authn_dbd_realm(request_rec *r, const char *user,
181 const char *realm, char **rethash)
182 {
183 apr_status_t rv;
184 const char *dbd_hash = NULL;
185 apr_dbd_prepared_t *statement;
186 apr_dbd_results_t *res = NULL;
187 apr_dbd_row_t *row = NULL;
188
189 authn_dbd_conf *conf = ap_get_module_config(r->per_dir_config,
190 &authn_dbd_module);
191 ap_dbd_t *dbd = authn_dbd_acquire_fn(r);
192 if (dbd == NULL) {
193 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
194 "Failed to acquire database connection to look up "
195 "user '%s:%s'", user, realm);
196 return AUTH_GENERAL_ERROR;
197 }
198 if (conf->realm == NULL) {
199 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
200 "No AuthDBDUserRealmQuery has been specified");
201 return AUTH_GENERAL_ERROR;
202 }
203 statement = apr_hash_get(dbd->prepared, conf->realm, APR_HASH_KEY_STRING);
204 if (statement == NULL) {
205 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
206 "A prepared statement could not be found for "
207 "AuthDBDUserRealmQuery with the key '%s'", conf->realm);
208 return AUTH_GENERAL_ERROR;
209 }
210 if (apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, statement,
211 0, user, realm, NULL) != 0) {
212 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
213 "Query execution error looking up '%s:%s' "
214 "in database", user, realm);
215 return AUTH_GENERAL_ERROR;
216 }
217 for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1);
218 rv != -1;
219 rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) {
220 if (rv != 0) {
221 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
222 "Error retrieving results while looking up '%s:%s' "
223 "in database", user, realm);
224 return AUTH_GENERAL_ERROR;
225 }
226 if (dbd_hash == NULL) {
227 #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
228 /* add the rest of the columns to the environment */
229 int i = 1;
230 const char *name;
231 for (name = apr_dbd_get_name(dbd->driver, res, i);
232 name != NULL;
233 name = apr_dbd_get_name(dbd->driver, res, i)) {
234
235 char *str = apr_pstrcat(r->pool, AUTHN_PREFIX,
236 name,
237 NULL);
238 int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */
239 while (str[j]) {
240 if (!apr_isalnum(str[j])) {
241 str[j] = '_';
242 }
243 else {
244 str[j] = apr_toupper(str[j]);
245 }
246 j++;
247 }
248 apr_table_set(r->subprocess_env, str,
249 apr_dbd_get_entry(dbd->driver, row, i));
250 i++;
251 }
252 #endif
253 dbd_hash = apr_dbd_get_entry(dbd->driver, row, 0);
254 }
255 /* we can't break out here or row won't get cleaned up */
256 }
257
258 if (!dbd_hash) {
259 return AUTH_USER_NOT_FOUND;
260 }
261
262 *rethash = apr_pstrdup(r->pool, dbd_hash);
263 return AUTH_USER_FOUND;
264 }
265 static void authn_dbd_hooks(apr_pool_t *p)
266 {
267 static const authn_provider authn_dbd_provider = {
268 &authn_dbd_password,
269 &authn_dbd_realm
270 };
271
272 ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "dbd", "0",
273 &authn_dbd_provider, AP_AUTH_INTERNAL_PER_CONF);
274 }
275 module AP_MODULE_DECLARE_DATA authn_dbd_module =
276 {
277 STANDARD20_MODULE_STUFF,
278 authn_dbd_cr_conf,
279 authn_dbd_merge_conf,
280 NULL,
281 NULL,
282 authn_dbd_cmds,
283 authn_dbd_hooks
284 };

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2