--- httpd-2.2.17/server/mpm/experimental/itk/itk.c 2011-03-05 18:12:47.000000000 +0100 +++ httpd-2.2.17.mpm-itk-perdir-regex/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 /* 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; }