]> granicus.if.org Git - apache/blob - modules/aaa/mod_authz_groupfile.c
Added many log numbers to log statements that
[apache] / modules / aaa / mod_authz_groupfile.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 /* This module is triggered by an
18  *
19  *          AuthGroupFile standard /path/to/file
20  *
21  * and the presense of a
22  *
23  *         require group <list-of-groups>
24  *
25  * In an applicable limit/directory block for that method.
26  *
27  * If there are no AuthGroupFile directives valid for
28  * the request; we DECLINED.
29  *
30  * If the AuthGroupFile is defined; but somehow not
31  * accessible: we SERVER_ERROR (was DECLINED).
32  *
33  * If there are no 'require ' directives defined for
34  * this request then we DECLINED (was OK).
35  *
36  * If there are no 'require ' directives valid for
37  * this request method then we DECLINED. (was OK)
38  *
39  * If there are any 'require group' blocks and we
40  * are not in any group - we HTTP_UNAUTHORIZE
41  *
42  */
43
44 #include "apr_strings.h"
45 #include "apr_lib.h" /* apr_isspace */
46
47 #include "ap_config.h"
48 #include "ap_provider.h"
49 #include "httpd.h"
50 #include "http_config.h"
51 #include "http_core.h"
52 #include "http_log.h"
53 #include "http_protocol.h"
54 #include "http_request.h"
55 #include "util_varbuf.h"
56
57 #include "mod_auth.h"
58 #include "mod_authz_owner.h"
59
60 typedef struct {
61     char *groupfile;
62 } authz_groupfile_config_rec;
63
64 static void *create_authz_groupfile_dir_config(apr_pool_t *p, char *d)
65 {
66     authz_groupfile_config_rec *conf = apr_palloc(p, sizeof(*conf));
67
68     conf->groupfile = NULL;
69     return conf;
70 }
71
72 static const command_rec authz_groupfile_cmds[] =
73 {
74     AP_INIT_TAKE1("AuthGroupFile", ap_set_file_slot,
75                   (void *)APR_OFFSETOF(authz_groupfile_config_rec, groupfile),
76                   OR_AUTHCFG,
77                   "text file containing group names and member user IDs"),
78     {NULL}
79 };
80
81 module AP_MODULE_DECLARE_DATA authz_groupfile_module;
82
83 #define VARBUF_INIT_LEN 512
84 #define VARBUF_MAX_LEN  (16*1024*1024)
85 static apr_status_t groups_for_user(apr_pool_t *p, char *user, char *grpfile,
86                                     apr_table_t ** out)
87 {
88     ap_configfile_t *f;
89     apr_table_t *grps = apr_table_make(p, 15);
90     apr_pool_t *sp;
91     struct ap_varbuf vb;
92     const char *group_name, *ll, *w;
93     apr_status_t status;
94     apr_size_t group_len;
95
96     if ((status = ap_pcfg_openfile(&f, p, grpfile)) != APR_SUCCESS) {
97         return status ;
98     }
99
100     apr_pool_create(&sp, p);
101     ap_varbuf_init(p, &vb, VARBUF_INIT_LEN);
102
103     while (!(ap_varbuf_cfg_getline(&vb, f, VARBUF_MAX_LEN))) {
104         if ((vb.buf[0] == '#') || (!vb.buf[0])) {
105             continue;
106         }
107         ll = vb.buf;
108         apr_pool_clear(sp);
109
110         group_name = ap_getword(sp, &ll, ':');
111         group_len = strlen(group_name);
112
113         while (group_len && apr_isspace(*(group_name + group_len - 1))) {
114             --group_len;
115         }
116
117         while (ll[0]) {
118             w = ap_getword_conf(sp, &ll);
119             if (!strcmp(w, user)) {
120                 apr_table_setn(grps, apr_pstrmemdup(p, group_name, group_len),
121                                "in");
122                 break;
123             }
124         }
125     }
126     ap_cfg_closefile(f);
127     apr_pool_destroy(sp);
128     ap_varbuf_free(&vb);
129
130     *out = grps;
131     return APR_SUCCESS;
132 }
133
134 static authz_status group_check_authorization(request_rec *r,
135                                               const char *require_args,
136                                               const void *parsed_require_args)
137 {
138     authz_groupfile_config_rec *conf = ap_get_module_config(r->per_dir_config,
139             &authz_groupfile_module);
140     char *user = r->user;
141
142     const char *err = NULL;
143     const ap_expr_info_t *expr = parsed_require_args;
144     const char *require;
145
146     const char *t, *w;
147     apr_table_t *grpstatus = NULL;
148     apr_status_t status;
149
150     if (!user) {
151         return AUTHZ_DENIED_NO_USER;
152     }
153
154     /* If there is no group file - then we are not
155      * configured. So decline.
156      */
157     if (!(conf->groupfile)) {
158         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01664)
159                         "No group file was specified in the configuration");
160         return AUTHZ_DENIED;
161     }
162
163     status = groups_for_user(r->pool, user, conf->groupfile,
164                                 &grpstatus);
165
166     if (status != APR_SUCCESS) {
167         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01665)
168                         "Could not open group file: %s",
169                         conf->groupfile);
170         return AUTHZ_DENIED;
171     }
172
173     if (apr_is_empty_table(grpstatus)) {
174         /* no groups available, so exit immediately */
175         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01666)
176                       "Authorization of user %s to access %s failed, reason: "
177                       "user doesn't appear in group file (%s).",
178                       r->user, r->uri, conf->groupfile);
179         return AUTHZ_DENIED;
180     }
181
182     require = ap_expr_str_exec(r, expr, &err);
183     if (err) {
184         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02592)
185                       "authz_groupfile authorize: require group: Can't "
186                       "evaluate require expression: %s", err);
187         return AUTHZ_DENIED;
188     }
189
190     t = require;
191     while ((w = ap_getword_conf(r->pool, &t)) && w[0]) {
192         if (apr_table_get(grpstatus, w)) {
193             return AUTHZ_GRANTED;
194         }
195     }
196
197     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01667)
198                     "Authorization of user %s to access %s failed, reason: "
199                     "user is not part of the 'require'ed group(s).",
200                     r->user, r->uri);
201
202     return AUTHZ_DENIED;
203 }
204
205 static APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group;
206
207 static authz_status filegroup_check_authorization(request_rec *r,
208                                                   const char *require_args,
209                                                   const void *parsed_require_args)
210 {
211     authz_groupfile_config_rec *conf = ap_get_module_config(r->per_dir_config,
212             &authz_groupfile_module);
213     char *user = r->user;
214     apr_table_t *grpstatus = NULL;
215     apr_status_t status;
216     const char *filegroup = NULL;
217
218     if (!user) {
219         return AUTHZ_DENIED_NO_USER;
220     }
221
222     /* If there is no group file - then we are not
223      * configured. So decline.
224      */
225     if (!(conf->groupfile)) {
226         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01668)
227                         "No group file was specified in the configuration");
228         return AUTHZ_DENIED;
229     }
230
231     status = groups_for_user(r->pool, user, conf->groupfile,
232                              &grpstatus);
233     if (status != APR_SUCCESS) {
234         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01669)
235                       "Could not open group file: %s",
236                       conf->groupfile);
237         return AUTHZ_DENIED;
238     }
239
240     if (apr_is_empty_table(grpstatus)) {
241         /* no groups available, so exit immediately */
242         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01670)
243                         "Authorization of user %s to access %s failed, reason: "
244                         "user doesn't appear in group file (%s).",
245                         r->user, r->uri, conf->groupfile);
246         return AUTHZ_DENIED;
247     }
248
249     filegroup = authz_owner_get_file_group(r);
250
251     if (filegroup) {
252         if (apr_table_get(grpstatus, filegroup)) {
253             return AUTHZ_GRANTED;
254         }
255     }
256     else {
257         /* No need to emit a error log entry because the call
258         to authz_owner_get_file_group already did it
259         for us.
260         */
261         return AUTHZ_DENIED;
262     }
263
264     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01671)
265                   "Authorization of user %s to access %s failed, reason: "
266                   "user is not part of the 'require'ed file group.",
267                   r->user, r->uri);
268
269     return AUTHZ_DENIED;
270 }
271
272 static const char *groupfile_parse_config(cmd_parms *cmd, const char *require_line,
273                                           const void **parsed_require_line)
274 {
275     const char *expr_err = NULL;
276     ap_expr_info_t *expr;
277
278     expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT,
279             &expr_err, NULL);
280
281     if (expr_err)
282         return apr_pstrcat(cmd->temp_pool,
283                            "Cannot parse expression in require line: ",
284                            expr_err, NULL);
285
286     *parsed_require_line = expr;
287
288     return NULL;
289 }
290
291 static const authz_provider authz_group_provider =
292 {
293     &group_check_authorization,
294     &groupfile_parse_config,
295 };
296
297 static const authz_provider authz_filegroup_provider =
298 {
299     &filegroup_check_authorization,
300     NULL,
301 };
302
303
304 static void authz_groupfile_getfns(void)
305 {
306     authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group);
307 }
308
309 static void register_hooks(apr_pool_t *p)
310 {
311     ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "group",
312                               AUTHZ_PROVIDER_VERSION,
313                               &authz_group_provider,
314                               AP_AUTH_INTERNAL_PER_CONF);
315     ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "file-group",
316                               AUTHZ_PROVIDER_VERSION,
317                               &authz_filegroup_provider,
318                               AP_AUTH_INTERNAL_PER_CONF);
319     ap_hook_optional_fn_retrieve(authz_groupfile_getfns, NULL, NULL, APR_HOOK_MIDDLE);
320 }
321
322 AP_DECLARE_MODULE(authz_groupfile) =
323 {
324     STANDARD20_MODULE_STUFF,
325     create_authz_groupfile_dir_config,/* dir config creater */
326     NULL,                             /* dir merger -- default is to override */
327     NULL,                             /* server config */
328     NULL,                             /* merge server config */
329     authz_groupfile_cmds,             /* command apr_table_t */
330     register_hooks                    /* register hooks */
331 };