head	1.1;
access;
symbols;
locks; strict;
comment	@# @;


1.1
date	2013.03.03.00.29.18;	author svnexp;	state Exp;
branches;
next	;


desc
@@


1.1
log
@## SVN ## Exported commit - http://svnweb.freebsd.org/changeset/base/313287
## SVN ## CVS IS DEPRECATED: http://wiki.freebsd.org/CvsIsDeprecated
@
text
@vim: syntax=diff

This patch is a supplement for the MPM-ITK patchset, adding the per-directory
setting AssignUserFromPath <path-regex> <user-pattern> <group-pattern>

Using a regex for setting the user and/or group name might seem scary, but
it has a number of uses in cases where a hard-coded list of <Directory>
clauses would be implactical:

    For personal home pages, either using mod_userdir or simply
    subdirectories named like the user name
    For vhosts using mod_vhost_alias

This patch is against MPM-ITK version 2.2.11-02. You might have to kneed it
a little if you are using a later version of MPM-ITK.

Please Note: This patch has only been briefly tested. Remember to test it
rigorously before applying it in a production environment!

Examples

    <Directory /home>
        AssignUserFromPath "^/home/([^/]+)" www-data $1-web
    </Directory>

 WWW: http://www.pvv.ntnu.no/~knuta/mpm-itk/

 To apply this additional diff to apache22-mpm-itk use
 make -DWITH_ITK_PERDIR_REGEX

===========================================================================
--- server/mpm/experimental/itk/itk.c	2011-03-05 18:12:47.000000000 +0100
+++ server/mpm/experimental/itk/itk.c	2011-03-06 23:28:49.000000000 +0100
@@@@ -60,6 +60,7 @@@@
 #include "ap_listen.h"
 #include "ap_mmn.h"
 #include "apr_poll.h"
+#include "ap_regex.h"
 
 #ifdef HAVE_BSTRING_H
 #include <bstring.h>            /* for IRIX, FD_SET calls bzero() */
@@@@ -164,6 +165,10 @@@@
     gid_t gid;
     char *username;
     int nice_value;
+    char *user_regex_string;
+    ap_regex_t *user_regex;
+    char *user_pattern;
+    char *group_pattern;
 } itk_per_dir_conf;
 
 typedef struct
@@@@ -1421,6 +1426,7 @@@@
     gid_t wanted_gid;
     const char *wanted_username;
     int err = 0;
+    int retval = OK;
     
     itk_server_conf *sconf =
         (itk_server_conf *) ap_get_module_config(r->server->module_config, &mpm_itk_module);
@@@@ -1458,6 +1464,35 @@@@
     wanted_gid = dconf->gid;
     wanted_username = dconf->username;
 
+    /* Determine uid and gid from regex, if available */
+    if (dconf->user_regex != NULL) {
+        apr_size_t nmatch = 10;
+        ap_regmatch_t pmatch[10];
+        char *user_string;
+        char *group_string;
+        struct passwd *user_struct;
+        struct group *group_struct;
+
+        if (ap_regexec(dconf->user_regex, r->filename, nmatch, pmatch, 0) == 0) {
+            user_string = ap_pregsub(r->pool, dconf->user_pattern, r->filename, nmatch, pmatch);
+            group_string = ap_pregsub(r->pool, dconf->group_pattern, r->filename, nmatch, pmatch);
+
+            if (!(user_struct = getpwnam(user_string))) {
+                _DBG("%s: No such user: '%s' (regex: '%s', pattern: '%s')",
+                     r->filename, user_string, dconf->user_regex_string, dconf->user_pattern);
+                retval = HTTP_INTERNAL_SERVER_ERROR;
+            } else if (!(group_struct = getgrnam(group_string))) {
+                _DBG("%s: No such group: '%s' (regex: '%s', pattern: '%s')", 
+                     r->filename, group_string, dconf->user_regex_string, dconf->group_pattern);
+                retval = HTTP_INTERNAL_SERVER_ERROR;
+            } else {
+                wanted_username = user_string;
+                wanted_uid = user_struct->pw_uid;
+                wanted_gid = group_struct->gr_gid;
+            }
+        }
+    }
+
     if (wanted_uid == -1 || wanted_gid == -1) {
         wanted_uid = unixd_config.user_id;
         wanted_gid = unixd_config.group_id;
@@@@ -1488,7 +1523,7 @@@@
         ap_lingering_close(r->connection);
         exit(0);
     }
-    return OK;
+    return retval;
 }
 
 static void itk_hooks(apr_pool_t *p)
@@@@ -1632,6 +1667,24 @@@@
     return NULL;
 }
 
+static const char *assign_user_id_regex (cmd_parms *cmd, itk_per_dir_conf *dconf, const char *regex, const char *user_string, const char *group_string)
+{
+    ap_regex_t *compiled_regexp;
+
+    compiled_regexp = ap_pregcomp(cmd->pool, regex, AP_REG_EXTENDED);
+    if (!compiled_regexp) {
+        return apr_pstrcat(cmd->pool,
+                           "AssignUserFromPath: cannot compile regular expression '",
+                           regex, "'", NULL);
+    }
+
+    dconf->user_regex_string = apr_pstrdup(cmd->pool, regex);
+    dconf->user_regex = compiled_regexp;
+    dconf->user_pattern = apr_pstrdup(cmd->pool, user_string);
+    dconf->group_pattern = apr_pstrdup(cmd->pool, group_string);
+    return NULL;
+}
+
 static const char *set_max_clients_vhost (cmd_parms *cmd, void *dummy, const char *arg)   
 {
     itk_server_conf *sconf =
@@@@ -1676,6 +1729,8 @@@@
               "Maximum value of MaxClients for this run of Apache"),
 AP_INIT_TAKE2("AssignUserID", assign_user_id, NULL, RSRC_CONF|ACCESS_CONF,
               "Tie a virtual host to a specific child process."),
+AP_INIT_TAKE3("AssignUserFromPath", assign_user_id_regex, NULL, RSRC_CONF|ACCESS_CONF,
+              "Use a regex to determine the user ID from a path in the file system. Use with care!"),
 AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF,
               "Maximum number of children alive at the same time for this virtual host."),
 AP_INIT_TAKE1("NiceValue", set_nice_value, NULL, RSRC_CONF|ACCESS_CONF,
@@@@ -1716,6 +1771,20 @@@@
     } else {
       c->nice_value = parent->nice_value;
     }
+    // The test for username != NULL means that we clear the regex settings if an
+    // explicit username is specified in a subdirectory, which is what I believe
+    // most people would expect.
+    if (child->user_regex_string != NULL || child->username != NULL) {
+      c->user_regex_string = child->user_regex_string;
+      c->user_regex = child->user_regex;
+      c->user_pattern = child->user_pattern;
+      c->group_pattern = child->group_pattern;
+    } else {
+      c->user_regex_string = parent->user_regex_string;
+      c->user_regex = parent->user_regex;
+      c->user_pattern = parent->user_pattern;
+      c->group_pattern = parent->group_pattern;
+    }
     return c;
 }
 
@
