]> granicus.if.org Git - apache-authnz-external/commitdiff
initial import
authorjan@unixpapa.com <jan@unixpapa.com@8c465660-3f02-11de-a81c-fde7d73ceb89>
Fri, 15 May 2009 13:38:56 +0000 (13:38 +0000)
committerjan@unixpapa.com <jan@unixpapa.com@8c465660-3f02-11de-a81c-fde7d73ceb89>
Fri, 15 May 2009 13:38:56 +0000 (13:38 +0000)
mod_authz_unixgroup/CHANGES [new file with mode: 0644]
mod_authz_unixgroup/INSTALL [new file with mode: 0644]
mod_authz_unixgroup/README [new file with mode: 0644]
mod_authz_unixgroup/mod_authz_unixgroup.c [new file with mode: 0644]

diff --git a/mod_authz_unixgroup/CHANGES b/mod_authz_unixgroup/CHANGES
new file mode 100644 (file)
index 0000000..98e6c70
--- /dev/null
@@ -0,0 +1,19 @@
+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
diff --git a/mod_authz_unixgroup/INSTALL b/mod_authz_unixgroup/INSTALL
new file mode 100644 (file)
index 0000000..97fbd09
--- /dev/null
@@ -0,0 +1,145 @@
+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
diff --git a/mod_authz_unixgroup/README b/mod_authz_unixgroup/README
new file mode 100644 (file)
index 0000000..5666e12
--- /dev/null
@@ -0,0 +1,61 @@
+                       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.
diff --git a/mod_authz_unixgroup/mod_authz_unixgroup.c b/mod_authz_unixgroup/mod_authz_unixgroup.c
new file mode 100644 (file)
index 0000000..765d25c
--- /dev/null
@@ -0,0 +1,251 @@
+#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 */
+};