1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2002 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"
62 #include "http_config.h"
63 #include "http_main.h"
66 #include "mpm_common.h"
69 #include "apr_thread_proc.h"
70 #include "apr_strings.h"
71 #include "apr_portable.h"
75 #ifdef HAVE_SYS_RESOURCE_H
76 #include <sys/resource.h>
93 unixd_config_rec unixd_config;
95 /* Set group privileges.
97 * Note that we use the username as set in the config files, rather than
98 * the lookup of to uid --- the same uid may have multiple passwd entries,
99 * with different sets of groups for each.
102 static int set_group_privs(void)
107 /* Get username if passed as a uid */
109 if (unixd_config.user_name[0] == '#') {
111 uid_t uid = atoi(&unixd_config.user_name[1]);
113 if ((ent = getpwuid(uid)) == NULL) {
114 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
115 "getpwuid: couldn't determine user name from uid %u, "
116 "you probably need to modify the User directive",
124 name = unixd_config.user_name;
126 #if !defined(OS2) && !defined(TPF)
127 /* OS/2 and TPF don't support groups. */
130 * Set the GID before initgroups(), since on some platforms
131 * setgid() is known to zap the group list.
133 if (setgid(unixd_config.group_id) == -1) {
134 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
135 "setgid: unable to set group id to Group %u",
136 (unsigned)unixd_config.group_id);
140 /* Reset `groups' attributes. */
142 if (initgroups(name, unixd_config.group_id) == -1) {
143 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
144 "initgroups: unable to set groups for User %s "
145 "and Group %u", name, (unsigned)unixd_config.group_id);
148 #endif /* !defined(OS2) && !defined(TPF) */
154 AP_DECLARE(int) unixd_setup_child(void)
156 if (set_group_privs()) {
160 /* Only try to switch if we're running as MANAGER.SYS */
161 if (geteuid() == 1 && unixd_config.user_id > 1) {
163 if (setuid(unixd_config.user_id) == -1) {
165 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
166 "setuid: unable to change to uid: %ld",
167 (long) unixd_config.user_id);
173 /* Only try to switch if we're running as root */
176 os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 ||
178 setuid(unixd_config.user_id) == -1)) {
179 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
180 "setuid: unable to change to uid: %ld",
181 (long) unixd_config.user_id);
189 AP_DECLARE(const char *) unixd_set_user(cmd_parms *cmd, void *dummy,
192 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
197 unixd_config.user_name = arg;
198 unixd_config.user_id = ap_uname2id(arg);
199 #if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
200 if (unixd_config.user_id == 0) {
201 return "Error:\tApache has not been designed to serve pages while\n"
202 "\trunning as root. There are known race conditions that\n"
203 "\twill allow any local user to read any file on the system.\n"
204 "\tIf you still desire to serve pages as root then\n"
205 "\tadd -DBIG_SECURITY_HOLE to the CFLAGS env variable\n"
206 "\tand then rebuild the server.\n"
207 "\tIt is strongly suggested that you instead modify the User\n"
208 "\tdirective in your httpd.conf file to list a non-root\n"
216 AP_DECLARE(const char *) unixd_set_group(cmd_parms *cmd, void *dummy,
219 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
224 unixd_config.group_id = ap_gname2id(arg);
229 AP_DECLARE(void) unixd_pre_config(apr_pool_t *ptemp)
233 unixd_config.user_name = DEFAULT_USER;
234 unixd_config.user_id = ap_uname2id(DEFAULT_USER);
235 unixd_config.group_id = ap_gname2id(DEFAULT_GROUP);
237 /* Check for suexec */
238 unixd_config.suexec_enabled = 0;
239 if ((apr_stat(&wrapper, SUEXEC_BIN,
240 APR_FINFO_NORM, ptemp)) != APR_SUCCESS) {
244 /* XXX - apr_stat is incapable of checking suid bits (grumble) */
245 /* if ((wrapper.filetype & S_ISUID) && wrapper.user == 0) { */
246 unixd_config.suexec_enabled = 1;
251 AP_DECLARE(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit,
252 const char *arg, const char * arg2, int type)
254 #if (defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)) && APR_HAVE_STRUCT_RLIMIT && APR_HAVE_GETRLIMIT
256 struct rlimit *limit;
257 /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
261 *plimit = (struct rlimit *)apr_pcalloc(cmd->pool, sizeof(**plimit));
263 if ((getrlimit(type, limit)) != 0) {
265 ap_log_error(APLOG_MARK, APLOG_ERR, errno, cmd->server,
266 "%s: getrlimit failed", cmd->cmd->name);
270 if ((str = ap_getword_conf(cmd->pool, &arg))) {
271 if (!strcasecmp(str, "max")) {
272 cur = limit->rlim_max;
279 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
280 "Invalid parameters for %s", cmd->cmd->name);
284 if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
288 /* if we aren't running as root, cannot increase max */
290 limit->rlim_cur = cur;
292 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
293 "Must be uid 0 to raise maximum %s", cmd->cmd->name);
298 limit->rlim_cur = cur;
301 limit->rlim_max = max;
306 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
307 "Platform does not support rlimit for %s", cmd->cmd->name);
312 APR_HOOK_LINK(get_suexec_identity)
315 AP_IMPLEMENT_HOOK_RUN_FIRST(ap_unix_identity_t *, get_suexec_identity,
316 (const request_rec *r), (r), NULL)
318 static apr_status_t ap_unix_create_privileged_process(
319 apr_proc_t *newproc, const char *progname,
320 const char * const *args,
321 const char * const *env,
322 apr_procattr_t *attr, ap_unix_identity_t *ugid,
326 const char **newargs;
328 char *execuser, *execgroup;
330 if (!unixd_config.suexec_enabled) {
331 return apr_proc_create(newproc, progname, args, env, attr, p);
334 execuser = apr_psprintf(p, "%ld", (long) ugid->uid);
335 execgroup = apr_psprintf(p, "%ld", (long) ugid->gid);
337 if (!execuser || !execgroup) {
347 /* allocate space for 4 new args, the input args, and a null terminator */
348 newargs = apr_palloc(p, sizeof(char *) * (i + 5));
349 newprogname = SUEXEC_BIN;
350 newargs[0] = SUEXEC_BIN;
351 newargs[1] = execuser;
352 newargs[2] = execgroup;
353 newargs[3] = apr_pstrdup(p, progname);
357 newargs[i + 4] = args[i];
360 return apr_proc_create(newproc, newprogname, newargs, env, attr, p);
363 AP_DECLARE(apr_status_t) ap_os_create_privileged_process(
364 const request_rec *r,
365 apr_proc_t *newproc, const char *progname,
366 const char * const *args,
367 const char * const *env,
368 apr_procattr_t *attr, apr_pool_t *p)
370 ap_unix_identity_t *ugid = ap_run_get_suexec_identity(r);
373 return apr_proc_create(newproc, progname, args, env, attr, p);
376 return ap_unix_create_privileged_process(newproc, progname, args, env,
380 AP_DECLARE(apr_status_t) unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex)
382 /* MPM shouldn't call us unless we're actually using a SysV sem;
383 * this is just to avoid compile issues on systems without that
386 #if APR_HAS_SYSVSEM_SERIALIZE
387 apr_os_proc_mutex_t ospmutex;
388 #if !APR_HAVE_UNION_SEMUN
391 struct semid_ds *buf;
399 apr_os_proc_mutex_get(&ospmutex, pmutex);
400 buf.sem_perm.uid = unixd_config.user_id;
401 buf.sem_perm.gid = unixd_config.group_id;
402 buf.sem_perm.mode = 0600;
404 if (semctl(ospmutex.crossproc, 0, IPC_SET, ick) < 0) {
412 AP_DECLARE(apr_status_t) unixd_accept(void **accepted, ap_listen_rec *lr,
420 status = apr_accept(&csd, lr->sd, ptrans);
421 if (status == APR_SUCCESS) {
423 apr_os_sock_get(&sockdes, csd);
424 if (sockdes >= FD_SETSIZE) {
425 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL,
426 "new file descriptor %d is too large; you probably need "
427 "to rebuild Apache with a larger FD_SETSIZE "
429 sockdes, FD_SETSIZE);
430 apr_socket_close(csd);
434 if (sockdes == 0) { /* 0 is invalid socket for TPF */
441 if (APR_STATUS_IS_EINTR(status)) {
444 /* Our old behaviour here was to continue after accept()
445 * errors. But this leads us into lots of troubles
446 * because most of the errors are quite fatal. For
447 * example, EMFILE can be caused by slow descriptor
448 * leaks (say in a 3rd party module, or libc). It's
449 * foolish for us to continue after an EMFILE. We also
450 * seem to tickle kernel bugs on some platforms which
451 * lead to never-ending loops here. So it seems best
452 * to just exit in most cases.
455 #if defined(HPUX11) && defined(ENOBUFS)
456 /* On HPUX 11.x, the 'ENOBUFS, No buffer space available'
457 * error occurs because the accept() cannot complete.
458 * You will not see ENOBUFS with 10.20 because the kernel
459 * hides any occurrence from being returned to user space.
460 * ENOBUFS with 11.x's TCP/IP stack is possible, and could
461 * occur intermittently. As a work-around, we are going to
468 /* EPROTO on certain older kernels really means
469 * ECONNABORTED, so we need to ignore it for them.
470 * See discussion in new-httpd archives nh.9701
473 * Also see nh.9603, search for EPROTO:
474 * There is potentially a bug in Solaris 2.x x<6,
475 * and other boxes that implement tcp sockets in
476 * userland (i.e. on top of STREAMS). On these
477 * systems, EPROTO can actually result in a fatal
478 * loop. See PR#981 for example. It's hard to
479 * handle both uses of EPROTO.
486 /* Linux generates the rest of these, other tcp
487 * stacks (i.e. bsd) tend to hide them behind
488 * getsockopt() interfaces. They occur when
489 * the net goes sour or the client disconnects
490 * after the three-way handshake has been done
491 * in the kernel but before userland has picked
510 * When the network layer has been shut down, there
511 * is not much use in simply exiting: the parent
512 * would simply re-create us (and we'd fail again).
513 * Use the CHILDFATAL code to tear the server down.
514 * @@@ Martin's idea for possible improvement:
515 * A different approach would be to define
516 * a new APEXIT_NETDOWN exit code, the reception
517 * of which would make the parent shutdown all
518 * children, then idle-loop until it detected that
519 * the network is up again, and restart the children.
520 * Ben Hyde noted that temporary ENETDOWN situations
521 * occur in mobile IP.
523 ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
524 "apr_accept: giving up.");
530 ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
531 "offload device inactive");
535 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf,
536 "select/accept error (%d)", status);
540 ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf,
541 "apr_accept: (client socket)");