]> granicus.if.org Git - apache-authnz-external/blob - mod_authz_unixgroup/mod_authz_unixgroup.c
Adding copyright info
[apache-authnz-external] / mod_authz_unixgroup / mod_authz_unixgroup.c
1 /* Copyright 2008 Jan Wolter - See LICENSE and NOTICE */
2
3 #include "apr_lib.h"
4
5 #include "ap_config.h"
6 #include "ap_provider.h"
7 #include "mod_auth.h"
8
9 #define APR_WANT_STRFUNC
10 #include "apr_want.h"
11 #include "apr_strings.h"
12
13 #include "httpd.h"
14 #include "http_config.h"
15 #include "http_core.h"
16 #include "http_log.h"
17 #include "http_protocol.h"
18 #include "http_request.h"       /* for ap_hook_(check_user_id | auth_checker)*/
19 #if HAVE_PWD_H
20 #include <pwd.h>
21 #endif
22 #if HAVE_GRP_H
23 #include <grp.h>
24 #endif
25 #if APR_HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 /*
30  * Structure for the module itself.  The actual definition of this structure
31  * is at the end of the file.
32  */
33 module AP_MODULE_DECLARE_DATA authz_unixgroup_module;
34
35 /*
36  *  Data type for per-directory configuration
37  */
38
39 typedef struct
40 {
41     int  enabled;
42     int  authoritative;
43
44 } authz_unixgroup_dir_config_rec;
45
46
47 /*
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.
51  */
52
53 static void *create_authz_unixgroup_dir_config(apr_pool_t *p, char *d)
54 {
55     authz_unixgroup_dir_config_rec *dir= (authz_unixgroup_dir_config_rec *)
56         apr_palloc(p, sizeof(authz_unixgroup_dir_config_rec));
57
58     dir->enabled= 0;
59     dir->authoritative= 1;      /* strong by default */
60
61     return dir;
62 }
63
64
65 /*
66  * Config file commands that this module can handle
67  */
68
69 static const command_rec authz_unixgroup_cmds[] =
70 {
71     AP_INIT_FLAG("AuthzUnixgroup",
72         ap_set_flag_slot,
73         (void *)APR_OFFSETOF(authz_unixgroup_dir_config_rec, enabled),
74         OR_AUTHCFG,
75         "Set to 'on' to enable unix group checking"),
76
77     AP_INIT_FLAG("AuthzUnixgroupAuthoritative",
78         ap_set_flag_slot,
79         (void *)APR_OFFSETOF(authz_unixgroup_dir_config_rec, authoritative),
80         OR_AUTHCFG,
81         "Set to 'off' to allow access control to be passed along to lower "
82             "modules if this module can't confirm access rights" ),
83
84     { NULL }
85 };
86
87
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.
92  */
93
94 static int check_unix_group(request_rec *r, const char *grouplist)
95 {
96     char **p;
97     struct group *grp;
98     char *user= r->user;
99     char *w, *at;
100
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.
105      */
106     if ((at= strchr(user, '@')) != NULL) *at= '\0';
107
108     /* Get info about login */
109     struct passwd *pwd= getpwnam(user);
110     if (pwd == NULL)
111     {
112         /* No such user - forget it */
113         if (at != NULL) *at= '@';
114         return 0;
115     }
116
117     /* Loop through list of groups passed in */
118     while (*grouplist != '\0')
119     {
120         w= ap_getword_white(r->pool, &grouplist);
121         if (apr_isdigit(w[0]))
122         {
123             /* Numeric group id */
124             int gid= atoi(w);
125
126             /* Check if it matches the user's primary group */
127             if (gid == pwd->pw_gid)
128             {
129                 if (at != NULL) *at= '@';
130                 return 1;
131             }
132
133             /* Get list of group members for numeric group id */
134             grp= getgrgid(gid);
135         }
136         else
137         {
138             /* Get gid and list of group members for group name */
139             grp= getgrnam(w);
140             /* Check if gid of this group matches user's primary gid */
141             if (grp != NULL && grp->gr_gid == pwd->pw_gid)
142             {
143                 if (at != NULL) *at= '@';
144                 return 1;
145             }
146         }
147
148         /* Walk through list of members, seeing if any match user login */
149         if (grp != NULL)
150             for (p= grp->gr_mem; *p != NULL; p++)
151             {
152                 if (!strcmp(user, *p))
153                 {
154                     if (at != NULL) *at= '@';
155                     return 1;
156                 }
157             }
158     }
159
160     /* Didn't find any matches, flunk him */
161     if (at != NULL) *at= '@';
162     return 0;
163 }
164
165
166 static int authz_unixgroup_check_user_access(request_rec *r) 
167 {
168     authz_unixgroup_dir_config_rec *dir= (authz_unixgroup_dir_config_rec *)
169         ap_get_module_config(r->per_dir_config, &authz_unixgroup_module);
170
171     int m= r->method_number;
172     int required_group= 0;
173     register int x;
174     const char *t, *w;
175     const apr_array_header_t *reqs_arr= ap_requires(r);
176     const char *filegroup= NULL;
177     require_line *reqs;
178
179     /* If not enabled, pass */
180     if ( !dir->enabled ) return DECLINED;
181
182     /* If there are no Require arguments, pass */
183     if (!reqs_arr) return DECLINED;
184     reqs=  (require_line *)reqs_arr->elts;
185
186     /* Loop through the "Require" argument list */
187     for(x= 0; x < reqs_arr->nelts; x++)
188     {
189         if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) continue;
190
191         t= reqs[x].requirement;
192         w= ap_getword_white(r->pool, &t);
193
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.
199          */
200         if ( !strcasecmp(w, "file-group"))
201         {
202             filegroup= apr_table_get(r->notes, AUTHZ_GROUP_NOTE);
203             if (filegroup == NULL) continue;
204         }
205
206         if ( !strcmp(w,"group") || filegroup != NULL)
207         {
208             required_group= 1;
209
210             if (filegroup)
211             {
212                 /* Check if user is in the group that owns the file */
213                 if (check_unix_group(r,filegroup))
214                     return OK;
215             }
216             else if (t[0])
217             {
218                 /* Pass rest of require line to authenticator */
219                 if (check_unix_group(r,t))
220                     return OK;
221             }
222         }
223     }
224     
225     /* If we didn't see a 'require group' or aren't authoritive, decline */
226     if (!required_group || !dir->authoritative)
227         return DECLINED;
228
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",
232         r->uri, r->user);
233
234     ap_note_basic_auth_failure(r);
235     return HTTP_UNAUTHORIZED;
236 }
237
238 static void authz_unixgroup_register_hooks(apr_pool_t *p)
239 {
240     ap_hook_auth_checker(authz_unixgroup_check_user_access, NULL, NULL,
241             APR_HOOK_MIDDLE);
242 }
243     
244
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 */
253 };