1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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
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.
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.
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.
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
47 * ====================================================================
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/>.
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.
59 /* This module is triggered by an
61 * AuthzGroupFile standard /path/to/file
63 * and the presense of a
65 * require group <list-of-groups>
67 * In an applicable limit/directory block for that method.
69 * If there are no AuthzGroupFile directives valid for
70 * the request; we DECLINED.
72 * If the AuthzGroupFile is defined; but somehow not
73 * accessible: we SERVER_ERROR (was DECLINED).
75 * If there are no 'require ' directives defined for
76 * this request then we DECLINED (was OK).
78 * If there are no 'require ' directives valid for
79 * this request method then we DECLINED. (was OK)
81 * If there are any 'require group' blocks and we
82 * are not in any group - we HTTP_UNAUTHORIZE
83 * unless we are non-authoritative; in which
88 #include "apr_strings.h"
89 #include "apr_md5.h" /* for apr_password_validate */
91 #include "ap_config.h"
93 #include "http_config.h"
94 #include "http_core.h"
96 #include "http_protocol.h"
97 #include "http_request.h"
102 } authz_groupfile_config_rec;
104 static void *create_authz_groupfile_dir_config(apr_pool_t *p, char *d)
106 authz_groupfile_config_rec *conf = apr_palloc(p, sizeof(*conf));
108 conf->groupfile = NULL;
109 conf->authoritative = 1; /* keep the fortress secure by default */
113 static const char *set_authz_groupfile_slot(cmd_parms *cmd, void *offset, const char *f,
116 if (t && strcmp(t, "standard")) {
117 return apr_pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL);
120 return ap_set_file_slot(cmd, offset, f);
123 static const command_rec authz_groupfile_cmds[] =
125 AP_INIT_TAKE12("AuthGroupFile", set_authz_groupfile_slot,
126 (void *)APR_OFFSETOF(authz_groupfile_config_rec, groupfile),
128 "text file containing group names and member user IDs"),
129 AP_INIT_FLAG("AuthzGroupFileAuthoritative", ap_set_flag_slot,
130 (void *)APR_OFFSETOF(authz_groupfile_config_rec,
133 "Set to 'no' to allow access control to be passed along to "
134 "lower modules if the 'require group' fails. (default is "
139 module AP_MODULE_DECLARE_DATA authz_groupfile_module;
141 static apr_status_t groups_for_user(apr_pool_t *p, char *user, char *grpfile,
145 apr_table_t *grps = apr_table_make(p, 15);
147 char l[MAX_STRING_LEN];
148 const char *group_name, *ll, *w;
151 if ((status = ap_pcfg_openfile(&f, p, grpfile)) != APR_SUCCESS) {
155 apr_pool_create(&sp, p);
157 while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
158 if ((l[0] == '#') || (!l[0])) {
164 group_name = ap_getword(sp, &ll, ':');
167 w = ap_getword_conf(sp, &ll);
168 if (!strcmp(w, user)) {
169 apr_table_setn(grps, apr_pstrdup(p, group_name), "in");
175 apr_pool_destroy(sp);
183 static int check_user_access(request_rec *r)
185 authz_groupfile_config_rec *conf = ap_get_module_config(r->per_dir_config,
186 &authz_groupfile_module);
187 char *user = r->user;
188 int m = r->method_number;
189 int method_restricted = 0;
190 register int x,has_entries;
192 apr_table_t *grpstatus;
193 const apr_array_header_t *reqs_arr = ap_requires(r);
198 return DECLINED; /* XXX change from legacy */
201 reqs = (require_line *)reqs_arr->elts;
203 /* If there is no group file - then we are not
204 * configured. So decline.
206 if (!(conf->groupfile))
209 if ((status = groups_for_user(r->pool, user, conf->groupfile,
210 &grpstatus)) != APR_SUCCESS) {
211 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
212 "Could not open group file: %s", conf->groupfile);
213 return HTTP_INTERNAL_SERVER_ERROR;
216 has_entries = apr_table_elts(grpstatus)->nelts;
218 for (x = 0; x < reqs_arr->nelts; x++) {
220 if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) {
223 method_restricted |= 1;
225 t = reqs[x].requirement;
226 w = ap_getword_white(r->pool, &t);
228 if (!strcmp(w, "group")) {
229 method_restricted |= 2;
232 w = ap_getword_conf(r->pool, &t);
233 if (apr_table_get(grpstatus, w)) {
241 /* No applicable requires for this method seen at all */
242 if (method_restricted == 0) {
243 return DECLINED; /* XXX change from legacy */
246 /* No applicable "requires group" for this method seen */
247 if ((method_restricted & 2) == 0) {
251 if (!(conf->authoritative)) {
255 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
256 "access to %s failed, reason: user %s not part of the "
257 "'require'ed group(s).", r->uri, user);
259 ap_note_basic_auth_failure(r);
260 return HTTP_UNAUTHORIZED;
263 static void register_hooks(apr_pool_t *p)
265 ap_hook_auth_checker(check_user_access,NULL,NULL,APR_HOOK_MIDDLE);
268 module AP_MODULE_DECLARE_DATA authz_groupfile_module =
270 STANDARD20_MODULE_STUFF,
271 create_authz_groupfile_dir_config,/* dir config creater */
272 NULL, /* dir merger -- default is to override */
273 NULL, /* server config */
274 NULL, /* merge server config */
275 authz_groupfile_cmds, /* command apr_table_t */
276 register_hooks /* register hooks */