]> granicus.if.org Git - apache/commitdiff
as announced and with no objections:
authorAndre Malo <nd@apache.org>
Wed, 15 Jan 2003 22:08:54 +0000 (22:08 +0000)
committerAndre Malo <nd@apache.org>
Wed, 15 Jan 2003 22:08:54 +0000 (22:08 +0000)
mod_authz_owner: forward port of require file-owner/file-group functionality

The goal of the module is to do all the neccessary file system work to
figure out username and groupname. "Require file-owner" is completely
resolved within the module. "file-group" is only determined there and the
groupname will be extracted from the stat call and stored within the
r->notes. Done that, the module will decline, so that the group database
modules (mod_authz_groupfile, mod_authz_dbm) can verify the groupname with
their lists.
Thus every group module that supports the file-group requirement must be
hooked after mod_authz_owner. They have to recognize "file-group" and read
the groupname from r->notes. (If there's no name stored, the modules should
ignore the file-group requirement). The backstopper module will do its work
in worst case.

not solved yet:
- the module doesn't work as one could expect if the file doesn't exist in
  the first request round (consider MultiViews) (the 1.3 version has the
  same problem). I played around with some subrequest techniques, but got
  no helpful result. Is there any magic to recognize the actual resulting
  filename (if there is)?

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@98281 13f79535-47bb-0310-9956-ffa450edef68

modules/aaa/config.m4
modules/aaa/mod_auth.h
modules/aaa/mod_authz_owner.c [new file with mode: 0644]

index 1d6d4632efc40250bea8921a2fe804628bd66fc6..cc9e3e7808e03615efefebd576d1a8439d94eb07 100644 (file)
@@ -26,6 +26,7 @@ APACHE_MODULE(authz_host, host-based authorization control, , , yes)
 APACHE_MODULE(authz_groupfile, 'require group' authorization control, , , yes)
 APACHE_MODULE(authz_user, 'require user' authorization control, , , yes)
 APACHE_MODULE(authz_dbm, DBM-based authorization control, , , most)
+APACHE_MODULE(authz_owner, 'require file-owner' authorization control, , , most)
 
 dnl - and just in case all of the above punt; a default handler to
 dnl keep the bad guys out.
