]> granicus.if.org Git - apache/blob - modules/aaa/mod_auth_dbm.c
PR:
[apache] / modules / aaa / mod_auth_dbm.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 /*
60  * http_auth: authentication
61  * 
62  * Rob McCool & Brian Behlendorf.
63  * 
64  * Adapted to Apache by rst.
65  *
66  * dirkx - Added Authoritative control to allow passing on to lower  
67  *         modules if and only if the userid is not known to this
68  *         module. A known user with a faulty or absent password still
69  *         causes an AuthRequired. The default is 'Authoritative', i.e.
70  *         no control is passed along.
71  */
72
73 #include "httpd.h"
74 #include "http_config.h"
75 #include "http_core.h"
76 #include "http_log.h"
77 #include "http_protocol.h"
78 #if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \
79     && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
80 #include <db1/ndbm.h>
81 #else
82 #include <ndbm.h>
83 #endif
84
85 /*
86  * Module definition information - the part between the -START and -END
87  * lines below is used by Configure. This could be stored in a separate
88  * instead.
89  *
90  * XXX: this needs updating for apache-2.0 configuration method
91  * MODULE-DEFINITION-START
92  * Name: auth_dbm_module
93  * ConfigStart
94     . ./helpers/find-dbm-lib
95  * ConfigEnd
96  * MODULE-DEFINITION-END
97  */
98
99 typedef struct {
100
101     char *auth_dbmpwfile;
102     char *auth_dbmgrpfile;
103     int auth_dbmauthoritative;
104
105 } dbm_auth_config_rec;
106
107 static void *create_dbm_auth_dir_config(ap_pool_t *p, char *d)
108 {
109     dbm_auth_config_rec *sec
110     = (dbm_auth_config_rec *) ap_pcalloc(p, sizeof(dbm_auth_config_rec));
111
112     sec->auth_dbmpwfile = NULL;
113     sec->auth_dbmgrpfile = NULL;
114     sec->auth_dbmauthoritative = 1;     /* fortress is secure by default */
115
116     return sec;
117 }
118
119 static const char *set_dbm_slot(cmd_parms *cmd, void *offset, char *f, char *t)
120 {
121     if (!t || strcmp(t, "dbm"))
122         return DECLINE_CMD;
123
124     return ap_set_file_slot(cmd, offset, f);
125 }
126
127 static const command_rec dbm_auth_cmds[] =
128 {
129     {"AuthDBMUserFile", ap_set_file_slot,
130      (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile),
131      OR_AUTHCFG, TAKE1, NULL},
132     {"AuthDBMGroupFile", ap_set_file_slot,
133      (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile),
134      OR_AUTHCFG, TAKE1, NULL},
135     {"AuthUserFile", set_dbm_slot,
136      (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile),
137      OR_AUTHCFG, TAKE12, NULL},
138     {"AuthGroupFile", set_dbm_slot,
139      (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile),
140      OR_AUTHCFG, TAKE12, NULL},
141     {"AuthDBMAuthoritative", ap_set_flag_slot,
142      (void *) XtOffsetOf(dbm_auth_config_rec, auth_dbmauthoritative),
143      OR_AUTHCFG, FLAG, "Set to 'no' to allow access control to be passed along to lower modules, if the UserID is not known in this module"},
144     {NULL}
145 };
146
147 module auth_dbm_module;
148
149 static char *get_dbm_pw(request_rec *r, char *user, char *auth_dbmpwfile)
150 {
151     DBM *f;
152     datum d, q;
153     char *pw = NULL;
154
155     q.dptr = user;
156 #ifndef NETSCAPE_DBM_COMPAT
157     q.dsize = strlen(q.dptr);
158 #else
159     q.dsize = strlen(q.dptr) + 1;
160 #endif
161
162
163     if (!(f = dbm_open(auth_dbmpwfile, O_RDONLY, 0664))) {
164         ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
165                     "could not open dbm auth file: %s", auth_dbmpwfile);
166         return NULL;
167     }
168
169     d = dbm_fetch(f, q);
170
171     if (d.dptr) {
172         pw = ap_palloc(r->pool, d.dsize + 1);
173         strncpy(pw, d.dptr, d.dsize);
174         pw[d.dsize] = '\0';     /* Terminate the string */
175     }
176
177     dbm_close(f);
178     return pw;
179 }
180
181 /* We do something strange with the group file.  If the group file
182  * contains any : we assume the format is
183  *      key=username value=":"groupname [":"anything here is ignored]
184  * otherwise we now (0.8.14+) assume that the format is
185  *      key=username value=groupname
186  * The first allows the password and group files to be the same 
187  * physical DBM file;   key=username value=password":"groupname[":"anything]
188  *
189  * mark@telescope.org, 22Sep95
190  */
191
192 static char *get_dbm_grp(request_rec *r, char *user, char *auth_dbmgrpfile)
193 {
194     char *grp_data = get_dbm_pw(r, user, auth_dbmgrpfile);
195     char *grp_colon;
196     char *grp_colon2;
197
198     if (grp_data == NULL)
199         return NULL;
200
201     if ((grp_colon = strchr(grp_data, ':')) != NULL) {
202         grp_colon2 = strchr(++grp_colon, ':');
203         if (grp_colon2)
204             *grp_colon2 = '\0';
205         return grp_colon;
206     }
207     return grp_data;
208 }
209
210 static int dbm_authenticate_basic_user(request_rec *r)
211 {
212     dbm_auth_config_rec *sec =
213     (dbm_auth_config_rec *) ap_get_module_config(r->per_dir_config,
214                                               &auth_dbm_module);
215     const char *sent_pw;
216     char *real_pw, *colon_pw;
217     ap_status_t invalid_pw;
218     int res;
219
220     if ((res = ap_get_basic_auth_pw(r, &sent_pw)))
221         return res;
222
223     if (!sec->auth_dbmpwfile)
224         return DECLINED;
225
226     if (!(real_pw = get_dbm_pw(r, r->user, sec->auth_dbmpwfile))) {
227         if (!(sec->auth_dbmauthoritative))
228             return DECLINED;
229         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
230                     "DBM user %s not found: %s", r->user, r->filename);
231         ap_note_basic_auth_failure(r);
232         return AUTH_REQUIRED;
233     }
234     /* Password is up to first : if exists */
235     colon_pw = strchr(real_pw, ':');
236     if (colon_pw) {
237         *colon_pw = '\0';
238     }
239     invalid_pw = ap_validate_password(sent_pw, real_pw);
240     if (invalid_pw != APR_SUCCESS) {
241         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
242                       "DBM user %s: authentication failure for \"%s\": %s",
243                       r->user, r->uri, invalid_pw);
244         ap_note_basic_auth_failure(r);
245         return AUTH_REQUIRED;
246     }
247     return OK;
248 }
249
250 /* Checking ID */
251
252 static int dbm_check_auth(request_rec *r)
253 {
254     dbm_auth_config_rec *sec =
255     (dbm_auth_config_rec *) ap_get_module_config(r->per_dir_config,
256                                               &auth_dbm_module);
257     char *user = r->user;
258     int m = r->method_number;
259
260     const ap_array_header_t *reqs_arr = ap_requires(r);
261     require_line *reqs = reqs_arr ? (require_line *) reqs_arr->elts : NULL;
262
263     register int x;
264     const char *t;
265     char *w;
266
267     if (!sec->auth_dbmgrpfile)
268         return DECLINED;
269     if (!reqs_arr)
270         return DECLINED;
271
272     for (x = 0; x < reqs_arr->nelts; x++) {
273
274         if (!(reqs[x].method_mask & (1 << m)))
275             continue;
276
277         t = reqs[x].requirement;
278         w = ap_getword_white(r->pool, &t);
279
280         if (!strcmp(w, "group") && sec->auth_dbmgrpfile) {
281             const char *orig_groups, *groups;
282             char *v;
283
284             if (!(groups = get_dbm_grp(r, user, sec->auth_dbmgrpfile))) {
285                 if (!(sec->auth_dbmauthoritative))
286                     return DECLINED;
287                 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
288                             "user %s not in DBM group file %s: %s",
289                             user, sec->auth_dbmgrpfile, r->filename);
290                 ap_note_basic_auth_failure(r);
291                 return AUTH_REQUIRED;
292             }
293             orig_groups = groups;
294             while (t[0]) {
295                 w = ap_getword_white(r->pool, &t);
296                 groups = orig_groups;
297                 while (groups[0]) {
298                     v = ap_getword(r->pool, &groups, ',');
299                     if (!strcmp(v, w))
300                         return OK;
301                 }
302             }
303             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
304                         "user %s not in right group: %s",
305                         user, r->filename);
306             ap_note_basic_auth_failure(r);
307             return AUTH_REQUIRED;
308         }
309     }
310
311     return DECLINED;
312 }
313
314 static void register_hooks(void)
315 {
316     ap_hook_check_user_id(dbm_authenticate_basic_user, NULL, NULL, AP_HOOK_MIDDLE);
317     ap_hook_auth_checker(dbm_check_auth, NULL, NULL, AP_HOOK_MIDDLE);
318 }
319
320 module auth_dbm_module =
321 {
322     STANDARD20_MODULE_STUFF,
323     create_dbm_auth_dir_config, /* dir config creater */
324     NULL,                       /* dir merger --- default is to override */
325     NULL,                       /* server config */
326     NULL,                       /* merge server config */
327     dbm_auth_cmds,              /* command ap_table_t */
328     NULL,                       /* handlers */
329     register_hooks              /* register hooks */
330 };