/[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 - (hide 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 fielding 420983 /* 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 niq 321247 *
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 chrisd 644525 #include "http_request.h"
22 minfrin 466865 #include "apr_lib.h"
23 niq 321247 #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 minfrin 466865 #include "apu_version.h"
29 niq 321247
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 niq 344349 return ap_set_string_slot(cmd, cfg, label);
77 niq 321247 }
78     static const command_rec authn_dbd_cmds[] =
79     {
80     AP_INIT_TAKE1("AuthDBDUserPWQuery", authn_dbd_prepare,
81 niq 329497 (void *)APR_OFFSETOF(authn_dbd_conf, user), ACCESS_CONF,
82 niq 321247 "Query used to fetch password for user"),
83 niq 329497 AP_INIT_TAKE1("AuthDBDUserRealmQuery", authn_dbd_prepare,
84     (void *)APR_OFFSETOF(authn_dbd_conf, realm), ACCESS_CONF,
85 niq 321247 "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 chrisd 639079 "Failed to acquire database connection to look up "
103     "user '%s'", user);
104 niq 321247 return AUTH_GENERAL_ERROR;
105     }
106    
107     if (conf->user == NULL) {
108 chrisd 639079 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
109     "No AuthDBDUserPWQuery has been specified");
110 niq 321247 return AUTH_GENERAL_ERROR;
111     }
112    
113     statement = apr_hash_get(dbd->prepared, conf->user, APR_HASH_KEY_STRING);
114     if (statement == NULL) {
115 chrisd 639079 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 niq 321247 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 chrisd 639079 "Query execution error looking up '%s' "
124     "in database", user);
125 niq 321247 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 chrisd 639079 "Error retrieving results while looking up '%s' "
133     "in database", user);
134 niq 321247 return AUTH_GENERAL_ERROR;
135     }
136     if (dbd_password == NULL) {
137 minfrin 466865 #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 minfrin 571798 int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */
149 minfrin 466865 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 niq 586765 apr_table_set(r->subprocess_env, str,
159     apr_dbd_get_entry(dbd->driver, row, i));
160 minfrin 466865 i++;
161     }
162     #endif
163 bnicholes 468042 dbd_password = apr_dbd_get_entry(dbd->driver, row, 0);
164 niq 321247 }
165 niq 329497 /* we can't break out here or row won't get cleaned up */
166 niq 321247 }
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 chrisd 639079 "Failed to acquire database connection to look up "
195     "user '%s:%s'", user, realm);
196 niq 321247 return AUTH_GENERAL_ERROR;
197     }
198     if (conf->realm == NULL) {
199 chrisd 639079 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
200     "No AuthDBDUserRealmQuery has been specified");
201 niq 321247 return AUTH_GENERAL_ERROR;
202     }
203     statement = apr_hash_get(dbd->prepared, conf->realm, APR_HASH_KEY_STRING);
204     if (statement == NULL) {
205 chrisd 639079 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 niq 321247 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 chrisd 639079 "Query execution error looking up '%s:%s' "
214     "in database", user, realm);
215 niq 321247 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 chrisd 639079 "Error retrieving results while looking up '%s:%s' "
223     "in database", user, realm);
224 niq 321247 return AUTH_GENERAL_ERROR;
225     }
226     if (dbd_hash == NULL) {
227 minfrin 466865 #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 minfrin 571798 int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */
239 minfrin 466865 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 niq 586765 apr_table_set(r->subprocess_env, str,
249     apr_dbd_get_entry(dbd->driver, row, i));
250 minfrin 466865 i++;
251     }
252     #endif
253 bnicholes 468042 dbd_hash = apr_dbd_get_entry(dbd->driver, row, 0);
254 niq 321247 }
255 niq 329497 /* we can't break out here or row won't get cleaned up */
256 niq 321247 }
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 jim 332306
272 chrisd 644525 ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "dbd", "0",
273     &authn_dbd_provider, AP_AUTH_INTERNAL_PER_CONF);
274 niq 321247 }
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