]> granicus.if.org Git - apache/blob - modules/aaa/mod_auth_db.c
579818e692570886bed2a9d1a81ad0c5174ee3fe
[apache] / modules / aaa / mod_auth_db.c
1 /* ====================================================================
2  * Copyright (c) 1995-2000 The Apache Software Foundation.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the Apache Software Foundation
19  *    for use in the Apache HTTP server project (http://www.apache.org/)."
20  *
21  * 4. The names "Apache Server" and "Apache Software Foundation" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    apache@apache.org.
25  *
26  * 5. Products derived from this software may not be called "Apache"
27  *    nor may "Apache" appear in their names without prior written
28  *    permission of the Apache Software Foundation.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the Apache Software Foundation
33  *    for use in the Apache HTTP server project (http://www.apache.org/)."
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE Apache Software Foundation ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE Apache Software Foundation OR
39  * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation and was originally based
51  * on public domain software written at the National Center for
52  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
53  * For more information on the Apache Software Foundation and the Apache HTTP server
54  * project, please see <http://www.apache.org/>.
55  *
56  */
57
58 /*
59  * mod_auth_db: authentication
60  * 
61  * Original work by Rob McCool & Brian Behlendorf.
62  * 
63  * Adapted to Apache by rst (mod_auth_dbm)
64  *
65  * Adapted for Berkeley DB by Andrew Cohen 
66  *
67  * mod_auth_db was based on mod_auth_dbm.
68  * 
69  * Warning, this is not a drop in replacement for mod_auth_dbm, 
70  * for people wanting to switch from dbm to Berkeley DB.
71  * It requires the use of AuthDBUserFile and AuthDBGroupFile
72  *           instead of   AuthDBMUserFile    AuthDBMGroupFile
73  *
74  * Also, in the configuration file you need to specify
75  *  db_auth_module rather than dbm_auth_module
76  *
77  * On some BSD systems (e.g. FreeBSD and NetBSD) dbm is automatically
78  * mapped to Berkeley DB. You can use either mod_auth_dbm or
79  * mod_auth_db. The latter makes it more obvious that it's Berkeley.
80  * On other platforms where you want to use the DB library you
81  * usually have to install it first. See http://www.sleepycat.com/
82  * for the distribution. The interface this module uses is the
83  * one from DB version 1.85 and 1.86, but DB version 2.x
84  * can also be used when compatibility mode is enabled.
85  *
86  * dirkx - Added Authoritative control to allow passing on to lower  
87  *         modules if and only if the userid is not known to this
88  *         module. A known user with a faulty or absent password still
89  *         causes an AuthRequired. The default is 'Authoritative', i.e.
90  *         no control is passed along.
91  */
92
93 #include "ap_config.h"
94 #include "httpd.h"
95 #include "http_config.h"
96 #include "http_core.h"
97 #include "http_log.h"
98 #include "http_protocol.h"
99 #ifdef HAVE_DB_H
100 #include <db.h>
101 #endif
102
103 #if defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2)
104 #define DB2
105 #endif
106
107 typedef struct {
108
109     char *auth_dbpwfile;
110     char *auth_dbgrpfile;
111     int auth_dbauthoritative;
112 } db_auth_config_rec;
113
114 static void *create_db_auth_dir_config(ap_context_t *p, char *d)
115 {
116     db_auth_config_rec *sec
117     = (db_auth_config_rec *) ap_pcalloc(p, sizeof(db_auth_config_rec));
118     sec->auth_dbpwfile = NULL;
119     sec->auth_dbgrpfile = NULL;
120     sec->auth_dbauthoritative = 1;      /* fortress is secure by default */
121     return sec;
122 }
123
124 static const char *set_db_slot(cmd_parms *cmd, void *offset, char *f, char *t)
125 {
126     if (!t || strcmp(t, "db"))
127         return DECLINE_CMD;
128
129     return ap_set_file_slot(cmd, offset, f);
130 }
131
132 static const command_rec db_auth_cmds[] =
133 {
134     {"AuthDBUserFile", ap_set_file_slot,
135      (void *) XtOffsetOf(db_auth_config_rec, auth_dbpwfile),
136      OR_AUTHCFG, TAKE1, NULL},
137     {"AuthDBGroupFile", ap_set_file_slot,
138      (void *) XtOffsetOf(db_auth_config_rec, auth_dbgrpfile),
139      OR_AUTHCFG, TAKE1, NULL},
140     {"AuthUserFile", set_db_slot,
141      (void *) XtOffsetOf(db_auth_config_rec, auth_dbpwfile),
142      OR_AUTHCFG, TAKE12, NULL},
143     {"AuthGroupFile", set_db_slot,
144      (void *) XtOffsetOf(db_auth_config_rec, auth_dbgrpfile),
145      OR_AUTHCFG, TAKE12, NULL},
146     {"AuthDBAuthoritative", ap_set_flag_slot,
147      (void *) XtOffsetOf(db_auth_config_rec, auth_dbauthoritative),
148      OR_AUTHCFG, FLAG,
149      "Set to 'no' to allow access control to be passed along to lower modules if the userID is not known to this module"},
150     {NULL}
151 };
152
153 module db_auth_module;
154
155 static char *get_db_pw(request_rec *r, char *user, const char *auth_dbpwfile)
156 {
157     DB *f;
158     DBT d, q;
159     char *pw = NULL;
160
161     memset(&d, 0, sizeof(d));
162     memset(&q, 0, sizeof(q));
163
164     q.data = user;
165     q.size = strlen(q.data);
166
167 #ifdef DB2
168     if (db_open(auth_dbpwfile, DB_HASH, DB_RDONLY, 0664, NULL, NULL, &f) != 0) {
169 #else
170     if (!(f = dbopen(auth_dbpwfile, O_RDONLY, 0664, DB_HASH, NULL))) {
171 #endif
172         ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
173                     "could not open db auth file: %s", auth_dbpwfile);
174         return NULL;
175     }
176
177 #ifdef DB2
178     if (!((f->get) (f, NULL, &q, &d, 0))) {
179 #else
180     if (!((f->get) (f, &q, &d, 0))) {
181 #endif
182         pw = ap_palloc(r->pool, d.size + 1);
183         strncpy(pw, d.data, d.size);
184         pw[d.size] = '\0';      /* Terminate the string */
185     }
186
187 #ifdef DB2
188     (f->close) (f, 0);
189 #else
190     (f->close) (f);
191 #endif
192     return pw;
193 }
194
195 /* We do something strange with the group file.  If the group file
196  * contains any : we assume the format is
197  *      key=username value=":"groupname [":"anything here is ignored]
198  * otherwise we now (0.8.14+) assume that the format is
199  *      key=username value=groupname
200  * The first allows the password and group files to be the same 
201  * physical DB file;   key=username value=password":"groupname[":"anything]
202  *
203  * mark@telescope.org, 22Sep95
204  */
205
206 static char *get_db_grp(request_rec *r, char *user, const char *auth_dbgrpfile)
207 {
208     char *grp_data = get_db_pw(r, user, auth_dbgrpfile);
209     char *grp_colon;
210     char *grp_colon2;
211
212     if (grp_data == NULL)
213         return NULL;
214
215     if ((grp_colon = strchr(grp_data, ':')) != NULL) {
216         grp_colon2 = strchr(++grp_colon, ':');
217         if (grp_colon2)
218             *grp_colon2 = '\0';
219         return grp_colon;
220     }
221     return grp_data;
222 }
223
224 static int db_authenticate_basic_user(request_rec *r)
225 {
226     db_auth_config_rec *sec =
227     (db_auth_config_rec *) ap_get_module_config(r->per_dir_config,
228                                              &db_auth_module);
229     const char *sent_pw;
230     char *real_pw, *colon_pw;
231     char *invalid_pw;
232     int res;
233
234     if ((res = ap_get_basic_auth_pw(r, &sent_pw)))
235         return res;
236
237     if (!sec->auth_dbpwfile)
238         return DECLINED;
239
240     if (!(real_pw = get_db_pw(r, r->user, sec->auth_dbpwfile))) {
241         if (!(sec->auth_dbauthoritative))
242             return DECLINED;
243         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
244                     "DB user %s not found: %s", r->user, r->filename);
245         ap_note_basic_auth_failure(r);
246         return AUTH_REQUIRED;
247     }
248     /* Password is up to first : if exists */
249     colon_pw = strchr(real_pw, ':');
250     if (colon_pw) {
251         *colon_pw = '\0';
252     }
253     invalid_pw = ap_validate_password(sent_pw, real_pw);
254     if (invalid_pw != NULL) {
255         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
256                       "DB user %s: authentication failure for \"%s\": %s",
257                       r->user, r->uri, invalid_pw);
258         ap_note_basic_auth_failure(r);
259         return AUTH_REQUIRED;
260     }
261     return OK;
262 }
263
264 /* Checking ID */
265
266 static int db_check_auth(request_rec *r)
267 {
268     db_auth_config_rec *sec =
269     (db_auth_config_rec *) ap_get_module_config(r->per_dir_config,
270                                              &db_auth_module);
271     char *user = r->user;
272     int m = r->method_number;
273
274     const ap_array_header_t *reqs_arr = ap_requires(r);
275     require_line *reqs = reqs_arr ? (require_line *) reqs_arr->elts : NULL;
276
277     register int x;
278     const char *t;
279     char *w;
280
281     if (!sec->auth_dbgrpfile)
282         return DECLINED;
283     if (!reqs_arr)
284         return DECLINED;
285
286     for (x = 0; x < reqs_arr->nelts; x++) {
287
288         if (!(reqs[x].method_mask & (1 << m)))
289             continue;
290
291         t = reqs[x].requirement;
292         w = ap_getword_white(r->pool, &t);
293
294         if (!strcmp(w, "group") && sec->auth_dbgrpfile) {
295             const char *orig_groups, *groups;
296             char *v;
297
298             if (!(groups = get_db_grp(r, user, sec->auth_dbgrpfile))) {
299                 if (!(sec->auth_dbauthoritative))
300                     return DECLINED;
301                 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
302                             "user %s not in DB group file %s: %s",
303                             user, sec->auth_dbgrpfile, r->filename);
304                 ap_note_basic_auth_failure(r);
305                 return AUTH_REQUIRED;
306             }
307             orig_groups = groups;
308             while (t[0]) {
309                 w = ap_getword_white(r->pool, &t);
310                 groups = orig_groups;
311                 while (groups[0]) {
312                     v = ap_getword(r->pool, &groups, ',');
313                     if (!strcmp(v, w))
314                         return OK;
315                 }
316             }
317             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
318                         "user %s not in right group: %s", user, r->filename);
319             ap_note_basic_auth_failure(r);
320             return AUTH_REQUIRED;
321         }
322     }
323
324     return DECLINED;
325 }
326
327
328 module db_auth_module =
329 {
330     STANDARD_MODULE_STUFF,
331     NULL,                       /* initializer */
332     create_db_auth_dir_config,  /* dir config creater */
333     NULL,                       /* dir merger --- default is to override */
334     NULL,                       /* server config */
335     NULL,                       /* merge server config */
336     db_auth_cmds,               /* command ap_table_t */
337     NULL,                       /* handlers */
338     NULL,                       /* filename translation */
339     db_authenticate_basic_user, /* check_user_id */
340     db_check_auth,              /* check auth */
341     NULL,                       /* check access */
342     NULL,                       /* type_checker */
343     NULL,                       /* fixups */
344     NULL,                       /* logger */
345     NULL,                       /* header parser */
346     NULL,                       /* child_init */
347     NULL,                       /* child_exit */
348     NULL                        /* post read-request */
349 };