Commit f105637f authored by Nick Kew's avatar Nick Kew
Browse files

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
parent 9862774e
Loading
Loading
Loading
Loading
+86 −1
Original line number Diff line number Diff line
@@ -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;
}
+0 −206
Original line number Diff line number Diff line
@@ -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)
+2 −9
Original line number Diff line number Diff line
@@ -80,14 +80,7 @@ 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,
+0 −2
Original line number Diff line number Diff line
@@ -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"),
+0 −2
Original line number Diff line number Diff line
@@ -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"),
Loading