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