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/* 18 * http_script: keeps all script-related ramblings together. 19 * 20 * Compliant to cgi/1.1 spec 21 * 22 * Adapted by rst from original NCSA code by Rob McCool 23 * 24 * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for 25 * custom error responses, and DOCUMENT_ROOT because we found it useful. 26 * It also adds SERVER_ADMIN - useful for scripts to know who to mail when 27 * they fail. 28 */ 29 30#include "apr_lib.h" 31#include "apr_strings.h" 32#include "apr_general.h" 33#include "apr_file_io.h" 34#include "apr_portable.h" 35#include "apr_buckets.h" 36#include "apr_optional.h" 37#include "apr_signal.h" 38 39#define APR_WANT_STRFUNC 40#include "apr_want.h" 41 42#if APR_HAVE_SYS_SOCKET_H 43#include <sys/socket.h> 44#endif 45#if APR_HAVE_UNISTD_H 46#include <unistd.h> 47#endif 48#if APR_HAVE_SYS_TYPES_H 49#include <sys/types.h> 50#endif 51 52#include "util_filter.h" 53#include "httpd.h" 54#include "http_config.h" 55#include "http_request.h" 56#include "http_core.h" 57#include "http_protocol.h" 58#include "http_main.h" 59#include "http_log.h" 60#include "util_script.h" 61#include "ap_mpm.h" 62#include "mpm_common.h" 63#include "mod_suexec.h" 64#include "../filters/mod_include.h" 65 66#include "mod_core.h" 67 68 69/* ### should be tossed in favor of APR */ 70#include <sys/stat.h> 71#include <sys/un.h> /* for sockaddr_un */ 72 73#if APR_HAVE_STRUCT_RLIMIT 74#if defined (RLIMIT_CPU) || defined (RLIMIT_NPROC) || defined (RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) 75#define AP_CGID_USE_RLIMIT 76#endif 77#endif 78 79module AP_MODULE_DECLARE_DATA cgid_module; 80 81static int cgid_start(apr_pool_t *p, server_rec *main_server, apr_proc_t *procnew); 82static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server); 83static int handle_exec(include_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *bb); 84 85static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgid_pfn_reg_with_ssi; 86static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgid_pfn_gtv; 87static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgid_pfn_ps; 88 89static apr_pool_t *pcgi = NULL; 90static pid_t daemon_pid; 91static int daemon_should_exit = 0; 92static server_rec *root_server = NULL; 93static apr_pool_t *root_pool = NULL; 94static const char *sockname; 95static struct sockaddr_un *server_addr; 96static apr_socklen_t server_addr_len; 97static pid_t parent_pid; 98static ap_unix_identity_t empty_ugid = { (uid_t)-1, (gid_t)-1, -1 }; 99 100/* The APR other-child API doesn't tell us how the daemon exited 101 * (SIGSEGV vs. exit(1)). The other-child maintenance function 102 * needs to decide whether to restart the daemon after a failure 103 * based on whether or not it exited due to a fatal startup error 104 * or something that happened at steady-state. This exit status 105 * is unlikely to collide with exit signals. 106 */ 107#define DAEMON_STARTUP_ERROR 254 108 109/* Read and discard the data in the brigade produced by a CGI script */ 110static void discard_script_output(apr_bucket_brigade *bb); 111 112/* This doer will only ever be called when we are sure that we have 113 * a valid ugid. 114 */ 115static ap_unix_identity_t *cgid_suexec_id_doer(const request_rec *r) 116{ 117 return (ap_unix_identity_t *) 118 ap_get_module_config(r->request_config, &cgid_module); 119} 120 121/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI 122 * in ScriptAliased directories, which means we need to know if this 123 * request came through ScriptAlias or not... so the Alias module 124 * leaves a note for us. 125 */ 126 127static int is_scriptaliased(request_rec *r) 128{ 129 const char *t = apr_table_get(r->notes, "alias-forced-type"); 130 return t && (!strcasecmp(t, "cgi-script")); 131} 132 133/* Configuration stuff */ 134 135#define DEFAULT_LOGBYTES 10385760 136#define DEFAULT_BUFBYTES 1024 137#define DEFAULT_SOCKET "cgisock" 138 139#define CGI_REQ 1 140#define SSI_REQ 2 141#define GETPID_REQ 3 /* get the pid of script created for prior request */ 142 143#define ERRFN_USERDATA_KEY "CGIDCHILDERRFN" 144 145/* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's 146 * pending connection queue. If a bunch of cgi requests arrive at about 147 * the same time, connections from httpd threads/processes will back up 148 * in the queue while the cgid process slowly forks off a child to process 149 * each connection on the unix socket. If the queue is too short, the 150 * httpd process will get ECONNREFUSED when trying to connect. 151 */ 152#ifndef DEFAULT_CGID_LISTENBACKLOG 153#define DEFAULT_CGID_LISTENBACKLOG 100 154#endif 155 156/* DEFAULT_CONNECT_ATTEMPTS controls how many times we'll try to connect 157 * to the cgi daemon from the thread/process handling the cgi request. 158 * Generally we want to retry when we get ECONNREFUSED since it is 159 * probably because the listen queue is full. We need to try harder so 160 * the client doesn't see it as a 503 error. 161 * 162 * Set this to 0 to continually retry until the connect works or Apache 163 * terminates. 164 */ 165#ifndef DEFAULT_CONNECT_ATTEMPTS 166#define DEFAULT_CONNECT_ATTEMPTS 15 167#endif 168 169typedef struct { 170 const char *logname; 171 long logbytes; 172 int bufbytes; 173} cgid_server_conf; 174 175#ifdef AP_CGID_USE_RLIMIT 176typedef struct { 177#ifdef RLIMIT_CPU 178 int limit_cpu_set; 179 struct rlimit limit_cpu; 180#endif 181#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) 182 int limit_mem_set; 183 struct rlimit limit_mem; 184#endif 185#ifdef RLIMIT_NPROC 186 int limit_nproc_set; 187 struct rlimit limit_nproc; 188#endif 189 190} cgid_rlimit_t; 191#endif 192 193typedef struct { 194 int req_type; /* request type (CGI_REQ, SSI_REQ, etc.) */ 195 unsigned long conn_id; /* connection id; daemon uses this as a hash value 196 * to find the script pid when it is time for that 197 * process to be cleaned up 198 */ 199 pid_t ppid; /* sanity check for config problems leading to 200 * wrong cgid socket use 201 */ 202 int env_count; 203 ap_unix_identity_t ugid; 204 apr_size_t filename_len; 205 apr_size_t argv0_len; 206 apr_size_t uri_len; 207 apr_size_t args_len; 208 int loglevel; /* to stuff in server_rec */ 209 210#ifdef AP_CGID_USE_RLIMIT 211 cgid_rlimit_t limits; 212#endif 213} cgid_req_t; 214 215/* This routine is called to create the argument list to be passed 216 * to the CGI script. When suexec is enabled, the suexec path, user, and 217 * group are the first three arguments to be passed; if not, all three 218 * must be NULL. The query info is split into separate arguments, where 219 * "+" is the separator between keyword arguments. 220 * 221 * Do not process the args if they containing an '=' assignment. 222 */ 223static char **create_argv(apr_pool_t *p, char *path, char *user, char *group, 224 char *av0, const char *args) 225{ 226 int x, numwords; 227 char **av; 228 char *w; 229 int idx = 0; 230 231 if (!(*args) || ap_strchr_c(args, '=')) { 232 numwords = 0; 233 } 234 else { 235 /* count the number of keywords */ 236 237 for (x = 0, numwords = 1; args[x]; x++) { 238 if (args[x] == '+') { 239 ++numwords; 240 } 241 } 242 } 243 244 if (numwords > APACHE_ARG_MAX - 5) { 245 numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */ 246 } 247 av = (char **) apr_pcalloc(p, (numwords + 5) * sizeof(char *)); 248 249 if (path) { 250 av[idx++] = path; 251 } 252 if (user) { 253 av[idx++] = user; 254 } 255 if (group) { 256 av[idx++] = group; 257 } 258 259 av[idx++] = apr_pstrdup(p, av0); 260 261 for (x = 1; x <= numwords; x++) { 262 w = ap_getword_nulls(p, &args, '+'); 263 ap_unescape_url(w); 264 av[idx++] = ap_escape_shell_cmd(p, w); 265 } 266 av[idx] = NULL; 267 return av; 268} 269 270#if APR_HAS_OTHER_CHILD 271static void cgid_maint(int reason, void *data, apr_wait_t status) 272{ 273 apr_proc_t *proc = data; 274 int mpm_state; 275 int stopping; 276 277 switch (reason) { 278 case APR_OC_REASON_DEATH: 279 apr_proc_other_child_unregister(data); 280 /* If apache is not terminating or restarting, 281 * restart the cgid daemon 282 */ 283 stopping = 1; /* if MPM doesn't support query, 284 * assume we shouldn't restart daemon 285 */ 286 if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state) == APR_SUCCESS && 287 mpm_state != AP_MPMQ_STOPPING) { 288 stopping = 0; 289 } 290 if (!stopping) { 291 if (status == DAEMON_STARTUP_ERROR) { 292 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, APLOGNO(01238) 293 "cgid daemon failed to initialize"); 294 } 295 else { 296 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(01239) 297 "cgid daemon process died, restarting"); 298 cgid_start(root_pool, root_server, proc); 299 } 300 } 301 break; 302 case APR_OC_REASON_RESTART: 303 /* don't do anything; server is stopping or restarting */ 304 apr_proc_other_child_unregister(data); 305 break; 306 case APR_OC_REASON_LOST: 307 /* Restart the child cgid daemon process */ 308 apr_proc_other_child_unregister(data); 309 cgid_start(root_pool, root_server, proc); 310 break; 311 case APR_OC_REASON_UNREGISTER: 312 /* we get here when pcgi is cleaned up; pcgi gets cleaned 313 * up when pconf gets cleaned up 314 */ 315 kill(proc->pid, SIGHUP); /* send signal to daemon telling it to die */ 316 317 /* Remove the cgi socket, we must do it here in order to try and 318 * guarantee the same permissions as when the socket was created. 319 */ 320 if (unlink(sockname) < 0 && errno != ENOENT) { 321 ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, APLOGNO(01240) 322 "Couldn't unlink unix domain socket %s", 323 sockname); 324 } 325 break; 326 } 327} 328#endif 329 330static apr_status_t close_unix_socket(void *thefd) 331{ 332 int fd = (int)((long)thefd); 333 334 return close(fd); 335} 336 337/* deal with incomplete reads and signals 338 * assume you really have to read buf_size bytes 339 */ 340static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) 341{ 342 char *buf = vbuf; 343 int rc; 344 size_t bytes_read = 0; 345 346 do { 347 do { 348 rc = read(fd, buf + bytes_read, buf_size - bytes_read); 349 } while (rc < 0 && errno == EINTR); 350 switch(rc) { 351 case -1: 352 return errno; 353 case 0: /* unexpected */ 354 return ECONNRESET; 355 default: 356 bytes_read += rc; 357 } 358 } while (bytes_read < buf_size); 359 360 return APR_SUCCESS; 361} 362 363/* deal with signals 364 */ 365static apr_status_t sock_write(int fd, const void *buf, size_t buf_size) 366{ 367 int rc; 368 369 do { 370 rc = write(fd, buf, buf_size); 371 } while (rc < 0 && errno == EINTR); 372 if (rc < 0) { 373 return errno; 374 } 375 376 return APR_SUCCESS; 377} 378 379static apr_status_t sock_writev(int fd, request_rec *r, int count, ...) 380{ 381 va_list ap; 382 int rc; 383 struct iovec *vec; 384 int i; 385 386 vec = (struct iovec *)apr_palloc(r->pool, count * sizeof(struct iovec)); 387 va_start(ap, count); 388 for (i = 0; i < count; i++) { 389 vec[i].iov_base = va_arg(ap, caddr_t); 390 vec[i].iov_len = va_arg(ap, apr_size_t); 391 } 392 va_end(ap); 393 394 do { 395 rc = writev(fd, vec, count); 396 } while (rc < 0 && errno == EINTR); 397 if (rc < 0) { 398 return errno; 399 } 400 401 return APR_SUCCESS; 402} 403 404static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, 405 cgid_req_t *req) 406{ 407 int i; 408 char **environ; 409 core_request_config *temp_core; 410 void **rconf; 411 apr_status_t stat; 412 413 r->server = apr_pcalloc(r->pool, sizeof(server_rec)); 414 415 /* read the request header */ 416 stat = sock_read(fd, req, sizeof(*req)); 417 if (stat != APR_SUCCESS) { 418 return stat; 419 } 420 r->server->log.level = req->loglevel; 421 if (req->req_type == GETPID_REQ) { 422 /* no more data sent for this request */ 423 return APR_SUCCESS; 424 } 425 426 /* handle module indexes and such */ 427 rconf = (void **)ap_create_request_config(r->pool); 428 429 temp_core = (core_request_config *)apr_palloc(r->pool, sizeof(core_module)); 430 rconf[AP_CORE_MODULE_INDEX] = (void *)temp_core; 431 r->request_config = (ap_conf_vector_t *)rconf; 432 ap_set_module_config(r->request_config, &cgid_module, (void *)&req->ugid); 433 434 /* Read the filename, argv0, uri, and args */ 435 r->filename = apr_pcalloc(r->pool, req->filename_len + 1); 436 *argv0 = apr_pcalloc(r->pool, req->argv0_len + 1); 437 r->uri = apr_pcalloc(r->pool, req->uri_len + 1); 438 if ((stat = sock_read(fd, r->filename, req->filename_len)) != APR_SUCCESS || 439 (stat = sock_read(fd, *argv0, req->argv0_len)) != APR_SUCCESS || 440 (stat = sock_read(fd, r->uri, req->uri_len)) != APR_SUCCESS) { 441 return stat; 442 } 443 444 r->args = apr_pcalloc(r->pool, req->args_len + 1); /* empty string if no args */ 445 if (req->args_len) { 446 if ((stat = sock_read(fd, r->args, req->args_len)) != APR_SUCCESS) { 447 return stat; 448 } 449 } 450 451 /* read the environment variables */ 452 environ = apr_pcalloc(r->pool, (req->env_count + 2) *sizeof(char *)); 453 for (i = 0; i < req->env_count; i++) { 454 apr_size_t curlen; 455 456 if ((stat = sock_read(fd, &curlen, sizeof(curlen))) != APR_SUCCESS) { 457 return stat; 458 } 459 environ[i] = apr_pcalloc(r->pool, curlen + 1); 460 if ((stat = sock_read(fd, environ[i], curlen)) != APR_SUCCESS) { 461 return stat; 462 } 463 } 464 *env = environ; 465 466#ifdef AP_CGID_USE_RLIMIT 467 if ((stat = sock_read(fd, &(req->limits), sizeof(cgid_rlimit_t))) != APR_SUCCESS) 468 return stat; 469#endif 470 471 return APR_SUCCESS; 472} 473 474static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env, 475 int req_type) 476{ 477 int i; 478 cgid_req_t req = {0}; 479 apr_status_t stat; 480 ap_unix_identity_t * ugid = ap_run_get_suexec_identity(r); 481 core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); 482 483 484 if (ugid == NULL) { 485 req.ugid = empty_ugid; 486 } else { 487 memcpy(&req.ugid, ugid, sizeof(ap_unix_identity_t)); 488 } 489 490 req.req_type = req_type; 491 req.ppid = parent_pid; 492 req.conn_id = r->connection->id; 493 for (req.env_count = 0; env[req.env_count]; req.env_count++) { 494 continue; 495 } 496 req.filename_len = strlen(r->filename); 497 req.argv0_len = strlen(argv0); 498 req.uri_len = strlen(r->uri); 499 req.args_len = r->args ? strlen(r->args) : 0; 500 req.loglevel = r->server->log.level; 501 502 /* Write the request header */ 503 if (req.args_len) { 504 stat = sock_writev(fd, r, 5, 505 &req, sizeof(req), 506 r->filename, req.filename_len, 507 argv0, req.argv0_len, 508 r->uri, req.uri_len, 509 r->args, req.args_len); 510 } else { 511 stat = sock_writev(fd, r, 4, 512 &req, sizeof(req), 513 r->filename, req.filename_len, 514 argv0, req.argv0_len, 515 r->uri, req.uri_len); 516 } 517 518 if (stat != APR_SUCCESS) { 519 return stat; 520 } 521 522 /* write the environment variables */ 523 for (i = 0; i < req.env_count; i++) { 524 apr_size_t curlen = strlen(env[i]); 525 526 if ((stat = sock_writev(fd, r, 2, &curlen, sizeof(curlen), 527 env[i], curlen)) != APR_SUCCESS) { 528 return stat; 529 } 530 } 531#if defined(RLIMIT_CPU) && defined(AP_CGID_USE_RLIMIT) 532 if (core_conf->limit_cpu) { 533 req.limits.limit_cpu = *(core_conf->limit_cpu); 534 req.limits.limit_cpu_set = 1; 535 } 536 else { 537 req.limits.limit_cpu_set = 0; 538 } 539#endif 540 541#if defined(AP_CGID_USE_RLIMIT) && (defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)) 542 if (core_conf->limit_mem) { 543 req.limits.limit_mem = *(core_conf->limit_mem); 544 req.limits.limit_mem_set = 1; 545 } 546 else { 547 req.limits.limit_mem_set = 0; 548 } 549 550#endif 551 552#if defined(RLIMIT_NPROC) && defined(AP_CGID_USE_RLIMIT) 553 if (core_conf->limit_nproc) { 554 req.limits.limit_nproc = *(core_conf->limit_nproc); 555 req.limits.limit_nproc_set = 1; 556 } 557 else { 558 req.limits.limit_nproc_set = 0; 559 } 560#endif 561 562#ifdef AP_CGID_USE_RLIMIT 563 if ( (stat = sock_write(fd, &(req.limits), sizeof(cgid_rlimit_t))) != APR_SUCCESS) 564 return stat; 565#endif 566 567 return APR_SUCCESS; 568} 569 570static void daemon_signal_handler(int sig) 571{ 572 if (sig == SIGHUP) { 573 ++daemon_should_exit; 574 } 575} 576 577static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err, 578 const char *description) 579{ 580 request_rec *r; 581 void *vr; 582 583 apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool); 584 r = vr; 585 586 /* sure we got r, but don't call ap_log_rerror() because we don't 587 * have r->headers_in and possibly other storage referenced by 588 * ap_log_rerror() 589 */ 590 ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description); 591} 592 593static int cgid_server(void *data) 594{ 595 int sd, sd2, rc; 596 mode_t omask; 597 apr_pool_t *ptrans; 598 server_rec *main_server = data; 599 apr_hash_t *script_hash = apr_hash_make(pcgi); 600 apr_status_t rv; 601 602 apr_pool_create(&ptrans, pcgi); 603 604 apr_signal(SIGCHLD, SIG_IGN); 605 apr_signal(SIGHUP, daemon_signal_handler); 606 607 /* Close our copy of the listening sockets */ 608 ap_close_listeners(); 609 610 /* cgid should use its own suexec doer */ 611 ap_hook_get_suexec_identity(cgid_suexec_id_doer, NULL, NULL, 612 APR_HOOK_REALLY_FIRST); 613 apr_hook_sort_all(); 614 615 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 616 ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01242) 617 "Couldn't create unix domain socket"); 618 return errno; 619 } 620 621 omask = umask(0077); /* so that only Apache can use socket */ 622 rc = bind(sd, (struct sockaddr *)server_addr, server_addr_len); 623 umask(omask); /* can't fail, so can't clobber errno */ 624 if (rc < 0) { 625 ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01243) 626 "Couldn't bind unix domain socket %s", 627 sockname); 628 return errno; 629 } 630 631 /* Not all flavors of unix use the current umask for AF_UNIX perms */ 632 rv = apr_file_perms_set(sockname, APR_FPROT_UREAD|APR_FPROT_UWRITE|APR_FPROT_UEXECUTE); 633 if (rv != APR_SUCCESS) { 634 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, main_server, APLOGNO(01244) 635 "Couldn't set permissions on unix domain socket %s", 636 sockname); 637 return rv; 638 } 639 640 if (listen(sd, DEFAULT_CGID_LISTENBACKLOG) < 0) { 641 ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01245) 642 "Couldn't listen on unix domain socket"); 643 return errno; 644 } 645 646 if (!geteuid()) { 647 if (chown(sockname, ap_unixd_config.user_id, -1) < 0) { 648 ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01246) 649 "Couldn't change owner of unix domain socket %s", 650 sockname); 651 return errno; 652 } 653 } 654 655 apr_pool_cleanup_register(pcgi, (void *)((long)sd), 656 close_unix_socket, close_unix_socket); 657 658 /* if running as root, switch to configured user/group */ 659 if ((rc = ap_run_drop_privileges(pcgi, ap_server_conf)) != 0) { 660 return rc; 661 } 662 663 while (!daemon_should_exit) { 664 int errfileno = STDERR_FILENO; 665 char *argv0 = NULL; 666 char **env = NULL; 667 const char * const *argv; 668 apr_int32_t in_pipe; 669 apr_int32_t out_pipe; 670 apr_int32_t err_pipe; 671 apr_cmdtype_e cmd_type; 672 request_rec *r; 673 apr_procattr_t *procattr = NULL; 674 apr_proc_t *procnew = NULL; 675 apr_file_t *inout; 676 cgid_req_t cgid_req; 677 apr_status_t stat; 678 void *key; 679 apr_socklen_t len; 680 struct sockaddr_un unix_addr; 681 682 apr_pool_clear(ptrans); 683 684 len = sizeof(unix_addr); 685 sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len); 686 if (sd2 < 0) { 687#if defined(ENETDOWN) 688 if (errno == ENETDOWN) { 689 /* The network has been shut down, no need to continue. Die gracefully */ 690 ++daemon_should_exit; 691 } 692#endif 693 if (errno != EINTR) { 694 ap_log_error(APLOG_MARK, APLOG_ERR, errno, 695 (server_rec *)data, APLOGNO(01247) 696 "Error accepting on cgid socket"); 697 } 698 continue; 699 } 700 701 r = apr_pcalloc(ptrans, sizeof(request_rec)); 702 procnew = apr_pcalloc(ptrans, sizeof(*procnew)); 703 r->pool = ptrans; 704 stat = get_req(sd2, r, &argv0, &env, &cgid_req); 705 if (stat != APR_SUCCESS) { 706 ap_log_error(APLOG_MARK, APLOG_ERR, stat, 707 main_server, APLOGNO(01248) 708 "Error reading request on cgid socket"); 709 close(sd2); 710 continue; 711 } 712 713 if (cgid_req.ppid != parent_pid) { 714 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, main_server, APLOGNO(01249) 715 "CGI request received from wrong server instance; " 716 "see ScriptSock directive"); 717 close(sd2); 718 continue; 719 } 720 721 if (cgid_req.req_type == GETPID_REQ) { 722 pid_t pid; 723 apr_status_t rv; 724 725 pid = (pid_t)((long)apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id))); 726 rv = sock_write(sd2, &pid, sizeof(pid)); 727 if (rv != APR_SUCCESS) { 728 ap_log_error(APLOG_MARK, APLOG_ERR, rv, 729 main_server, APLOGNO(01250) 730 "Error writing pid %" APR_PID_T_FMT " to handler", pid); 731 } 732 close(sd2); 733 continue; 734 } 735 736 apr_os_file_put(&r->server->error_log, &errfileno, 0, r->pool); 737 apr_os_file_put(&inout, &sd2, 0, r->pool); 738 739 if (cgid_req.req_type == SSI_REQ) { 740 in_pipe = APR_NO_PIPE; 741 out_pipe = APR_FULL_BLOCK; 742 err_pipe = APR_NO_PIPE; 743 cmd_type = APR_SHELLCMD; 744 } 745 else { 746 in_pipe = APR_CHILD_BLOCK; 747 out_pipe = APR_CHILD_BLOCK; 748 err_pipe = APR_CHILD_BLOCK; 749 cmd_type = APR_PROGRAM; 750 } 751 752 if (((rc = apr_procattr_create(&procattr, ptrans)) != APR_SUCCESS) || 753 ((cgid_req.req_type == CGI_REQ) && 754 (((rc = apr_procattr_io_set(procattr, 755 in_pipe, 756 out_pipe, 757 err_pipe)) != APR_SUCCESS) || 758 /* XXX apr_procattr_child_*_set() is creating an unnecessary 759 * pipe between this process and the child being created... 760 * It is cleaned up with the temporary pool for this request. 761 */ 762 ((rc = apr_procattr_child_err_set(procattr, r->server->error_log, NULL)) != APR_SUCCESS) || 763 ((rc = apr_procattr_child_in_set(procattr, inout, NULL)) != APR_SUCCESS))) || 764 ((rc = apr_procattr_child_out_set(procattr, inout, NULL)) != APR_SUCCESS) || 765 ((rc = apr_procattr_dir_set(procattr, 766 ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) || 767 ((rc = apr_procattr_cmdtype_set(procattr, cmd_type)) != APR_SUCCESS) || 768#ifdef AP_CGID_USE_RLIMIT 769#ifdef RLIMIT_CPU 770 ( (cgid_req.limits.limit_cpu_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, 771 &cgid_req.limits.limit_cpu)) != APR_SUCCESS)) || 772#endif 773#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) 774 ( (cgid_req.limits.limit_mem_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, 775 &cgid_req.limits.limit_mem)) != APR_SUCCESS)) || 776#endif 777#ifdef RLIMIT_NPROC 778 ( (cgid_req.limits.limit_nproc_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, 779 &cgid_req.limits.limit_nproc)) != APR_SUCCESS)) || 780#endif 781#endif 782 783 ((rc = apr_procattr_child_errfn_set(procattr, cgid_child_errfn)) != APR_SUCCESS)) { 784 /* Something bad happened, tell the world. 785 * ap_log_rerror() won't work because the header table used by 786 * ap_log_rerror() hasn't been replicated in the phony r 787 */ 788 ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, APLOGNO(01251) 789 "couldn't set child process attributes: %s", r->filename); 790 791 procnew->pid = 0; /* no process to clean up */ 792 close(sd2); 793 } 794 else { 795 apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); 796 797 argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args); 798 799 /* We want to close sd2 for the new CGI process too. 800 * If it is left open it'll make ap_pass_brigade() block 801 * waiting for EOF if CGI forked something running long. 802 * close(sd2) here should be okay, as CGI channel 803 * is already dup()ed by apr_procattr_child_{in,out}_set() 804 * above. 805 */ 806 close(sd2); 807 808 if (memcmp(&empty_ugid, &cgid_req.ugid, sizeof(empty_ugid))) { 809 /* We have a valid identity, and can be sure that 810 * cgid_suexec_id_doer will return a valid ugid 811 */ 812 rc = ap_os_create_privileged_process(r, procnew, argv0, argv, 813 (const char * const *)env, 814 procattr, ptrans); 815 } else { 816 rc = apr_proc_create(procnew, argv0, argv, 817 (const char * const *)env, 818 procattr, ptrans); 819 } 820 821 if (rc != APR_SUCCESS) { 822 /* Bad things happened. Everyone should have cleaned up. 823 * ap_log_rerror() won't work because the header table used by 824 * ap_log_rerror() hasn't been replicated in the phony r 825 */ 826 ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, APLOGNO(01252) 827 "couldn't create child process: %d: %s", rc, 828 apr_filepath_name_get(r->filename)); 829 830 procnew->pid = 0; /* no process to clean up */ 831 } 832 } 833 834 /* If the script process was created, remember the pid for 835 * later cleanup. If the script process wasn't created, clear 836 * out any prior pid with the same key. 837 * 838 * We don't want to leak storage for the key, so only allocate 839 * a key if the key doesn't exist yet in the hash; there are 840 * only a limited number of possible keys (one for each 841 * possible thread in the server), so we can allocate a copy 842 * of the key the first time a thread has a cgid request. 843 * Note that apr_hash_set() only uses the storage passed in 844 * for the key if it is adding the key to the hash for the 845 * first time; new key storage isn't needed for replacing the 846 * existing value of a key. 847 */ 848 849 if (apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id))) { 850 key = &cgid_req.conn_id; 851 } 852 else { 853 key = apr_pmemdup(pcgi, &cgid_req.conn_id, sizeof(cgid_req.conn_id)); 854 } 855 apr_hash_set(script_hash, key, sizeof(cgid_req.conn_id), 856 (void *)((long)procnew->pid)); 857 } 858 return -1; /* should be <= 0 to distinguish from startup errors */ 859} 860 861static int cgid_start(apr_pool_t *p, server_rec *main_server, 862 apr_proc_t *procnew) 863{ 864 865 daemon_should_exit = 0; /* clear setting from previous generation */ 866 if ((daemon_pid = fork()) < 0) { 867 ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01253) 868 "mod_cgid: Couldn't spawn cgid daemon process"); 869 return DECLINED; 870 } 871 else if (daemon_pid == 0) { 872 if (pcgi == NULL) { 873 apr_pool_create(&pcgi, p); 874 } 875 exit(cgid_server(main_server) > 0 ? DAEMON_STARTUP_ERROR : -1); 876 } 877 procnew->pid = daemon_pid; 878 procnew->err = procnew->in = procnew->out = NULL; 879 apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); 880#if APR_HAS_OTHER_CHILD 881 apr_proc_other_child_register(procnew, cgid_maint, procnew, NULL, p); 882#endif 883 return OK; 884} 885 886static int cgid_pre_config(apr_pool_t *pconf, apr_pool_t *plog, 887 apr_pool_t *ptemp) 888{ 889 sockname = ap_append_pid(pconf, DEFAULT_SOCKET, "."); 890 return OK; 891} 892 893static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, 894 server_rec *main_server) 895{ 896 apr_proc_t *procnew = NULL; 897 const char *userdata_key = "cgid_init"; 898 int ret = OK; 899 void *data; 900 901 root_server = main_server; 902 root_pool = p; 903 904 apr_pool_userdata_get(&data, userdata_key, main_server->process->pool); 905 if (!data) { 906 procnew = apr_pcalloc(main_server->process->pool, sizeof(*procnew)); 907 procnew->pid = -1; 908 procnew->err = procnew->in = procnew->out = NULL; 909 apr_pool_userdata_set((const void *)procnew, userdata_key, 910 apr_pool_cleanup_null, main_server->process->pool); 911 return ret; 912 } 913 else { 914 procnew = data; 915 } 916 917 if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) { 918 char *tmp_sockname; 919 920 parent_pid = getpid(); 921 tmp_sockname = ap_runtime_dir_relative(p, sockname); 922 if (strlen(tmp_sockname) > sizeof(server_addr->sun_path) - 1) { 923 tmp_sockname[sizeof(server_addr->sun_path)] = '\0'; 924 ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server, APLOGNO(01254) 925 "The length of the ScriptSock path exceeds maximum, " 926 "truncating to %s", tmp_sockname); 927 } 928 sockname = tmp_sockname; 929 930 server_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) + strlen(sockname); 931 server_addr = (struct sockaddr_un *)apr_palloc(p, server_addr_len + 1); 932 server_addr->sun_family = AF_UNIX; 933 strcpy(server_addr->sun_path, sockname); 934 935 ret = cgid_start(p, main_server, procnew); 936 if (ret != OK ) { 937 return ret; 938 } 939 cgid_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler); 940 cgid_pfn_gtv = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value); 941 cgid_pfn_ps = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string); 942 943 if ((cgid_pfn_reg_with_ssi) && (cgid_pfn_gtv) && (cgid_pfn_ps)) { 944 /* Required by mod_include filter. This is how mod_cgid registers 945 * with mod_include to provide processing of the exec directive. 946 */ 947 cgid_pfn_reg_with_ssi("exec", handle_exec); 948 } 949 } 950 return ret; 951} 952 953static void *create_cgid_config(apr_pool_t *p, server_rec *s) 954{ 955 cgid_server_conf *c = 956 (cgid_server_conf *) apr_pcalloc(p, sizeof(cgid_server_conf)); 957 958 c->logname = NULL; 959 c->logbytes = DEFAULT_LOGBYTES; 960 c->bufbytes = DEFAULT_BUFBYTES; 961 return c; 962} 963 964static void *merge_cgid_config(apr_pool_t *p, void *basev, void *overridesv) 965{ 966 cgid_server_conf *base = (cgid_server_conf *) basev, *overrides = (cgid_server_conf *) overridesv; 967 968 return overrides->logname ? overrides : base; 969} 970 971static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg) 972{ 973 server_rec *s = cmd->server; 974 cgid_server_conf *conf = ap_get_module_config(s->module_config, 975 &cgid_module); 976 977 conf->logname = ap_server_root_relative(cmd->pool, arg); 978 979 if (!conf->logname) { 980 return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ", 981 arg, NULL); 982 } 983 return NULL; 984} 985 986static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy, const char *arg) 987{ 988 server_rec *s = cmd->server; 989 cgid_server_conf *conf = ap_get_module_config(s->module_config, 990 &cgid_module); 991 992 conf->logbytes = atol(arg); 993 return NULL; 994} 995 996static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, const char *arg) 997{ 998 server_rec *s = cmd->server; 999 cgid_server_conf *conf = ap_get_module_config(s->module_config, 1000 &cgid_module); 1001 1002 conf->bufbytes = atoi(arg); 1003 return NULL; 1004} 1005 1006static const char *set_script_socket(cmd_parms *cmd, void *dummy, const char *arg) 1007{ 1008 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 1009 if (err != NULL) { 1010 return err; 1011 } 1012 1013 /* Make sure the pid is appended to the sockname */ 1014 sockname = ap_append_pid(cmd->pool, arg, "."); 1015 sockname = ap_runtime_dir_relative(cmd->pool, sockname); 1016 1017 if (!sockname) { 1018 return apr_pstrcat(cmd->pool, "Invalid ScriptSock path", 1019 arg, NULL); 1020 } 1021 1022 return NULL; 1023} 1024 1025static const command_rec cgid_cmds[] = 1026{ 1027 AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF, 1028 "the name of a log for script debugging info"), 1029 AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, 1030 "the maximum length (in bytes) of the script debug log"), 1031 AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, 1032 "the maximum size (in bytes) to record of a POST request"), 1033 AP_INIT_TAKE1("ScriptSock", set_script_socket, NULL, RSRC_CONF, 1034 "the name of the socket to use for communication with " 1035 "the cgi daemon."), 1036 {NULL} 1037}; 1038 1039static int log_scripterror(request_rec *r, cgid_server_conf * conf, int ret, 1040 apr_status_t rv, char *error) 1041{ 1042 apr_file_t *f = NULL; 1043 struct stat finfo; 1044 char time_str[APR_CTIME_LEN]; 1045 int log_flags = rv ? APLOG_ERR : APLOG_ERR; 1046 1047 ap_log_rerror(APLOG_MARK, log_flags, rv, r, 1048 "%s: %s", error, r->filename); 1049 1050 /* XXX Very expensive mainline case! Open, then getfileinfo! */ 1051 if (!conf->logname || 1052 ((stat(conf->logname, &finfo) == 0) 1053 && (finfo.st_size > conf->logbytes)) || 1054 (apr_file_open(&f, conf->logname, 1055 APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) { 1056 return ret; 1057 } 1058 1059 /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */ 1060 apr_ctime(time_str, apr_time_now()); 1061 apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri, 1062 r->args ? "?" : "", r->args ? r->args : "", r->protocol); 1063 /* "%% 500 /usr/local/apache/cgid-bin */ 1064 apr_file_printf(f, "%%%% %d %s\n", ret, r->filename); 1065 1066 apr_file_printf(f, "%%error\n%s\n", error); 1067 1068 apr_file_close(f); 1069 return ret; 1070} 1071 1072static int log_script(request_rec *r, cgid_server_conf * conf, int ret, 1073 char *dbuf, const char *sbuf, apr_bucket_brigade *bb, 1074 apr_file_t *script_err) 1075{ 1076 const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in); 1077 const apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts; 1078 char argsbuffer[HUGE_STRING_LEN]; 1079 apr_file_t *f = NULL; 1080 apr_bucket *e; 1081 const char *buf; 1082 apr_size_t len; 1083 apr_status_t rv; 1084 int first; 1085 int i; 1086 struct stat finfo; 1087 char time_str[APR_CTIME_LEN]; 1088 1089 /* XXX Very expensive mainline case! Open, then getfileinfo! */ 1090 if (!conf->logname || 1091 ((stat(conf->logname, &finfo) == 0) 1092 && (finfo.st_size > conf->logbytes)) || 1093 (apr_file_open(&f, conf->logname, 1094 APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) { 1095 /* Soak up script output */ 1096 discard_script_output(bb); 1097 if (script_err) { 1098 while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, 1099 script_err) == APR_SUCCESS) 1100 continue; 1101 } 1102 return ret; 1103 } 1104 1105 /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */ 1106 apr_ctime(time_str, apr_time_now()); 1107 apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri, 1108 r->args ? "?" : "", r->args ? r->args : "", r->protocol); 1109 /* "%% 500 /usr/local/apache/cgid-bin" */ 1110 apr_file_printf(f, "%%%% %d %s\n", ret, r->filename); 1111 1112 apr_file_puts("%request\n", f); 1113 for (i = 0; i < hdrs_arr->nelts; ++i) { 1114 if (!hdrs[i].key) 1115 continue; 1116 apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); 1117 } 1118 if ((r->method_number == M_POST || r->method_number == M_PUT) 1119 && *dbuf) { 1120 apr_file_printf(f, "\n%s\n", dbuf); 1121 } 1122 1123 apr_file_puts("%response\n", f); 1124 hdrs_arr = apr_table_elts(r->err_headers_out); 1125 hdrs = (const apr_table_entry_t *) hdrs_arr->elts; 1126 1127 for (i = 0; i < hdrs_arr->nelts; ++i) { 1128 if (!hdrs[i].key) 1129 continue; 1130 apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); 1131 } 1132 1133 if (sbuf && *sbuf) 1134 apr_file_printf(f, "%s\n", sbuf); 1135 1136 first = 1; 1137 1138 for (e = APR_BRIGADE_FIRST(bb); 1139 e != APR_BRIGADE_SENTINEL(bb); 1140 e = APR_BUCKET_NEXT(e)) 1141 { 1142 if (APR_BUCKET_IS_EOS(e)) { 1143 break; 1144 } 1145 rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ); 1146 if (rv != APR_SUCCESS || (len == 0)) { 1147 break; 1148 } 1149 if (first) { 1150 apr_file_puts("%stdout\n", f); 1151 first = 0; 1152 } 1153 apr_file_write_full(f, buf, len, NULL); 1154 apr_file_puts("\n", f); 1155 } 1156 1157 if (script_err) { 1158 if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, 1159 script_err) == APR_SUCCESS) { 1160 apr_file_puts("%stderr\n", f); 1161 apr_file_puts(argsbuffer, f); 1162 while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, 1163 script_err) == APR_SUCCESS) 1164 apr_file_puts(argsbuffer, f); 1165 apr_file_puts("\n", f); 1166 } 1167 } 1168 1169 if (script_err) { 1170 apr_file_close(script_err); 1171 } 1172 1173 apr_file_close(f); 1174 return ret; 1175} 1176 1177static int connect_to_daemon(int *sdptr, request_rec *r, 1178 cgid_server_conf *conf) 1179{ 1180 int sd; 1181 int connect_tries; 1182 apr_interval_time_t sliding_timer; 1183 1184 connect_tries = 0; 1185 sliding_timer = 100000; /* 100 milliseconds */ 1186 while (1) { 1187 ++connect_tries; 1188 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 1189 return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno, 1190 APLOGNO(01255) "unable to create socket to cgi daemon"); 1191 } 1192 if (connect(sd, (struct sockaddr *)server_addr, server_addr_len) < 0) { 1193 if (errno == ECONNREFUSED && connect_tries < DEFAULT_CONNECT_ATTEMPTS) { 1194 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r, APLOGNO(01256) 1195 "connect #%d to cgi daemon failed, sleeping before retry", 1196 connect_tries); 1197 close(sd); 1198 apr_sleep(sliding_timer); 1199 if (sliding_timer < apr_time_from_sec(2)) { 1200 sliding_timer *= 2; 1201 } 1202 } 1203 else { 1204 close(sd); 1205 return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno, APLOGNO(01257) 1206 "unable to connect to cgi daemon after multiple tries"); 1207 } 1208 } 1209 else { 1210 apr_pool_cleanup_register(r->pool, (void *)((long)sd), 1211 close_unix_socket, apr_pool_cleanup_null); 1212 break; /* we got connected! */ 1213 } 1214 /* gotta try again, but make sure the cgid daemon is still around */ 1215 if (kill(daemon_pid, 0) != 0) { 1216 return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno, APLOGNO(01258) 1217 "cgid daemon is gone; is Apache terminating?"); 1218 } 1219 } 1220 *sdptr = sd; 1221 return OK; 1222} 1223 1224static void discard_script_output(apr_bucket_brigade *bb) 1225{ 1226 apr_bucket *e; 1227 const char *buf; 1228 apr_size_t len; 1229 apr_status_t rv; 1230 1231 for (e = APR_BRIGADE_FIRST(bb); 1232 e != APR_BRIGADE_SENTINEL(bb); 1233 e = APR_BUCKET_NEXT(e)) 1234 { 1235 if (APR_BUCKET_IS_EOS(e)) { 1236 break; 1237 } 1238 rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ); 1239 if (rv != APR_SUCCESS) { 1240 break; 1241 } 1242 } 1243} 1244 1245/**************************************************************** 1246 * 1247 * Actual cgid handling... 1248 */ 1249 1250struct cleanup_script_info { 1251 request_rec *r; 1252 unsigned long conn_id; 1253 cgid_server_conf *conf; 1254}; 1255 1256static apr_status_t dead_yet(pid_t pid, apr_interval_time_t max_wait) 1257{ 1258 apr_interval_time_t interval = 10000; /* 10 ms */ 1259 apr_interval_time_t total = 0; 1260 1261 do { 1262#ifdef _AIX 1263 /* On AIX, for processes like mod_cgid's script children where 1264 * SIGCHLD is ignored, kill(pid,0) returns success for up to 1265 * one second after the script child exits, based on when a 1266 * daemon runs to clean up unnecessary process table entries. 1267 * getpgid() can report the proper info (-1/ESRCH) immediately. 1268 */ 1269 if (getpgid(pid) < 0) { 1270#else 1271 if (kill(pid, 0) < 0) { 1272#endif 1273 return APR_SUCCESS; 1274 } 1275 apr_sleep(interval); 1276 total = total + interval; 1277 if (interval < 500000) { 1278 interval *= 2; 1279 } 1280 } while (total < max_wait); 1281 return APR_EGENERAL; 1282} 1283 1284static apr_status_t cleanup_nonchild_process(request_rec *r, pid_t pid) 1285{ 1286 kill(pid, SIGTERM); /* in case it isn't dead yet */ 1287 if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) { 1288 return APR_SUCCESS; 1289 } 1290 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01259) 1291 "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL", 1292 pid); 1293 kill(pid, SIGKILL); 1294 if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) { 1295 return APR_SUCCESS; 1296 } 1297 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01260) 1298 "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL again", 1299 pid); 1300 kill(pid, SIGKILL); 1301 1302 return APR_EGENERAL; 1303} 1304 1305static apr_status_t cleanup_script(void *vptr) 1306{ 1307 struct cleanup_script_info *info = vptr; 1308 int sd; 1309 int rc; 1310 cgid_req_t req = {0}; 1311 pid_t pid; 1312 apr_status_t stat; 1313 1314 rc = connect_to_daemon(&sd, info->r, info->conf); 1315 if (rc != OK) { 1316 return APR_EGENERAL; 1317 } 1318 1319 /* we got a socket, and there is already a cleanup registered for it */ 1320 1321 req.req_type = GETPID_REQ; 1322 req.ppid = parent_pid; 1323 req.conn_id = info->r->connection->id; 1324 1325 stat = sock_write(sd, &req, sizeof(req)); 1326 if (stat != APR_SUCCESS) { 1327 return stat; 1328 } 1329 1330 /* wait for pid of script */ 1331 stat = sock_read(sd, &pid, sizeof(pid)); 1332 if (stat != APR_SUCCESS) { 1333 return stat; 1334 } 1335 1336 if (pid == 0) { 1337 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, info->r, APLOGNO(01261) 1338 "daemon couldn't find CGI process for connection %lu", 1339 info->conn_id); 1340 return APR_EGENERAL; 1341 } 1342 return cleanup_nonchild_process(info->r, pid); 1343} 1344 1345static int cgid_handler(request_rec *r) 1346{ 1347 int retval, nph, dbpos; 1348 char *argv0, *dbuf; 1349 apr_bucket_brigade *bb; 1350 apr_bucket *b; 1351 cgid_server_conf *conf; 1352 int is_included; 1353 int seen_eos, child_stopped_reading; 1354 int sd; 1355 char **env; 1356 apr_file_t *tempsock; 1357 struct cleanup_script_info *info; 1358 apr_status_t rv; 1359 1360 if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { 1361 return DECLINED; 1362 } 1363 1364 conf = ap_get_module_config(r->server->module_config, &cgid_module); 1365 is_included = !strcmp(r->protocol, "INCLUDED"); 1366 1367 if ((argv0 = strrchr(r->filename, '/')) != NULL) { 1368 argv0++; 1369 } 1370 else { 1371 argv0 = r->filename; 1372 } 1373 1374 nph = !(strncmp(argv0, "nph-", 4)); 1375 1376 argv0 = r->filename; 1377 1378 if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) { 1379 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01262) 1380 "Options ExecCGI is off in this directory"); 1381 } 1382 1383 if (nph && is_included) { 1384 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01263) 1385 "attempt to include NPH CGI script"); 1386 } 1387 1388#if defined(OS2) || defined(WIN32) 1389#error mod_cgid does not work on this platform. If you teach it to, look 1390#error at mod_cgi.c for required code in this path. 1391#else 1392 if (r->finfo.filetype == APR_NOFILE) { 1393 return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(01264) 1394 "script not found or unable to stat"); 1395 } 1396#endif 1397 if (r->finfo.filetype == APR_DIR) { 1398 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01265) 1399 "attempt to invoke directory as script"); 1400 } 1401 1402 if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) && 1403 r->path_info && *r->path_info) 1404 { 1405 /* default to accept */ 1406 return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(01266) 1407 "AcceptPathInfo off disallows user's path"); 1408 } 1409/* 1410 if (!ap_suexec_enabled) { 1411 if (!ap_can_exec(&r->finfo)) 1412 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01267) 1413 "file permissions deny server execution"); 1414 } 1415*/ 1416 ap_add_common_vars(r); 1417 ap_add_cgi_vars(r); 1418 env = ap_create_environment(r->pool, r->subprocess_env); 1419 1420 if ((retval = connect_to_daemon(&sd, r, conf)) != OK) { 1421 return retval; 1422 } 1423 1424 rv = send_req(sd, r, argv0, env, CGI_REQ); 1425 if (rv != APR_SUCCESS) { 1426 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01268) 1427 "write to cgi daemon process"); 1428 } 1429 1430 info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); 1431 info->r = r; 1432 info->conn_id = r->connection->id; 1433 info->conf = conf; 1434 apr_pool_cleanup_register(r->pool, info, 1435 cleanup_script, 1436 apr_pool_cleanup_null); 1437 /* We are putting the socket discriptor into an apr_file_t so that we can 1438 * use a pipe bucket to send the data to the client. APR will create 1439 * a cleanup for the apr_file_t which will close the socket, so we'll 1440 * get rid of the cleanup we registered when we created the socket. 1441 */ 1442 1443 apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool); 1444 apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket); 1445 1446 /* Transfer any put/post args, CERN style... 1447 * Note that we already ignore SIGPIPE in the core server. 1448 */ 1449 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); 1450 seen_eos = 0; 1451 child_stopped_reading = 0; 1452 dbuf = NULL; 1453 dbpos = 0; 1454 if (conf->logname) { 1455 dbuf = apr_palloc(r->pool, conf->bufbytes + 1); 1456 } 1457 do { 1458 apr_bucket *bucket; 1459 1460 rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, 1461 APR_BLOCK_READ, HUGE_STRING_LEN); 1462 1463 if (rv != APR_SUCCESS) { 1464 if (APR_STATUS_IS_TIMEUP(rv)) { 1465 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01269) 1466 "Timeout during reading request entity data"); 1467 return HTTP_REQUEST_TIME_OUT; 1468 } 1469 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01270) 1470 "Error reading request entity data"); 1471 return HTTP_INTERNAL_SERVER_ERROR; 1472 } 1473 1474 for (bucket = APR_BRIGADE_FIRST(bb); 1475 bucket != APR_BRIGADE_SENTINEL(bb); 1476 bucket = APR_BUCKET_NEXT(bucket)) 1477 { 1478 const char *data; 1479 apr_size_t len; 1480 1481 if (APR_BUCKET_IS_EOS(bucket)) { 1482 seen_eos = 1; 1483 break; 1484 } 1485 1486 /* We can't do much with this. */ 1487 if (APR_BUCKET_IS_FLUSH(bucket)) { 1488 continue; 1489 } 1490 1491 /* If the child stopped, we still must read to EOS. */ 1492 if (child_stopped_reading) { 1493 continue; 1494 } 1495 1496 /* read */ 1497 apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); 1498 1499 if (conf->logname && dbpos < conf->bufbytes) { 1500 int cursize; 1501 1502 if ((dbpos + len) > conf->bufbytes) { 1503 cursize = conf->bufbytes - dbpos; 1504 } 1505 else { 1506 cursize = len; 1507 } 1508 memcpy(dbuf + dbpos, data, cursize); 1509 dbpos += cursize; 1510 } 1511 1512 /* Keep writing data to the child until done or too much time 1513 * elapses with no progress or an error occurs. 1514 */ 1515 rv = apr_file_write_full(tempsock, data, len, NULL); 1516 1517 if (rv != APR_SUCCESS) { 1518 /* silly script stopped reading, soak up remaining message */ 1519 child_stopped_reading = 1; 1520 } 1521 } 1522 apr_brigade_cleanup(bb); 1523 } 1524 while (!seen_eos); 1525 1526 if (conf->logname) { 1527 dbuf[dbpos] = '\0'; 1528 } 1529 1530 /* we're done writing, or maybe we didn't write at all; 1531 * force EOF on child's stdin so that the cgi detects end (or 1532 * absence) of data 1533 */ 1534 shutdown(sd, 1); 1535 1536 /* Handle script return... */ 1537 if (!nph) { 1538 conn_rec *c = r->connection; 1539 const char *location; 1540 char sbuf[MAX_STRING_LEN]; 1541 int ret; 1542 1543 bb = apr_brigade_create(r->pool, c->bucket_alloc); 1544 b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); 1545 APR_BRIGADE_INSERT_TAIL(bb, b); 1546 b = apr_bucket_eos_create(c->bucket_alloc); 1547 APR_BRIGADE_INSERT_TAIL(bb, b); 1548 1549 if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, 1550 APLOG_MODULE_INDEX))) 1551 { 1552 ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL); 1553 1554 /* 1555 * ret could be HTTP_NOT_MODIFIED in the case that the CGI script 1556 * does not set an explicit status and ap_meets_conditions, which 1557 * is called by ap_scan_script_header_err_brigade, detects that 1558 * the conditions of the requests are met and the response is 1559 * not modified. 1560 * In this case set r->status and return OK in order to prevent 1561 * running through the error processing stack as this would 1562 * break with mod_cache, if the conditions had been set by 1563 * mod_cache itself to validate a stale entity. 1564 * BTW: We circumvent the error processing stack anyway if the 1565 * CGI script set an explicit status code (whatever it is) and 1566 * the only possible values for ret here are: 1567 * 1568 * HTTP_NOT_MODIFIED (set by ap_meets_conditions) 1569 * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) 1570 * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the 1571 * processing of the response of the CGI script, e.g broken headers 1572 * or a crashed CGI process). 1573 */ 1574 if (ret == HTTP_NOT_MODIFIED) { 1575 r->status = ret; 1576 return OK; 1577 } 1578 1579 return ret; 1580 } 1581 1582 location = apr_table_get(r->headers_out, "Location"); 1583 1584 if (location && location[0] == '/' && r->status == 200) { 1585 1586 /* Soak up all the script output */ 1587 discard_script_output(bb); 1588 apr_brigade_destroy(bb); 1589 /* This redirect needs to be a GET no matter what the original 1590 * method was. 1591 */ 1592 r->method = "GET"; 1593 r->method_number = M_GET; 1594 1595 /* We already read the message body (if any), so don't allow 1596 * the redirected request to think it has one. We can ignore 1597 * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. 1598 */ 1599 apr_table_unset(r->headers_in, "Content-Length"); 1600 1601 ap_internal_redirect_handler(location, r); 1602 return OK; 1603 } 1604 else if (location && r->status == 200) { 1605 /* XXX: Note that if a script wants to produce its own Redirect 1606 * body, it now has to explicitly *say* "Status: 302" 1607 */ 1608 discard_script_output(bb); 1609 apr_brigade_destroy(bb); 1610 return HTTP_MOVED_TEMPORARILY; 1611 } 1612 1613 ap_pass_brigade(r->output_filters, bb); 1614 } 1615 1616 if (nph) { 1617 conn_rec *c = r->connection; 1618 struct ap_filter_t *cur; 1619 1620 /* get rid of all filters up through protocol... since we 1621 * haven't parsed off the headers, there is no way they can 1622 * work 1623 */ 1624 1625 cur = r->proto_output_filters; 1626 while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { 1627 cur = cur->next; 1628 } 1629 r->output_filters = r->proto_output_filters = cur; 1630 1631 bb = apr_brigade_create(r->pool, c->bucket_alloc); 1632 b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); 1633 APR_BRIGADE_INSERT_TAIL(bb, b); 1634 b = apr_bucket_eos_create(c->bucket_alloc); 1635 APR_BRIGADE_INSERT_TAIL(bb, b); 1636 ap_pass_brigade(r->output_filters, bb); 1637 } 1638 1639 return OK; /* NOT r->status, even if it has changed. */ 1640} 1641 1642 1643 1644 1645/*============================================================================ 1646 *============================================================================ 1647 * This is the beginning of the cgi filter code moved from mod_include. This 1648 * is the code required to handle the "exec" SSI directive. 1649 *============================================================================ 1650 *============================================================================*/ 1651static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f, 1652 apr_bucket_brigade *bb, char *s) 1653{ 1654 request_rec *r = f->r; 1655 request_rec *rr = ap_sub_req_lookup_uri(s, r, f->next); 1656 int rr_status; 1657 1658 if (rr->status != HTTP_OK) { 1659 ap_destroy_sub_req(rr); 1660 return APR_EGENERAL; 1661 } 1662 1663 /* No hardwired path info or query allowed */ 1664 if ((rr->path_info && rr->path_info[0]) || rr->args) { 1665 ap_destroy_sub_req(rr); 1666 return APR_EGENERAL; 1667 } 1668 if (rr->finfo.filetype != APR_REG) { 1669 ap_destroy_sub_req(rr); 1670 return APR_EGENERAL; 1671 } 1672 1673 /* Script gets parameters of the *document*, for back compatibility */ 1674 rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */ 1675 rr->args = r->args; 1676 1677 /* Force sub_req to be treated as a CGI request, even if ordinary 1678 * typing rules would have called it something else. 1679 */ 1680 ap_set_content_type(rr, CGI_MAGIC_TYPE); 1681 1682 /* Run it. */ 1683 rr_status = ap_run_sub_req(rr); 1684 if (ap_is_HTTP_REDIRECT(rr_status)) { 1685 const char *location = apr_table_get(rr->headers_out, "Location"); 1686 1687 if (location) { 1688 char *buffer; 1689 1690 location = ap_escape_html(rr->pool, location); 1691 buffer = apr_pstrcat(ctx->pool, "<a href=\"", location, "\">", 1692 location, "</a>", NULL); 1693 1694 APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(buffer, 1695 strlen(buffer), ctx->pool, 1696 f->c->bucket_alloc)); 1697 } 1698 } 1699 1700 ap_destroy_sub_req(rr); 1701 1702 return APR_SUCCESS; 1703} 1704 1705/* This is the special environment used for running the "exec cmd=" 1706 * variety of SSI directives. 1707 */ 1708static void add_ssi_vars(request_rec *r) 1709{ 1710 apr_table_t *e = r->subprocess_env; 1711 1712 if (r->path_info && r->path_info[0] != '\0') { 1713 request_rec *pa_req; 1714 1715 apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info)); 1716 1717 pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, NULL); 1718 if (pa_req->filename) { 1719 apr_table_setn(e, "PATH_TRANSLATED", 1720 apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL)); 1721 } 1722 ap_destroy_sub_req(pa_req); 1723 } 1724 1725 if (r->args) { 1726 char *arg_copy = apr_pstrdup(r->pool, r->args); 1727 1728 apr_table_setn(e, "QUERY_STRING", r->args); 1729 ap_unescape_url(arg_copy); 1730 apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy)); 1731 } 1732} 1733 1734static int include_cmd(include_ctx_t *ctx, ap_filter_t *f, 1735 apr_bucket_brigade *bb, char *command) 1736{ 1737 char **env; 1738 int sd; 1739 int retval; 1740 apr_file_t *tempsock = NULL; 1741 request_rec *r = f->r; 1742 cgid_server_conf *conf = ap_get_module_config(r->server->module_config, 1743 &cgid_module); 1744 struct cleanup_script_info *info; 1745 1746 add_ssi_vars(r); 1747 env = ap_create_environment(r->pool, r->subprocess_env); 1748 1749 if ((retval = connect_to_daemon(&sd, r, conf)) != OK) { 1750 return retval; 1751 } 1752 1753 send_req(sd, r, command, env, SSI_REQ); 1754 1755 info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); 1756 info->r = r; 1757 info->conn_id = r->connection->id; 1758 info->conf = conf; 1759 /* for this type of request, the script is invoked through an 1760 * intermediate shell process... cleanup_script is only able 1761 * to knock out the shell process, not the actual script 1762 */ 1763 apr_pool_cleanup_register(r->pool, info, 1764 cleanup_script, 1765 apr_pool_cleanup_null); 1766 1767 /* We are putting the socket discriptor into an apr_file_t so that we can 1768 * use a pipe bucket to send the data to the client. APR will create 1769 * a cleanup for the apr_file_t which will close the socket, so we'll 1770 * get rid of the cleanup we registered when we created the socket. 1771 */ 1772 apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool); 1773 apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket); 1774 1775 APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pipe_create(tempsock, 1776 f->c->bucket_alloc)); 1777 ctx->flush_now = 1; 1778 1779 return APR_SUCCESS; 1780} 1781 1782static apr_status_t handle_exec(include_ctx_t *ctx, ap_filter_t *f, 1783 apr_bucket_brigade *bb) 1784{ 1785 char *tag = NULL; 1786 char *tag_val = NULL; 1787 request_rec *r = f->r; 1788 char *file = r->filename; 1789 char parsed_string[MAX_STRING_LEN]; 1790 1791 if (!ctx->argc) { 1792 ap_log_rerror(APLOG_MARK, 1793 (ctx->flags & SSI_FLAG_PRINTING) 1794 ? APLOG_ERR : APLOG_WARNING, 1795 0, r, "missing argument for exec element in %s", 1796 r->filename); 1797 } 1798 1799 if (!(ctx->flags & SSI_FLAG_PRINTING)) { 1800 return APR_SUCCESS; 1801 } 1802 1803 if (!ctx->argc) { 1804 SSI_CREATE_ERROR_BUCKET(ctx, f, bb); 1805 return APR_SUCCESS; 1806 } 1807 1808 if (ctx->flags & SSI_FLAG_NO_EXEC) { 1809 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01271) "exec used but not allowed " 1810 "in %s", r->filename); 1811 SSI_CREATE_ERROR_BUCKET(ctx, f, bb); 1812 return APR_SUCCESS; 1813 } 1814 1815 while (1) { 1816 cgid_pfn_gtv(ctx, &tag, &tag_val, SSI_VALUE_DECODED); 1817 if (!tag || !tag_val) { 1818 break; 1819 } 1820 1821 if (!strcmp(tag, "cmd")) { 1822 apr_status_t rv; 1823 1824 cgid_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string), 1825 SSI_EXPAND_LEAVE_NAME); 1826 1827 rv = include_cmd(ctx, f, bb, parsed_string); 1828 if (rv != APR_SUCCESS) { 1829 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01272) 1830 "execution failure for parameter \"%s\" " 1831 "to tag exec in file %s", tag, r->filename); 1832 SSI_CREATE_ERROR_BUCKET(ctx, f, bb); 1833 break; 1834 } 1835 } 1836 else if (!strcmp(tag, "cgi")) { 1837 apr_status_t rv; 1838 1839 cgid_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string), 1840 SSI_EXPAND_DROP_NAME); 1841 1842 rv = include_cgi(ctx, f, bb, parsed_string); 1843 if (rv != APR_SUCCESS) { 1844 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01273) "invalid CGI ref " 1845 "\"%s\" in %s", tag_val, file); 1846 SSI_CREATE_ERROR_BUCKET(ctx, f, bb); 1847 break; 1848 } 1849 } 1850 else { 1851 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01274) "unknown parameter " 1852 "\"%s\" to tag exec in %s", tag, file); 1853 SSI_CREATE_ERROR_BUCKET(ctx, f, bb); 1854 break; 1855 } 1856 } 1857 1858 return APR_SUCCESS; 1859} 1860/*============================================================================ 1861 *============================================================================ 1862 * This is the end of the cgi filter code moved from mod_include. 1863 *============================================================================ 1864 *============================================================================*/ 1865 1866 1867static void register_hook(apr_pool_t *p) 1868{ 1869 static const char * const aszPre[] = { "mod_include.c", NULL }; 1870 1871 ap_hook_pre_config(cgid_pre_config, NULL, NULL, APR_HOOK_MIDDLE); 1872 ap_hook_post_config(cgid_init, aszPre, NULL, APR_HOOK_MIDDLE); 1873 ap_hook_handler(cgid_handler, NULL, NULL, APR_HOOK_MIDDLE); 1874} 1875 1876AP_DECLARE_MODULE(cgid) = { 1877 STANDARD20_MODULE_STUFF, 1878 NULL, /* dir config creater */ 1879 NULL, /* dir merger --- default is to override */ 1880 create_cgid_config, /* server config */ 1881 merge_cgid_config, /* merge server config */ 1882 cgid_cmds, /* command table */ 1883 register_hook /* register_handlers */ 1884}; 1885 1886