--- /dev/null
+v1.0.1 (Jan Wolter - Aug 6, 2008)
+------------------------------------
+ * Delete various logging statements that were really just there for
+ debugging and should have been removed sooner.
+
+ * If there is an '@' in the user's login name, strip off that and anything
+ after it. An '@' sign is never legal in an unix login name, and some
+ authentication modules, like mod_auth_kerb, append an "@domain" to the
+ user's login name.
+
+ Both of the above modifications are inspired by patches made by Ken Lalonde
+ <ken at globalremit dot com>.
+
+ * Included "http_request.h" header file to surpress a harmless compile-time
+ warning.
+
+v1.0.0 (Jan Wolter - Feb 19, 2006)
+------------------------------------
+ * Original release
--- /dev/null
+How to install mod_authz_unixgroup.c into Apache:
+
+NOTES:
+
+ * There are two ways of installing mod_authz_unixgroup.
+
+ (1) You can statically link it with Apache. This requires rebuilding
+ Apache in such a way that mod_authz_unixgroup will be compiled in.
+
+ (2) You can make mod_authz_unixgroup a dynamically loaded module. If
+ your Apache has been built to support dynamically loaded modules
+ you can do this without rebuilding Apache, so it is pretty easy.
+ Performance may be slightly worse with this option. For information
+ on dynamically loaded modules see http://www.apache.org/docs/dso.html
+
+ Instructions for both options are given here.
+
+ * There is also documentation in the README file. If you find this document
+ unclear, reading that may help.
+
+
+INSTALL METHOD A: Dynamically Linking Mod_authz_unixgroup using apxs:
+---------------------------------------------------------------------
+
+Step 1:
+ Ensure that your Apache server is configured to handle dynamically
+ loaded modules. To check this, run Apache server with the -l command
+ flag, like
+
+ httpd -l
+
+ If mod_so.c is one of the compiled-in modules, then you are ready
+ to go.
+
+Step 2:
+ Compile the module using the following command in the
+ mod_authz_unixgroup distribution directory:
+
+ apxs -c mod_authz_unixgroup.c
+
+ 'Apxs' is the Apache extension tool. It is part of the standard
+ Apache installation. If you don't have it, then your Apache server
+ is probably not set up for handling dynamically loaded modules.
+ This should create a file named 'mod_authz_unixgroup.so'.
+
+Step 3:
+ Install the module. Apxs can do this for you too. Do the following
+ command (as root so you can write to Apache's directories and config
+ files):
+
+ apxs -i -a mod_authz_unixgroup.la
+
+ This will create mod_authz_unixgroup.so and copy it into the proper
+ place, and add appropriate AddModule and LoadModule commands to the
+ configuration files. (Actually, it may get the LoadModule command
+ wrong. See below.)
+
+Step 4:
+ Go to the CONFIGURATION instructions below.
+
+
+INSTALL METHOD B: Statically Linking
+------------------------------------
+
+Step 1:
+ Read the instructions on how to configure the Apache server in the
+ INSTALL file provided with the Apache source.
+
+Step 2:
+ When you run the ./configure script, include an --with-module flag,
+ giving the full pathname to the mod_authz_unixgroup.c file in this
+ distribution. For example, if you have unpacked this distribution
+ in /usr/local/src/mod_authz_unixgroup and are building Apache for
+ installation in /usr/local/apache, you might do:
+
+ ./configure --prefix=/usr/local/apache \
+ --with-module=aaa:/usr/local/src/mod_authz_unixgroup/mod_authz_unixgroup.c
+
+ This will copy the mod_authz_unixgroup.c file into the correct place in
+ the Apache source tree and set things up to link it in.
+
+Step 3:
+ Type "make" to compile Apache and "make install" to install it.
+
+Step 4:
+ Go to the CONFIGURATION instructions below.
+
+
+CONFIGURATION:
+--------------
+
+Mod_authz_unixgroup is pretty simple to use. First, you need to enable it
+for whatever directory you want to use it in, by inserting the following
+directive either in a .htaccess file in the directory or a <Directory> block
+in the httpd.conf file:
+
+ AuthzUnixgroup on
+
+Second, you will need a require directive like
+
+ Require group admin
+or
+ Require group students teachers staff
+
+Obviously this only makes sense in a directory where you are doing
+authentication. This could be any kind of authentication, but it makes
+most sense if you are using it in combination with authentication out of
+the unix password file, perhaps using mod_auth_external together with
+pwauth, or mod_auth_shadow. The "Require group" directive will then
+cause mod_authz_unixgroup to check if the user is in one of the groups
+listed, and reject the authentication if they are not. A user is considered
+to be in a group if either (1) the group is the user's primary group
+identified by it's gid number in /etc/passwd, or (2) the group is listed
+in /etc/group and the user id is listed as a member of that group.
+
+If you are authenticating out of something other than the unix password
+database, then this can be used, but the effect is a bit odd. To pass
+the "Require group" test, there must (1) exist a unix account with the same
+name as the account the user authenticated in, and (2) that unix account must
+be in one of the unix groups listed on the Require line.
+
+It is also possible to list groups by gid number instead of name, like
+
+ Require group 10
+
+would be equivalent to "Require group admin" if the gid listed for the group
+admin in /etc/group is 10.
+
+If mod_authz_owner is enabled in your httpd, then that will work with
+mod_authz_unixgroup to check access based on file groups. For example if
+we do:
+
+ AuthzUnixgroup on
+ Require file-group
+
+Then a user will be able to access a file if and only if that file is owned
+by a group of which the user is a member.
+
+By default, mod_authz_unixgroup is authoritative. If you want to use more
+than one group checker, like mod_authz_unixgroup together with
+mod_authz_groupfile or mod_authz_dbm, then you'll want to make them non-
+authoritative, so that if one fails, the other will be tried. You can
+make mod_authz_unixgroup non-authoritative by saying:
+
+ AuthzUnixgroupAuthoritative off
--- /dev/null
+ Mod_Authz_Unixgroup version 1.0.1
+
+ Author: Jan Wolter
+ Website: http://www.unixpapa.com/mod_authz_unixgroup/
+ Requires: Apache 2.1 or later on a Unix server
+
+Mod_Authz_Unixgroup is a unix group access control modules for Apache 2.1 and
+later. If you are having users authenticate with real Unix login ID over the
+net, using something like my mod_authnz_external/pwauth combination, and you
+want to do access control based on unix group membership, then
+mod_authz_unixgroup is exactly what you need.
+
+Let's say that you were using this with mod_authnz_external and pwauth. Your
+.htaccess file for a protected directory would probably start with the
+following directives:
+
+ AuthType Basic
+ AuthName mysite
+ AuthBasicProvider external
+ AuthExternal pwauth
+
+That would cause mod_auth_basic and mod_authnz_external to do authentication
+based on the Unix passwd database. Mod_Authz_Unixgroup would come into play
+if you wanted to further restrict access to specific Unix groups. You might
+append the following directives:
+
+ AuthzUnixgroup on
+ Require group staff admin
+
+This would allow only access to accounts in the 'staff' or 'admin' unix groups.
+You can alternately specify groups by their gid numbers instead of their names.
+
+Or you could use mod_authz_unixgroup together with the standard apache module
+mod_authz_owner to do something like:
+
+ Require file-group
+
+This would allow access to the page, only the user was a member of the unix
+group that owns the file.
+
+Though it makes the most sense to use this with unix passwd authentication,
+it can be used with other databases. In that case it would grant access if,
+(1) the name the user authenticated with exactly matched the name of a real
+unix account on the server, and (2) that real unix account was in one of the
+required groups. However, I think this would be a pretty senseless way to
+use this module. I expect that it will really only be used by user of
+mod_authnz_external/pwauth.
+
+Some authentication modules, like mod_auth_kerb, use usernames that have
+domains appended to them, like "whomever@krb.ncsu.edu". In such cases,
+mod_authz_unixgroup will take the part before the @-sign as the username
+and ignore the rest.
+
+Mod_authnz_external is available from:
+ http://www.unixpapa.com/mod_auth_external/
+
+Pwauth is available from:
+ http://www.unixpapa.com/pwauth/
+
+It might also be possible to use this with mod_auth_shadow, expecially if a
+authn/authz version of that is ever released.
--- /dev/null
+#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;
+
+/*
+ * Data type for per-directory configuration
+ */
+
+typedef struct
+{
+ int enabled;
+ int authoritative;
+
+} authz_unixgroup_dir_config_rec;
+
+
+/*
+ * Creator for per-dir configurations. This is called via the hook in the
+ * module declaration to allocate and initialize the per-directory
+ * configuration data structures declared above.
+ */
+
+static void *create_authz_unixgroup_dir_config(apr_pool_t *p, char *d)
+{
+ authz_unixgroup_dir_config_rec *dir= (authz_unixgroup_dir_config_rec *)
+ apr_palloc(p, sizeof(authz_unixgroup_dir_config_rec));
+
+ dir->enabled= 0;
+ dir->authoritative= 1; /* strong by default */
+
+ return dir;
+}
+
+
+/*
+ * Config file commands that this module can handle
+ */
+
+static const command_rec authz_unixgroup_cmds[] =
+{
+ AP_INIT_FLAG("AuthzUnixgroup",
+ ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authz_unixgroup_dir_config_rec, enabled),
+ OR_AUTHCFG,
+ "Set to 'on' to enable unix group checking"),
+
+ AP_INIT_FLAG("AuthzUnixgroupAuthoritative",
+ ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authz_unixgroup_dir_config_rec, authoritative),
+ OR_AUTHCFG,
+ "Set to 'off' to allow access control to be passed along to lower "
+ "modules if this module can't confirm access rights" ),
+
+ { NULL }
+};
+
+
+/* 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_white(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 int authz_unixgroup_check_user_access(request_rec *r)
+{
+ authz_unixgroup_dir_config_rec *dir= (authz_unixgroup_dir_config_rec *)
+ ap_get_module_config(r->per_dir_config, &authz_unixgroup_module);
+
+ int m= r->method_number;
+ int required_group= 0;
+ register int x;
+ const char *t, *w;
+ const apr_array_header_t *reqs_arr= ap_requires(r);
+ const char *filegroup= NULL;
+ require_line *reqs;
+
+ /* If not enabled, pass */
+ if ( !dir->enabled ) return DECLINED;
+
+ /* If there are no Require arguments, pass */
+ if (!reqs_arr) return DECLINED;
+ reqs= (require_line *)reqs_arr->elts;
+
+ /* Loop through the "Require" argument list */
+ for(x= 0; x < reqs_arr->nelts; x++)
+ {
+ if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) continue;
+
+ t= reqs[x].requirement;
+ w= ap_getword_white(r->pool, &t);
+
+ /* The 'file-group' directive causes mod_authz_owner to store the
+ * group name of the file we are trying to access in a note attached
+ * to the request. It's our job to decide if the user actually is
+ * in that group. If the note is missing, we just ignore it.
+ * Probably mod_authz_owner is not installed.
+ */
+ if ( !strcasecmp(w, "file-group"))
+ {
+ filegroup= apr_table_get(r->notes, AUTHZ_GROUP_NOTE);
+ if (filegroup == NULL) continue;
+ }
+
+ if ( !strcmp(w,"group") || filegroup != NULL)
+ {
+ required_group= 1;
+
+ if (filegroup)
+ {
+ /* Check if user is in the group that owns the file */
+ if (check_unix_group(r,filegroup))
+ return OK;
+ }
+ else if (t[0])
+ {
+ /* Pass rest of require line to authenticator */
+ if (check_unix_group(r,t))
+ return OK;
+ }
+ }
+ }
+
+ /* If we didn't see a 'require group' or aren't authoritive, decline */
+ if (!required_group || !dir->authoritative)
+ return DECLINED;
+
+ /* Authentication failed and we are authoritive, declare unauthorized */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "access to %s failed, reason: user %s not allowed access",
+ r->uri, r->user);
+
+ ap_note_basic_auth_failure(r);
+ return HTTP_UNAUTHORIZED;
+}
+
+static void authz_unixgroup_register_hooks(apr_pool_t *p)
+{
+ ap_hook_auth_checker(authz_unixgroup_check_user_access, NULL, NULL,
+ APR_HOOK_MIDDLE);
+}
+
+
+module AP_MODULE_DECLARE_DATA authz_unixgroup_module = {
+ STANDARD20_MODULE_STUFF,
+ create_authz_unixgroup_dir_config, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ NULL, /* create per-server config */
+ NULL, /* merge per-server config */
+ authz_unixgroup_cmds, /* command apr_table_t */
+ authz_unixgroup_register_hooks /* register hooks */
+};