File: mod_authz_unixgroup.c

package info (click to toggle)
libapache2-mod-authz-unixgroup 1.1.0-0.1
  • links: PTS
  • area: main
  • in suites: buster, jessie, jessie-kfreebsd, sid, stretch
  • size: 80 kB
  • ctags: 9
  • sloc: ansic: 130; makefile: 37
file content (196 lines) | stat: -rw-r--r-- 5,427 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* Copyright 2008 Jan Wolter - See LICENSE and NOTICE */

#include "apr_lib.h"

#include "ap_config.h"
#include "ap_provider.h"
#include "mod_auth.h"

#define APR_WANT_STRFUNC
#include "apr_want.h"
#include "apr_strings.h"

#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"	/* for ap_hook_(check_user_id | auth_checker)*/
#if HAVE_PWD_H
#include <pwd.h>
#endif
#if HAVE_GRP_H
#include <grp.h>
#endif
#if APR_HAVE_UNISTD_H
#include <unistd.h>
#endif

/*
 * Structure for the module itself.  The actual definition of this structure
 * is at the end of the file.
 */
module AP_MODULE_DECLARE_DATA authz_unixgroup_module;

/* A handle for retrieving the requested file's group from mod_authnz_owner */
APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r));


/* Check if the named user is in the given list of groups.  The list of
 * groups is a string with groups separated by white space.  Group ids
 * can either be unix group names or numeric group id numbers.  There must
 * be a unix login corresponding to the named user.
 */

static int check_unix_group(request_rec *r, const char *grouplist)
{
    char **p;
    struct group *grp;
    char *user= r->user;
    char *w, *at;

    /* Strip @ sign and anything following it from the username.  Some
     * authentication modules, like mod_auth_kerb like appending such
     * stuff to user names, but an @ sign is never legal in a unix login
     * name, so it should be safe to always discard such stuff.
     */
    if ((at= strchr(user, '@')) != NULL) *at= '\0';

    /* Get info about login */
    struct passwd *pwd= getpwnam(user);
    if (pwd == NULL)
    {
	/* No such user - forget it */
	if (at != NULL) *at= '@';
    	return 0;
    }

    /* Loop through list of groups passed in */
    while (*grouplist != '\0')
    {
	w= ap_getword_conf(r->pool, &grouplist);
	if (apr_isdigit(w[0]))
	{
	    /* Numeric group id */
	    int gid= atoi(w);

	    /* Check if it matches the user's primary group */
	    if (gid == pwd->pw_gid)
	    {
		if (at != NULL) *at= '@';
		return 1;
	    }

	    /* Get list of group members for numeric group id */
	    grp= getgrgid(gid);
	}
	else
	{
	    /* Get gid and list of group members for group name */
	    grp= getgrnam(w);
	    /* Check if gid of this group matches user's primary gid */
	    if (grp != NULL && grp->gr_gid == pwd->pw_gid)
	    {
		if (at != NULL) *at= '@';
		return 1;
	    }
	}

	/* Walk through list of members, seeing if any match user login */
	if (grp != NULL)
	    for (p= grp->gr_mem; *p != NULL; p++)
	    {
		if (!strcmp(user, *p))
		{
		    if (at != NULL) *at= '@';
		    return 1;
		}
	    }
    }

    /* Didn't find any matches, flunk him */
    if (at != NULL) *at= '@';
    return 0;
}

static authz_status unixgroup_check_authorization(request_rec *r,
        const char *require_args, const void *parsed_require_args)
{
    /* If no authenticated user, pass */
    if ( !r->user ) return AUTHZ_DENIED_NO_USER;

    if (check_unix_group(r,require_args))
	return AUTHZ_GRANTED;

    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
        "Authorization of user %s to access %s failed. "
        "User not in Required unix groups (%s).",
        r->user, r->uri, require_args);

    return AUTHZ_DENIED;
}

APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group;

static authz_status unixfilegroup_check_authorization(request_rec *r,
        const char *require_args, const void *parsed_require_args)
{
    const char *filegroup= NULL;

    /* If no authenticated user, pass */
    if ( !r->user ) return AUTHZ_DENIED_NO_USER;

    /* Get group name for requested file from mod_authz_owner */
    filegroup= authz_owner_get_file_group(r);

    if (!filegroup)
        /* No errog log entry, because mod_authz_owner already made one */
        return AUTHZ_DENIED;

    if (check_unix_group(r,filegroup))
	return AUTHZ_GRANTED;
    
    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
        "Authorization of user %s to access %s failed. "
        "User not in Required unix file group (%s).",
        r->user, r->uri, filegroup);

    return AUTHZ_DENIED;
}

static const authz_provider authz_unixgroup_provider =
{
    &unixgroup_check_authorization,
    NULL,
};

static const authz_provider authz_unixfilegroup_provider =
{
    &unixfilegroup_check_authorization,
    NULL,
};

static void authz_unixgroup_register_hooks(apr_pool_t *p)
{
    /* Get a handle on mod_authz_owner */
    authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group);

    /* Register authz providers */
    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "unix-group",
            AUTHZ_PROVIDER_VERSION,
            &authz_unixgroup_provider, AP_AUTH_INTERNAL_PER_CONF);

    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "unix-file-group",
            AUTHZ_PROVIDER_VERSION,
            &authz_unixfilegroup_provider, AP_AUTH_INTERNAL_PER_CONF);
}
    
module AP_MODULE_DECLARE_DATA authz_unixgroup_module = {
    STANDARD20_MODULE_STUFF,
    NULL,				  /* create per-dir config */
    NULL,			          /* merge per-dir config */
    NULL,			          /* create per-server config */
    NULL,			          /* merge per-server config */
    NULL,		         	  /* command apr_table_t */
    authz_unixgroup_register_hooks        /* register hooks */
};