]> granicus.if.org Git - apache/blob - modules/aaa/mod_authz_dbm.c
Cleanup effort in prep for GA push:
[apache] / modules / aaa / mod_authz_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 #define APR_WANT_STRFUNC
18 #include "apr_want.h"
19 #include "apr_strings.h"
20 #include "apr_dbm.h"
21 #include "apr_md5.h"
22
23 #include "httpd.h"
24 #include "http_config.h"
25 #include "ap_provider.h"
26 #include "http_core.h"
27 #include "http_log.h"
28 #include "http_protocol.h"
29 #include "http_request.h"   /* for ap_hook_(check_user_id | auth_checker)*/
30
31 #include "mod_auth.h"
32
33 typedef struct {
34     const char *grpfile;
35     const char *dbmtype;
36 } authz_dbm_config_rec;
37
38 APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r));
39
40
41 /* This should go into APR; perhaps with some nice
42  * caching/locking/flocking of the open dbm file.
43  */
44 static char *get_dbm_entry_as_str(apr_pool_t *pool, apr_dbm_t *f, char *key)
45 {
46     apr_datum_t d, q;
47     q.dptr = key;
48
49 #ifndef NETSCAPE_DBM_COMPAT
50     q.dsize = strlen(q.dptr);
51 #else
52     q.dsize = strlen(q.dptr) + 1;
53 #endif
54
55     if (apr_dbm_fetch(f, q, &d) == APR_SUCCESS && d.dptr) {
56         return apr_pstrmemdup(pool, d.dptr, d.dsize);
57     }
58
59     return NULL;
60 }
61
62 static void *create_authz_dbm_dir_config(apr_pool_t *p, char *d)
63 {
64     authz_dbm_config_rec *conf = apr_palloc(p, sizeof(*conf));
65
66     conf->grpfile = NULL;
67     conf->dbmtype = "default";
68
69     return conf;
70 }
71
72 static const command_rec authz_dbm_cmds[] =
73 {
74     AP_INIT_TAKE1("AuthDBMGroupFile", ap_set_file_slot,
75      (void *)APR_OFFSETOF(authz_dbm_config_rec, grpfile),
76      OR_AUTHCFG, "database file containing group names and member user IDs"),
77     AP_INIT_TAKE1("AuthzDBMType", ap_set_string_slot,
78      (void *)APR_OFFSETOF(authz_dbm_config_rec, dbmtype),
79      OR_AUTHCFG, "what type of DBM file the group file is"),
80     {NULL}
81 };
82
83 module AP_MODULE_DECLARE_DATA authz_dbm_module;
84
85 /* We do something strange with the group file.  If the group file
86  * contains any : we assume the format is
87  *      key=username value=":"groupname [":"anything here is ignored]
88  * otherwise we now (0.8.14+) assume that the format is
89  *      key=username value=groupname
90  * The first allows the password and group files to be the same
91  * physical DBM file;   key=username value=password":"groupname[":"anything]
92  *
93  * mark@telescope.org, 22Sep95
94  */
95
96 static apr_status_t get_dbm_grp(request_rec *r, char *key1, char *key2,
97                                 const char *dbmgrpfile, const char *dbtype,
98                                 const char ** out)
99 {
100     char *grp_colon, *val;
101     apr_status_t retval;
102     apr_dbm_t *f;
103
104     retval = apr_dbm_open_ex(&f, dbtype, dbmgrpfile, APR_DBM_READONLY,
105                              APR_OS_DEFAULT, r->pool);
106
107     if (retval != APR_SUCCESS) {
108         return retval;
109     }
110
111     /* Try key2 only if key1 failed */
112     if (!(val = get_dbm_entry_as_str(r->pool, f, key1))) {
113         val = get_dbm_entry_as_str(r->pool, f, key2);
114     }
115
116     apr_dbm_close(f);
117
118     if (val && (grp_colon = ap_strchr(val, ':')) != NULL) {
119         char *grp_colon2 = ap_strchr(++grp_colon, ':');
120
121         if (grp_colon2) {
122             *grp_colon2 = '\0';
123         }
124         *out = grp_colon;
125     }
126     else {
127         *out = val;
128     }
129
130     return retval;
131 }
132
133 static authz_status dbmgroup_check_authorization(request_rec *r,
134                                                  const char *require_args,
135                                                  const void *parsed_require_args)
136 {
137     authz_dbm_config_rec *conf = ap_get_module_config(r->per_dir_config,
138                                                       &authz_dbm_module);
139     char *user = r->user;
140     const char *t;
141     char *w;
142     const char *orig_groups = NULL;
143     const char *realm = ap_auth_name(r);
144     const char *groups;
145     char *v;
146
147     if (!user) {
148         return AUTHZ_DENIED_NO_USER;
149     }
150
151     if (!conf->grpfile) {
152         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
153                         "No group file was specified in the configuration");
154         return AUTHZ_DENIED;
155     }
156
157     /* fetch group data from dbm file only once. */
158     if (!orig_groups) {
159         apr_status_t status;
160
161         status = get_dbm_grp(r, apr_pstrcat(r->pool, user, ":", realm, NULL),
162                              user, conf->grpfile, conf->dbmtype, &groups);
163
164         if (status != APR_SUCCESS) {
165             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
166                           "could not open dbm (type %s) group access "
167                           "file: %s", conf->dbmtype, conf->grpfile);
168             return AUTHZ_GENERAL_ERROR;
169         }
170
171         if (groups == NULL) {
172             /* no groups available, so exit immediately */
173             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
174                           "Authorization of user %s to access %s failed, reason: "
175                           "user doesn't appear in DBM group file (%s).",
176                           r->user, r->uri, conf->grpfile);
177             return AUTHZ_DENIED;
178         }
179
180         orig_groups = groups;
181     }
182
183     t = require_args;
184     while ((w = ap_getword_white(r->pool, &t)) && w[0]) {
185         groups = orig_groups;
186         while (groups[0]) {
187             v = ap_getword(r->pool, &groups, ',');
188             if (!strcmp(v, w)) {
189                 return AUTHZ_GRANTED;
190             }
191         }
192     }
193
194     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
195                   "Authorization of user %s to access %s failed, reason: "
196                   "user is not part of the 'require'ed group(s).",
197                   r->user, r->uri);
198
199     return AUTHZ_DENIED;
200 }
201
202 APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group;
203
204 static authz_status dbmfilegroup_check_authorization(request_rec *r,
205                                                      const char *require_args,
206                                                      const void *parsed_require_args)
207 {
208     authz_dbm_config_rec *conf = ap_get_module_config(r->per_dir_config,
209                                                       &authz_dbm_module);
210     char *user = r->user;
211     const char *realm = ap_auth_name(r);
212     const char *filegroup = NULL;
213     const char *orig_groups = NULL;
214     apr_status_t status;
215     const char *groups;
216     char *v;
217
218     if (!user) {
219         return AUTHZ_DENIED_NO_USER;
220     }
221
222     if (!conf->grpfile) {
223         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
224                         "No group file was specified in the configuration");
225         return AUTHZ_DENIED;
226     }
227
228     /* fetch group data from dbm file. */
229     status = get_dbm_grp(r, apr_pstrcat(r->pool, user, ":", realm, NULL),
230                          user, conf->grpfile, conf->dbmtype, &groups);
231
232     if (status != APR_SUCCESS) {
233         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
234                       "could not open dbm (type %s) group access "
235                       "file: %s", conf->dbmtype, conf->grpfile);
236         return AUTHZ_DENIED;
237     }
238
239     if (groups == NULL) {
240         /* no groups available, so exit immediately */
241         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
242                       "Authorization of user %s to access %s failed, reason: "
243                       "user doesn't appear in DBM group file (%s).",
244                       r->user, r->uri, conf->grpfile);
245         return AUTHZ_DENIED;
246     }
247
248     orig_groups = groups;
249
250     filegroup = authz_owner_get_file_group(r);
251
252     if (filegroup) {
253         groups = orig_groups;
254         while (groups[0]) {
255             v = ap_getword(r->pool, &groups, ',');
256             if (!strcmp(v, filegroup)) {
257                 return AUTHZ_GRANTED;
258             }
259         }
260     }
261
262     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
263                   "Authorization of user %s to access %s failed, reason: "
264                   "user is not part of the 'require'ed group(s).",
265                   r->user, r->uri);
266
267     return AUTHZ_DENIED;
268 }
269
270 static const authz_provider authz_dbmgroup_provider =
271 {
272     &dbmgroup_check_authorization,
273     NULL,
274 };
275
276 static const authz_provider authz_dbmfilegroup_provider =
277 {
278     &dbmfilegroup_check_authorization,
279     NULL,
280 };
281
282
283 static void register_hooks(apr_pool_t *p)
284 {
285     authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group);
286
287     ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbm-group",
288                               AUTHZ_PROVIDER_VERSION,
289                               &authz_dbmgroup_provider,
290                               AP_AUTH_INTERNAL_PER_CONF);
291     ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbm-file-group",
292                               AUTHZ_PROVIDER_VERSION,
293                               &authz_dbmfilegroup_provider,
294                               AP_AUTH_INTERNAL_PER_CONF);
295 }
296
297 AP_DECLARE_MODULE(authz_dbm) =
298 {
299     STANDARD20_MODULE_STUFF,
300     create_authz_dbm_dir_config, /* dir config creater */
301     NULL,                        /* dir merger --- default is to override */
302     NULL,                        /* server config */
303     NULL,                        /* merge server config */
304     authz_dbm_cmds,              /* command apr_table_t */
305     register_hooks               /* register hooks */
306 };