1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "ap_config.h" 18#include "httpd.h" 19#include "http_config.h" 20#include "http_main.h" 21#include "http_log.h" 22#include "unixd.h" 23#include "mpm_common.h" 24#include "os.h" 25#include "ap_mpm.h" 26#include "apr_thread_proc.h" 27#include "apr_strings.h" 28#include "apr_portable.h" 29#ifdef HAVE_PWD_H 30#include <pwd.h> 31#endif 32#ifdef HAVE_SYS_RESOURCE_H 33#include <sys/resource.h> 34#endif 35/* XXX */ 36#include <sys/stat.h> 37#ifdef HAVE_UNISTD_H 38#include <unistd.h> 39#endif 40#ifdef HAVE_GRP_H 41#include <grp.h> 42#endif 43#ifdef HAVE_STRINGS_H 44#include <strings.h> 45#endif 46#ifdef HAVE_SYS_SEM_H 47#include <sys/sem.h> 48#endif 49#ifdef HAVE_SYS_PRCTL_H 50#include <sys/prctl.h> 51#endif 52 53unixd_config_rec ap_unixd_config; 54 55APLOG_USE_MODULE(core); 56 57AP_DECLARE(void) ap_unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit, 58 const char *arg, 59 const char * arg2, int type) 60{ 61#if (defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)) && APR_HAVE_STRUCT_RLIMIT && APR_HAVE_GETRLIMIT 62 char *str; 63 struct rlimit *limit; 64 /* If your platform doesn't define rlim_t then typedef it in ap_config.h */ 65 rlim_t cur = 0; 66 rlim_t max = 0; 67 68 *plimit = (struct rlimit *)apr_pcalloc(cmd->pool, sizeof(**plimit)); 69 limit = *plimit; 70 if ((getrlimit(type, limit)) != 0) { 71 *plimit = NULL; 72 ap_log_error(APLOG_MARK, APLOG_ERR, errno, cmd->server, APLOGNO(02172) 73 "%s: getrlimit failed", cmd->cmd->name); 74 return; 75 } 76 77 if (*(str = ap_getword_conf(cmd->pool, &arg)) != '\0') { 78 if (!strcasecmp(str, "max")) { 79 cur = limit->rlim_max; 80 } 81 else { 82 cur = atol(str); 83 } 84 } 85 else { 86 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server, APLOGNO(02173) 87 "Invalid parameters for %s", cmd->cmd->name); 88 return; 89 } 90 91 if (arg2 && (*(str = ap_getword_conf(cmd->pool, &arg2)) != '\0')) { 92 max = atol(str); 93 } 94 95 /* if we aren't running as root, cannot increase max */ 96 if (geteuid()) { 97 limit->rlim_cur = cur; 98 if (max && (max > limit->rlim_max)) { 99 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server, APLOGNO(02174) 100 "Must be uid 0 to raise maximum %s", cmd->cmd->name); 101 } 102 else if (max) { 103 limit->rlim_max = max; 104 } 105 } 106 else { 107 if (cur) { 108 limit->rlim_cur = cur; 109 } 110 if (max) { 111 limit->rlim_max = max; 112 } 113 } 114#else 115 116 ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server, APLOGNO(02175) 117 "Platform does not support rlimit for %s", cmd->cmd->name); 118#endif 119} 120 121APR_HOOK_STRUCT( 122 APR_HOOK_LINK(get_suexec_identity) 123) 124 125AP_IMPLEMENT_HOOK_RUN_FIRST(ap_unix_identity_t *, get_suexec_identity, 126 (const request_rec *r), (r), NULL) 127 128static apr_status_t ap_unix_create_privileged_process( 129 apr_proc_t *newproc, const char *progname, 130 const char * const *args, 131 const char * const *env, 132 apr_procattr_t *attr, ap_unix_identity_t *ugid, 133 apr_pool_t *p) 134{ 135 int i = 0; 136 const char **newargs; 137 char *newprogname; 138 char *execuser, *execgroup; 139 const char *argv0; 140 141 if (!ap_unixd_config.suexec_enabled) { 142 return apr_proc_create(newproc, progname, args, env, attr, p); 143 } 144 145 argv0 = ap_strrchr_c(progname, '/'); 146 /* Allow suexec's "/" check to succeed */ 147 if (argv0 != NULL) { 148 argv0++; 149 } 150 else { 151 argv0 = progname; 152 } 153 154 155 if (ugid->userdir) { 156 execuser = apr_psprintf(p, "~%ld", (long) ugid->uid); 157 } 158 else { 159 execuser = apr_psprintf(p, "%ld", (long) ugid->uid); 160 } 161 execgroup = apr_psprintf(p, "%ld", (long) ugid->gid); 162 163 if (!execuser || !execgroup) { 164 return APR_ENOMEM; 165 } 166 167 i = 0; 168 while (args[i]) 169 i++; 170 /* allocate space for 4 new args, the input args, and a null terminator */ 171 newargs = apr_palloc(p, sizeof(char *) * (i + 4)); 172 newprogname = SUEXEC_BIN; 173 newargs[0] = SUEXEC_BIN; 174 newargs[1] = execuser; 175 newargs[2] = execgroup; 176 newargs[3] = apr_pstrdup(p, argv0); 177 178 /* 179 ** using a shell to execute suexec makes no sense thus 180 ** we force everything to be APR_PROGRAM, and never 181 ** APR_SHELLCMD 182 */ 183 if(apr_procattr_cmdtype_set(attr, APR_PROGRAM) != APR_SUCCESS) { 184 return APR_EGENERAL; 185 } 186 187 i = 1; 188 do { 189 newargs[i + 3] = args[i]; 190 } while (args[i++]); 191 192 return apr_proc_create(newproc, newprogname, newargs, env, attr, p); 193} 194 195AP_DECLARE(apr_status_t) ap_os_create_privileged_process( 196 const request_rec *r, 197 apr_proc_t *newproc, const char *progname, 198 const char * const *args, 199 const char * const *env, 200 apr_procattr_t *attr, apr_pool_t *p) 201{ 202 ap_unix_identity_t *ugid = ap_run_get_suexec_identity(r); 203 204 if (ugid == NULL) { 205 return apr_proc_create(newproc, progname, args, env, attr, p); 206 } 207 208 return ap_unix_create_privileged_process(newproc, progname, args, env, 209 attr, ugid, p); 210} 211 212/* XXX move to APR and externalize (but implement differently :) ) */ 213static apr_lockmech_e proc_mutex_mech(apr_proc_mutex_t *pmutex) 214{ 215 const char *mechname = apr_proc_mutex_name(pmutex); 216 217 if (!strcmp(mechname, "sysvsem")) { 218 return APR_LOCK_SYSVSEM; 219 } 220 else if (!strcmp(mechname, "flock")) { 221 return APR_LOCK_FLOCK; 222 } 223 return APR_LOCK_DEFAULT; 224} 225 226AP_DECLARE(apr_status_t) ap_unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex) 227{ 228 if (!geteuid()) { 229 apr_lockmech_e mech = proc_mutex_mech(pmutex); 230 231 switch(mech) { 232#if APR_HAS_SYSVSEM_SERIALIZE 233 case APR_LOCK_SYSVSEM: 234 { 235 apr_os_proc_mutex_t ospmutex; 236#if !APR_HAVE_UNION_SEMUN 237 union semun { 238 long val; 239 struct semid_ds *buf; 240 unsigned short *array; 241 }; 242#endif 243 union semun ick; 244 struct semid_ds buf = { { 0 } }; 245 246 apr_os_proc_mutex_get(&ospmutex, pmutex); 247 buf.sem_perm.uid = ap_unixd_config.user_id; 248 buf.sem_perm.gid = ap_unixd_config.group_id; 249 buf.sem_perm.mode = 0600; 250 ick.buf = &buf; 251 if (semctl(ospmutex.crossproc, 0, IPC_SET, ick) < 0) { 252 return errno; 253 } 254 } 255 break; 256#endif 257#if APR_HAS_FLOCK_SERIALIZE 258 case APR_LOCK_FLOCK: 259 { 260 const char *lockfile = apr_proc_mutex_lockfile(pmutex); 261 262 if (lockfile) { 263 if (chown(lockfile, ap_unixd_config.user_id, 264 -1 /* no gid change */) < 0) { 265 return errno; 266 } 267 } 268 } 269 break; 270#endif 271 default: 272 /* do nothing */ 273 break; 274 } 275 } 276 return APR_SUCCESS; 277} 278 279AP_DECLARE(apr_status_t) ap_unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex) 280{ 281#if !APR_PROC_MUTEX_IS_GLOBAL 282 apr_os_global_mutex_t osgmutex; 283 apr_os_global_mutex_get(&osgmutex, gmutex); 284 return ap_unixd_set_proc_mutex_perms(osgmutex.proc_mutex); 285#else /* APR_PROC_MUTEX_IS_GLOBAL */ 286 /* In this case, apr_proc_mutex_t and apr_global_mutex_t are the same. */ 287 return ap_unixd_set_proc_mutex_perms(gmutex); 288#endif /* APR_PROC_MUTEX_IS_GLOBAL */ 289} 290 291AP_DECLARE(apr_status_t) ap_unixd_accept(void **accepted, ap_listen_rec *lr, 292 apr_pool_t *ptrans) 293{ 294 apr_socket_t *csd; 295 apr_status_t status; 296#ifdef _OSD_POSIX 297 int sockdes; 298#endif 299 300 *accepted = NULL; 301 status = apr_socket_accept(&csd, lr->sd, ptrans); 302 if (status == APR_SUCCESS) { 303 *accepted = csd; 304#ifdef _OSD_POSIX 305 apr_os_sock_get(&sockdes, csd); 306 if (sockdes >= FD_SETSIZE) { 307 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, APLOGNO(02176) 308 "new file descriptor %d is too large; you probably need " 309 "to rebuild Apache with a larger FD_SETSIZE " 310 "(currently %d)", 311 sockdes, FD_SETSIZE); 312 apr_socket_close(csd); 313 return APR_EINTR; 314 } 315#endif 316 return APR_SUCCESS; 317 } 318 319 if (APR_STATUS_IS_EINTR(status)) { 320 return status; 321 } 322 /* Our old behaviour here was to continue after accept() 323 * errors. But this leads us into lots of troubles 324 * because most of the errors are quite fatal. For 325 * example, EMFILE can be caused by slow descriptor 326 * leaks (say in a 3rd party module, or libc). It's 327 * foolish for us to continue after an EMFILE. We also 328 * seem to tickle kernel bugs on some platforms which 329 * lead to never-ending loops here. So it seems best 330 * to just exit in most cases. 331 */ 332 switch (status) { 333#if defined(HPUX11) && defined(ENOBUFS) 334 /* On HPUX 11.x, the 'ENOBUFS, No buffer space available' 335 * error occurs because the accept() cannot complete. 336 * You will not see ENOBUFS with 10.20 because the kernel 337 * hides any occurrence from being returned to user space. 338 * ENOBUFS with 11.x's TCP/IP stack is possible, and could 339 * occur intermittently. As a work-around, we are going to 340 * ignore ENOBUFS. 341 */ 342 case ENOBUFS: 343#endif 344 345#ifdef EPROTO 346 /* EPROTO on certain older kernels really means 347 * ECONNABORTED, so we need to ignore it for them. 348 * See discussion in new-httpd archives nh.9701 349 * search for EPROTO. 350 * 351 * Also see nh.9603, search for EPROTO: 352 * There is potentially a bug in Solaris 2.x x<6, 353 * and other boxes that implement tcp sockets in 354 * userland (i.e. on top of STREAMS). On these 355 * systems, EPROTO can actually result in a fatal 356 * loop. See PR#981 for example. It's hard to 357 * handle both uses of EPROTO. 358 */ 359 case EPROTO: 360#endif 361#ifdef ECONNABORTED 362 case ECONNABORTED: 363#endif 364 /* Linux generates the rest of these, other tcp 365 * stacks (i.e. bsd) tend to hide them behind 366 * getsockopt() interfaces. They occur when 367 * the net goes sour or the client disconnects 368 * after the three-way handshake has been done 369 * in the kernel but before userland has picked 370 * up the socket. 371 */ 372#ifdef ECONNRESET 373 case ECONNRESET: 374#endif 375#ifdef ETIMEDOUT 376 case ETIMEDOUT: 377#endif 378#ifdef EHOSTUNREACH 379 case EHOSTUNREACH: 380#endif 381#ifdef ENETUNREACH 382 case ENETUNREACH: 383#endif 384 /* EAGAIN/EWOULDBLOCK can be returned on BSD-derived 385 * TCP stacks when the connection is aborted before 386 * we call connect, but only because our listener 387 * sockets are non-blocking (AP_NONBLOCK_WHEN_MULTI_LISTEN) 388 */ 389#ifdef EAGAIN 390 case EAGAIN: 391#endif 392#ifdef EWOULDBLOCK 393#if !defined(EAGAIN) || EAGAIN != EWOULDBLOCK 394 case EWOULDBLOCK: 395#endif 396#endif 397 break; 398#ifdef ENETDOWN 399 case ENETDOWN: 400 /* 401 * When the network layer has been shut down, there 402 * is not much use in simply exiting: the parent 403 * would simply re-create us (and we'd fail again). 404 * Use the CHILDFATAL code to tear the server down. 405 * @@@ Martin's idea for possible improvement: 406 * A different approach would be to define 407 * a new APEXIT_NETDOWN exit code, the reception 408 * of which would make the parent shutdown all 409 * children, then idle-loop until it detected that 410 * the network is up again, and restart the children. 411 * Ben Hyde noted that temporary ENETDOWN situations 412 * occur in mobile IP. 413 */ 414 ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, APLOGNO(02177) 415 "apr_socket_accept: giving up."); 416 return APR_EGENERAL; 417#endif /*ENETDOWN*/ 418 419 default: 420 /* If the socket has been closed in ap_close_listeners() 421 * by the restart/stop action, we may get EBADF. 422 * Do not print an error in this case. 423 */ 424 if (!lr->active) { 425 ap_log_error(APLOG_MARK, APLOG_DEBUG, status, ap_server_conf, APLOGNO(02178) 426 "apr_socket_accept failed for inactive listener"); 427 return status; 428 } 429 ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf, APLOGNO(02179) 430 "apr_socket_accept: (client socket)"); 431 return APR_EGENERAL; 432 } 433 return status; 434} 435 436 437#ifdef _OSD_POSIX 438 439#include "apr_lib.h" 440 441#define USER_LEN 8 442 443typedef enum 444{ 445 bs2_unknown, /* not initialized yet. */ 446 bs2_noFORK, /* no fork() because -X flag was specified */ 447 bs2_FORK, /* only fork() because uid != 0 */ 448 bs2_UFORK /* Normally, ufork() is used to switch identities. */ 449} bs2_ForkType; 450 451static bs2_ForkType forktype = bs2_unknown; 452 453/* Determine the method for forking off a child in such a way as to 454 * set both the POSIX and BS2000 user id's to the unprivileged user. 455 */ 456static bs2_ForkType os_forktype(int one_process) 457{ 458 /* have we checked the OS version before? If yes return the previous 459 * result - the OS release isn't going to change suddenly! 460 */ 461 if (forktype == bs2_unknown) { 462 /* not initialized yet */ 463 464 /* No fork if the one_process option was set */ 465 if (one_process) { 466 forktype = bs2_noFORK; 467 } 468 /* If the user is unprivileged, use the normal fork() only. */ 469 else if (getuid() != 0) { 470 forktype = bs2_FORK; 471 } 472 else 473 forktype = bs2_UFORK; 474 } 475 return forktype; 476} 477 478 479 480/* This routine complements the setuid() call: it causes the BS2000 job 481 * environment to be switched to the target user's user id. 482 * That is important if CGI scripts try to execute native BS2000 commands. 483 */ 484int os_init_job_environment(server_rec *server, const char *user_name, int one_process) 485{ 486 bs2_ForkType type = os_forktype(one_process); 487 488 /* We can be sure that no change to uid==0 is possible because of 489 * the checks in http_core.c:set_user() 490 */ 491 492 if (one_process) { 493 494 type = forktype = bs2_noFORK; 495 496 ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, APLOGNO(02180) 497 "The debug mode of Apache should only " 498 "be started by an unprivileged user!"); 499 return 0; 500 } 501 502 return 0; 503} 504 505/* BS2000 requires a "special" version of fork() before a setuid() call */ 506pid_t os_fork(const char *user) 507{ 508 pid_t pid; 509 char username[USER_LEN+1]; 510 511 switch (os_forktype(0)) { 512 513 case bs2_FORK: 514 pid = fork(); 515 break; 516 517 case bs2_UFORK: 518 apr_cpystrn(username, user, sizeof username); 519 520 /* Make user name all upper case - for some versions of ufork() */ 521 ap_str_toupper(username); 522 523 pid = ufork(username); 524 if (pid == -1 && errno == EPERM) { 525 ap_log_error(APLOG_MARK, APLOG_EMERG, errno, 526 ap_server_conf, APLOGNO(02181) "ufork: Possible mis-configuration " 527 "for user %s - Aborting.", user); 528 exit(1); 529 } 530 break; 531 532 default: 533 pid = 0; 534 break; 535 } 536 537 return pid; 538} 539 540#endif /* _OSD_POSIX */ 541 542