upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / modules / aaa / mod_auth_dbm.c
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  * dirkx - Added Authoritative control to allow passing on to lower  
25  *         modules if and only if the userid is not known to this
26  *         module. A known user with a faulty or absent password still
27  *         causes an AuthRequired. The default is 'Authoritative', i.e.
28  *         no control is passed along.
29  */
30
31 #define APR_WANT_STRFUNC
32 #include "apr_want.h"
33 #include "apr_strings.h"
34 #include "apr_dbm.h"
35 #include "apr_md5.h"            /* for apr_password_validate */
36
37 #include "httpd.h"
38 #include "http_config.h"
39 #include "http_core.h"
40 #include "http_log.h"
41 #include "http_protocol.h"
42 #include "http_request.h"   /* for ap_hook_(check_user_id | auth_checker)*/
43
44
45 typedef struct {
46     char *auth_dbmpwfile;
47     char *auth_dbmgrpfile;
48     char *auth_dbmtype;
49     int auth_dbmauthoritative;
50 } dbm_auth_config_rec;
51
52 static void *create_dbm_auth_dir_config(apr_pool_t *p, char *d)
53 {
54     dbm_auth_config_rec *conf = apr_palloc(p, sizeof(*conf));
55
56     conf->auth_dbmpwfile = NULL;
57     conf->auth_dbmgrpfile = NULL;
58     conf->auth_dbmtype = "default";
59     conf->auth_dbmauthoritative = 1;  /* fortress is secure by default */
60
61     return conf;
62 }
63
64 static const char *set_dbm_slot(cmd_parms *cmd, void *offset,
65                                 const char *f, const char *t)
66 {
67     if (!t || strcmp(t, "dbm"))
68         return DECLINE_CMD;
69
70     return ap_set_file_slot(cmd, offset, f);
71 }
72
73 static const char *set_dbm_type(cmd_parms *cmd, 
74                                 void *dir_config, 
75                                 const char *arg)
76 {
77     dbm_auth_config_rec *conf = dir_config;
78    
79     conf->auth_dbmtype = apr_pstrdup(cmd->pool, arg);
80     return NULL;
81 }
82
83 static const command_rec dbm_auth_cmds[] =
84 {
85     AP_INIT_TAKE1("AuthDBMUserFile", ap_set_file_slot,
86      (void *)APR_OFFSETOF(dbm_auth_config_rec, auth_dbmpwfile),
87      OR_AUTHCFG, "dbm database file containing user IDs and passwords"),
88     AP_INIT_TAKE1("AuthDBMGroupFile", ap_set_file_slot,
89      (void *)APR_OFFSETOF(dbm_auth_config_rec, auth_dbmgrpfile),
90      OR_AUTHCFG, "dbm database file containing group names and member user IDs"),
91     AP_INIT_TAKE12("AuthUserFile", set_dbm_slot,
92      (void *)APR_OFFSETOF(dbm_auth_config_rec, auth_dbmpwfile),
93      OR_AUTHCFG, NULL),
94     AP_INIT_TAKE12("AuthGroupFile", set_dbm_slot,
95      (void *)APR_OFFSETOF(dbm_auth_config_rec, auth_dbmgrpfile),
96      OR_AUTHCFG, NULL),
97     AP_INIT_TAKE1("AuthDBMType", set_dbm_type,
98      NULL,
99      OR_AUTHCFG, "what type of DBM file the user file is"),
100     AP_INIT_FLAG("AuthDBMAuthoritative", ap_set_flag_slot,
101      (void *)APR_OFFSETOF(dbm_auth_config_rec, auth_dbmauthoritative),
102      OR_AUTHCFG, "Set to 'no' to allow access control to be passed along to lower modules, if the UserID is not known in this module"),
103     {NULL}
104 };
105
106 module AP_MODULE_DECLARE_DATA auth_dbm_module;
107
108 static char *get_dbm_pw(request_rec *r, 
109                         char *user, 
110                         char *auth_dbmpwfile, 
111                         char *dbtype)
112 {
113     apr_dbm_t *f;
114     apr_datum_t d, q;
115     char *pw = NULL;
116     apr_status_t retval;
117     q.dptr = user;
118 #ifndef NETSCAPE_DBM_COMPAT
119     q.dsize = strlen(q.dptr);
120 #else
121     q.dsize = strlen(q.dptr) + 1;
122 #endif
123
124     retval = apr_dbm_open_ex(&f, dbtype, auth_dbmpwfile, APR_DBM_READONLY, 
125                              APR_OS_DEFAULT, r->pool);
126     if (retval != APR_SUCCESS) {
127         ap_log_rerror(APLOG_MARK, APLOG_ERR, retval, r,
128                       "could not open dbm (type %s) auth file: %s", dbtype, 
129                       auth_dbmpwfile);
130         return NULL;
131     }
132     if (apr_dbm_fetch(f, q, &d) == APR_SUCCESS && d.dptr) {
133         pw = apr_palloc(r->pool, d.dsize + 1);
134         strncpy(pw, d.dptr, d.dsize);
135         pw[d.dsize] = '\0'; /* Terminate the string */
136     }
137
138     apr_dbm_close(f);
139     return pw;
140 }
141
142 /* We do something strange with the group file.  If the group file
143  * contains any : we assume the format is
144  *      key=username value=":"groupname [":"anything here is ignored]
145  * otherwise we now (0.8.14+) assume that the format is
146  *      key=username value=groupname
147  * The first allows the password and group files to be the same 
148  * physical DBM file;   key=username value=password":"groupname[":"anything]
149  *
150  * mark@telescope.org, 22Sep95
151  */
152
153 static char *get_dbm_grp(request_rec *r, char *user, char *auth_dbmgrpfile, 
154                          char *dbtype)
155 {
156     char *grp_data = get_dbm_pw(r, user, auth_dbmgrpfile,dbtype);
157     char *grp_colon;
158     char *grp_colon2;
159
160     if (grp_data == NULL)
161         return NULL;
162
163     if ((grp_colon = strchr(grp_data, ':')) != NULL) {
164         grp_colon2 = strchr(++grp_colon, ':');
165         if (grp_colon2)
166             *grp_colon2 = '\0';
167         return grp_colon;
168     }
169     return grp_data;
170 }
171
172 static int dbm_authenticate_basic_user(request_rec *r)
173 {
174     dbm_auth_config_rec *conf = ap_get_module_config(r->per_dir_config,
175                                                      &auth_dbm_module);
176     const char *sent_pw;
177     char *real_pw, *colon_pw;
178     apr_status_t invalid_pw;
179     int res;
180
181     if ((res = ap_get_basic_auth_pw(r, &sent_pw)))
182         return res;
183
184     if (!conf->auth_dbmpwfile)
185         return DECLINED;
186
187     if (!(real_pw = get_dbm_pw(r, r->user, conf->auth_dbmpwfile,
188                                conf->auth_dbmtype))) {
189         if (!(conf->auth_dbmauthoritative))
190             return DECLINED;
191         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
192                       "DBM user %s not found: %s", r->user, r->filename);
193         ap_note_basic_auth_failure(r);
194         return HTTP_UNAUTHORIZED;
195     }
196     /* Password is up to first : if exists */
197     colon_pw = strchr(real_pw, ':');
198     if (colon_pw) {
199         *colon_pw = '\0';
200     }
201     invalid_pw = apr_password_validate(sent_pw, real_pw);
202     if (invalid_pw != APR_SUCCESS) {
203         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
204                       "DBM user %s: authentication failure for \"%s\": "
205                       "Password Mismatch",
206                       r->user, r->uri);
207         ap_note_basic_auth_failure(r);
208         return HTTP_UNAUTHORIZED;
209     }
210     return OK;
211 }
212
213 /* Checking ID */
214
215 static int dbm_check_auth(request_rec *r)
216 {
217     dbm_auth_config_rec *conf = ap_get_module_config(r->per_dir_config,
218                                                      &auth_dbm_module);
219     char *user = r->user;
220     int m = r->method_number;
221
222     const apr_array_header_t *reqs_arr = ap_requires(r);
223     require_line *reqs = reqs_arr ? (require_line *) reqs_arr->elts : NULL;
224
225     register int x;
226     const char *t;
227     char *w;
228
229     if (!conf->auth_dbmgrpfile)
230         return DECLINED;
231     if (!reqs_arr)
232         return DECLINED;
233
234     for (x = 0; x < reqs_arr->nelts; x++) {
235
236         if (!(reqs[x].method_mask & (AP_METHOD_BIT << m)))
237             continue;
238
239         t = reqs[x].requirement;
240         w = ap_getword_white(r->pool, &t);
241
242         if (!strcmp(w, "group") && conf->auth_dbmgrpfile) {
243             const char *orig_groups, *groups;
244             char *v;
245
246             if (!(groups = get_dbm_grp(r, user, conf->auth_dbmgrpfile,
247                                        conf->auth_dbmtype))) {
248                 if (!(conf->auth_dbmauthoritative))
249                     return DECLINED;
250                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
251                             "user %s not in DBM group file %s: %s",
252                             user, conf->auth_dbmgrpfile, r->filename);
253                 ap_note_basic_auth_failure(r);
254                 return HTTP_UNAUTHORIZED;
255             }
256             orig_groups = groups;
257             while (t[0]) {
258                 w = ap_getword_white(r->pool, &t);
259                 groups = orig_groups;
260                 while (groups[0]) {
261                     v = ap_getword(r->pool, &groups, ',');
262                     if (!strcmp(v, w))
263                         return OK;
264                 }
265             }
266             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
267                           "user %s not in right group: %s",
268                           user, r->filename);
269             ap_note_basic_auth_failure(r);
270             return HTTP_UNAUTHORIZED;
271         }
272     }
273
274     return DECLINED;
275 }
276
277 static void register_hooks(apr_pool_t *p)
278 {
279     ap_hook_check_user_id(dbm_authenticate_basic_user, NULL, NULL,
280                           APR_HOOK_MIDDLE);
281     ap_hook_auth_checker(dbm_check_auth, NULL, NULL, APR_HOOK_MIDDLE);
282 }
283
284 module AP_MODULE_DECLARE_DATA auth_dbm_module =
285 {
286     STANDARD20_MODULE_STUFF,
287     create_dbm_auth_dir_config, /* dir config creater */
288     NULL,                       /* dir merger --- default is to override */
289     NULL,                       /* server config */
290     NULL,                       /* merge server config */
291     dbm_auth_cmds,              /* command apr_table_t */
292     register_hooks              /* register hooks */
293 };