1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2003 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>
92 #ifdef HAVE_SYS_PRCTL_H
93 #include <sys/prctl.h>
96 unixd_config_rec unixd_config;
98 /* Set group privileges.
100 * Note that we use the username as set in the config files, rather than
101 * the lookup of to uid --- the same uid may have multiple passwd entries,
102 * with different sets of groups for each.
105 static int set_group_privs(void)
110 /* Get username if passed as a uid */
112 if (unixd_config.user_name[0] == '#') {
114 uid_t uid = atoi(&unixd_config.user_name[1]);
116 if ((ent = getpwuid(uid)) == NULL) {
117 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
118 "getpwuid: couldn't determine user name from uid %u, "
119 "you probably need to modify the User directive",
127 name = unixd_config.user_name;
129 #if !defined(OS2) && !defined(TPF)
130 /* OS/2 and TPF don't support groups. */
133 * Set the GID before initgroups(), since on some platforms
134 * setgid() is known to zap the group list.
136 if (setgid(unixd_config.group_id) == -1) {
137 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
138 "setgid: unable to set group id to Group %u",
139 (unsigned)unixd_config.group_id);
143 /* Reset `groups' attributes. */
145 if (initgroups(name, unixd_config.group_id) == -1) {
146 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
147 "initgroups: unable to set groups for User %s "
148 "and Group %u", name, (unsigned)unixd_config.group_id);
151 #endif /* !defined(OS2) && !defined(TPF) */
157 AP_DECLARE(int) unixd_setup_child(void)
159 if (set_group_privs()) {
163 /* Only try to switch if we're running as MANAGER.SYS */
164 if (geteuid() == 1 && unixd_config.user_id > 1) {
166 if (setuid(unixd_config.user_id) == -1) {
168 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
169 "setuid: unable to change to uid: %ld",
170 (long) unixd_config.user_id);
176 /* Only try to switch if we're running as root */
179 os_init_job_environment(NULL, unixd_config.user_name, ap_exists_config_define("DEBUG")) != 0 ||
181 setuid(unixd_config.user_id) == -1)) {
182 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
183 "setuid: unable to change to uid: %ld",
184 (long) unixd_config.user_id);
187 #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
188 /* this applies to Linux 2.4+ */
189 #ifdef AP_MPM_WANT_SET_COREDUMPDIR
190 if (ap_coredumpdir_configured) {
191 if (prctl(PR_SET_DUMPABLE, 1)) {
192 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
193 "set dumpable failed - this child will not coredump"
194 " after software errors");
204 AP_DECLARE(const char *) unixd_set_user(cmd_parms *cmd, void *dummy,
207 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
212 unixd_config.user_name = arg;
213 unixd_config.user_id = ap_uname2id(arg);
214 #if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
215 if (unixd_config.user_id == 0) {
216 return "Error:\tApache has not been designed to serve pages while\n"
217 "\trunning as root. There are known race conditions that\n"
218 "\twill allow any local user to read any file on the system.\n"
219 "\tIf you still desire to serve pages as root then\n"
220 "\tadd -DBIG_SECURITY_HOLE to the CFLAGS env variable\n"
221 "\tand then rebuild the server.\n"
222 "\tIt is strongly suggested that you instead modify the User\n"
223 "\tdirective in your httpd.conf file to list a non-root\n"
231 AP_DECLARE(const char *) unixd_set_group(cmd_parms *cmd, void *dummy,
234 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
239 unixd_config.group_id = ap_gname2id(arg);
244 AP_DECLARE(void) unixd_pre_config(apr_pool_t *ptemp)
248 unixd_config.user_name = DEFAULT_USER;
249 unixd_config.user_id = ap_uname2id(DEFAULT_USER);
250 unixd_config.group_id = ap_gname2id(DEFAULT_GROUP);
252 /* Check for suexec */
253 unixd_config.suexec_enabled = 0;
254 if ((apr_stat(&wrapper, SUEXEC_BIN,
255 APR_FINFO_NORM, ptemp)) != APR_SUCCESS) {
259 /* XXX - apr_stat is incapable of checking suid bits (grumble) */
260 /* if ((wrapper.filetype & S_ISUID) && wrapper.user == 0) { */
261 unixd_config.suexec_enabled = 1;
266 AP_DECLARE(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit,
267 const char *arg, const char * arg2, int type)
269 #if (defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)) && APR_HAVE_STRUCT_RLIMIT && APR_HAVE_GETRLIMIT
271 struct rlimit *limit;
272 /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
276 *plimit = (struct rlimit *)apr_pcalloc(cmd->pool, sizeof(**plimit));
278 if ((getrlimit(type, limit)) != 0) {
280 ap_log_error(APLOG_MARK, APLOG_ERR, errno, cmd->server,
281 "%s: getrlimit failed", cmd->cmd->name);
285 if ((str = ap_getword_conf(cmd->pool, &arg))) {
286 if (!strcasecmp(str, "max")) {
287 cur = limit->rlim_max;
294 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
295 "Invalid parameters for %s", cmd->cmd->name);
299 if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
303 /* if we aren't running as root, cannot increase max */
305 limit->rlim_cur = cur;
307 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
308 "Must be uid 0 to raise maximum %s", cmd->cmd->name);
313 limit->rlim_cur = cur;
316 limit->rlim_max = max;
321 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
322 "Platform does not support rlimit for %s", cmd->cmd->name);
327 APR_HOOK_LINK(get_suexec_identity)
330 AP_IMPLEMENT_HOOK_RUN_FIRST(ap_unix_identity_t *, get_suexec_identity,
331 (const request_rec *r), (r), NULL)
333 static apr_status_t ap_unix_create_privileged_process(
334 apr_proc_t *newproc, const char *progname,
335 const char * const *args,
336 const char * const *env,
337 apr_procattr_t *attr, ap_unix_identity_t *ugid,
341 const char **newargs;
343 char *execuser, *execgroup;
346 if (!unixd_config.suexec_enabled) {
347 return apr_proc_create(newproc, progname, args, env, attr, p);
350 argv0 = ap_strrchr_c(progname, '/');
351 /* Allow suexec's "/" check to succeed */
361 execuser = apr_psprintf(p, "~%ld", (long) ugid->uid);
364 execuser = apr_psprintf(p, "%ld", (long) ugid->uid);
366 execgroup = apr_psprintf(p, "%ld", (long) ugid->gid);
368 if (!execuser || !execgroup) {
378 /* allocate space for 4 new args, the input args, and a null terminator */
379 newargs = apr_palloc(p, sizeof(char *) * (i + 4));
380 newprogname = SUEXEC_BIN;
381 newargs[0] = SUEXEC_BIN;
382 newargs[1] = execuser;
383 newargs[2] = execgroup;
384 newargs[3] = apr_pstrdup(p, argv0);
387 ** using a shell to execute suexec makes no sense thus
388 ** we force everything to be APR_PROGRAM, and never
391 if(apr_procattr_cmdtype_set(attr, APR_PROGRAM) != APR_SUCCESS) {
397 newargs[i + 3] = args[i];
400 return apr_proc_create(newproc, newprogname, newargs, env, attr, p);
403 AP_DECLARE(apr_status_t) ap_os_create_privileged_process(
404 const request_rec *r,
405 apr_proc_t *newproc, const char *progname,
406 const char * const *args,
407 const char * const *env,
408 apr_procattr_t *attr, apr_pool_t *p)
410 ap_unix_identity_t *ugid = ap_run_get_suexec_identity(r);
413 return apr_proc_create(newproc, progname, args, env, attr, p);
416 return ap_unix_create_privileged_process(newproc, progname, args, env,
420 /* XXX move to APR and externalize (but implement differently :) ) */
421 static apr_lockmech_e proc_mutex_mech(apr_proc_mutex_t *pmutex)
423 const char *mechname = apr_proc_mutex_name(pmutex);
425 if (!strcmp(mechname, "sysvsem")) {
426 return APR_LOCK_SYSVSEM;
428 else if (!strcmp(mechname, "flock")) {
429 return APR_LOCK_FLOCK;
431 return APR_LOCK_DEFAULT;
434 AP_DECLARE(apr_status_t) unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex)
437 apr_lockmech_e mech = proc_mutex_mech(pmutex);
440 #if APR_HAS_SYSVSEM_SERIALIZE
441 case APR_LOCK_SYSVSEM:
443 apr_os_proc_mutex_t ospmutex;
444 #if !APR_HAVE_UNION_SEMUN
447 struct semid_ds *buf;
448 unsigned short *array;
454 apr_os_proc_mutex_get(&ospmutex, pmutex);
455 buf.sem_perm.uid = unixd_config.user_id;
456 buf.sem_perm.gid = unixd_config.group_id;
457 buf.sem_perm.mode = 0600;
459 if (semctl(ospmutex.crossproc, 0, IPC_SET, ick) < 0) {
465 #if APR_HAS_FLOCK_SERIALIZE
468 const char *lockfile = apr_proc_mutex_lockfile(pmutex);
471 if (chown(lockfile, unixd_config.user_id,
472 -1 /* no gid change */) < 0) {
487 AP_DECLARE(apr_status_t) unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex)
489 #if !APR_PROC_MUTEX_IS_GLOBAL
490 apr_os_global_mutex_t osgmutex;
491 apr_os_global_mutex_get(&osgmutex, gmutex);
492 return unixd_set_proc_mutex_perms(osgmutex.proc_mutex);
493 #else /* APR_PROC_MUTEX_IS_GLOBAL */
494 /* In this case, apr_proc_mutex_t and apr_global_mutex_t are the same. */
495 return unixd_set_proc_mutex_perms(gmutex);
496 #endif /* APR_PROC_MUTEX_IS_GLOBAL */
499 AP_DECLARE(apr_status_t) unixd_accept(void **accepted, ap_listen_rec *lr,
507 status = apr_socket_accept(&csd, lr->sd, ptrans);
508 if (status == APR_SUCCESS) {
510 apr_os_sock_get(&sockdes, csd);
511 if (sockdes >= FD_SETSIZE) {
512 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
513 "new file descriptor %d is too large; you probably need "
514 "to rebuild Apache with a larger FD_SETSIZE "
516 sockdes, FD_SETSIZE);
517 apr_socket_close(csd);
521 if (sockdes == 0) { /* 0 is invalid socket for TPF */
528 if (APR_STATUS_IS_EINTR(status)) {
531 /* Our old behaviour here was to continue after accept()
532 * errors. But this leads us into lots of troubles
533 * because most of the errors are quite fatal. For
534 * example, EMFILE can be caused by slow descriptor
535 * leaks (say in a 3rd party module, or libc). It's
536 * foolish for us to continue after an EMFILE. We also
537 * seem to tickle kernel bugs on some platforms which
538 * lead to never-ending loops here. So it seems best
539 * to just exit in most cases.
542 #if defined(HPUX11) && defined(ENOBUFS)
543 /* On HPUX 11.x, the 'ENOBUFS, No buffer space available'
544 * error occurs because the accept() cannot complete.
545 * You will not see ENOBUFS with 10.20 because the kernel
546 * hides any occurrence from being returned to user space.
547 * ENOBUFS with 11.x's TCP/IP stack is possible, and could
548 * occur intermittently. As a work-around, we are going to
555 /* EPROTO on certain older kernels really means
556 * ECONNABORTED, so we need to ignore it for them.
557 * See discussion in new-httpd archives nh.9701
560 * Also see nh.9603, search for EPROTO:
561 * There is potentially a bug in Solaris 2.x x<6,
562 * and other boxes that implement tcp sockets in
563 * userland (i.e. on top of STREAMS). On these
564 * systems, EPROTO can actually result in a fatal
565 * loop. See PR#981 for example. It's hard to
566 * handle both uses of EPROTO.
573 /* Linux generates the rest of these, other tcp
574 * stacks (i.e. bsd) tend to hide them behind
575 * getsockopt() interfaces. They occur when
576 * the net goes sour or the client disconnects
577 * after the three-way handshake has been done
578 * in the kernel but before userland has picked
597 * When the network layer has been shut down, there
598 * is not much use in simply exiting: the parent
599 * would simply re-create us (and we'd fail again).
600 * Use the CHILDFATAL code to tear the server down.
601 * @@@ Martin's idea for possible improvement:
602 * A different approach would be to define
603 * a new APEXIT_NETDOWN exit code, the reception
604 * of which would make the parent shutdown all
605 * children, then idle-loop until it detected that
606 * the network is up again, and restart the children.
607 * Ben Hyde noted that temporary ENETDOWN situations
608 * occur in mobile IP.
610 ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
611 "apr_socket_accept: giving up.");
617 ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
618 "offload device inactive");
622 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
623 "select/accept error (%d)", status);
627 ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf,
628 "apr_socket_accept: (client socket)");