unixd.c revision e078b71848a5949808244305f451ea0884744842
3802a3d3d7af51ddff31943d5514382f01265770Lennart Poettering/* ====================================================================
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * The Apache Software License, Version 1.1
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * reserved.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * Redistribution and use in source and binary forms, with or without
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * modification, are permitted provided that the following conditions
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * are met:
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * 1. Redistributions of source code must retain the above copyright
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * notice, this list of conditions and the following disclaimer.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * 2. Redistributions in binary form must reproduce the above copyright
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * notice, this list of conditions and the following disclaimer in
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * the documentation and/or other materials provided with the
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * distribution.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * 3. The end-user documentation included with the redistribution,
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * if any, must include the following acknowledgment:
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * "This product includes software developed by the
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * Apache Software Foundation (http://www.apache.org/)."
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * Alternately, this acknowledgment may appear in the software itself,
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * if and wherever such third-party acknowledgments normally appear.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * 4. The names "Apache" and "Apache Software Foundation" must
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * not be used to endorse or promote products derived from this
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * software without prior written permission. For written
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * permission, please contact apache@apache.org.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * 5. Products derived from this software may not be called "Apache",
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * nor may "Apache" appear in their name, without prior written
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * permission of the Apache Software Foundation.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * SUCH DAMAGE.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * ====================================================================
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * This software consists of voluntary contributions made by many
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * individuals on behalf of the Apache Software Foundation. For more
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * information on the Apache Software Foundation, please see
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * <http://www.apache.org/>.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * Portions of this software are based upon public domain software
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * originally written at the National Center for Supercomputing Applications,
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * University of Illinois, Urbana-Champaign.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek */
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "ap_config.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#define CORE_PRIVATE
fac9c0d508f72cc5d469c969a4acc3694247c03bDaniel Mack#include "httpd.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "http_config.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "http_main.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "http_log.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "unixd.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "mpm_common.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "os.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "ap_mpm.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "apr_thread_proc.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "apr_strings.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include "apr_portable.h"
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#ifdef HAVE_PWD_H
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include <pwd.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#ifdef HAVE_SYS_RESOURCE_H
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include <sys/resource.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek/* XXX */
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include <sys/stat.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#ifdef HAVE_UNISTD_H
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include <unistd.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif
b8bde11658366290521e3d03316378b482600323Jan Engelhardt#ifdef HAVE_GRP_H
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include <grp.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#ifdef HAVE_STRINGS_H
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include <strings.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#ifdef HAVE_SYS_SEM_H
b8bde11658366290521e3d03316378b482600323Jan Engelhardt#include <sys/sem.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#ifdef HAVE_SYS_PRCTL_H
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#include <sys/prctl.h>
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmekunixd_config_rec unixd_config;
b8bde11658366290521e3d03316378b482600323Jan Engelhardt
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek/* Set group privileges.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek *
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * Note that we use the username as set in the config files, rather than
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * the lookup of to uid --- the same uid may have multiple passwd entries,
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * with different sets of groups for each.
b8bde11658366290521e3d03316378b482600323Jan Engelhardt */
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmekstatic int set_group_privs(void)
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek{
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek if (!geteuid()) {
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek const char *name;
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek /* Get username if passed as a uid */
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek if (unixd_config.user_name[0] == '#') {
b8bde11658366290521e3d03316378b482600323Jan Engelhardt struct passwd *ent;
b8bde11658366290521e3d03316378b482600323Jan Engelhardt uid_t uid = atoi(&unixd_config.user_name[1]);
b8bde11658366290521e3d03316378b482600323Jan Engelhardt
b8bde11658366290521e3d03316378b482600323Jan Engelhardt if ((ent = getpwuid(uid)) == NULL) {
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
dca348bcbb462305864526c587495a14a76bfcdeJan Engelhardt "getpwuid: couldn't determine user name from uid %u, "
dca348bcbb462305864526c587495a14a76bfcdeJan Engelhardt "you probably need to modify the User directive",
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek (unsigned)uid);
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek return -1;
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek }
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek name = ent->pw_name;
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek }
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek else
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek name = unixd_config.user_name;
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#if !defined(OS2) && !defined(TPF)
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek /* OS/2 and TPF don't support groups. */
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek /*
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * Set the GID before initgroups(), since on some platforms
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek * setgid() is known to zap the group list.
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek */
b8bde11658366290521e3d03316378b482600323Jan Engelhardt if (setgid(unixd_config.group_id) == -1) {
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
5aded369782f28255bc6b494ca905d7acaea7a56Zbigniew Jędrzejewski-Szmek "setgid: unable to set group id to Group %u",
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek (unsigned)unixd_config.group_id);
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek return -1;
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek }
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek /* Reset `groups' attributes. */
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek if (initgroups(name, unixd_config.group_id) == -1) {
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek "initgroups: unable to set groups for User %s "
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek "and Group %u", name, (unsigned)unixd_config.group_id);
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek return -1;
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek }
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek#endif /* !defined(OS2) && !defined(TPF) */
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek }
effbc8e4f70fc70e4a4a8a1dc77228dd187f9c22Zbigniew Jędrzejewski-Szmek return 0;
}
AP_DECLARE(int) unixd_setup_child(void)
{
if (set_group_privs()) {
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(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);
/* Check for suexec */
unixd_config.suexec_enabled = 0;
if ((apr_stat(&wrapper, SUEXEC_BIN,
APR_FINFO_NORM, ptemp)) != APR_SUCCESS) {
return;
}
/* XXX - apr_stat is incapable of checking suid bits (grumble) */
/* if ((wrapper.filetype & S_ISUID) && 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)
{
#if (defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)) && APR_HAVE_STRUCT_RLIMIT && APR_HAVE_GETRLIMIT
char *str;
struct rlimit *limit;
/* If your platform doesn't define rlim_t then typedef it in ap_config.h */
rlim_t cur = 0;
rlim_t max = 0;
*plimit = (struct rlimit *)apr_pcalloc(cmd->pool, sizeof(**plimit));
limit = *plimit;
if ((getrlimit(type, limit)) != 0) {
*plimit = NULL;
ap_log_error(APLOG_MARK, APLOG_ERR, errno, cmd->server,
"%s: getrlimit failed", cmd->cmd->name);
return;
}
if ((str = ap_getword_conf(cmd->pool, &arg))) {
if (!strcasecmp(str, "max")) {
cur = limit->rlim_max;
}
else {
cur = atol(str);
}
}
else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
"Invalid parameters for %s", cmd->cmd->name);
return;
}
if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
max = atol(str);
}
/* if we aren't running as root, cannot increase max */
if (geteuid()) {
limit->rlim_cur = cur;
if (max) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
"Must be uid 0 to raise maximum %s", cmd->cmd->name);
}
}
else {
if (cur) {
limit->rlim_cur = cur;
}
if (max) {
limit->rlim_max = max;
}
}
#else
ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
"Platform does not support rlimit for %s", cmd->cmd->name);
#endif
}
APR_HOOK_STRUCT(
APR_HOOK_LINK(get_suexec_identity)
)
AP_IMPLEMENT_HOOK_RUN_FIRST(ap_unix_identity_t *, get_suexec_identity,
(const request_rec *r), (r), NULL)
static apr_status_t ap_unix_create_privileged_process(
apr_proc_t *newproc, const char *progname,
const char * const *args,
const char * const *env,
apr_procattr_t *attr, ap_unix_identity_t *ugid,
apr_pool_t *p)
{
int i = 0;
const char **newargs;
char *newprogname;
char *execuser, *execgroup;
const char *argv0;
if (!unixd_config.suexec_enabled) {
return apr_proc_create(newproc, progname, args, env, attr, p);
}
argv0 = ap_strrchr_c(progname, '/');
/* Allow suexec's "/" check to succeed */
if (argv0 != NULL) {
argv0++;
}
else {
argv0 = progname;
}
if (ugid->userdir) {
execuser = apr_psprintf(p, "~%ld", (long) ugid->uid);
}
else {
execuser = apr_psprintf(p, "%ld", (long) ugid->uid);
}
execgroup = apr_psprintf(p, "%ld", (long) ugid->gid);
if (!execuser || !execgroup) {
return APR_ENOMEM;
}
i = 0;
if (args) {
while (args[i]) {
i++;
}
}
/* allocate space for 4 new args, the input args, and a null terminator */
newargs = apr_palloc(p, sizeof(char *) * (i + 4));
newprogname = SUEXEC_BIN;
newargs[0] = SUEXEC_BIN;
newargs[1] = execuser;
newargs[2] = execgroup;
newargs[3] = apr_pstrdup(p, argv0);
/*
** using a shell to execute suexec makes no sense thus
** we force everything to be APR_PROGRAM, and never
** APR_SHELLCMD
*/
if(apr_procattr_cmdtype_set(attr, APR_PROGRAM) != APR_SUCCESS) {
return APR_EGENERAL;
}
i = 1;
do {
newargs[i + 3] = args[i];
} while (args[i++]);
return apr_proc_create(newproc, newprogname, newargs, env, attr, p);
}
AP_DECLARE(apr_status_t) ap_os_create_privileged_process(
const request_rec *r,
apr_proc_t *newproc, const char *progname,
const char * const *args,
const char * const *env,
apr_procattr_t *attr, apr_pool_t *p)
{
ap_unix_identity_t *ugid = ap_run_get_suexec_identity(r);
if (ugid == NULL) {
return apr_proc_create(newproc, progname, args, env, attr, p);
}
return ap_unix_create_privileged_process(newproc, progname, args, env,
attr, ugid, p);
}
/* XXX move to APR and externalize (but implement differently :) ) */
static apr_lockmech_e proc_mutex_mech(apr_proc_mutex_t *pmutex)
{
const char *mechname = apr_proc_mutex_name(pmutex);
if (!strcmp(mechname, "sysvsem")) {
return APR_LOCK_SYSVSEM;
}
else if (!strcmp(mechname, "flock")) {
return APR_LOCK_FLOCK;
}
return APR_LOCK_DEFAULT;
}
AP_DECLARE(apr_status_t) unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex)
{
if (!geteuid()) {
apr_lockmech_e mech = proc_mutex_mech(pmutex);
switch(mech) {
#if APR_HAS_SYSVSEM_SERIALIZE
case APR_LOCK_SYSVSEM:
{
apr_os_proc_mutex_t ospmutex;
#if !APR_HAVE_UNION_SEMUN
union semun {
long val;
struct semid_ds *buf;
ushort *array;
};
#endif
union semun ick;
struct semid_ds buf;
apr_os_proc_mutex_get(&ospmutex, pmutex);
buf.sem_perm.uid = unixd_config.user_id;
buf.sem_perm.gid = unixd_config.group_id;
buf.sem_perm.mode = 0600;
ick.buf = &buf;
if (semctl(ospmutex.crossproc, 0, IPC_SET, ick) < 0) {
return errno;
}
}
break;
#endif
#if APR_HAS_FLOCK_SERIALIZE
case APR_LOCK_FLOCK:
{
const char *lockfile = apr_proc_mutex_lockfile(pmutex);
if (lockfile) {
if (chown(lockfile, unixd_config.user_id,
-1 /* no gid change */) < 0) {
return errno;
}
}
}
break;
#endif
default:
/* do nothing */
break;
}
}
return APR_SUCCESS;
}
AP_DECLARE(apr_status_t) unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex)
{
#if !APR_PROC_MUTEX_IS_GLOBAL
apr_os_global_mutex_t osgmutex;
apr_os_global_mutex_get(&osgmutex, gmutex);
return unixd_set_proc_mutex_perms(osgmutex.proc_mutex);
#else /* APR_PROC_MUTEX_IS_GLOBAL */
/* In this case, apr_proc_mutex_t and apr_global_mutex_t are the same. */
return unixd_set_proc_mutex_perms(gmutex);
#endif /* APR_PROC_MUTEX_IS_GLOBAL */
}
AP_DECLARE(apr_status_t) unixd_accept(void **accepted, ap_listen_rec *lr,
apr_pool_t *ptrans)
{
apr_socket_t *csd;
apr_status_t status;
int sockdes;
*accepted = NULL;
status = apr_socket_accept(&csd, lr->sd, ptrans);
if (status == APR_SUCCESS) {
*accepted = csd;
apr_os_sock_get(&sockdes, csd);
if (sockdes >= FD_SETSIZE) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
"new file descriptor %d is too large; you probably need "
"to rebuild Apache with a larger FD_SETSIZE "
"(currently %d)",
sockdes, FD_SETSIZE);
apr_socket_close(csd);
return APR_EINTR;
}
#ifdef TPF
if (sockdes == 0) { /* 0 is invalid socket for TPF */
return APR_EINTR;
}
#endif
return status;
}
if (APR_STATUS_IS_EINTR(status)) {
return status;
}
/* Our old behaviour here was to continue after accept()
* errors. But this leads us into lots of troubles
* because most of the errors are quite fatal. For
* example, EMFILE can be caused by slow descriptor
* leaks (say in a 3rd party module, or libc). It's
* foolish for us to continue after an EMFILE. We also
* seem to tickle kernel bugs on some platforms which
* lead to never-ending loops here. So it seems best
* to just exit in most cases.
*/
switch (status) {
#if defined(HPUX11) && defined(ENOBUFS)
/* On HPUX 11.x, the 'ENOBUFS, No buffer space available'
* error occurs because the accept() cannot complete.
* You will not see ENOBUFS with 10.20 because the kernel
* hides any occurrence from being returned to user space.
* ENOBUFS with 11.x's TCP/IP stack is possible, and could
* occur intermittently. As a work-around, we are going to
* ignore ENOBUFS.
*/
case ENOBUFS:
#endif
#ifdef EPROTO
/* EPROTO on certain older kernels really means
* ECONNABORTED, so we need to ignore it for them.
* See discussion in new-httpd archives nh.9701
* search for EPROTO.
*
* Also see nh.9603, search for EPROTO:
* There is potentially a bug in Solaris 2.x x<6,
* and other boxes that implement tcp sockets in
* userland (i.e. on top of STREAMS). On these
* systems, EPROTO can actually result in a fatal
* loop. See PR#981 for example. It's hard to
* handle both uses of EPROTO.
*/
case EPROTO:
#endif
#ifdef ECONNABORTED
case ECONNABORTED:
#endif
/* Linux generates the rest of these, other tcp
* stacks (i.e. bsd) tend to hide them behind
* getsockopt() interfaces. They occur when
* the net goes sour or the client disconnects
* after the three-way handshake has been done
* in the kernel but before userland has picked
* up the socket.
*/
#ifdef ECONNRESET
case ECONNRESET:
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT:
#endif
#ifdef EHOSTUNREACH
case EHOSTUNREACH:
#endif
#ifdef ENETUNREACH
case ENETUNREACH:
#endif
break;
#ifdef ENETDOWN
case ENETDOWN:
/*
* When the network layer has been shut down, there
* is not much use in simply exiting: the parent
* would simply re-create us (and we'd fail again).
* Use the CHILDFATAL code to tear the server down.
* @@@ Martin's idea for possible improvement:
* A different approach would be to define
* a new APEXIT_NETDOWN exit code, the reception
* of which would make the parent shutdown all
* children, then idle-loop until it detected that
* the network is up again, and restart the children.
* Ben Hyde noted that temporary ENETDOWN situations
* occur in mobile IP.
*/
ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
"apr_socket_accept: giving up.");
return APR_EGENERAL;
#endif /*ENETDOWN*/
#ifdef TPF
case EINACT:
ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
"offload device inactive");
return APR_EGENERAL;
break;
default:
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
"select/accept error (%d)", status);
return APR_EGENERAL;
#else
default:
ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf,
"apr_socket_accept: (client socket)");
return APR_EGENERAL;
#endif
}
return status;
}