1 /* Copyright 1999-2004 The Apache Software Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include "ap_config.h"
19 #include "http_config.h"
20 #include "http_main.h"
23 #include "mpm_common.h"
26 #include "apr_thread_proc.h"
27 #include "apr_strings.h"
28 #include "apr_portable.h"
32 #ifdef HAVE_SYS_RESOURCE_H
33 #include <sys/resource.h>
49 #ifdef HAVE_SYS_PRCTL_H
50 #include <sys/prctl.h>
53 unixd_config_rec unixd_config;
55 /* Set group privileges.
57 * Note that we use the username as set in the config files, rather than
58 * the lookup of to uid --- the same uid may have multiple passwd entries,
59 * with different sets of groups for each.
62 static int set_group_privs(void)
67 /* Get username if passed as a uid */
69 if (unixd_config.user_name[0] == '#') {
71 uid_t uid = atoi(&unixd_config.user_name[1]);
73 if ((ent = getpwuid(uid)) == NULL) {
74 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
75 "getpwuid: couldn't determine user name from uid %u, "
76 "you probably need to modify the User directive",
84 name = unixd_config.user_name;
86 #if !defined(OS2) && !defined(TPF)
87 /* OS/2 and TPF don't support groups. */
90 * Set the GID before initgroups(), since on some platforms
91 * setgid() is known to zap the group list.
93 if (setgid(unixd_config.group_id) == -1) {
94 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
95 "setgid: unable to set group id to Group %u",
96 (unsigned)unixd_config.group_id);
100 /* Reset `groups' attributes. */
102 if (initgroups(name, unixd_config.group_id) == -1) {
103 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
104 "initgroups: unable to set groups for User %s "
105 "and Group %u", name, (unsigned)unixd_config.group_id);
108 #endif /* !defined(OS2) && !defined(TPF) */
114 AP_DECLARE(int) unixd_setup_child(void)
116 if (set_group_privs()) {
120 /* Only try to switch if we're running as MANAGER.SYS */
121 if (geteuid() == 1 && unixd_config.user_id > 1) {
123 if (setuid(unixd_config.user_id) == -1) {
125 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
126 "setuid: unable to change to uid: %ld",
127 (long) unixd_config.user_id);
133 /* Only try to switch if we're running as root */
136 os_init_job_environment(NULL, unixd_config.user_name, ap_exists_config_define("DEBUG")) != 0 ||
138 setuid(unixd_config.user_id) == -1)) {
139 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
140 "setuid: unable to change to uid: %ld",
141 (long) unixd_config.user_id);
144 #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
145 /* this applies to Linux 2.4+ */
146 #ifdef AP_MPM_WANT_SET_COREDUMPDIR
147 if (ap_coredumpdir_configured) {
148 if (prctl(PR_SET_DUMPABLE, 1)) {
149 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
150 "set dumpable failed - this child will not coredump"
151 " after software errors");
161 AP_DECLARE(const char *) unixd_set_user(cmd_parms *cmd, void *dummy,
164 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
169 unixd_config.user_name = arg;
170 unixd_config.user_id = ap_uname2id(arg);
171 #if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
172 if (unixd_config.user_id == 0) {
173 return "Error:\tApache has not been designed to serve pages while\n"
174 "\trunning as root. There are known race conditions that\n"
175 "\twill allow any local user to read any file on the system.\n"
176 "\tIf you still desire to serve pages as root then\n"
177 "\tadd -DBIG_SECURITY_HOLE to the CFLAGS env variable\n"
178 "\tand then rebuild the server.\n"
179 "\tIt is strongly suggested that you instead modify the User\n"
180 "\tdirective in your httpd.conf file to list a non-root\n"
188 AP_DECLARE(const char *) unixd_set_group(cmd_parms *cmd, void *dummy,
191 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
196 unixd_config.group_id = ap_gname2id(arg);
201 AP_DECLARE(void) unixd_pre_config(apr_pool_t *ptemp)
205 unixd_config.user_name = DEFAULT_USER;
206 unixd_config.user_id = ap_uname2id(DEFAULT_USER);
207 unixd_config.group_id = ap_gname2id(DEFAULT_GROUP);
209 /* Check for suexec */
210 unixd_config.suexec_enabled = 0;
211 if ((apr_stat(&wrapper, SUEXEC_BIN,
212 APR_FINFO_NORM, ptemp)) != APR_SUCCESS) {
216 if ((wrapper.protection & APR_USETID) && wrapper.user == 0) {
217 unixd_config.suexec_enabled = 1;
222 AP_DECLARE(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit,
223 const char *arg, const char * arg2, int type)
225 #if (defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)) && APR_HAVE_STRUCT_RLIMIT && APR_HAVE_GETRLIMIT
227 struct rlimit *limit;
228 /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
232 *plimit = (struct rlimit *)apr_pcalloc(cmd->pool, sizeof(**plimit));
234 if ((getrlimit(type, limit)) != 0) {
236 ap_log_error(APLOG_MARK, APLOG_ERR, errno, cmd->server,
237 "%s: getrlimit failed", cmd->cmd->name);
241 if ((str = ap_getword_conf(cmd->pool, &arg))) {
242 if (!strcasecmp(str, "max")) {
243 cur = limit->rlim_max;
250 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
251 "Invalid parameters for %s", cmd->cmd->name);
255 if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
259 /* if we aren't running as root, cannot increase max */
261 limit->rlim_cur = cur;
263 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
264 "Must be uid 0 to raise maximum %s", cmd->cmd->name);
269 limit->rlim_cur = cur;
272 limit->rlim_max = max;
277 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
278 "Platform does not support rlimit for %s", cmd->cmd->name);
283 APR_HOOK_LINK(get_suexec_identity)
286 AP_IMPLEMENT_HOOK_RUN_FIRST(ap_unix_identity_t *, get_suexec_identity,
287 (const request_rec *r), (r), NULL)
289 static apr_status_t ap_unix_create_privileged_process(
290 apr_proc_t *newproc, const char *progname,
291 const char * const *args,
292 const char * const *env,
293 apr_procattr_t *attr, ap_unix_identity_t *ugid,
297 const char **newargs;
299 char *execuser, *execgroup;
302 if (!unixd_config.suexec_enabled) {
303 return apr_proc_create(newproc, progname, args, env, attr, p);
306 argv0 = ap_strrchr_c(progname, '/');
307 /* Allow suexec's "/" check to succeed */
317 execuser = apr_psprintf(p, "~%ld", (long) ugid->uid);
320 execuser = apr_psprintf(p, "%ld", (long) ugid->uid);
322 execgroup = apr_psprintf(p, "%ld", (long) ugid->gid);
324 if (!execuser || !execgroup) {
334 /* allocate space for 4 new args, the input args, and a null terminator */
335 newargs = apr_palloc(p, sizeof(char *) * (i + 4));
336 newprogname = SUEXEC_BIN;
337 newargs[0] = SUEXEC_BIN;
338 newargs[1] = execuser;
339 newargs[2] = execgroup;
340 newargs[3] = apr_pstrdup(p, argv0);
343 ** using a shell to execute suexec makes no sense thus
344 ** we force everything to be APR_PROGRAM, and never
347 if(apr_procattr_cmdtype_set(attr, APR_PROGRAM) != APR_SUCCESS) {
353 newargs[i + 3] = args[i];
356 return apr_proc_create(newproc, newprogname, newargs, env, attr, p);
359 AP_DECLARE(apr_status_t) ap_os_create_privileged_process(
360 const request_rec *r,
361 apr_proc_t *newproc, const char *progname,
362 const char * const *args,
363 const char * const *env,
364 apr_procattr_t *attr, apr_pool_t *p)
366 ap_unix_identity_t *ugid = ap_run_get_suexec_identity(r);
369 return apr_proc_create(newproc, progname, args, env, attr, p);
372 return ap_unix_create_privileged_process(newproc, progname, args, env,
376 /* XXX move to APR and externalize (but implement differently :) ) */
377 static apr_lockmech_e proc_mutex_mech(apr_proc_mutex_t *pmutex)
379 const char *mechname = apr_proc_mutex_name(pmutex);
381 if (!strcmp(mechname, "sysvsem")) {
382 return APR_LOCK_SYSVSEM;
384 else if (!strcmp(mechname, "flock")) {
385 return APR_LOCK_FLOCK;
387 return APR_LOCK_DEFAULT;
390 AP_DECLARE(apr_status_t) unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex)
393 apr_lockmech_e mech = proc_mutex_mech(pmutex);
396 #if APR_HAS_SYSVSEM_SERIALIZE
397 case APR_LOCK_SYSVSEM:
399 apr_os_proc_mutex_t ospmutex;
400 #if !APR_HAVE_UNION_SEMUN
403 struct semid_ds *buf;
404 unsigned short *array;
410 apr_os_proc_mutex_get(&ospmutex, pmutex);
411 buf.sem_perm.uid = unixd_config.user_id;
412 buf.sem_perm.gid = unixd_config.group_id;
413 buf.sem_perm.mode = 0600;
415 if (semctl(ospmutex.crossproc, 0, IPC_SET, ick) < 0) {
421 #if APR_HAS_FLOCK_SERIALIZE
424 const char *lockfile = apr_proc_mutex_lockfile(pmutex);
427 if (chown(lockfile, unixd_config.user_id,
428 -1 /* no gid change */) < 0) {
443 AP_DECLARE(apr_status_t) unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex)
445 #if !APR_PROC_MUTEX_IS_GLOBAL
446 apr_os_global_mutex_t osgmutex;
447 apr_os_global_mutex_get(&osgmutex, gmutex);
448 return unixd_set_proc_mutex_perms(osgmutex.proc_mutex);
449 #else /* APR_PROC_MUTEX_IS_GLOBAL */
450 /* In this case, apr_proc_mutex_t and apr_global_mutex_t are the same. */
451 return unixd_set_proc_mutex_perms(gmutex);
452 #endif /* APR_PROC_MUTEX_IS_GLOBAL */
455 AP_DECLARE(apr_status_t) unixd_accept(void **accepted, ap_listen_rec *lr,
462 status = apr_socket_accept(&csd, lr->sd, ptrans);
463 if (status == APR_SUCCESS) {
468 if (APR_STATUS_IS_EINTR(status)) {
471 /* Our old behaviour here was to continue after accept()
472 * errors. But this leads us into lots of troubles
473 * because most of the errors are quite fatal. For
474 * example, EMFILE can be caused by slow descriptor
475 * leaks (say in a 3rd party module, or libc). It's
476 * foolish for us to continue after an EMFILE. We also
477 * seem to tickle kernel bugs on some platforms which
478 * lead to never-ending loops here. So it seems best
479 * to just exit in most cases.
482 #if defined(HPUX11) && defined(ENOBUFS)
483 /* On HPUX 11.x, the 'ENOBUFS, No buffer space available'
484 * error occurs because the accept() cannot complete.
485 * You will not see ENOBUFS with 10.20 because the kernel
486 * hides any occurrence from being returned to user space.
487 * ENOBUFS with 11.x's TCP/IP stack is possible, and could
488 * occur intermittently. As a work-around, we are going to
495 /* EPROTO on certain older kernels really means
496 * ECONNABORTED, so we need to ignore it for them.
497 * See discussion in new-httpd archives nh.9701
500 * Also see nh.9603, search for EPROTO:
501 * There is potentially a bug in Solaris 2.x x<6,
502 * and other boxes that implement tcp sockets in
503 * userland (i.e. on top of STREAMS). On these
504 * systems, EPROTO can actually result in a fatal
505 * loop. See PR#981 for example. It's hard to
506 * handle both uses of EPROTO.
513 /* Linux generates the rest of these, other tcp
514 * stacks (i.e. bsd) tend to hide them behind
515 * getsockopt() interfaces. They occur when
516 * the net goes sour or the client disconnects
517 * after the three-way handshake has been done
518 * in the kernel but before userland has picked
533 /* EAGAIN/EWOULDBLOCK can be returned on BSD-derived
534 * TCP stacks when the connection is aborted before
535 * we call connect, but only because our listener
536 * sockets are non-blocking (AP_NONBLOCK_WHEN_MULTI_LISTEN)
542 #if !defined(EAGAIN) || EAGAIN != EWOULDBLOCK
550 * When the network layer has been shut down, there
551 * is not much use in simply exiting: the parent
552 * would simply re-create us (and we'd fail again).
553 * Use the CHILDFATAL code to tear the server down.
554 * @@@ Martin's idea for possible improvement:
555 * A different approach would be to define
556 * a new APEXIT_NETDOWN exit code, the reception
557 * of which would make the parent shutdown all
558 * children, then idle-loop until it detected that
559 * the network is up again, and restart the children.
560 * Ben Hyde noted that temporary ENETDOWN situations
561 * occur in mobile IP.
563 ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
564 "apr_socket_accept: giving up.");
570 ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,
571 "offload device inactive");
575 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
576 "select/accept error (%d)", status);
580 ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf,
581 "apr_socket_accept: (client socket)");