Return-Path: Delivered-To: apmail-apache-cvs-archive@apache.org Received: (qmail 12423 invoked by uid 500); 28 Jul 2000 17:45:27 -0000 Mailing-List: contact apache-cvs-help@apache.org; run by ezmlm Precedence: bulk X-No-Archive: yes Reply-To: new-httpd@apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list apache-cvs@apache.org Received: (qmail 12369 invoked by uid 500); 28 Jul 2000 17:45:19 -0000 Delivered-To: apmail-apache-2.0-cvs@apache.org Date: 28 Jul 2000 17:45:17 -0000 Message-ID: <20000728174517.12359.qmail@locus.apache.org> From: rbb@locus.apache.org To: apache-2.0-cvs@apache.org Subject: cvs commit: apache-2.0/src/modules/mpm/perchild perchild.c rbb 00/07/28 10:45:15 Modified: src/modules/mpm/perchild perchild.c Log: Update the perchild MPM. At this point, it is possible to specify that a child process runs as a specified user. That child process is not currently tied to a virtual host. Using this MPM, I can launch Apache and have it serve as both nobody and rbb. Revision Changes Path 1.2 +127 -9 apache-2.0/src/modules/mpm/perchild/perchild.c Index: perchild.c =================================================================== RCS file: /home/cvs/apache-2.0/src/modules/mpm/perchild/perchild.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- perchild.c 2000/07/27 00:16:31 1.1 +++ perchild.c 2000/07/28 17:45:13 1.2 @@ -59,6 +59,7 @@ #define CORE_PRIVATE #include "ap_config.h" +#include "apr_hash.h" #include "apr_strings.h" #include "apr_portable.h" #include "apr_file_io.h" @@ -87,9 +88,20 @@ #ifdef HAVE_NETINET_TCP_H #include #endif +#include +#include #include #include +typedef struct child_info_t child_info_t; + +struct child_info_t { + uid_t uid; + gid_t gid; +}; +static int curr_child_num = 0; /* how many children have been setup so + far */ + /* * Actual definitions of config globals */ @@ -107,6 +119,8 @@ static int num_listenfds = 0; static ap_socket_t **listenfds; +static ap_hash_t *child_hash; + struct ap_ctable ap_child_table[HARD_SERVER_LIMIT]; /* @@ -650,6 +664,83 @@ return NULL; } +/* Set group privileges. + * + * Note that we use the username as set in the config files, rather than + * the lookup of to uid --- the same uid may have multiple passwd entries, + * with different sets of groups for each. + */ + +static int set_group_privs(uid_t uid, gid_t gid) +{ + if (!geteuid()) { + const char *name; + + /* Get username if passed as a uid */ + + struct passwd *ent; + + if ((ent = getpwuid(uid)) == NULL) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "getpwuid: couldn't determine user name from uid %u, " + "you probably need to modify the User directive", + (unsigned)uid); + return -1; + } + + name = ent->pw_name; + + /* + * Set the GID before initgroups(), since on some platforms + * setgid() is known to zap the group list. + */ + if (setgid(gid) == -1) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "setgid: unable to set group id to Group %u", + (unsigned)gid); + return -1; + } + + /* Reset `groups' attributes. */ + + if (initgroups(name, gid) == -1) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "initgroups: unable to set groups for User %s " + "and Group %u", name, (unsigned)gid); + return -1; + } + } + return 0; +} + + +static int perchild_setup_child(int childnum) +{ + child_info_t *ug; + char child_num_str[5]; + + ap_snprintf(child_num_str, 5, "%d", childnum); + ug = ap_hash_get(child_hash, child_num_str, 1); + if (!ug) { + return unixd_setup_child(); + } + if (set_group_privs(ug->uid, ug->gid)) { + return -1; + } + /* Only try to switch if we're running as root */ + if (!geteuid() && ( +#ifdef _OSD_POSIX + os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 || +#endif + setuid(ug->uid) == -1)) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "setuid: unable to change to uid: %ld", + (long) ug->uid); + return -1; + } + return 0; +} + static void child_main(int child_num_arg) { sigset_t sig_mask; @@ -672,7 +763,7 @@ clean_child_exit(APEXIT_CHILDFATAL); } - if (unixd_setup_child()) { + if (perchild_setup_child(child_num)) { clean_child_exit(APEXIT_CHILDFATAL); } @@ -1153,6 +1244,7 @@ lock_fname = DEFAULT_LOCKFILE; max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; ap_perchild_set_maintain_connection_status(1); + child_hash = ap_make_hash(p); ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); } @@ -1355,16 +1447,42 @@ ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); return NULL; } -static const char *set_childprocess(cmd_parms *cmd, void *dummy, const char *arg) + +static ap_status_t reset_child_process(void *data) { + curr_child_num = 0; + return APR_SUCCESS; } -/* + +static const char *set_childprocess(cmd_parms *cmd, void *dummy, const char *u, + const char *g) +{ + child_info_t *ug = ap_palloc(cmd->pool, sizeof(*ug)); + char child_num_str[5]; + + if (curr_child_num > num_daemons) { + return "Trying to use more child ID's than NumServers. Increase " + "NumServers in your config file."; + } + + ug->uid = atoi(u); + ug->gid = atoi(g); + ap_snprintf(child_num_str, 5, "%d", curr_child_num++); + ap_hash_set(child_hash, ap_pstrdup(cmd->pool, child_num_str), 1, ug); + + ap_register_cleanup(cmd->pool, &curr_child_num, reset_child_process, ap_null_cleanup); + + return NULL; +} + + +#if 0 if (unlink(sconf->sockname) < 0 && errno != ENOENT) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, "Couldn't unlink unix domain socket %s", sconf->sockname); - /* just a warning; don't bail out + /* JUSt a warning; don't bail out */ } if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { @@ -1377,10 +1495,10 @@ unix_addr.sun_family = AF_UNIX; strcpy(unix_addr.sun_path, sconf->sockname); - omask = umask(0077); /* so that only Apache can use socket + omask = umask(0077); /* so that only Apache can use socket */ rc = bind(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)); -*/ - +} +#endif @@ -1411,8 +1529,8 @@ "Whether or not to maintain status information on current connections"), AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, "The location of the directory Apache changes to before dumping core"), -AP_INIT_TAKE1("ChildProcess", set_childprocess, NULL, RSRC_CONF, - "Which child process is responsible for serving this virtual host"), +AP_INIT_TAKE2("ChildProcess", set_childprocess, NULL, RSRC_CONF, + "The User and Group this child Process should run as."), { NULL } };