1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * ====================================================================
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
59 #include "ap_config.h"
61 #include "http_config.h"
62 #include "http_main.h"
68 #ifdef HAVE_SYS_RESOURCE_H
69 #include <sys/resource.h>
78 unixd_config_rec unixd_config;
80 /* Set group privileges.
82 * Note that we use the username as set in the config files, rather than
83 * the lookup of to uid --- the same uid may have multiple passwd entries,
84 * with different sets of groups for each.
87 static int set_group_privs(void)
92 /* Get username if passed as a uid */
94 if (unixd_config.user_name[0] == '#') {
96 uid_t uid = atoi(&unixd_config.user_name[1]);
98 if ((ent = getpwuid(uid)) == NULL) {
99 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
100 "getpwuid: couldn't determine user name from uid %u, "
101 "you probably need to modify the User directive",
109 name = unixd_config.user_name;
111 #if !defined(OS2) && !defined(TPF)
112 /* OS/2 and TPF don't support groups. */
115 * Set the GID before initgroups(), since on some platforms
116 * setgid() is known to zap the group list.
118 if (setgid(unixd_config.group_id) == -1) {
119 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
120 "setgid: unable to set group id to Group %u",
121 (unsigned)unixd_config.group_id);
125 /* Reset `groups' attributes. */
127 if (initgroups(name, unixd_config.group_id) == -1) {
128 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
129 "initgroups: unable to set groups for User %s "
130 "and Group %u", name, (unsigned)unixd_config.group_id);
133 #endif /* !defined(OS2) && !defined(TPF) */
139 int unixd_setup_child(void)
141 if (set_group_privs()) {
145 /* Only try to switch if we're running as MANAGER.SYS */
146 if (geteuid() == 1 && unixd_config.user_id > 1) {
148 if (setuid(unixd_config.user_id) == -1) {
150 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
151 "setuid: unable to change to uid: %ld",
152 (long) unixd_config.user_id);
158 /* Only try to switch if we're running as root */
161 os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 ||
163 setuid(unixd_config.user_id) == -1)) {
164 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
165 "setuid: unable to change to uid: %ld",
166 (long) unixd_config.user_id);
174 const char *unixd_set_user(cmd_parms *cmd, void *dummy, const char *arg)
176 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
181 unixd_config.user_name = arg;
182 unixd_config.user_id = ap_uname2id(arg);
183 #if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
184 if (unixd_config.user_id == 0) {
185 return "Error:\tApache has not been designed to serve pages while\n"
186 "\trunning as root. There are known race conditions that\n"
187 "\twill allow any local user to read any file on the system.\n"
188 "\tIf you still desire to serve pages as root then\n"
189 "\tadd -DBIG_SECURITY_HOLE to the EXTRA_CFLAGS line in your\n"
190 "\tsrc/Configuration file and rebuild the server. It is\n"
191 "\tstrongly suggested that you instead modify the User\n"
192 "\tdirective in your httpd.conf file to list a non-root\n"
200 const char *unixd_set_group(cmd_parms *cmd, void *dummy, const char *arg)
202 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
207 unixd_config.group_id = ap_gname2id(arg);
212 void unixd_pre_config(void)
214 unixd_config.user_name = DEFAULT_USER;
215 unixd_config.user_id = ap_uname2id(DEFAULT_USER);
216 unixd_config.group_id = ap_gname2id(DEFAULT_GROUP);
219 #ifdef NEED_AP_SYS_SIGLIST
221 const char *ap_sys_siglist[NumSIG];
223 #define store_str(array,index,string) \
224 (ap_assert(index < (sizeof(array)/sizeof(array[0]))),array[index]=string)
226 void unixd_siglist_init(void)
230 ap_sys_siglist[0] = "Signal 0";
232 store_str(ap_sys_siglist,SIGHUP,"Hangup");
235 store_str(ap_sys_siglist,SIGINT,"Interrupt");
238 store_str(ap_sys_siglist,SIGQUIT,"Quit");
241 store_str(ap_sys_siglist,SIGILL,"Illegal instruction");
244 store_str(ap_sys_siglist,SIGTRAP,"Trace/BPT trap");
247 store_str(ap_sys_siglist,SIGIOT,"IOT instruction");
250 store_str(ap_sys_siglist,SIGABRT,"Abort");
253 store_str(ap_sys_siglist,SIGEMT,"Emulator trap");
256 store_str(ap_sys_siglist,SIGFPE,"Arithmetic exception");
259 store_str(ap_sys_siglist,SIGKILL,"Killed");
262 store_str(ap_sys_siglist,SIGBUS,"Bus error");
265 store_str(ap_sys_siglist,SIGSEGV,"Segmentation fault");
268 store_str(ap_sys_siglist,SIGSYS,"Bad system call");
271 store_str(ap_sys_siglist,SIGPIPE,"Broken pipe");
274 store_str(ap_sys_siglist,SIGALRM,"Alarm clock");
277 store_str(ap_sys_siglist,SIGTERM,"Terminated");
280 store_str(ap_sys_siglist,SIGUSR1,"User defined signal 1");
283 store_str(ap_sys_siglist,SIGUSR2,"User defined signal 2");
286 store_str(ap_sys_siglist,SIGCLD,"Child status change");
289 store_str(ap_sys_siglist,SIGCHLD,"Child status change");
292 store_str(ap_sys_siglist,SIGPWR,"Power-fail restart");
295 store_str(ap_sys_siglist,SIGWINCH,"Window changed");
298 store_str(ap_sys_siglist,SIGURG,"urgent socket condition");
301 store_str(ap_sys_siglist,SIGPOLL,"Pollable event occurred");
304 store_str(ap_sys_siglist,SIGIO,"socket I/O possible");
307 store_str(ap_sys_siglist,SIGSTOP,"Stopped (signal)");
310 store_str(ap_sys_siglist,SIGTSTP,"Stopped");
313 store_str(ap_sys_siglist,SIGCONT,"Continued");
316 store_str(ap_sys_siglist,SIGTTIN,"Stopped (tty input)");
319 store_str(ap_sys_siglist,SIGTTOU,"Stopped (tty output)");
322 store_str(ap_sys_siglist,SIGVTALRM,"virtual timer expired");
325 store_str(ap_sys_siglist,SIGPROF,"profiling timer expired");
328 store_str(ap_sys_siglist,SIGXCPU,"exceeded cpu limit");
331 store_str(ap_sys_siglist,SIGXFSZ,"exceeded file size limit");
333 for (sig=0; sig < sizeof(ap_sys_siglist)/sizeof(ap_sys_siglist[0]); ++sig)
334 if (ap_sys_siglist[sig] == NULL)
335 ap_sys_siglist[sig] = "";
337 #endif /* NEED_AP_SYS_SIGLIST */
339 #if defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)
340 API_EXPORT(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit,
341 const char *arg, const char * arg2, int type)
344 struct rlimit *limit;
345 /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
349 *plimit = (struct rlimit *)ap_pcalloc(cmd->pool, sizeof(**plimit));
351 if ((getrlimit(type, limit)) != 0) {
353 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
354 "%s: getrlimit failed", cmd->cmd->name);
358 if ((str = ap_getword_conf(cmd->pool, &arg))) {
359 if (!strcasecmp(str, "max")) {
360 cur = limit->rlim_max;
367 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
368 "Invalid parameters for %s", cmd->cmd->name);
372 if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
376 /* if we aren't running as root, cannot increase max */
378 limit->rlim_cur = cur;
380 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
381 "Must be uid 0 to raise maximum %s", cmd->cmd->name);
386 limit->rlim_cur = cur;
389 limit->rlim_max = max;