Apache HTTPD
mod_cgid.c
Go to the documentation of this file.
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 * This modules uses a httpd core function (ap_add_common_vars) to add some new env vars,
25 * like REDIRECT_URL and REDIRECT_QUERY_STRING for custom error responses and DOCUMENT_ROOT.
26 * It also adds SERVER_ADMIN - useful for scripts to know who to mail when they fail.
27 *
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 "ap_mpm.h"
61#include "mpm_common.h"
62#include "mod_suexec.h"
63#include "../filters/mod_include.h"
64
65#include "mod_core.h"
66
67
68/* ### should be tossed in favor of APR */
69#include <sys/stat.h>
70#include <sys/un.h> /* for sockaddr_un */
71
72#if APR_HAVE_STRUCT_RLIMIT
73#if defined (RLIMIT_CPU) || defined (RLIMIT_NPROC) || defined (RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
74#define AP_CGID_USE_RLIMIT
75#endif
76#endif
77
78module AP_MODULE_DECLARE_DATA cgid_module;
79
82
85static int daemon_should_exit = 0;
88static const char *sockname;
89static struct sockaddr_un *server_addr;
92static ap_unix_identity_t empty_ugid = { (uid_t)-1, (gid_t)-1, -1 };
93
97
98/* The APR other-child API doesn't tell us how the daemon exited
99 * (SIGSEGV vs. exit(1)). The other-child maintenance function
100 * needs to decide whether to restart the daemon after a failure
101 * based on whether or not it exited due to a fatal startup error
102 * or something that happened at steady-state. This exit status
103 * is unlikely to collide with exit signals.
104 */
105#define DAEMON_STARTUP_ERROR 254
106
107/* Read and discard the data in the brigade produced by a CGI script */
109
110/* This doer will only ever be called when we are sure that we have
111 * a valid ugid.
112 */
118
119/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
120 * in ScriptAliased directories, which means we need to know if this
121 * request came through ScriptAlias or not... so the Alias module
122 * leaves a note for us.
123 */
124
126{
127 const char *t = apr_table_get(r->notes, "alias-forced-type");
128 return t && (!strcasecmp(t, "cgi-script"));
129}
130
131/* Configuration stuff */
132
133#define DEFAULT_LOGBYTES 10385760
134#define DEFAULT_BUFBYTES 1024
135#define DEFAULT_SOCKET "cgisock"
136
137#define CGI_REQ 1
138#define SSI_REQ 2
139#define GETPID_REQ 3 /* get the pid of script created for prior request */
140
141#define ERRFN_USERDATA_KEY "CGIDCHILDERRFN"
142
143/* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's
144 * pending connection queue. If a bunch of cgi requests arrive at about
145 * the same time, connections from httpd threads/processes will back up
146 * in the queue while the cgid process slowly forks off a child to process
147 * each connection on the unix socket. If the queue is too short, the
148 * httpd process will get ECONNREFUSED when trying to connect.
149 */
150#ifndef DEFAULT_CGID_LISTENBACKLOG
151#define DEFAULT_CGID_LISTENBACKLOG 100
152#endif
153
154/* DEFAULT_CONNECT_ATTEMPTS controls how many times we'll try to connect
155 * to the cgi daemon from the thread/process handling the cgi request.
156 * Generally we want to retry when we get ECONNREFUSED since it is
157 * probably because the listen queue is full. We need to try harder so
158 * the client doesn't see it as a 503 error.
159 *
160 * Set this to 0 to continually retry until the connect works or Apache
161 * terminates.
162 */
163#ifndef DEFAULT_CONNECT_ATTEMPTS
164#define DEFAULT_CONNECT_ATTEMPTS 15
165#endif
166
167#ifndef DEFAULT_CONNECT_STARTUP_DELAY
168#define DEFAULT_CONNECT_STARTUP_DELAY 60
169#endif
170
171typedef struct {
172 const char *logname;
176
177#ifdef AP_CGID_USE_RLIMIT
178typedef struct {
179#ifdef RLIMIT_CPU
180 int limit_cpu_set;
181 struct rlimit limit_cpu;
182#endif
183#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
184 int limit_mem_set;
185 struct rlimit limit_mem;
186#endif
187#ifdef RLIMIT_NPROC
188 int limit_nproc_set;
189 struct rlimit limit_nproc;
190#endif
191
193#endif
194
195typedef struct {
196 int req_type; /* request type (CGI_REQ, SSI_REQ, etc.) */
197 unsigned long conn_id; /* connection id; daemon uses this as a hash value
198 * to find the script pid when it is time for that
199 * process to be cleaned up
200 */
201 pid_t ppid; /* sanity check for config problems leading to
202 * wrong cgid socket use
203 */
210 int loglevel; /* to stuff in server_rec */
211
212#ifdef AP_CGID_USE_RLIMIT
214#endif
215} cgid_req_t;
216
217#define cgi_server_conf cgid_server_conf
218#define cgi_module cgid_module
219
220#ifdef HAVE_CGID_FDPASSING
221/* Pull in CGI bucket implementation. */
222#define WANT_CGI_BUCKET
223#endif
224#include "cgi_common.h"
225
226/* This routine is called to create the argument list to be passed
227 * to the CGI script. When suexec is enabled, the suexec path, user, and
228 * group are the first three arguments to be passed; if not, all three
229 * must be NULL. The query info is split into separate arguments, where
230 * "+" is the separator between keyword arguments.
231 *
232 * Do not process the args if they containing an '=' assignment.
233 */
234static char **create_argv(apr_pool_t *p, char *path, char *user, char *group,
235 char *av0, const char *args)
236{
237 int x, numwords;
238 char **av;
239 char *w;
240 int idx = 0;
241
242 if (!(*args) || ap_strchr_c(args, '=')) {
243 numwords = 0;
244 }
245 else {
246 /* count the number of keywords */
247
248 for (x = 0, numwords = 1; args[x]; x++) {
249 if (args[x] == '+') {
250 ++numwords;
251 }
252 }
253 }
254
255 if (numwords > APACHE_ARG_MAX - 5) {
256 numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */
257 }
258 av = (char **) apr_pcalloc(p, (numwords + 5) * sizeof(char *));
259
260 if (path) {
261 av[idx++] = path;
262 }
263 if (user) {
264 av[idx++] = user;
265 }
266 if (group) {
267 av[idx++] = group;
268 }
269
270 av[idx++] = apr_pstrdup(p, av0);
271
272 for (x = 1; x <= numwords; x++) {
273 w = ap_getword_nulls(p, &args, '+');
275 av[idx++] = ap_escape_shell_cmd(p, w);
276 }
277 av[idx] = NULL;
278 return av;
279}
280
281#if APR_HAS_OTHER_CHILD
282static void cgid_maint(int reason, void *data, apr_wait_t status)
283{
285 int mpm_state;
286 int stopping;
287
288 switch (reason) {
291 /* If apache is not terminating or restarting,
292 * restart the cgid daemon
293 */
294 stopping = 1; /* if MPM doesn't support query,
295 * assume we shouldn't restart daemon
296 */
299 stopping = 0;
300 }
301 if (!stopping) {
304 "cgid daemon failed to initialize");
305 }
306 else {
308 "cgid daemon process died, restarting");
310 }
311 }
312 break;
314 /* don't do anything; server is stopping or restarting */
316 break;
318 /* Restart the child cgid daemon process */
321 break;
323 /* we get here when pcgi is cleaned up; pcgi gets cleaned
324 * up when pconf gets cleaned up
325 */
326 kill(proc->pid, SIGHUP); /* send signal to daemon telling it to die */
327
328 /* Remove the cgi socket, we must do it here in order to try and
329 * guarantee the same permissions as when the socket was created.
330 */
331 if (unlink(sockname) < 0 && errno != ENOENT) {
333 "Couldn't unlink unix domain socket %s",
334 sockname);
335 }
336 break;
337 }
338}
339#endif
340
342{
343 int fd = (int)((long)thefd);
344
345 return close(fd);
346}
347
348/* Read from the socket dealing with incomplete messages and signals.
349 * Returns 0 on success or errno on failure. Stderr fd passed as
350 * auxiliary data from other end is written to *errfd, or else stderr
351 * fileno if not present. */
352static apr_status_t sock_readhdr(int fd, int *errfd, void *vbuf, size_t buf_size)
353{
354 int rc;
355#ifndef HAVE_CGID_FDPASSING
356 char *buf = vbuf;
357 size_t bytes_read = 0;
358
359 if (errfd) *errfd = 0;
360
361 do {
362 do {
363 rc = read(fd, buf + bytes_read, buf_size - bytes_read);
364 } while (rc < 0 && errno == EINTR);
365 switch(rc) {
366 case -1:
367 return errno;
368 case 0: /* unexpected */
369 return ECONNRESET;
370 default:
371 bytes_read += rc;
372 }
373 } while (bytes_read < buf_size);
374
375
376#else /* with FD passing */
377 struct msghdr msg = {0};
378 struct iovec vec = {vbuf, buf_size};
379 struct cmsghdr *cmsg;
380 union { /* union to ensure alignment */
381 struct cmsghdr cm;
382 char buf[CMSG_SPACE(sizeof(int))];
383 } u;
384
385 msg.msg_iov = &vec;
386 msg.msg_iovlen = 1;
387
388 if (errfd) {
389 msg.msg_control = u.buf;
390 msg.msg_controllen = sizeof(u.buf);
391 *errfd = 0;
392 }
393
394 /* use MSG_WAITALL to skip loop on truncated reads */
395 do {
396 rc = recvmsg(fd, &msg, MSG_WAITALL);
397 } while (rc < 0 && errno == EINTR);
398
399 if (rc == 0) {
400 return ECONNRESET;
401 }
402 else if (rc < 0) {
403 return errno;
404 }
405 else if (rc != buf_size) {
406 /* MSG_WAITALL should ensure the recvmsg blocks until the
407 * entire length is read, but let's be paranoid. */
408 return APR_INCOMPLETE;
409 }
410
411 if (errfd
412 && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL
413 && cmsg->cmsg_len == CMSG_LEN(sizeof(*errfd))
414 && cmsg->cmsg_level == SOL_SOCKET
415 && cmsg->cmsg_type == SCM_RIGHTS) {
416 *errfd = *((int *) CMSG_DATA(cmsg));
417 }
418#endif
419
420 return APR_SUCCESS;
421}
422
423/* As sock_readhdr but without auxiliary fd passing. */
424static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size)
425{
426 return sock_readhdr(fd, NULL, vbuf, buf_size);
427}
428
429/* deal with signals
430 */
431static apr_status_t sock_write(int fd, const void *buf, size_t buf_size)
432{
433 int rc;
434
435 do {
436 rc = write(fd, buf, buf_size);
437 } while (rc < 0 && errno == EINTR);
438 if (rc < 0) {
439 return errno;
440 }
441
442 return APR_SUCCESS;
443}
444
445static apr_status_t sock_writev(int fd, int auxfd, request_rec *r, int count, ...)
446{
447 va_list ap;
448 int rc;
449 struct iovec *vec;
450 int i;
451
452 vec = (struct iovec *)apr_palloc(r->pool, count * sizeof(struct iovec));
453 va_start(ap, count);
454 for (i = 0; i < count; i++) {
455 vec[i].iov_base = va_arg(ap, caddr_t);
456 vec[i].iov_len = va_arg(ap, apr_size_t);
457 }
458 va_end(ap);
459
460#ifndef HAVE_CGID_FDPASSING
461 do {
462 rc = writev(fd, vec, count);
463 } while (rc < 0 && errno == EINTR);
464#else
465 {
466 struct msghdr msg = { 0 };
467 struct cmsghdr *cmsg;
468 union { /* union for alignment */
469 char buf[CMSG_SPACE(sizeof(int))];
470 struct cmsghdr align;
471 } u;
472
473 msg.msg_iov = vec;
474 msg.msg_iovlen = count;
475
476 if (auxfd) {
477 msg.msg_control = u.buf;
478 msg.msg_controllen = sizeof(u.buf);
479
480 cmsg = CMSG_FIRSTHDR(&msg);
481 cmsg->cmsg_level = SOL_SOCKET;
482 cmsg->cmsg_type = SCM_RIGHTS;
483 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
484 *((int *) CMSG_DATA(cmsg)) = auxfd;
485 }
486
487 do {
488 rc = sendmsg(fd, &msg, 0);
489 } while (rc < 0 && errno == EINTR);
490 }
491#endif
492
493 if (rc < 0) {
494 return errno;
495 }
496
497 return APR_SUCCESS;
498}
499
500static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env,
501 int *errfd, cgid_req_t *req)
502{
503 int i;
504 char **environ;
506 void **rconf;
508
509 r->server = apr_pcalloc(r->pool, sizeof(server_rec));
510
511 /* read the request header */
512 stat = sock_readhdr(fd, errfd, req, sizeof(*req));
513 if (stat != APR_SUCCESS) {
514 return stat;
515 }
516 r->server->log.level = req->loglevel;
517 if (req->req_type == GETPID_REQ) {
518 /* no more data sent for this request */
519 return APR_SUCCESS;
520 }
521
522 /* Sanity check the structure received. */
523 if (req->env_count < 0 || req->uri_len == 0
524 || req->filename_len > APR_PATH_MAX || req->filename_len == 0
525 || req->argv0_len > APR_PATH_MAX || req->argv0_len == 0
526 || req->loglevel > APLOG_TRACE8) {
527 return APR_EINVAL;
528 }
529
530 /* handle module indexes and such */
532
533 temp_core = (core_request_config *)apr_palloc(r->pool, sizeof(core_module));
536 ap_set_module_config(r->request_config, &cgid_module, (void *)&req->ugid);
537
538 /* Read the filename, argv0, uri, and args */
539 r->filename = apr_pcalloc(r->pool, req->filename_len + 1);
540 *argv0 = apr_pcalloc(r->pool, req->argv0_len + 1);
541 r->uri = apr_pcalloc(r->pool, req->uri_len + 1);
542 if ((stat = sock_read(fd, r->filename, req->filename_len)) != APR_SUCCESS ||
543 (stat = sock_read(fd, *argv0, req->argv0_len)) != APR_SUCCESS ||
544 (stat = sock_read(fd, r->uri, req->uri_len)) != APR_SUCCESS) {
545 return stat;
546 }
547
548 r->args = apr_pcalloc(r->pool, req->args_len + 1); /* empty string if no args */
549 if (req->args_len) {
550 if ((stat = sock_read(fd, r->args, req->args_len)) != APR_SUCCESS) {
551 return stat;
552 }
553 }
554
555 /* read the environment variables */
556 environ = apr_pcalloc(r->pool, (req->env_count + 2) *sizeof(char *));
557 for (i = 0; i < req->env_count; i++) {
559
560 if ((stat = sock_read(fd, &curlen, sizeof(curlen))) != APR_SUCCESS) {
561 return stat;
562 }
563 environ[i] = apr_pcalloc(r->pool, curlen + 1);
564 if ((stat = sock_read(fd, environ[i], curlen)) != APR_SUCCESS) {
565 return stat;
566 }
567 }
568 *env = environ;
569
570#ifdef AP_CGID_USE_RLIMIT
571 if ((stat = sock_read(fd, &(req->limits), sizeof(cgid_rlimit_t))) != APR_SUCCESS)
572 return stat;
573#endif
574
575 return APR_SUCCESS;
576}
577
579 const char *argv0, char **env, int req_type)
580{
581 int i;
582 cgid_req_t req = {0};
586 int errfd;
587
588
589 if (ugid == NULL) {
590 req.ugid = empty_ugid;
591 } else {
592 memcpy(&req.ugid, ugid, sizeof(ap_unix_identity_t));
593 }
594
595 req.req_type = req_type;
596 req.ppid = parent_pid;
597 req.conn_id = r->connection->id;
598 for (req.env_count = 0; env[req.env_count]; req.env_count++) {
599 continue;
600 }
601 req.filename_len = strlen(r->filename);
602 req.argv0_len = strlen(argv0);
603 req.uri_len = strlen(r->uri);
604 req.args_len = r->args ? strlen(r->args) : 0;
605 req.loglevel = r->server->log.level;
606
607 if (errpipe)
609 else
610 errfd = 0;
611
612 /* Write the request header */
613 if (req.args_len) {
614 stat = sock_writev(fd, errfd, r, 5,
615 &req, sizeof(req),
616 r->filename, req.filename_len,
617 argv0, req.argv0_len,
618 r->uri, req.uri_len,
619 r->args, req.args_len);
620 } else {
621 stat = sock_writev(fd, errfd, r, 4,
622 &req, sizeof(req),
623 r->filename, req.filename_len,
624 argv0, req.argv0_len,
625 r->uri, req.uri_len);
626 }
627
628 if (stat != APR_SUCCESS) {
629 return stat;
630 }
631
632 /* write the environment variables */
633 for (i = 0; i < req.env_count; i++) {
634 apr_size_t curlen = strlen(env[i]);
635
636 if ((stat = sock_writev(fd, 0, r, 2, &curlen, sizeof(curlen),
637 env[i], curlen)) != APR_SUCCESS) {
638 return stat;
639 }
640 }
641#if defined(RLIMIT_CPU) && defined(AP_CGID_USE_RLIMIT)
642 if (core_conf->limit_cpu) {
643 req.limits.limit_cpu = *(core_conf->limit_cpu);
644 req.limits.limit_cpu_set = 1;
645 }
646 else {
647 req.limits.limit_cpu_set = 0;
648 }
649#endif
650
651#if defined(AP_CGID_USE_RLIMIT) && (defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS))
652 if (core_conf->limit_mem) {
653 req.limits.limit_mem = *(core_conf->limit_mem);
654 req.limits.limit_mem_set = 1;
655 }
656 else {
657 req.limits.limit_mem_set = 0;
658 }
659
660#endif
661
662#if defined(RLIMIT_NPROC) && defined(AP_CGID_USE_RLIMIT)
663 if (core_conf->limit_nproc) {
664 req.limits.limit_nproc = *(core_conf->limit_nproc);
665 req.limits.limit_nproc_set = 1;
666 }
667 else {
668 req.limits.limit_nproc_set = 0;
669 }
670#endif
671
672#ifdef AP_CGID_USE_RLIMIT
673 if ( (stat = sock_write(fd, &(req.limits), sizeof(cgid_rlimit_t))) != APR_SUCCESS)
674 return stat;
675#endif
676
677 return APR_SUCCESS;
678}
679
681{
682 if (sig == SIGHUP) {
684 }
685}
686
687/* Callback executed in the forked child process if exec of the CGI
688 * script fails. For the fd-passing case, output to stderr goes to
689 * the client (request handling thread) and is logged via
690 * ap_log_rerror there. For the non-fd-passing case, the "fake"
691 * request_rec passed via userdata is used to log. */
693 const char *description)
694{
695 void *vr;
696
698 if (vr) {
699 request_rec *r = vr;
700
701 /* sure we got r, but don't call ap_log_rerror() because we don't
702 * have r->headers_in and possibly other storage referenced by
703 * ap_log_rerror()
704 */
705 ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description);
706 }
707 else {
708 const char *logstr;
709
710 logstr = apr_psprintf(pool, APLOGNO(01241) "error spawning CGI child: %s (%pm)\n",
711 description, &err);
713 fflush(stderr);
714 }
715}
716
717static int cgid_server(void *data)
718{
719 int sd, sd2, rc;
724 apr_status_t rv;
725
727 apr_pool_tag(ptrans, "cgid_ptrans");
728
731
732 /* Close our copy of the listening sockets */
734
735 /* cgid should use its own suexec doer */
739
740 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
742 "Couldn't create unix domain socket");
743 return errno;
744 }
745
746 apr_pool_cleanup_register(pcgi, (void *)((long)sd),
748
749 omask = umask(0077); /* so that only Apache can use socket */
750 rc = bind(sd, (struct sockaddr *)server_addr, server_addr_len);
751 umask(omask); /* can't fail, so can't clobber errno */
752 if (rc < 0) {
754 "Couldn't bind unix domain socket %s",
755 sockname);
756 return errno;
757 }
758
759 /* Not all flavors of unix use the current umask for AF_UNIX perms */
761 if (rv != APR_SUCCESS) {
763 "Couldn't set permissions on unix domain socket %s",
764 sockname);
765 return rv;
766 }
767
768 if (listen(sd, DEFAULT_CGID_LISTENBACKLOG) < 0) {
770 "Couldn't listen on unix domain socket");
771 return errno;
772 }
773
774 if (!geteuid()) {
775 if (chown(sockname, ap_unixd_config.user_id, -1) < 0) {
777 "Couldn't change owner of unix domain socket %s",
778 sockname);
779 return errno;
780 }
781 }
782
783 /* if running as root, switch to configured user/group */
785 return rc;
786 }
787
788 while (!daemon_should_exit) {
789 int errfileno;
790 char *argv0 = NULL;
791 char **env = NULL;
792 const char * const *argv;
793 apr_int32_t in_pipe;
794 apr_int32_t out_pipe;
795 apr_int32_t err_pipe;
796 apr_cmdtype_e cmd_type;
797 request_rec *r;
798 apr_procattr_t *procattr = NULL;
803 void *key;
805 struct sockaddr_un unix_addr;
806
808
809 len = sizeof(unix_addr);
810 sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len);
811 if (sd2 < 0) {
812#if defined(ENETDOWN)
813 if (errno == ENETDOWN) {
814 /* The network has been shut down, no need to continue. Die gracefully */
816 }
817#endif
818 if (errno != EINTR) {
820 (server_rec *)data, APLOGNO(01247)
821 "Error accepting on cgid socket");
822 }
823 continue;
824 }
825
826 r = apr_pcalloc(ptrans, sizeof(request_rec));
827 procnew = apr_pcalloc(ptrans, sizeof(*procnew));
828 r->pool = ptrans;
830 if (stat != APR_SUCCESS) {
832 main_server, APLOGNO(01248)
833 "Error reading request on cgid socket");
834 close(sd2);
835 continue;
836 }
837
838 if (cgid_req.ppid != parent_pid) {
840 "CGI request received from wrong server instance; "
841 "see ScriptSock directive");
842 close(sd2);
843 continue;
844 }
845
846 if (cgid_req.req_type == GETPID_REQ) {
847 pid_t pid;
848 apr_status_t rv;
849
850 pid = (pid_t)((long)apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id)));
851 rv = sock_write(sd2, &pid, sizeof(pid));
852 if (rv != APR_SUCCESS) {
854 main_server, APLOGNO(01250)
855 "Error writing pid %" APR_PID_T_FMT " to handler", pid);
856 }
857 close(sd2);
858 continue;
859 }
860
861 if (errfileno == 0) {
863 }
864 else {
866 "using passed fd %d as stderr", errfileno);
867 /* Limit the received fd lifetime to pool lifetime */
870 }
872 apr_os_file_put(&inout, &sd2, 0, r->pool);
873
874 if (cgid_req.req_type == SSI_REQ) {
875 in_pipe = APR_NO_PIPE;
876 out_pipe = APR_FULL_BLOCK;
877 err_pipe = APR_NO_PIPE;
878 cmd_type = APR_SHELLCMD;
879 }
880 else {
881 in_pipe = APR_CHILD_BLOCK;
882 out_pipe = APR_CHILD_BLOCK;
883 err_pipe = APR_CHILD_BLOCK;
884 cmd_type = APR_PROGRAM;
885 }
886
887 if (((rc = apr_procattr_create(&procattr, ptrans)) != APR_SUCCESS) ||
888 ((cgid_req.req_type == CGI_REQ) &&
889 (((rc = apr_procattr_io_set(procattr,
890 in_pipe,
891 out_pipe,
892 err_pipe)) != APR_SUCCESS) ||
893 /* XXX apr_procattr_child_*_set() is creating an unnecessary
894 * pipe between this process and the child being created...
895 * It is cleaned up with the temporary pool for this request.
896 */
898 ((rc = apr_procattr_child_in_set(procattr, inout, NULL)) != APR_SUCCESS))) ||
899 ((rc = apr_procattr_child_out_set(procattr, inout, NULL)) != APR_SUCCESS) ||
900 ((rc = apr_procattr_dir_set(procattr,
902 ((rc = apr_procattr_cmdtype_set(procattr, cmd_type)) != APR_SUCCESS) ||
905 ( (cgid_req.limits.limit_cpu_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU,
906 &cgid_req.limits.limit_cpu)) != APR_SUCCESS)) ||
907#endif
909 ( (cgid_req.limits.limit_mem_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM,
910 &cgid_req.limits.limit_mem)) != APR_SUCCESS)) ||
911#endif
913 ( (cgid_req.limits.limit_nproc_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC,
914 &cgid_req.limits.limit_nproc)) != APR_SUCCESS)) ||
915#endif
916#endif
917
919 /* Something bad happened, tell the world.
920 * ap_log_rerror() won't work because the header table used by
921 * ap_log_rerror() hasn't been replicated in the phony r
922 */
924 "couldn't set child process attributes: %s", r->filename);
925
926 procnew->pid = 0; /* no process to clean up */
927 close(sd2);
928 }
929 else {
930 if (errfileno == STDERR_FILENO) {
931 /* Used by cgid_child_errfn without fd-passing. */
933 }
934
935 argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args);
936
937 /* We want to close sd2 for the new CGI process too.
938 * If it is left open it'll make ap_pass_brigade() block
939 * waiting for EOF if CGI forked something running long.
940 * close(sd2) here should be okay, as CGI channel
941 * is already dup()ed by apr_procattr_child_{in,out}_set()
942 * above.
943 */
944 close(sd2);
945
946 if (memcmp(&empty_ugid, &cgid_req.ugid, sizeof(empty_ugid))) {
947 /* We have a valid identity, and can be sure that
948 * cgid_suexec_id_doer will return a valid ugid
949 */
951 (const char * const *)env,
952 procattr, ptrans);
953 } else {
955 (const char * const *)env,
956 procattr, ptrans);
957 }
958
959 if (rc != APR_SUCCESS) {
960 /* Bad things happened. Everyone should have cleaned up.
961 * ap_log_rerror() won't work because the header table used by
962 * ap_log_rerror() hasn't been replicated in the phony r
963 */
965 "couldn't create child process: %d: %s", rc,
967
968 procnew->pid = 0; /* no process to clean up */
969 }
970 }
971
972 /* If the script process was created, remember the pid for
973 * later cleanup. If the script process wasn't created, clear
974 * out any prior pid with the same key.
975 *
976 * We don't want to leak storage for the key, so only allocate
977 * a key if the key doesn't exist yet in the hash; there are
978 * only a limited number of possible keys (one for each
979 * possible thread in the server), so we can allocate a copy
980 * of the key the first time a thread has a cgid request.
981 * Note that apr_hash_set() only uses the storage passed in
982 * for the key if it is adding the key to the hash for the
983 * first time; new key storage isn't needed for replacing the
984 * existing value of a key.
985 */
986
987 if (apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id))) {
988 key = &cgid_req.conn_id;
989 }
990 else {
991 key = apr_pmemdup(pcgi, &cgid_req.conn_id, sizeof(cgid_req.conn_id));
992 }
993 apr_hash_set(script_hash, key, sizeof(cgid_req.conn_id),
994 (void *)((long)procnew->pid));
995 }
996 return -1; /* should be <= 0 to distinguish from startup errors */
997}
998
1001{
1002
1003 daemon_should_exit = 0; /* clear setting from previous generation */
1004 if ((daemon_pid = fork()) < 0) {
1006 "mod_cgid: Couldn't spawn cgid daemon process");
1007 return DECLINED;
1008 }
1009 else if (daemon_pid == 0) {
1010 if (pcgi == NULL) {
1012 apr_pool_tag(pcgi, "cgid_pcgi");
1013 }
1015 }
1016 procnew->pid = daemon_pid;
1017 procnew->err = procnew->in = procnew->out = NULL;
1019#if APR_HAS_OTHER_CHILD
1021#endif
1022 return OK;
1023}
1024
1026 apr_pool_t *ptemp)
1027{
1029 return OK;
1030}
1031
1034{
1036 const char *userdata_key = "cgid_init";
1037 int ret = OK;
1038 void *data;
1039
1041 root_pool = p;
1042
1044 if (!data) {
1046 procnew->pid = -1;
1047 procnew->err = procnew->in = procnew->out = NULL;
1050 return ret;
1051 }
1052 else {
1053 procnew = data;
1054 }
1055
1057 char *tmp_sockname;
1058
1059 parent_pid = getpid();
1061 if (strlen(tmp_sockname) > sizeof(server_addr->sun_path) - 1) {
1062 tmp_sockname[sizeof(server_addr->sun_path)] = '\0';
1064 "The length of the ScriptSock path exceeds maximum, "
1065 "truncating to %s", tmp_sockname);
1066 }
1068
1071 server_addr->sun_family = AF_UNIX;
1072 strcpy(server_addr->sun_path, sockname);
1073
1075 if (ret != OK ) {
1076 return ret;
1077 }
1078 }
1079 return ret;
1080}
1081
1083{
1086
1087 c->logname = NULL;
1088 c->logbytes = DEFAULT_LOGBYTES;
1089 c->bufbytes = DEFAULT_BUFBYTES;
1090 return c;
1091}
1092
1099
1101{
1103 return c;
1104}
1105
1106static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg)
1107
1108{
1109 server_rec *s = cmd->server;
1110 cgid_server_conf *conf = ap_get_module_config(s->module_config,
1111 &cgid_module);
1112
1113 conf->logname = ap_server_root_relative(cmd->pool, arg);
1114
1115 if (!conf->logname) {
1116 return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ",
1117 arg, NULL);
1118 }
1119 return NULL;
1120}
1121
1122static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy, const char *arg)
1123{
1124 server_rec *s = cmd->server;
1125 cgid_server_conf *conf = ap_get_module_config(s->module_config,
1126 &cgid_module);
1127
1128 conf->logbytes = atol(arg);
1129 return NULL;
1130}
1131
1132static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, const char *arg)
1133{
1134 server_rec *s = cmd->server;
1135 cgid_server_conf *conf = ap_get_module_config(s->module_config,
1136 &cgid_module);
1137
1138 conf->bufbytes = atoi(arg);
1139 return NULL;
1140}
1141
1142static const char *set_script_socket(cmd_parms *cmd, void *dummy, const char *arg)
1143{
1144 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1145 if (err != NULL) {
1146 return err;
1147 }
1148
1149 /* Make sure the pid is appended to the sockname */
1150 sockname = ap_append_pid(cmd->pool, arg, ".");
1152
1153 if (!sockname) {
1154 return apr_pstrcat(cmd->pool, "Invalid ScriptSock path",
1155 arg, NULL);
1156 }
1157
1158 return NULL;
1159}
1160static const char *set_script_timeout(cmd_parms *cmd, void *dummy, const char *arg)
1161{
1162 cgid_dirconf *dc = dummy;
1163
1164 if (ap_timeout_parameter_parse(arg, &dc->timeout, "s") != APR_SUCCESS) {
1165 return "CGIDScriptTimeout has wrong format";
1166 }
1167
1168 return NULL;
1169}
1170static const command_rec cgid_cmds[] =
1171{
1173 "the name of a log for script debugging info"),
1174 AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF,
1175 "the maximum length (in bytes) of the script debug log"),
1176 AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF,
1177 "the maximum size (in bytes) to record of a POST request"),
1179 "the name of the socket to use for communication with "
1180 "the cgi daemon."),
1182 "The amount of time to wait between successful reads from "
1183 "the CGI script, in seconds."),
1184
1185 {NULL}
1186};
1187
1189 char *dbuf, const char *sbuf, apr_bucket_brigade *bb,
1191{
1193 const apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
1195 apr_file_t *f = NULL;
1196 apr_bucket *e;
1197 const char *buf;
1199 apr_status_t rv;
1200 int first;
1201 int i;
1202 struct stat finfo;
1203 char time_str[APR_CTIME_LEN];
1204
1205 /* XXX Very expensive mainline case! Open, then getfileinfo! */
1206 if (!conf->logname ||
1207 ((stat(conf->logname, &finfo) == 0)
1208 && (finfo.st_size > conf->logbytes)) ||
1209 (apr_file_open(&f, conf->logname,
1211 /* Soak up script output */
1213 if (script_err) {
1216 continue;
1217 }
1218 return ret;
1219 }
1220
1221 /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */
1222 apr_ctime(time_str, apr_time_now());
1223 apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
1224 r->args ? "?" : "", r->args ? r->args : "", r->protocol);
1225 /* "%% 500 /usr/local/apache/cgid-bin" */
1226 apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
1227
1228 apr_file_puts("%request\n", f);
1229 for (i = 0; i < hdrs_arr->nelts; ++i) {
1230 if (!hdrs[i].key)
1231 continue;
1232 apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
1233 }
1234 if ((r->method_number == M_POST || r->method_number == M_PUT)
1235 && *dbuf) {
1236 apr_file_printf(f, "\n%s\n", dbuf);
1237 }
1238
1239 apr_file_puts("%response\n", f);
1241 hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
1242
1243 for (i = 0; i < hdrs_arr->nelts; ++i) {
1244 if (!hdrs[i].key)
1245 continue;
1246 apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
1247 }
1248
1249 if (sbuf && *sbuf)
1250 apr_file_printf(f, "%s\n", sbuf);
1251
1252 first = 1;
1253
1254 for (e = APR_BRIGADE_FIRST(bb);
1255 e != APR_BRIGADE_SENTINEL(bb);
1256 e = APR_BUCKET_NEXT(e))
1257 {
1258 if (APR_BUCKET_IS_EOS(e)) {
1259 break;
1260 }
1262 if (rv != APR_SUCCESS || (len == 0)) {
1263 break;
1264 }
1265 if (first) {
1266 apr_file_puts("%stdout\n", f);
1267 first = 0;
1268 }
1270 apr_file_puts("\n", f);
1271 }
1272
1273 if (script_err) {
1275 script_err) == APR_SUCCESS) {
1276 apr_file_puts("%stderr\n", f);
1281 apr_file_puts("\n", f);
1282 }
1283 }
1284
1285 if (script_err) {
1287 }
1288
1290 return ret;
1291}
1292
1294 cgid_server_conf *conf)
1295{
1296 int sd;
1297 int connect_tries;
1298 int connect_errno;
1300
1301 connect_tries = 0;
1302 sliding_timer = 100000; /* 100 milliseconds */
1303 while (1) {
1304 connect_errno = 0;
1305 ++connect_tries;
1306 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
1308 APLOGNO(01255), "unable to create socket to cgi daemon");
1309 }
1310 if (connect(sd, (struct sockaddr *)server_addr, server_addr_len) < 0) {
1311 /* Save errno for later */
1313 /* ECONNREFUSED means the listen queue is full; ENOENT means that
1314 * the cgid server either hasn't started up yet, or we're pointing
1315 * at the wrong socket file */
1316 if ((errno == ECONNREFUSED || errno == ENOENT) &&
1319 "connect #%d to cgi daemon failed, sleeping before retry",
1321 close(sd);
1324 sliding_timer *= 2;
1325 }
1326 }
1327 else {
1328 close(sd);
1330 "unable to connect to cgi daemon after multiple tries");
1331 }
1332 }
1333 else {
1334 apr_pool_cleanup_register(r->pool, (void *)((long)sd),
1336 break; /* we got connected! */
1337 }
1338
1339 /* If we didn't find the socket but the server was not recently restarted,
1340 * chances are there's something wrong with the cgid daemon
1341 */
1342 if (connect_errno == ENOENT &&
1346 APLOGNO(02833),
1348 "ScriptSock ", sockname, " does not exist", NULL));
1349 }
1350
1351 /* gotta try again, but make sure the cgid daemon is still around */
1352 if (connect_errno != ENOENT && kill(daemon_pid, 0) != 0) {
1354 "cgid daemon is gone; is Apache terminating?");
1355 }
1356 }
1357 *sdptr = sd;
1358 return OK;
1359}
1360
1361/****************************************************************
1362 *
1363 * Actual cgid handling...
1364 */
1365
1371
1373{
1374 apr_interval_time_t interval = 10000; /* 10 ms */
1375 apr_interval_time_t total = 0;
1376
1377 do {
1378#ifdef _AIX
1379 /* On AIX, for processes like mod_cgid's script children where
1380 * SIGCHLD is ignored, kill(pid,0) returns success for up to
1381 * one second after the script child exits, based on when a
1382 * daemon runs to clean up unnecessary process table entries.
1383 * getpgid() can report the proper info (-1/ESRCH) immediately.
1384 */
1385 if (getpgid(pid) < 0) {
1386#else
1387 if (kill(pid, 0) < 0) {
1388#endif
1389 return APR_SUCCESS;
1390 }
1391 apr_sleep(interval);
1392 total = total + interval;
1393 if (interval < 500000) {
1394 interval *= 2;
1395 }
1396 } while (total < max_wait);
1397 return APR_EGENERAL;
1398}
1399
1401{
1402 kill(pid, SIGTERM); /* in case it isn't dead yet */
1403 if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {
1404 return APR_SUCCESS;
1405 }
1407 "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL",
1408 pid);
1409 kill(pid, SIGKILL);
1410 if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {
1411 return APR_SUCCESS;
1412 }
1414 "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL again",
1415 pid);
1416 kill(pid, SIGKILL);
1417
1418 return APR_EGENERAL;
1419}
1420
1422 cgid_req_t req = {0};
1424 int rc, sd;
1425
1426 rc = connect_to_daemon(&sd, r, conf);
1427 if (rc != OK) {
1428 return APR_EGENERAL;
1429 }
1430
1431 req.req_type = GETPID_REQ;
1432 req.ppid = parent_pid;
1433 req.conn_id = r->connection->id;
1434
1435 stat = sock_write(sd, &req, sizeof(req));
1436 if (stat != APR_SUCCESS) {
1437 return stat;
1438 }
1439
1440 /* wait for pid of script */
1441 stat = sock_read(sd, pid, sizeof(*pid));
1442 if (stat != APR_SUCCESS) {
1443 return stat;
1444 }
1445
1446 /* Don't accept zero as a pid here, calling kill(0, SIGTERM) etc
1447 * later is unpleasant. */
1448 if (*pid == 0) {
1450 "daemon couldn't find CGI process for connection %lu",
1451 r->connection->id);
1452 return APR_EGENERAL;
1453 }
1454
1455 return APR_SUCCESS;
1456}
1457
1458
1460{
1461 struct cleanup_script_info *info = vptr;
1462 return cleanup_nonchild_process(info->r, info->pid);
1463}
1464
1466{
1467 conn_rec *c = r->connection;
1468 int retval, nph;
1469 char *argv0, *dbuf;
1472 apr_bucket *b;
1474 int is_included;
1475 int sd;
1476 char **env;
1478 struct cleanup_script_info *info;
1479 apr_status_t rv;
1480 cgid_dirconf *dc;
1482
1483 if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) {
1484 return DECLINED;
1485 }
1486
1487 conf = ap_get_module_config(r->server->module_config, &cgid_module);
1488 dc = ap_get_module_config(r->per_dir_config, &cgid_module);
1489
1490 timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout;
1491 is_included = !strcmp(r->protocol, "INCLUDED");
1492
1493 if ((argv0 = strrchr(r->filename, '/')) != NULL) {
1494 argv0++;
1495 }
1496 else {
1497 argv0 = r->filename;
1498 }
1499
1500 nph = !(strncmp(argv0, "nph-", 4));
1501
1502 argv0 = r->filename;
1503
1505 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01262),
1506 "Options ExecCGI is off in this directory");
1507 }
1508
1509 if (nph && is_included) {
1510 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01263),
1511 "attempt to include NPH CGI script");
1512 }
1513
1514#if defined(OS2) || defined(WIN32)
1515#error mod_cgid does not work on this platform. If you teach it to, look
1516#error at mod_cgi.c for required code in this path.
1517#else
1518 if (r->finfo.filetype == APR_NOFILE) {
1519 return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(01264),
1520 "script not found or unable to stat");
1521 }
1522#endif
1523 if (r->finfo.filetype == APR_DIR) {
1524 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01265),
1525 "attempt to invoke directory as script");
1526 }
1527
1529 r->path_info && *r->path_info)
1530 {
1531 /* default to accept */
1532 return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(01266),
1533 "AcceptPathInfo off disallows user's path");
1534 }
1535 /*
1536 if (!ap_suexec_enabled) {
1537 if (!ap_can_exec(&r->finfo))
1538 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01267)
1539 "file permissions deny server execution");
1540 }
1541 */
1542
1543#ifdef HAVE_CGID_FDPASSING
1545 if (rv) {
1547 "could not create pipe for stderr");
1548 }
1549#else
1550 script_err = NULL;
1551 errpipe_out = NULL;
1552#endif
1553
1554 /*
1555 * httpd core function used to add common environment variables like
1556 * DOCUMENT_ROOT.
1557 */
1561
1562 if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
1563 return retval;
1564 }
1565
1566 rv = send_req(sd, errpipe_out, r, argv0, env, CGI_REQ);
1567 if (rv != APR_SUCCESS) {
1569 "could not send request to cgi daemon");
1570 }
1571
1572 /* The write-end of the pipe is only used by the server, so close
1573 * it here. */
1575
1576 info = apr_palloc(r->pool, sizeof(struct cleanup_script_info));
1577 info->conf = conf;
1578 info->r = r;
1579 rv = get_cgi_pid(r, conf, &(info->pid));
1580
1581 if (rv == APR_SUCCESS) {
1584 }
1585 else {
1587 "failed reading PID from cgi daemon");
1588 }
1589
1590 /* We are putting the socket discriptor into an apr_file_t so that we can
1591 * use a pipe bucket to send the data to the client. APR will create
1592 * a cleanup for the apr_file_t which will close the socket, so we'll
1593 * get rid of the cleanup we registered when we created the socket.
1594 */
1595
1596 apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool);
1598 apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket);
1599
1600 /* Buffer for logging script stdout. */
1601 if (conf->logname) {
1603 dbuf = apr_palloc(r->pool, dbufsize + 1);
1604 }
1605 else {
1606 dbuf = NULL;
1607 dbufsize = 0;
1608 }
1609
1610 /* Read the request body. */
1612 if (rv) {
1614 "Error reading request entity data");
1616 }
1617
1618 /* we're done writing, or maybe we didn't write at all;
1619 * force EOF on child's stdin so that the cgi detects end (or
1620 * absence) of data
1621 */
1622 shutdown(sd, 1);
1623
1624 bb = apr_brigade_create(r->pool, c->bucket_alloc);
1625#ifdef HAVE_CGID_FDPASSING
1626 b = cgi_bucket_create(r, dc->timeout, tempsock, script_err, c->bucket_alloc);
1627 if (b == NULL)
1628 return HTTP_INTERNAL_SERVER_ERROR; /* should call log_scripterror() w/ _UNAVAILABLE? */
1629#else
1630 b = apr_bucket_pipe_create(tempsock, c->bucket_alloc);
1631#endif
1633 b = apr_bucket_eos_create(c->bucket_alloc);
1635
1637}
1638
1639/* Handling include= for mod_include. */
1641 apr_bucket_brigade *bb, char *s)
1642{
1643 request_rec *r = f->r;
1645 int rr_status;
1646
1647 if (rr->status != HTTP_OK) {
1649 return APR_EGENERAL;
1650 }
1651
1652 /* No hardwired path info or query allowed */
1653 if ((rr->path_info && rr->path_info[0]) || rr->args) {
1655 return APR_EGENERAL;
1656 }
1657 if (rr->finfo.filetype != APR_REG) {
1659 return APR_EGENERAL;
1660 }
1661
1662 /* Script gets parameters of the *document*, for back compatibility */
1663 rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */
1664 rr->args = r->args;
1665
1666 /* Force sub_req to be treated as a CGI request, even if ordinary
1667 * typing rules would have called it something else.
1668 */
1670
1671 /* Run it. */
1674 const char *location = apr_table_get(rr->headers_out, "Location");
1675
1676 if (location) {
1677 char *buffer;
1678
1679 location = ap_escape_html(rr->pool, location);
1680 buffer = apr_pstrcat(ctx->pool, "<a href=\"", location, "\">",
1681 location, "</a>", NULL);
1682
1684 strlen(buffer), ctx->pool,
1685 f->c->bucket_alloc));
1686 }
1687 }
1688
1690
1691 return APR_SUCCESS;
1692}
1693
1694/* This is the special environment used for running the "exec cmd="
1695 * variety of SSI directives.
1696 */
1698{
1700
1701 if (r->path_info && r->path_info[0] != '\0') {
1703
1705
1707 if (pa_req->filename) {
1708 apr_table_setn(e, "PATH_TRANSLATED",
1709 apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL));
1710 }
1712 }
1713
1714 if (r->args) {
1715 char *arg_copy = apr_pstrdup(r->pool, r->args);
1716
1717 apr_table_setn(e, "QUERY_STRING", r->args);
1719 apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy));
1720 }
1721}
1722
1724 apr_bucket_brigade *bb, const char *command)
1725{
1726 char **env;
1727 int sd;
1728 int retval;
1730 request_rec *r = f->r;
1732 &cgid_module);
1733 cgid_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgid_module);
1734
1735 struct cleanup_script_info *info;
1736 apr_status_t rv;
1737
1738 add_ssi_vars(r);
1740
1741 if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
1742 return retval;
1743 }
1744
1745 send_req(sd, NULL, r, command, env, SSI_REQ);
1746
1747 info = apr_palloc(r->pool, sizeof(struct cleanup_script_info));
1748 info->conf = conf;
1749 info->r = r;
1750 rv = get_cgi_pid(r, conf, &(info->pid));
1751 if (APR_SUCCESS == rv) {
1752 /* for this type of request, the script is invoked through an
1753 * intermediate shell process... cleanup_script is only able
1754 * to knock out the shell process, not the actual script
1755 */
1759 }
1760 else {
1761 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "error determining cgi PID (for SSI)");
1762 }
1763
1767
1768 /* We are putting the socket discriptor into an apr_file_t so that we can
1769 * use a pipe bucket to send the data to the client. APR will create
1770 * a cleanup for the apr_file_t which will close the socket, so we'll
1771 * get rid of the cleanup we registered when we created the socket.
1772 */
1773 apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool);
1774 if (dc->timeout > 0) {
1776 }
1777 else {
1779 }
1780
1781 apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket);
1782
1784 f->c->bucket_alloc));
1785 ctx->flush_now = 1;
1786
1787 return APR_SUCCESS;
1788}
1789
1799
1802 create_cgid_dirconf, /* dir config creater */
1803 NULL, /* dir merger --- default is to override */
1804 create_cgid_config, /* server config */
1805 merge_cgid_config, /* merge server config */
1806 cgid_cmds, /* command table */
1807 register_hook /* register_handlers */
1808};
1809
Apache Multi-Processing Module library.
const char apr_size_t len
Definition ap_regex.h:187
mode_t
Definition aplibtool.c:31
#define listen
#define accept
#define writev
#define socket
#define shutdown
#define connect
#define bind
APR-UTIL Buckets/Bucket Brigades.
APR File I/O Handling.
APR Miscellaneous library routines.
APR general purpose library routines.
APR-UTIL registration of functions exported by modules.
APR Portability Routines.
APR Signal Handling.
APR Strings library.
APR Standard Headers Support.
static void cgi_optfns_retrieve(void)
Definition cgi_common.h:208
static int cgi_handle_response(request_rec *r, int nph, apr_bucket_brigade *bb, apr_interval_time_t timeout, cgi_server_conf *conf, char *logdata, apr_file_t *script_err)
Definition cgi_common.h:420
static int log_scripterror(request_rec *r, cgi_server_conf *conf, int ret, apr_status_t rv, const char *logno, const char *error)
Definition cgi_common.h:64
static apr_status_t cgi_handle_request(request_rec *r, apr_file_t *script_out, apr_bucket_brigade *bb, char *logbuf, apr_size_t logbufbytes)
Definition cgi_common.h:557
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
char * ap_runtime_dir_relative(apr_pool_t *p, const char *fname)
Definition config.c:1610
#define ap_get_module_config(v, m)
ap_conf_vector_t * ap_create_request_config(apr_pool_t *p)
Definition config.c:356
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
struct ap_conf_vector_t ap_conf_vector_t
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
char * ap_server_root_relative(apr_pool_t *p, const char *fname)
Definition config.c:1594
void ap_hook_handler(ap_HOOK_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:170
#define ap_set_module_config(v, m, val)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
request_rec int int apr_table_t const char * path
request_rec * r
void ap_hook_optional_fn_retrieve(ap_HOOK_optional_fn_retrieve_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:195
const char server_rec * main_server
#define HUGE_STRING_LEN
Definition httpd.h:303
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define OPT_EXECCGI
Definition http_core.h:78
#define AP_SQ_MS_CREATE_PRE_CONFIG
Definition http_core.h:1047
int ap_state_query(int query_code)
Definition core.c:5378
#define AP_SQ_MAIN_STATE
Definition http_core.h:1030
#define ap_get_core_module_config(v)
Definition http_core.h:383
#define AP_CORE_MODULE_INDEX
Definition http_core.h:382
int ap_allow_options(request_rec *r)
Definition core.c:771
void ap_close_listeners(void)
Definition listen.c:763
#define APLOG_TRACE8
Definition http_log.h:79
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_DEBUG
Definition http_log.h:71
server_rec * ap_server_conf
Definition config.c:62
const unsigned char * buf
Definition util_md5.h:50
apr_status_t ap_os_create_privileged_process(const request_rec *r, apr_proc_t *newproc, const char *progname, const char *const *args, const char *const *env, apr_procattr_t *attr, apr_pool_t *p)
int ap_map_http_request_error(apr_status_t rv, int status)
void ap_set_content_type_ex(request_rec *r, const char *ct, int trusted)
request_rec * ap_sub_req_lookup_uri(const char *new_uri, const request_rec *r, ap_filter_t *next_filter)
Definition request.c:2297
int ap_run_sub_req(request_rec *r)
Definition request.c:2528
void ap_destroy_sub_req(request_rec *r)
Definition request.c:2547
void ap_add_common_vars(request_rec *r)
char ** ap_create_environment(apr_pool_t *p, apr_table_t *t)
#define APACHE_ARG_MAX
Definition util_script.h:40
void ap_add_cgi_vars(request_rec *r)
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
int ap_run_drop_privileges(apr_pool_t *pchild, server_rec *s)
Definition mpm_common.c:94
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_EINVAL
Definition apr_errno.h:711
unsigned int count
Definition apr_md5.h:152
#define APR_OC_REASON_RESTART
#define APR_OC_REASON_LOST
#define APR_OC_REASON_UNREGISTER
#define APR_OC_REASON_DEATH
apr_file_t * f
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define APR_BUCKET_NEXT(e)
apr_bucket * e
#define APR_BRIGADE_SENTINEL(b)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define APR_BRIGADE_FIRST(b)
apr_file_t * fd
#define apr_bucket_read(e, str, len, block)
@ APR_BLOCK_READ
Definition apr_buckets.h:58
const char *const * aszPre
Definition apr_hooks.h:345
#define APR_HOOK_REALLY_FIRST
Definition apr_hooks.h:299
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_redis_t * rc
Definition apr_redis.h:173
#define ACCESS_CONF
#define RSRC_CONF
#define HTTP_OK
Definition httpd.h:490
#define HTTP_BAD_REQUEST
Definition httpd.h:508
#define HTTP_SERVICE_UNAVAILABLE
Definition httpd.h:538
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define ap_is_HTTP_REDIRECT(x)
Definition httpd.h:552
#define HTTP_FORBIDDEN
Definition httpd.h:511
#define HTTP_NOT_FOUND
Definition httpd.h:512
#define M_PUT
Definition httpd.h:593
#define M_POST
Definition httpd.h:594
#define STANDARD20_MODULE_STUFF
char * ap_append_pid(apr_pool_t *p, const char *string, const char *delim)
Definition util.c:2595
#define ap_escape_uri(ppool, path)
Definition httpd.h:1836
char * ap_escape_shell_cmd(apr_pool_t *p, const char *s)
Definition util.c:1812
#define ap_strchr_c(s, c)
Definition httpd.h:2353
char * ap_make_dirstr_parent(apr_pool_t *p, const char *s)
Definition util.c:692
char * ap_getword_nulls(apr_pool_t *p, const char **line, char stop)
Definition util.c:779
#define ap_escape_html(p, s)
Definition httpd.h:1860
int ap_unescape_url(char *url)
Definition util.c:1939
apr_status_t ap_timeout_parameter_parse(const char *timeout_parameter, apr_interval_time_t *timeout, const char *default_time_unit)
Definition util.c:2622
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
@ APR_REG
@ APR_DIR
@ APR_NOFILE
const char * key
const struct iovec * vec
void apr_size_t apr_size_t * bytes_read
void * data
char * buffer
#define APR_APPEND
Definition apr_file_io.h:96
#define APR_WRITE
Definition apr_file_io.h:94
#define APR_CREATE
Definition apr_file_io.h:95
#define APR_FPROT_UEXECUTE
#define APR_FPROT_UWRITE
#define APR_OS_DEFAULT
#define APR_FPROT_UREAD
int strcasecmp(const char *a, const char *b)
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_vformatter_buff_t const char va_list ap
Definition apr_lib.h:176
char const *const char const *const ** env
apr_sockaddr_t * sockaddr
apr_interval_time_t t
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
#define apr_signal(a, b)
Definition apr_signal.h:71
const char * s
Definition apr_strings.h:95
const apr_array_header_t * first
Definition apr_tables.h:207
apr_proc_t * proc
apr_int32_t apr_int32_t apr_int32_t err
#define APR_FULL_BLOCK
int sig
#define APR_LIMIT_MEM
#define APR_LIMIT_NPROC
apr_cmdtype_e cmd
#define APR_LIMIT_CPU
const char const char *const * args
#define APR_NO_PIPE
int reason
#define APR_CHILD_BLOCK
apr_cmdtype_e
int int status
@ APR_KILL_AFTER_TIMEOUT
@ APR_SHELLCMD
@ APR_PROGRAM
#define APR_CTIME_LEN
Definition apr_time.h:198
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
#define apr_time_sec(time)
Definition apr_time.h:63
#define apr_time_from_sec(sec)
Definition apr_time.h:78
#define CGI_MAGIC_TYPE
Definition httpd.h:705
apr_status_t ap_mpm_query(int query_code, int *result)
Definition mpm_common.c:421
#define AP_MPMQ_MPM_STATE
Definition ap_mpm.h:174
#define AP_MPMQ_STOPPING
Definition ap_mpm.h:142
#define AP_REQ_REJECT_PATH_INFO
Definition httpd.h:763
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
Command line options.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static char ** create_argv(apr_pool_t *p, char *path, char *user, char *group, char *av0, const char *args)
Definition mod_cgid.c:234
static int include_cmd(include_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *bb, const char *command)
Definition mod_cgid.c:1723
static apr_socklen_t server_addr_len
Definition mod_cgid.c:90
static int connect_to_daemon(int *sdptr, request_rec *r, cgid_server_conf *conf)
Definition mod_cgid.c:1293
static void daemon_signal_handler(int sig)
Definition mod_cgid.c:680
static const char * set_scriptlog_length(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_cgid.c:1122
static int cgid_start(apr_pool_t *p, server_rec *main_server, apr_proc_t *procnew)
Definition mod_cgid.c:999
static apr_pool_t * pcgi
Definition mod_cgid.c:83
static apr_status_t send_req(int fd, apr_file_t *errpipe, request_rec *r, const char *argv0, char **env, int req_type)
Definition mod_cgid.c:578
#define CGI_REQ
Definition mod_cgid.c:137
#define DAEMON_STARTUP_ERROR
Definition mod_cgid.c:105
#define ERRFN_USERDATA_KEY
Definition mod_cgid.c:141
static const char * set_script_timeout(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_cgid.c:1160
static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, int *errfd, cgid_req_t *req)
Definition mod_cgid.c:500
static void register_hook(apr_pool_t *p)
Definition mod_cgid.c:1790
static const char * set_script_socket(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_cgid.c:1142
static apr_pool_t * root_pool
Definition mod_cgid.c:87
static int log_script(request_rec *r, cgid_server_conf *conf, int ret, char *dbuf, const char *sbuf, apr_bucket_brigade *bb, apr_file_t *script_err)
Definition mod_cgid.c:1188
static const char * set_scriptlog_buffer(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_cgid.c:1132
static apr_status_t get_cgi_pid(request_rec *r, cgid_server_conf *conf, pid_t *pid)
Definition mod_cgid.c:1421
static int cgid_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
Definition mod_cgid.c:1025
#define DEFAULT_CGID_LISTENBACKLOG
Definition mod_cgid.c:151
static int cgid_server(void *data)
Definition mod_cgid.c:717
static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err, const char *description)
Definition mod_cgid.c:692
#define DEFAULT_LOGBYTES
Definition mod_cgid.c:133
static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server)
Definition mod_cgid.c:1032
static struct sockaddr_un * server_addr
Definition mod_cgid.c:89
static ap_unix_identity_t * cgid_suexec_id_doer(const request_rec *r)
Definition mod_cgid.c:113
static server_rec * root_server
Definition mod_cgid.c:86
static apr_status_t dead_yet(pid_t pid, apr_interval_time_t max_wait)
Definition mod_cgid.c:1372
static pid_t parent_pid
Definition mod_cgid.c:91
static void * create_cgid_config(apr_pool_t *p, server_rec *s)
Definition mod_cgid.c:1082
static pid_t daemon_pid
Definition mod_cgid.c:84
static const char * sockname
Definition mod_cgid.c:88
#define SSI_REQ
Definition mod_cgid.c:138
static int is_scriptaliased(request_rec *r)
Definition mod_cgid.c:125
static apr_status_t cleanup_script(void *vptr)
Definition mod_cgid.c:1459
static apr_status_t sock_readhdr(int fd, int *errfd, void *vbuf, size_t buf_size)
Definition mod_cgid.c:352
#define DEFAULT_CONNECT_ATTEMPTS
Definition mod_cgid.c:164
#define GETPID_REQ
Definition mod_cgid.c:139
static void add_ssi_vars(request_rec *r)
Definition mod_cgid.c:1697
static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *bb, char *s)
Definition mod_cgid.c:1640
static const char * set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_cgid.c:1106
#define DEFAULT_SOCKET
Definition mod_cgid.c:135
#define DEFAULT_BUFBYTES
Definition mod_cgid.c:134
static int daemon_should_exit
Definition mod_cgid.c:85
static apr_status_t close_unix_socket(void *thefd)
Definition mod_cgid.c:341
static void discard_script_output(apr_bucket_brigade *bb)
static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size)
Definition mod_cgid.c:424
static apr_status_t cleanup_nonchild_process(request_rec *r, pid_t pid)
Definition mod_cgid.c:1400
static void * merge_cgid_config(apr_pool_t *p, void *basev, void *overridesv)
Definition mod_cgid.c:1093
static apr_status_t sock_write(int fd, const void *buf, size_t buf_size)
Definition mod_cgid.c:431
#define DEFAULT_CONNECT_STARTUP_DELAY
Definition mod_cgid.c:168
static void * create_cgid_dirconf(apr_pool_t *p, char *dummy)
Definition mod_cgid.c:1100
static const command_rec cgid_cmds[]
Definition mod_cgid.c:1170
static apr_status_t sock_writev(int fd, int auxfd, request_rec *r, int count,...)
Definition mod_cgid.c:445
static int cgid_handler(request_rec *r)
Definition mod_cgid.c:1465
static ap_unix_identity_t empty_ugid
Definition mod_cgid.c:92
mod_core private header file
const char * argv[3]
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
SuExec Extension Module for Apache.
Multi-Processing Modules functions.
static int mpm_state
scoreboard * ap_scoreboard_image
Definition scoreboard.c:44
static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, step_vars_storage *step_vars)
Definition sed1.c:766
The representation of a filter chain.
int level
Definition httpd.h:1317
apr_filetype_e filetype
Definition apr_tables.h:81
apr_interval_time_t timeout
Definition mod_cgid.c:95
apr_size_t args_len
Definition mod_cgid.c:209
int env_count
Definition mod_cgid.c:204
apr_size_t argv0_len
Definition mod_cgid.c:207
ap_unix_identity_t ugid
Definition mod_cgid.c:205
unsigned long conn_id
Definition mod_cgid.c:197
apr_size_t filename_len
Definition mod_cgid.c:206
int req_type
Definition mod_cgid.c:196
pid_t ppid
Definition mod_cgid.c:201
apr_size_t uri_len
Definition mod_cgid.c:208
int loglevel
Definition mod_cgid.c:210
const char * logname
Definition mod_cgid.c:172
request_rec * r
Definition mod_cgid.c:1367
cgid_server_conf * conf
Definition mod_cgid.c:1368
Structure to store things which are per connection.
Definition httpd.h:1152
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
long id
Definition httpd.h:1187
Per-directory configuration.
Definition http_core.h:527
Per-request configuration.
Definition http_core.h:394
apr_time_t restart_time
Definition scoreboard.h:129
apr_pool_t * pool
Definition httpd.h:831
A structure that represents the current request.
Definition httpd.h:845
char * uri
Definition httpd.h:1016
const char * handler
Definition httpd.h:994
apr_table_t * notes
Definition httpd.h:985
int used_path_info
Definition httpd.h:1036
int method_number
Definition httpd.h:898
apr_pool_t * pool
Definition httpd.h:847
char * filename
Definition httpd.h:1018
conn_rec * connection
Definition httpd.h:849
apr_table_t * err_headers_out
Definition httpd.h:981
apr_finfo_t finfo
Definition httpd.h:1094
struct ap_conf_vector_t * request_config
Definition httpd.h:1049
apr_table_t * headers_in
Definition httpd.h:976
char * protocol
Definition httpd.h:879
apr_table_t * subprocess_env
Definition httpd.h:983
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
const char * method
Definition httpd.h:900
char * path_info
Definition httpd.h:1024
char * args
Definition httpd.h:1026
global_score * global
Definition scoreboard.h:161
A structure to store information for each virtual server.
Definition httpd.h:1322
apr_interval_time_t timeout
Definition httpd.h:1372
process_rec * process
Definition httpd.h:1324
apr_file_t * error_log
Definition httpd.h:1333
struct ap_conf_vector_t * module_config
Definition httpd.h:1341
struct ap_logconf log
Definition httpd.h:1335
apr_status_t apr_ctime(char *date_str, apr_time_t t)
Definition timestr.c:90
Apache filter library.
IN ULONG IN INT timeout
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray
INT info