]> granicus.if.org Git - apache/blob - modules/aaa/mod_authz_groupfile.c
Upon further review, it seems silly to add z the here when we didn't add
[apache] / modules / aaa / mod_authz_groupfile.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
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
17  *    distribution.
18  *
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.
25  *
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.
30  *
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.
34  *
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
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
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/>.
53  *
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.
57  */
58
59 /* This module is triggered by an
60  *
61  *          AuthzGroupFile standard /path/to/file
62  *
63  * and the presense of a
64  *
65  *         require group <list-of-groups>
66  * 
67  * In an applicable limit/directory block for that method.
68  *
69  * If there are no AuthzGroupFile directives valid for 
70  * the request; we DECLINED.
71  * 
72  * If the AuthzGroupFile is defined; but somehow not
73  * accessible: we SERVER_ERROR (was DECLINED).
74  *
75  * If there are no 'require ' directives defined for
76  * this request then we DECLINED (was OK).
77  * 
78  * If there are no 'require ' directives valid for
79  * this request method then we DECLINED. (was OK)
80  *
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  
84  * case we DECLINED.
85  *
86  */
87
88 #include "apr_strings.h"
89 #include "apr_md5.h"            /* for apr_password_validate */
90
91 #include "ap_config.h"
92 #include "httpd.h"
93 #include "http_config.h"
94 #include "http_core.h"
95 #include "http_log.h"
96 #include "http_protocol.h"
97 #include "http_request.h"
98
99 typedef struct {
100     char *groupfile;
101     int authoritative;
102 } authz_groupfile_config_rec;
103
104 static void *create_authz_groupfile_dir_config(apr_pool_t *p, char *d)
105 {
106     authz_groupfile_config_rec *conf = apr_palloc(p, sizeof(*conf));
107
108     conf->groupfile = NULL;    
109     conf->authoritative = 1; /* keep the fortress secure by default */
110     return conf;
111 }
112
113 static const char *set_authz_groupfile_slot(cmd_parms *cmd, void *offset, const char *f, 
114                                  const char *t)
115 {
116     if (t && strcmp(t, "standard")) {
117         return apr_pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL);
118     }
119
120     return ap_set_file_slot(cmd, offset, f);
121 }
122
123 static const command_rec authz_groupfile_cmds[] =
124 {
125     AP_INIT_TAKE12("AuthGroupFile", set_authz_groupfile_slot,
126                    (void *)APR_OFFSETOF(authz_groupfile_config_rec, groupfile),
127                    OR_AUTHCFG,
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,
131                                       authoritative),
132                  OR_AUTHCFG,
133                  "Set to 'no' to allow access control to be passed along to "
134                  "lower modules if the 'require group' fails. (default is "
135                  "no)."),
136     {NULL}
137 };
138
139 module AP_MODULE_DECLARE_DATA authz_groupfile_module;
140
141 static apr_status_t groups_for_user(apr_pool_t *p, char *user, char *grpfile,
142                                     apr_table_t ** out)
143 {
144     ap_configfile_t *f;
145     apr_table_t *grps = apr_table_make(p, 15);
146     apr_pool_t *sp;
147     char l[MAX_STRING_LEN];
148     const char *group_name, *ll, *w;
149     apr_status_t status;
150
151     if ((status = ap_pcfg_openfile(&f, p, grpfile)) != APR_SUCCESS) {
152         return status ;
153     }
154
155     apr_pool_create(&sp, p);
156
157     while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
158         if ((l[0] == '#') || (!l[0])) {
159             continue;
160         }
161         ll = l;
162         apr_pool_clear(sp);
163
164         group_name = ap_getword(sp, &ll, ':');
165
166         while (ll[0]) {
167             w = ap_getword_conf(sp, &ll);
168             if (!strcmp(w, user)) {
169                 apr_table_setn(grps, apr_pstrdup(p, group_name), "in");
170                 break;
171             }
172         }
173     }
174     ap_cfg_closefile(f);
175     apr_pool_destroy(sp);
176
177     *out = grps;
178     return APR_SUCCESS;
179 }
180
181 /* Checking ID */
182
183 static int check_user_access(request_rec *r)
184 {
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;
191     const char *t, *w;
192     apr_table_t *grpstatus;
193     const apr_array_header_t *reqs_arr = ap_requires(r);
194     require_line *reqs;
195     apr_status_t status;
196
197     if (!reqs_arr) {
198         return DECLINED; /* XXX change from legacy */
199     } 
200     
201     reqs = (require_line *)reqs_arr->elts;
202
203     /* If there is no group file - then we are not
204      * configured. So decline. 
205      */
206     if (!(conf->groupfile))
207          return DECLINED; 
208
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;
214     };
215
216     has_entries = apr_table_elts(grpstatus)->nelts;
217
218     for (x = 0; x < reqs_arr->nelts; x++) {
219
220         if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) {
221             continue;
222         }
223         method_restricted |= 1;
224
225         t = reqs[x].requirement;
226         w = ap_getword_white(r->pool, &t);
227
228         if (!strcmp(w, "group")) {
229             method_restricted |= 2;
230              if (has_entries) {
231             while (t[0]) {
232                 w = ap_getword_conf(r->pool, &t);
233                 if (apr_table_get(grpstatus, w)) {
234                     return OK;
235                 }
236             }
237          }
238         }
239     }
240
241     /* No applicable requires for this method seen at all */
242     if (method_restricted == 0) {
243         return DECLINED; /* XXX change from legacy */
244     }
245
246     /* No applicable "requires group" for this method seen */
247     if ((method_restricted & 2) == 0) {
248         return DECLINED;
249     }
250
251     if (!(conf->authoritative)) {
252         return DECLINED;
253     }
254
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);
258         
259     ap_note_basic_auth_failure(r);
260     return HTTP_UNAUTHORIZED;
261 }
262
263 static void register_hooks(apr_pool_t *p)
264 {
265     ap_hook_auth_checker(check_user_access,NULL,NULL,APR_HOOK_MIDDLE);
266 }
267
268 module AP_MODULE_DECLARE_DATA authz_groupfile_module =
269 {
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 */
277 };