From 368d9bb3351c2ee56598617fa3bd1a820608a896 Mon Sep 17 00:00:00 2001 From: Nick Kew Date: Tue, 4 Nov 2008 00:44:56 +0000 Subject: [PATCH] Further unixd hacks to remove duplication between old-unixd and mod_unixd, and get it working with old MPMS[1] + mod_unixd. It's still an uneasy split, as some modules (mod_cgid, suexec)[2] also use unixd. More thinking+hacking due. [1] Should be prefork/worker/event, but only worker is tested. [2] cgid is OK, suexec is untested. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@711146 13f79535-47bb-0310-9956-ffa450edef68 --- modules/arch/unix/mod_unixd.c | 87 ++++++++++- os/unix/unixd.c | 206 -------------------------- os/unix/unixd.h | 11 +- server/mpm/experimental/event/event.c | 2 - server/mpm/prefork/prefork.c | 2 - server/mpm/worker/worker.c | 2 - 6 files changed, 88 insertions(+), 222 deletions(-) diff --git a/modules/arch/unix/mod_unixd.c b/modules/arch/unix/mod_unixd.c index 487748bdf8..54239a4b0d 100644 --- a/modules/arch/unix/mod_unixd.c +++ b/modules/arch/unix/mod_unixd.c @@ -56,15 +56,19 @@ #define DEFAULT_GROUP "#-1" #endif +#if 0 typedef struct { const char *user_name; uid_t user_id; gid_t group_id; const char *chroot_dir; } unixd_config_t; +#else +#include "unixd.h" +#endif -unixd_config_t unixd_config; +//unixd_config_t unixd_config; /* Set group privileges. * @@ -273,12 +277,22 @@ static int unixd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { + apr_finfo_t wrapper; unixd_config.user_name = DEFAULT_USER; unixd_config.user_id = ap_uname2id(DEFAULT_USER); unixd_config.group_id = ap_gname2id(DEFAULT_GROUP); unixd_config.chroot_dir = NULL; /* none */ + /* Check for suexec */ + unixd_config.suexec_enabled = 0; + if ((apr_stat(&wrapper, SUEXEC_BIN, APR_FINFO_NORM, ptemp)) + == APR_SUCCESS) { + if ((wrapper.protection & APR_USETID) && wrapper.user == 0) { + unixd_config.suexec_enabled = 1; + } + } + sys_privileges_handlers(1); return OK; } @@ -311,3 +325,74 @@ module AP_MODULE_DECLARE_DATA unixd_module = { unixd_cmds, unixd_hooks }; + +AP_DECLARE(int) unixd_setup_child(void) +{ + if (set_group_privs()) { + return -1; + } + + if (NULL != unixd_config.chroot_dir) { + if (geteuid()) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "Cannot chroot when not started as root"); + return -1; + } + if (chdir(unixd_config.chroot_dir) != 0) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "Can't chdir to %s", unixd_config.chroot_dir); + return -1; + } + if (chroot(unixd_config.chroot_dir) != 0) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "Can't chroot to %s", unixd_config.chroot_dir); + return -1; + } + if (chdir("/") != 0) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "Can't chdir to new root"); + return -1; + } + } + +#ifdef MPE + /* Only try to switch if we're running as MANAGER.SYS */ + if (geteuid() == 1 && unixd_config.user_id > 1) { + GETPRIVMODE(); + if (setuid(unixd_config.user_id) == -1) { + GETUSERMODE(); + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "setuid: unable to change to uid: %ld", + (long) unixd_config.user_id); + exit(1); + } + GETUSERMODE(); + } +#else + /* Only try to switch if we're running as root */ + if (!geteuid() && ( +#ifdef _OSD_POSIX + os_init_job_environment(NULL, unixd_config.user_name, ap_exists_config_define("DEBUG")) != 0 || +#endif + setuid(unixd_config.user_id) == -1)) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "setuid: unable to change to uid: %ld", + (long) unixd_config.user_id); + return -1; + } +#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) + /* this applies to Linux 2.4+ */ +#ifdef AP_MPM_WANT_SET_COREDUMPDIR + if (ap_coredumpdir_configured) { + if (prctl(PR_SET_DUMPABLE, 1)) { + ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, + "set dumpable failed - this child will not coredump" + " after software errors"); + } + } +#endif +#endif +#endif + return 0; +} + diff --git a/os/unix/unixd.c b/os/unix/unixd.c index 3e3ba7823e..bd0baeb163 100644 --- a/os/unix/unixd.c +++ b/os/unix/unixd.c @@ -52,212 +52,6 @@ unixd_config_rec unixd_config; -/* 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(void) -{ - if (!geteuid()) { - const char *name; - - /* Get username if passed as a uid */ - - if (unixd_config.user_name[0] == '#') { - struct passwd *ent; - uid_t uid = atol(&unixd_config.user_name[1]); - - if ((ent = getpwuid(uid)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "getpwuid: couldn't determine user name from uid %ld, " - "you probably need to modify the User directive", - (long)uid); - return -1; - } - - name = ent->pw_name; - } - else - name = unixd_config.user_name; - -#if !defined(OS2) && !defined(TPF) - /* OS/2 and TPF don't support groups. */ - - /* - * Set the GID before initgroups(), since on some platforms - * setgid() is known to zap the group list. - */ - if (setgid(unixd_config.group_id) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setgid: unable to set group id to Group %u", - (unsigned)unixd_config.group_id); - return -1; - } - - /* Reset `groups' attributes. */ - - if (initgroups(name, unixd_config.group_id) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "initgroups: unable to set groups for User %s " - "and Group %u", name, (unsigned)unixd_config.group_id); - return -1; - } -#endif /* !defined(OS2) && !defined(TPF) */ - } - return 0; -} - - -AP_DECLARE(int) unixd_setup_child(void) -{ - if (set_group_privs()) { - return -1; - } - - if (NULL != unixd_config.chroot_dir) { - if (geteuid()) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "Cannot chroot when not started as root"); - return -1; - } - if (chdir(unixd_config.chroot_dir) != 0) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "Can't chdir to %s", unixd_config.chroot_dir); - return -1; - } - if (chroot(unixd_config.chroot_dir) != 0) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "Can't chroot to %s", unixd_config.chroot_dir); - return -1; - } - if (chdir("/") != 0) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "Can't chdir to new root"); - return -1; - } - } - -#ifdef MPE - /* Only try to switch if we're running as MANAGER.SYS */ - if (geteuid() == 1 && unixd_config.user_id > 1) { - GETPRIVMODE(); - if (setuid(unixd_config.user_id) == -1) { - GETUSERMODE(); - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setuid: unable to change to uid: %ld", - (long) unixd_config.user_id); - exit(1); - } - GETUSERMODE(); - } -#else - /* Only try to switch if we're running as root */ - if (!geteuid() && ( -#ifdef _OSD_POSIX - os_init_job_environment(NULL, unixd_config.user_name, ap_exists_config_define("DEBUG")) != 0 || -#endif - setuid(unixd_config.user_id) == -1)) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setuid: unable to change to uid: %ld", - (long) unixd_config.user_id); - return -1; - } -#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) - /* this applies to Linux 2.4+ */ -#ifdef AP_MPM_WANT_SET_COREDUMPDIR - if (ap_coredumpdir_configured) { - if (prctl(PR_SET_DUMPABLE, 1)) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "set dumpable failed - this child will not coredump" - " after software errors"); - } - } -#endif -#endif -#endif - return 0; -} - - -AP_DECLARE(const char *) unixd_set_user(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - unixd_config.user_name = arg; - unixd_config.user_id = ap_uname2id(arg); -#if !defined (BIG_SECURITY_HOLE) && !defined (OS2) - if (unixd_config.user_id == 0) { - return "Error:\tApache has not been designed to serve pages while\n" - "\trunning as root. There are known race conditions that\n" - "\twill allow any local user to read any file on the system.\n" - "\tIf you still desire to serve pages as root then\n" - "\tadd -DBIG_SECURITY_HOLE to the CFLAGS env variable\n" - "\tand then rebuild the server.\n" - "\tIt is strongly suggested that you instead modify the User\n" - "\tdirective in your httpd.conf file to list a non-root\n" - "\tuser.\n"; - } -#endif - - return NULL; -} - -AP_DECLARE(const char *) unixd_set_group(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - unixd_config.group_id = ap_gname2id(arg); - - return NULL; -} -AP_DECLARE(const char *) unixd_set_chroot_dir(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - if (!ap_is_directory(cmd->pool, arg)) { - return "ChrootDir must be a valid directory"; - } - - unixd_config.chroot_dir = arg; - return NULL; -} - -AP_DECLARE(void) unixd_pre_config(apr_pool_t *ptemp) -{ - apr_finfo_t wrapper; - - unixd_config.user_name = DEFAULT_USER; - unixd_config.user_id = ap_uname2id(DEFAULT_USER); - unixd_config.group_id = ap_gname2id(DEFAULT_GROUP); - - unixd_config.chroot_dir = NULL; /* none */ - - /* Check for suexec */ - unixd_config.suexec_enabled = 0; - if ((apr_stat(&wrapper, SUEXEC_BIN, - APR_FINFO_NORM, ptemp)) != APR_SUCCESS) { - return; - } - - if ((wrapper.protection & APR_USETID) && wrapper.user == 0) { - unixd_config.suexec_enabled = 1; - } -} - AP_DECLARE(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg, const char * arg2, int type) diff --git a/os/unix/unixd.h b/os/unix/unixd.h index a916f0f50d..c165d15944 100644 --- a/os/unix/unixd.h +++ b/os/unix/unixd.h @@ -80,15 +80,8 @@ typedef struct { } unixd_config_rec; AP_DECLARE_DATA extern unixd_config_rec unixd_config; -AP_DECLARE(int) unixd_setup_child(void); -AP_DECLARE(void) unixd_pre_config(apr_pool_t *ptemp); -AP_DECLARE(const char *) unixd_set_user(cmd_parms *cmd, void *dummy, - const char *arg); -AP_DECLARE(const char *) unixd_set_group(cmd_parms *cmd, void *dummy, - const char *arg); -AP_DECLARE(const char *) unixd_set_chroot_dir(cmd_parms *cmd, void *dummy, - const char *arg); - +AP_DECLARE(int) unixd_setup_child(void); /* mod_cgid needs this */ + #if defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS) AP_DECLARE(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg, const char * arg2, int type); diff --git a/server/mpm/experimental/event/event.c b/server/mpm/experimental/event/event.c index bef7b85e39..ce59bbd315 100644 --- a/server/mpm/experimental/event/event.c +++ b/server/mpm/experimental/event/event.c @@ -2358,7 +2358,6 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog, parent_pid = ap_my_pid = getpid(); } - unixd_pre_config(ptemp); ap_listen_pre_config(); ap_daemons_to_start = DEFAULT_START_DAEMON; min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; @@ -2718,7 +2717,6 @@ static const char *set_thread_limit(cmd_parms * cmd, void *dummy, } static const command_rec event_cmds[] = { - UNIX_DAEMON_COMMANDS, LISTEN_COMMANDS, AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, "Number of child processes launched at server startup"), diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 28cfcfdca9..326d4d3627 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -1279,7 +1279,6 @@ static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp parent_pid = ap_my_pid = getpid(); } - unixd_pre_config(ptemp); ap_listen_pre_config(); ap_daemons_to_start = DEFAULT_START_DAEMON; ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON; @@ -1498,7 +1497,6 @@ static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *ar } static const command_rec prefork_cmds[] = { -UNIX_DAEMON_COMMANDS, LISTEN_COMMANDS, AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, "Number of child processes launched at server startup"), diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index 16ade8fcac..fd71aa9aac 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -1940,7 +1940,6 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, parent_pid = ap_my_pid = getpid(); } - unixd_pre_config(ptemp); ap_listen_pre_config(); ap_daemons_to_start = DEFAULT_START_DAEMON; min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; @@ -2299,7 +2298,6 @@ static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *ar } static const command_rec worker_cmds[] = { -UNIX_DAEMON_COMMANDS, LISTEN_COMMANDS, AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, "Number of child processes launched at server startup"), -- 2.50.1