index bf334601b09699eae7139690841d02d3cfd51dd7..2e0bfd08e1a4b606dbd90f89d42c3825b0f6c84c 100644 (file)
@@ -67,6 +67,8 @@ extern "C" {
 
 #define AUTHN_PROVIDER_GROUP "authn"
 #define AUTHN_DEFAULT_PROVIDER "file"
+    
+#define AUTHZ_GROUP_NOTE "authz_group_note"
 
 typedef enum {
     AUTH_DENIED,
diff --git a/modules/aaa/mod_authz_owner.c b/modules/aaa/mod_authz_owner.c
new file mode 100644 (file)
index 0000000..f679b9a
--- /dev/null
@@ -0,0 +1,295 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+/*
+ * http_auth: authentication
+ * 
+ * Rob McCool
+ * 
+ * Adapted to Apache by rst.
+ *
+ * dirkx - Added Authoritative control to allow passing on to lower
+ *         modules if and only if the userid is not known to this
+ *         module. A known user with a faulty or absent password still
+ *         causes an AuthRequired. The default is 'Authoritative', i.e.
+ *         no control is passed along.
+ */
+
+#include "apr_strings.h"
+#include "apr_file_info.h"
+#include "apr_user.h"
+
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_request.h"
+
+#include "mod_auth.h"     /* for AUTHZ_GROUP_NOTE */
+
+typedef struct {
+    int authoritative;
+} authz_owner_config_rec;
+
+static void *create_authz_owner_dir_config(apr_pool_t *p, char *d)
+{
+    authz_owner_config_rec *conf = apr_palloc(p, sizeof(*conf));
+
+    conf->authoritative = 1; /* keep the fortress secure by default */
+    return conf;
+}
+
+static const command_rec authz_owner_cmds[] =
+{
+    AP_INIT_FLAG("AuthzOwnerAuthoritative", ap_set_flag_slot,
+                 (void *)APR_OFFSETOF(authz_owner_config_rec, authoritative),
+                 OR_AUTHCFG,
+                 "Set to 'Off' to allow access control to be passed along to "
+                 "lower modules. (default is On.)"),
+    {NULL}
+};
+
+module AP_MODULE_DECLARE_DATA authz_owner_module;
+
+static int check_file_owner(request_rec *r)
+{
+    authz_owner_config_rec *conf = ap_get_module_config(r->per_dir_config,
+                                                        &authz_owner_module);
+    int m = r->method_number;
+    register int x;
+    const char *t, *w;
+    const apr_array_header_t *reqs_arr = ap_requires(r);
+    require_line *reqs;
+    int required_owner = 0;
+    apr_status_t status = 0;
+    char *reason = NULL;
+
+    if (!reqs_arr) {
+        return DECLINED;
+    }
+
+    reqs = (require_line *)reqs_arr->elts;
+    for (x = 0; x < reqs_arr->nelts; x++) {
+
+        /* if authoritative = On then break if a require already failed. */
+        if (reason && conf->authoritative) {
+            break;
+        }
+
+        if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) {
+            continue;
+        }
+
+        t = reqs[x].requirement;
+        w = ap_getword_white(r->pool, &t);
+
+        if (!strcmp(w, "file-owner")) {
+#if !APR_HAS_USER
+            if ((required_owner & ~1) && conf->authoritative) {
+                break;
+            }
+
+            required_owner |= 1; /* remember the requirement */
+            reason = "'Require file-owner' is not supported on this platform.";
+            continue;
+#else  /* APR_HAS_USER */
+            char *owner = NULL;
+            apr_finfo_t finfo;
+
+            if ((required_owner & ~1) && conf->authoritative) {
+                break;
+            }
+
+            required_owner |= 1; /* remember the requirement */
+
+            if (!r->filename) {
+                reason = "no filename available";
+                continue;
+            }
+
+            status = apr_stat(&finfo, r->filename, APR_FINFO_USER, r->pool);
+            if (status != APR_SUCCESS) {
+                reason = apr_pstrcat(r->pool, "could not stat file ",
+                                     r->filename, NULL);
+                continue;
+            }
+
+            if (!(finfo.valid & APR_FINFO_USER)) {
+                reason = "no file owner information available";
+                continue;
+            }
+
+            status = apr_uid_name_get(&owner, finfo.user, r->pool);
+            if (status != APR_SUCCESS || !owner) {
+                reason = "could not get name of file owner";
+                continue;
+            }
+
+            if (strcmp(owner, r->user)) {
+                reason = apr_psprintf(r->pool, "file owner %s does not match.",
+                                      owner);
+                continue;
+            }
+
+            /* this user is authorized */
+            return OK;
+#endif /* APR_HAS_USER */
+        }
+
+        /* file-group only figures out the file's group and lets
+         * other modules do the actual authorization (against a group file/db).
+         * Thus, these modules have to hook themselves after
+         * mod_authz_owner and of course recognize 'file-group', too.
+         */
+        if (!strcmp(w, "file-group")) {
+#if !APR_HAS_USER
+            if ((required_owner & ~6) && conf->authoritative) {
+                break;
+            }
+
+            required_owner |= 2; /* remember the requirement */
+            reason = "'Require file-group' is not supported on this platform.";
+            continue;
+#else  /* APR_HAS_USER */
+            char *group = NULL;
+            apr_finfo_t finfo;
+
+            if ((required_owner & ~6) && conf->authoritative) {
+                break;
+            }
+
+            required_owner |= 2; /* remember the requirement */
+
+            if (!r->filename) {
+                reason = "no filename available";
+                continue;
+            }
+
+            status = apr_stat(&finfo, r->filename, APR_FINFO_GROUP, r->pool);
+            if (status != APR_SUCCESS) {
+                reason = apr_pstrcat(r->pool, "could not stat file ",
+                                     r->filename, NULL);
+                continue;
+            }
+
+            if (!(finfo.valid & APR_FINFO_GROUP)) {
+                reason = "no file group information available";
+                continue;
+            }
+
+            status = apr_gid_name_get(&group, finfo.group, r->pool);
+            if (status != APR_SUCCESS || !group) {
+                reason = "could not get name of file group";
+                continue;
+            }
+
+            /* store group name in a note and let others decide... */
+            apr_table_setn(r->notes, AUTHZ_GROUP_NOTE, group);
+            required_owner |= 4;
+            continue;
+#endif /* APR_HAS_USER */
+        }
+    }
+
+    if (!required_owner || !conf->authoritative) {
+        return DECLINED;
+    }
+    
+    /* allow file-group passed to group db modules either if this is the
+     * only applicable requirement here or if a file-owner failed but we're
+     * not authoritative.
+     * This allows configurations like:
+     *
+     * AuthzOwnerAuthoritative Off
+     * require file-owner
+     * require file-group
+     *
+     * with the semantical meaning of "either owner or group must match"
+     * (inclusive or)
+     *
+     * [ 6 == 2 | 4; 7 == 1 | 2 | 4 ] should I use #defines instead?
+     */
+    if (required_owner == 6 || (required_owner == 7 && !conf->authoritative)) {
+        return DECLINED;
+    }
+
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
+                  "Authorization of user %s to access %s failed, reason: %s",
+                  r->user, r->uri, reason ? reason : "unknown");
+
+    ap_note_auth_failure(r);
+    return HTTP_UNAUTHORIZED;
+}
+
+static void register_hooks(apr_pool_t *p)
+{
+    ap_hook_auth_checker(check_file_owner, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA authz_owner_module =
+{
+    STANDARD20_MODULE_STUFF,
+    create_authz_owner_dir_config, /* dir config creater */
+    NULL,                          /* dir merger --- default is to override */
+    NULL,                          /* server config */
+    NULL,                          /* merge server config */
+    authz_owner_cmds,              /* command apr_table_t */
+    register_hooks                 /* register hooks */
+};