1 /* Copyright 2008 Jan Wolter - See LICENSE and NOTICE */
6 #include "ap_provider.h"
9 #define APR_WANT_STRFUNC
11 #include "apr_strings.h"
14 #include "http_config.h"
15 #include "http_core.h"
17 #include "http_protocol.h"
18 #include "http_request.h" /* for ap_hook_(check_user_id | auth_checker)*/
30 * Structure for the module itself. The actual definition of this structure
31 * is at the end of the file.
33 module AP_MODULE_DECLARE_DATA authz_unixgroup_module;
36 * Data type for per-directory configuration
44 } authz_unixgroup_dir_config_rec;
48 * Creator for per-dir configurations. This is called via the hook in the
49 * module declaration to allocate and initialize the per-directory
50 * configuration data structures declared above.
53 static void *create_authz_unixgroup_dir_config(apr_pool_t *p, char *d)
55 authz_unixgroup_dir_config_rec *dir= (authz_unixgroup_dir_config_rec *)
56 apr_palloc(p, sizeof(authz_unixgroup_dir_config_rec));
59 dir->authoritative= 1; /* strong by default */
66 * Config file commands that this module can handle
69 static const command_rec authz_unixgroup_cmds[] =
71 AP_INIT_FLAG("AuthzUnixgroup",
73 (void *)APR_OFFSETOF(authz_unixgroup_dir_config_rec, enabled),
75 "Set to 'on' to enable unix group checking"),
77 AP_INIT_FLAG("AuthzUnixgroupAuthoritative",
79 (void *)APR_OFFSETOF(authz_unixgroup_dir_config_rec, authoritative),
81 "Set to 'off' to allow access control to be passed along to lower "
82 "modules if this module can't confirm access rights" ),
88 /* Check if the named user is in the given list of groups. The list of
89 * groups is a string with groups separated by white space. Group ids
90 * can either be unix group names or numeric group id numbers. There must
91 * be a unix login corresponding to the named user.
94 static int check_unix_group(request_rec *r, const char *grouplist)
101 /* Strip @ sign and anything following it from the username. Some
102 * authentication modules, like mod_auth_kerb like appending such
103 * stuff to user names, but an @ sign is never legal in a unix login
104 * name, so it should be safe to always discard such stuff.
106 if ((at= strchr(user, '@')) != NULL) *at= '\0';
108 /* Get info about login */
109 struct passwd *pwd= getpwnam(user);
112 /* No such user - forget it */
113 if (at != NULL) *at= '@';
117 /* Loop through list of groups passed in */
118 while (*grouplist != '\0')
120 w= ap_getword_white(r->pool, &grouplist);
121 if (apr_isdigit(w[0]))
123 /* Numeric group id */
126 /* Check if it matches the user's primary group */
127 if (gid == pwd->pw_gid)
129 if (at != NULL) *at= '@';
133 /* Get list of group members for numeric group id */
138 /* Get gid and list of group members for group name */
140 /* Check if gid of this group matches user's primary gid */
141 if (grp != NULL && grp->gr_gid == pwd->pw_gid)
143 if (at != NULL) *at= '@';
148 /* Walk through list of members, seeing if any match user login */
150 for (p= grp->gr_mem; *p != NULL; p++)
152 if (!strcmp(user, *p))
154 if (at != NULL) *at= '@';
160 /* Didn't find any matches, flunk him */
161 if (at != NULL) *at= '@';
166 static int authz_unixgroup_check_user_access(request_rec *r)
168 authz_unixgroup_dir_config_rec *dir= (authz_unixgroup_dir_config_rec *)
169 ap_get_module_config(r->per_dir_config, &authz_unixgroup_module);
171 int m= r->method_number;
172 int required_group= 0;
175 const apr_array_header_t *reqs_arr= ap_requires(r);
176 const char *filegroup= NULL;
179 /* If not enabled, pass */
180 if ( !dir->enabled ) return DECLINED;
182 /* If there are no Require arguments, pass */
183 if (!reqs_arr) return DECLINED;
184 reqs= (require_line *)reqs_arr->elts;
186 /* Loop through the "Require" argument list */
187 for(x= 0; x < reqs_arr->nelts; x++)
189 if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) continue;
191 t= reqs[x].requirement;
192 w= ap_getword_white(r->pool, &t);
194 /* The 'file-group' directive causes mod_authz_owner to store the
195 * group name of the file we are trying to access in a note attached
196 * to the request. It's our job to decide if the user actually is
197 * in that group. If the note is missing, we just ignore it.
198 * Probably mod_authz_owner is not installed.
200 if ( !strcasecmp(w, "file-group"))
202 filegroup= apr_table_get(r->notes, AUTHZ_GROUP_NOTE);
203 if (filegroup == NULL) continue;
206 if ( !strcmp(w,"group") || filegroup != NULL)
212 /* Check if user is in the group that owns the file */
213 if (check_unix_group(r,filegroup))
218 /* Pass rest of require line to authenticator */
219 if (check_unix_group(r,t))
225 /* If we didn't see a 'require group' or aren't authoritive, decline */
226 if (!required_group || !dir->authoritative)
229 /* Authentication failed and we are authoritive, declare unauthorized */
230 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
231 "access to %s failed, reason: user %s not allowed access",
234 ap_note_basic_auth_failure(r);
235 return HTTP_UNAUTHORIZED;
238 static void authz_unixgroup_register_hooks(apr_pool_t *p)
240 ap_hook_auth_checker(authz_unixgroup_check_user_access, NULL, NULL,
245 module AP_MODULE_DECLARE_DATA authz_unixgroup_module = {
246 STANDARD20_MODULE_STUFF,
247 create_authz_unixgroup_dir_config, /* create per-dir config */
248 NULL, /* merge per-dir config */
249 NULL, /* create per-server config */
250 NULL, /* merge per-server config */
251 authz_unixgroup_cmds, /* command apr_table_t */
252 authz_unixgroup_register_hooks /* register hooks */