Use Apache 2.4's new generic expression parser to support setting uid/gid dynamically, possibly based on the URL or other request-specific factors. Here is a simple example with help from mod_rewrite: RewriteEngine on RewriteRule /~([a-z]+)/ - [E=ITKUID:$1] AssignUserIDExpr %{reqenv:ITKUID} Index: httpd-2.4.2/server/mpm/itk/itk.c =================================================================== --- httpd-2.4.2.orig/server/mpm/itk/itk.c +++ httpd-2.4.2/server/mpm/itk/itk.c @@ -41,6 +41,8 @@ #if APR_HAVE_SYS_TYPES_H #include #endif +#include +#include #include "ap_config.h" #include "httpd.h" @@ -59,6 +61,7 @@ #include "ap_listen.h" #include "ap_mmn.h" #include "apr_poll.h" +#include "ap_expr.h" #include "seccomp.h" @@ -181,6 +184,8 @@ typedef struct gid_t gid; char *username; int nice_value; + ap_expr_info_t *uid_expr; + ap_expr_info_t *gid_expr; } itk_per_dir_conf; typedef struct @@ -1608,6 +1613,48 @@ static int itk_post_perdir_config(reques wanted_username = ap_unixd_config.user_name; } + /* AssignUserIDExpr and AssignGroupIDExpr override AssignUserID and defaults. */ + if (dconf->uid_expr != NULL) { + struct passwd *ent; + const char *err; + wanted_username = ap_expr_str_exec(r, dconf->uid_expr, &err); + if (err) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ + "Error while parsing AssignUserIDExpr expression: %s", + err); + return HTTP_INTERNAL_SERVER_ERROR; + } + + if (!(ent = getpwnam(wanted_username))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ + "AssignUserIDExpr returned '%s', which is not a valid user name", + wanted_username); + return HTTP_INTERNAL_SERVER_ERROR; + } + + wanted_uid = ent->pw_uid; + } + if (dconf->gid_expr != NULL) { + struct group *ent; + const char *err; + const char *wanted_groupname = ap_expr_str_exec(r, dconf->gid_expr, &err); + if (err) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ + "Error while parsing AssignGroupIDExpr expression: %s", + err); + return HTTP_INTERNAL_SERVER_ERROR; + } + + if (!(ent = getgrnam(wanted_groupname))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ + "AssignGroupIDExpr returned '%s', which is not a valid group name", + wanted_username); + return HTTP_INTERNAL_SERVER_ERROR; + } + + wanted_gid = ent->gr_gid; + } + if (!err && wanted_uid != -1 && wanted_gid != -1 && (getuid() != wanted_uid || getgid() != wanted_gid)) { if (setgid(wanted_gid)) { _DBG("setgid(%d): %s", wanted_gid, strerror(errno)); @@ -1802,6 +1849,53 @@ static const char *limit_gid_range(cmd_p return NULL; } +static const char *assign_user_id_expr (cmd_parms *cmd, void *ptr, const char *user_name_expr) +{ + itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr; + + const char *err; + + err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS); + if (err) { + return err; + } + + dconf->uid_expr = ap_expr_parse_cmd_mi(cmd, + user_name_expr, + AP_EXPR_FLAG_STRING_RESULT, + &err, + NULL, + AP_CORE_MODULE_INDEX); + if (err) { + return err; + } + + return NULL; +} + +static const char *assign_group_id_expr (cmd_parms *cmd, void *ptr, const char *group_name_expr) +{ + itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr; + + const char *err; + + err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS); + if (err) { + return err; + } + + dconf->gid_expr = ap_expr_parse_cmd_mi(cmd, + group_name_expr, + AP_EXPR_FLAG_STRING_RESULT, + &err, + NULL, + AP_CORE_MODULE_INDEX); + if (err) { + return err; + } + return NULL; +} + static const char *set_max_clients_vhost (cmd_parms *cmd, void *dummy, const char *arg) { itk_server_conf *sconf = @@ -1847,6 +1941,10 @@ AP_INIT_TAKE1("ServerLimit", set_server_ "Maximum value of MaxRequestWorkers 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_RAW_ARGS("AssignUserIDExpr", assign_user_id_expr, NULL, RSRC_CONF|ACCESS_CONF, + "Choose user ID given an expression. Will override AssignUserID."), +AP_INIT_RAW_ARGS("AssignGroupIDExpr", assign_group_id_expr, NULL, RSRC_CONF|ACCESS_CONF, + "Choose group ID given an expression. Will override AssignUserID."), AP_INIT_TAKE2("LimitUIDRange", limit_uid_range, NULL, RSRC_CONF, "If seccomp v2 is available (Linux 3.5.0+), limit the process's possible " "uid to the given range (inclusive endpoints)"), @@ -1870,6 +1968,7 @@ static void *itk_create_dir_config(apr_p itk_per_dir_conf *c = (itk_per_dir_conf *) apr_pcalloc(p, sizeof(itk_per_dir_conf)); c->uid = c->gid = -1; + c->uid_expr = c->gid_expr = NULL; c->nice_value = UNSET_NICE_VALUE; return c; } @@ -1891,6 +1990,16 @@ static void *itk_merge_dir_config(apr_po c->uid = parent->uid; c->gid = parent->gid; } + if (child->uid_expr != NULL) { + c->uid_expr = child->uid_expr; + } else { + c->uid_expr = parent->uid_expr; + } + if (child->gid_expr != NULL) { + c->gid_expr = child->gid_expr; + } else { + c->gid_expr = parent->gid_expr; + } if (child->nice_value != UNSET_NICE_VALUE) { c->nice_value = child->nice_value; } else {