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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * http_script: keeps all script-related ramblings together.
20 * Compliant to cgi/1.1 spec
22 * Adapted by rst from original NCSA code by Rob McCool
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
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"
39 #define APR_WANT_STRFUNC
42 #if APR_HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
48 #if APR_HAVE_SYS_TYPES_H
49 #include <sys/types.h>
52 #include "util_filter.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"
60 #include "util_script.h"
62 #include "mpm_common.h"
63 #include "mod_suexec.h"
64 #include "../filters/mod_include.h"
69 /* ### should be tossed in favor of APR */
71 #include <sys/un.h> /* for sockaddr_un */
74 module AP_MODULE_DECLARE_DATA cgid_module
;
76 static int cgid_start(apr_pool_t
*p
, server_rec
*main_server
, apr_proc_t
*procnew
);
77 static int cgid_init(apr_pool_t
*p
, apr_pool_t
*plog
, apr_pool_t
*ptemp
, server_rec
*main_server
);
78 static int handle_exec(include_ctx_t
*ctx
, ap_filter_t
*f
, apr_bucket_brigade
*bb
);
80 static APR_OPTIONAL_FN_TYPE(ap_register_include_handler
) *cgid_pfn_reg_with_ssi
;
81 static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value
) *cgid_pfn_gtv
;
82 static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string
) *cgid_pfn_ps
;
84 static apr_pool_t
*pcgi
= NULL
;
85 static int total_modules
= 0;
86 static pid_t daemon_pid
;
87 static int daemon_should_exit
= 0;
88 static server_rec
*root_server
= NULL
;
89 static apr_pool_t
*root_pool
= NULL
;
90 static const char *sockname
;
91 static pid_t parent_pid
;
92 static ap_unix_identity_t empty_ugid
= { (uid_t
)-1, (gid_t
)-1, -1 };
94 /* The APR other-child API doesn't tell us how the daemon exited
95 * (SIGSEGV vs. exit(1)). The other-child maintenance function
96 * needs to decide whether to restart the daemon after a failure
97 * based on whether or not it exited due to a fatal startup error
98 * or something that happened at steady-state. This exit status
99 * is unlikely to collide with exit signals.
101 #define DAEMON_STARTUP_ERROR 254
103 /* Read and discard the data in the brigade produced by a CGI script */
104 static void discard_script_output(apr_bucket_brigade
*bb
);
106 /* This doer will only ever be called when we are sure that we have
109 static ap_unix_identity_t
*cgid_suexec_id_doer(const request_rec
*r
)
111 return (ap_unix_identity_t
*)
112 ap_get_module_config(r
->request_config
, &cgid_module
);
115 /* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
116 * in ScriptAliased directories, which means we need to know if this
117 * request came through ScriptAlias or not... so the Alias module
118 * leaves a note for us.
121 static int is_scriptaliased(request_rec
*r
)
123 const char *t
= apr_table_get(r
->notes
, "alias-forced-type");
124 return t
&& (!strcasecmp(t
, "cgi-script"));
127 /* Configuration stuff */
129 #define DEFAULT_LOGBYTES 10385760
130 #define DEFAULT_BUFBYTES 1024
131 #define DEFAULT_SOCKET DEFAULT_REL_RUNTIMEDIR "/cgisock"
135 #define GETPID_REQ 3 /* get the pid of script created for prior request */
137 #define ERRFN_USERDATA_KEY "CGIDCHILDERRFN"
139 /* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's
140 * pending connection queue. If a bunch of cgi requests arrive at about
141 * the same time, connections from httpd threads/processes will back up
142 * in the queue while the cgid process slowly forks off a child to process
143 * each connection on the unix socket. If the queue is too short, the
144 * httpd process will get ECONNREFUSED when trying to connect.
146 #ifndef DEFAULT_CGID_LISTENBACKLOG
147 #define DEFAULT_CGID_LISTENBACKLOG 100
150 /* DEFAULT_CONNECT_ATTEMPTS controls how many times we'll try to connect
151 * to the cgi daemon from the thread/process handling the cgi request.
152 * Generally we want to retry when we get ECONNREFUSED since it is
153 * probably because the listen queue is full. We need to try harder so
154 * the client doesn't see it as a 503 error.
156 * Set this to 0 to continually retry until the connect works or Apache
159 #ifndef DEFAULT_CONNECT_ATTEMPTS
160 #define DEFAULT_CONNECT_ATTEMPTS 15
170 int req_type
; /* request type (CGI_REQ, SSI_REQ, etc.) */
171 unsigned long conn_id
; /* connection id; daemon uses this as a hash value
172 * to find the script pid when it is time for that
173 * process to be cleaned up
175 pid_t ppid
; /* sanity check for config problems leading to
176 * wrong cgid socket use
178 int core_module_index
;
180 ap_unix_identity_t ugid
;
181 apr_size_t filename_len
;
182 apr_size_t argv0_len
;
185 int loglevel
; /* to stuff in server_rec */
188 /* This routine is called to create the argument list to be passed
189 * to the CGI script. When suexec is enabled, the suexec path, user, and
190 * group are the first three arguments to be passed; if not, all three
191 * must be NULL. The query info is split into separate arguments, where
192 * "+" is the separator between keyword arguments.
194 * Do not process the args if they containing an '=' assignment.
196 static char **create_argv(apr_pool_t
*p
, char *path
, char *user
, char *group
,
197 char *av0
, const char *args
)
204 if (!(*args
) || ap_strchr_c(args
, '=')) {
208 /* count the number of keywords */
210 for (x
= 0, numwords
= 1; args
[x
]; x
++) {
211 if (args
[x
] == '+') {
217 if (numwords
> APACHE_ARG_MAX
- 5) {
218 numwords
= APACHE_ARG_MAX
- 5; /* Truncate args to prevent overrun */
220 av
= (char **) apr_pcalloc(p
, (numwords
+ 5) * sizeof(char *));
232 av
[idx
++] = apr_pstrdup(p
, av0
);
234 for (x
= 1; x
<= numwords
; x
++) {
235 w
= ap_getword_nulls(p
, &args
, '+');
237 av
[idx
++] = ap_escape_shell_cmd(p
, w
);
243 #if APR_HAS_OTHER_CHILD
244 static void cgid_maint(int reason
, void *data
, apr_wait_t status
)
246 apr_proc_t
*proc
= data
;
251 case APR_OC_REASON_DEATH
:
252 apr_proc_other_child_unregister(data
);
253 /* If apache is not terminating or restarting,
254 * restart the cgid daemon
256 stopping
= 1; /* if MPM doesn't support query,
257 * assume we shouldn't restart daemon
259 if (ap_mpm_query(AP_MPMQ_MPM_STATE
, &mpm_state
) == APR_SUCCESS
&&
260 mpm_state
!= AP_MPMQ_STOPPING
) {
264 if (status
== DAEMON_STARTUP_ERROR
) {
265 ap_log_error(APLOG_MARK
, APLOG_CRIT
, 0, NULL
,
266 "cgid daemon failed to initialize");
269 ap_log_error(APLOG_MARK
, APLOG_ERR
, 0, NULL
,
270 "cgid daemon process died, restarting");
271 cgid_start(root_pool
, root_server
, proc
);
275 case APR_OC_REASON_RESTART
:
276 /* don't do anything; server is stopping or restarting */
277 apr_proc_other_child_unregister(data
);
279 case APR_OC_REASON_LOST
:
280 /* Restart the child cgid daemon process */
281 apr_proc_other_child_unregister(data
);
282 cgid_start(root_pool
, root_server
, proc
);
284 case APR_OC_REASON_UNREGISTER
:
285 /* we get here when pcgi is cleaned up; pcgi gets cleaned
286 * up when pconf gets cleaned up
288 kill(proc
->pid
, SIGHUP
); /* send signal to daemon telling it to die */
290 /* Remove the cgi socket, we must do it here in order to try and
291 * guarantee the same permissions as when the socket was created.
293 if (unlink(sockname
) < 0 && errno
!= ENOENT
) {
294 ap_log_error(APLOG_MARK
, APLOG_ERR
, errno
, NULL
,
295 "Couldn't unlink unix domain socket %s",
303 /* deal with incomplete reads and signals
304 * assume you really have to read buf_size bytes
306 static apr_status_t
sock_read(int fd
, void *vbuf
, size_t buf_size
)
310 size_t bytes_read
= 0;
314 rc
= read(fd
, buf
+ bytes_read
, buf_size
- bytes_read
);
315 } while (rc
< 0 && errno
== EINTR
);
319 case 0: /* unexpected */
324 } while (bytes_read
< buf_size
);
331 static apr_status_t
sock_write(int fd
, const void *buf
, size_t buf_size
)
336 rc
= write(fd
, buf
, buf_size
);
337 } while (rc
< 0 && errno
== EINTR
);
345 static apr_status_t
sock_writev(int fd
, request_rec
*r
, int count
, ...)
353 vec
= (struct iovec
*)apr_palloc(r
->pool
, count
* sizeof(struct iovec
));
355 for (i
= 0; i
< count
; i
++) {
356 vec
[i
].iov_base
= va_arg(ap
, caddr_t
);
357 vec
[i
].iov_len
= va_arg(ap
, apr_size_t
);
358 total_bytes
+= vec
[i
].iov_len
;
363 rc
= writev(fd
, vec
, count
);
364 } while (rc
< 0 && errno
== EINTR
);
372 static apr_status_t
get_req(int fd
, request_rec
*r
, char **argv0
, char ***env
,
377 core_request_config
*temp_core
;
381 r
->server
= apr_pcalloc(r
->pool
, sizeof(server_rec
));
383 /* read the request header */
384 stat
= sock_read(fd
, req
, sizeof(*req
));
385 if (stat
!= APR_SUCCESS
) {
388 r
->server
->loglevel
= req
->loglevel
;
389 if (req
->req_type
== GETPID_REQ
) {
390 /* no more data sent for this request */
394 /* handle module indexes and such */
395 rconf
= (void **) apr_pcalloc(r
->pool
, sizeof(void *) * (total_modules
+ DYNAMIC_MODULE_LIMIT
));
397 temp_core
= (core_request_config
*)apr_palloc(r
->pool
, sizeof(core_module
));
398 rconf
[req
->core_module_index
] = (void *)temp_core
;
399 r
->request_config
= (ap_conf_vector_t
*)rconf
;
400 ap_set_module_config(r
->request_config
, &cgid_module
, (void *)&req
->ugid
);
402 /* Read the filename, argv0, uri, and args */
403 r
->filename
= apr_pcalloc(r
->pool
, req
->filename_len
+ 1);
404 *argv0
= apr_pcalloc(r
->pool
, req
->argv0_len
+ 1);
405 r
->uri
= apr_pcalloc(r
->pool
, req
->uri_len
+ 1);
406 if ((stat
= sock_read(fd
, r
->filename
, req
->filename_len
)) != APR_SUCCESS
||
407 (stat
= sock_read(fd
, *argv0
, req
->argv0_len
)) != APR_SUCCESS
||
408 (stat
= sock_read(fd
, r
->uri
, req
->uri_len
)) != APR_SUCCESS
) {
412 r
->args
= apr_pcalloc(r
->pool
, req
->args_len
+ 1); /* empty string if no args */
414 if ((stat
= sock_read(fd
, r
->args
, req
->args_len
)) != APR_SUCCESS
) {
419 /* read the environment variables */
420 environ
= apr_pcalloc(r
->pool
, (req
->env_count
+ 2) *sizeof(char *));
421 for (i
= 0; i
< req
->env_count
; i
++) {
424 if ((stat
= sock_read(fd
, &curlen
, sizeof(curlen
))) != APR_SUCCESS
) {
427 environ
[i
] = apr_pcalloc(r
->pool
, curlen
+ 1);
428 if ((stat
= sock_read(fd
, environ
[i
], curlen
)) != APR_SUCCESS
) {
436 sock_read(fd
, &j
, sizeof(int));
438 temp_core
->limit_cpu
= (struct rlimit
*)apr_palloc (sizeof(struct rlimit
));
439 sock_read(fd
, temp_core
->limit_cpu
, sizeof(struct rlimit
));
442 temp_core
->limit_cpu
= NULL
;
446 #if defined (RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
447 sock_read(fd
, &j
, sizeof(int));
449 temp_core
->limit_mem
= (struct rlimit
*)apr_palloc(r
->pool
, sizeof(struct rlimit
));
450 sock_read(fd
, temp_core
->limit_mem
, sizeof(struct rlimit
));
453 temp_core
->limit_mem
= NULL
;
458 sock_read(fd
, &j
, sizeof(int));
460 temp_core
->limit_nproc
= (struct rlimit
*)apr_palloc(r
->pool
, sizeof(struct rlimit
));
461 sock_read(fd
, temp_core
->limit_nproc
, sizeof(struct rlimit
));
464 temp_core
->limit_nproc
= NULL
;
472 static apr_status_t
send_req(int fd
, request_rec
*r
, char *argv0
, char **env
,
476 cgid_req_t req
= {0};
478 ap_unix_identity_t
* ugid
= ap_run_get_suexec_identity(r
);
481 req
.ugid
= empty_ugid
;
483 memcpy(&req
.ugid
, ugid
, sizeof(ap_unix_identity_t
));
486 req
.req_type
= req_type
;
487 req
.ppid
= parent_pid
;
488 req
.conn_id
= r
->connection
->id
;
489 req
.core_module_index
= core_module
.module_index
;
490 for (req
.env_count
= 0; env
[req
.env_count
]; req
.env_count
++) {
493 req
.filename_len
= strlen(r
->filename
);
494 req
.argv0_len
= strlen(argv0
);
495 req
.uri_len
= strlen(r
->uri
);
496 req
.args_len
= r
->args
? strlen(r
->args
) : 0;
497 req
.loglevel
= r
->server
->loglevel
;
499 /* Write the request header */
501 stat
= sock_writev(fd
, r
, 5,
503 r
->filename
, req
.filename_len
,
504 argv0
, req
.argv0_len
,
506 r
->args
, req
.args_len
);
508 stat
= sock_writev(fd
, r
, 4,
510 r
->filename
, req
.filename_len
,
511 argv0
, req
.argv0_len
,
512 r
->uri
, req
.uri_len
);
515 if (stat
!= APR_SUCCESS
) {
519 /* write the environment variables */
520 for (i
= 0; i
< req
.env_count
; i
++) {
521 apr_size_t curlen
= strlen(env
[i
]);
523 if ((stat
= sock_writev(fd
, r
, 2, &curlen
, sizeof(curlen
),
524 env
[i
], curlen
)) != APR_SUCCESS
) {
531 if (conf
->limit_cpu
) {
533 stat
= sock_write(fd
, &len
, sizeof(int));
534 stat
= sock_write(fd
, conf
->limit_cpu
, sizeof(struct rlimit
));
538 stat
= sock_write(fd
, &len
, sizeof(int));
542 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
543 if (conf
->limit_mem
) {
545 stat
= sock_write(fd
, &len
, sizeof(int));
546 stat
= sock_write(fd
, conf
->limit_mem
, sizeof(struct rlimit
));
550 stat
= sock_write(fd
, &len
, sizeof(int));
555 if (conf
->limit_nproc
) {
557 stat
= sock_write(fd
, &len
, sizeof(int));
558 stat
= sock_write(fd
, conf
->limit_nproc
, sizeof(struct rlimit
));
562 stat
= sock_write(fd
, &len
, sizeof(int));
569 static void daemon_signal_handler(int sig
)
572 ++daemon_should_exit
;
576 static void cgid_child_errfn(apr_pool_t
*pool
, apr_status_t err
,
577 const char *description
)
582 apr_pool_userdata_get(&vr
, ERRFN_USERDATA_KEY
, pool
);
585 /* sure we got r, but don't call ap_log_rerror() because we don't
586 * have r->headers_in and possibly other storage referenced by
589 ap_log_error(APLOG_MARK
, APLOG_ERR
, err
, r
->server
, "%s", description
);
592 static int cgid_server(void *data
)
594 struct sockaddr_un unix_addr
;
599 server_rec
*main_server
= data
;
600 apr_hash_t
*script_hash
= apr_hash_make(pcgi
);
603 apr_pool_create(&ptrans
, pcgi
);
605 apr_signal(SIGCHLD
, SIG_IGN
);
606 apr_signal(SIGHUP
, daemon_signal_handler
);
608 /* Close our copy of the listening sockets */
609 ap_close_listeners();
611 /* cgid should use its own suexec doer */
612 ap_hook_get_suexec_identity(cgid_suexec_id_doer
, NULL
, NULL
,
613 APR_HOOK_REALLY_FIRST
);
616 if ((sd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0) {
617 ap_log_error(APLOG_MARK
, APLOG_ERR
, errno
, main_server
,
618 "Couldn't create unix domain socket");
622 memset(&unix_addr
, 0, sizeof(unix_addr
));
623 unix_addr
.sun_family
= AF_UNIX
;
624 apr_cpystrn(unix_addr
.sun_path
, sockname
, sizeof unix_addr
.sun_path
);
626 omask
= umask(0077); /* so that only Apache can use socket */
627 rc
= bind(sd
, (struct sockaddr
*)&unix_addr
, sizeof(unix_addr
));
628 umask(omask
); /* can't fail, so can't clobber errno */
630 ap_log_error(APLOG_MARK
, APLOG_ERR
, errno
, main_server
,
631 "Couldn't bind unix domain socket %s",
636 /* Not all flavors of unix use the current umask for AF_UNIX perms */
637 rv
= apr_file_perms_set(sockname
, APR_FPROT_UREAD
|APR_FPROT_UWRITE
|APR_FPROT_UEXECUTE
);
638 if (rv
!= APR_SUCCESS
) {
639 ap_log_error(APLOG_MARK
, APLOG_CRIT
, rv
, main_server
,
640 "Couldn't set permissions on unix domain socket %s",
645 if (listen(sd
, DEFAULT_CGID_LISTENBACKLOG
) < 0) {
646 ap_log_error(APLOG_MARK
, APLOG_ERR
, errno
, main_server
,
647 "Couldn't listen on unix domain socket");
652 if (chown(sockname
, ap_unixd_config
.user_id
, -1) < 0) {
653 ap_log_error(APLOG_MARK
, APLOG_ERR
, errno
, main_server
,
654 "Couldn't change owner of unix domain socket %s",
660 /* if running as root, switch to configured user/group */
661 if ((rc
= ap_run_drop_privileges(pcgi
, ap_server_conf
)) != 0) {
665 while (!daemon_should_exit
) {
666 int errfileno
= STDERR_FILENO
;
669 const char * const *argv
;
671 apr_int32_t out_pipe
;
672 apr_int32_t err_pipe
;
673 apr_cmdtype_e cmd_type
;
675 apr_procattr_t
*procattr
= NULL
;
676 apr_proc_t
*procnew
= NULL
;
682 apr_pool_clear(ptrans
);
684 len
= sizeof(unix_addr
);
685 sd2
= accept(sd
, (struct sockaddr
*)&unix_addr
, &len
);
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
;
693 if (errno
!= EINTR
) {
694 ap_log_error(APLOG_MARK
, APLOG_ERR
, errno
,
696 "Error accepting on cgid socket");
701 r
= apr_pcalloc(ptrans
, sizeof(request_rec
));
702 procnew
= apr_pcalloc(ptrans
, sizeof(*procnew
));
704 stat
= get_req(sd2
, r
, &argv0
, &env
, &cgid_req
);
705 if (stat
!= APR_SUCCESS
) {
706 ap_log_error(APLOG_MARK
, APLOG_ERR
, stat
,
708 "Error reading request on cgid socket");
713 if (cgid_req
.ppid
!= parent_pid
) {
714 ap_log_error(APLOG_MARK
, APLOG_CRIT
, 0, main_server
,
715 "CGI request received from wrong server instance; "
716 "see ScriptSock directive");
721 if (cgid_req
.req_type
== GETPID_REQ
) {
724 pid
= (pid_t
)((long)apr_hash_get(script_hash
, &cgid_req
.conn_id
, sizeof(cgid_req
.conn_id
)));
725 if (write(sd2
, &pid
, sizeof(pid
)) != sizeof(pid
)) {
726 ap_log_error(APLOG_MARK
, APLOG_ERR
, 0,
728 "Error writing pid %" APR_PID_T_FMT
" to handler", pid
);
734 apr_os_file_put(&r
->server
->error_log
, &errfileno
, 0, r
->pool
);
735 apr_os_file_put(&inout
, &sd2
, 0, r
->pool
);
737 if (cgid_req
.req_type
== SSI_REQ
) {
738 in_pipe
= APR_NO_PIPE
;
739 out_pipe
= APR_FULL_BLOCK
;
740 err_pipe
= APR_NO_PIPE
;
741 cmd_type
= APR_SHELLCMD
;
744 in_pipe
= APR_CHILD_BLOCK
;
745 out_pipe
= APR_CHILD_BLOCK
;
746 err_pipe
= APR_CHILD_BLOCK
;
747 cmd_type
= APR_PROGRAM
;
750 if (((rc
= apr_procattr_create(&procattr
, ptrans
)) != APR_SUCCESS
) ||
751 ((cgid_req
.req_type
== CGI_REQ
) &&
752 (((rc
= apr_procattr_io_set(procattr
,
755 err_pipe
)) != APR_SUCCESS
) ||
756 /* XXX apr_procattr_child_*_set() is creating an unnecessary
757 * pipe between this process and the child being created...
758 * It is cleaned up with the temporary pool for this request.
760 ((rc
= apr_procattr_child_err_set(procattr
, r
->server
->error_log
, NULL
)) != APR_SUCCESS
) ||
761 ((rc
= apr_procattr_child_in_set(procattr
, inout
, NULL
)) != APR_SUCCESS
))) ||
762 ((rc
= apr_procattr_child_out_set(procattr
, inout
, NULL
)) != APR_SUCCESS
) ||
763 ((rc
= apr_procattr_dir_set(procattr
,
764 ap_make_dirstr_parent(r
->pool
, r
->filename
))) != APR_SUCCESS
) ||
765 ((rc
= apr_procattr_cmdtype_set(procattr
, cmd_type
)) != APR_SUCCESS
) ||
766 ((rc
= apr_procattr_child_errfn_set(procattr
, cgid_child_errfn
)) != APR_SUCCESS
)) {
767 /* Something bad happened, tell the world.
768 * ap_log_rerror() won't work because the header table used by
769 * ap_log_rerror() hasn't been replicated in the phony r
771 ap_log_error(APLOG_MARK
, APLOG_ERR
, rc
, r
->server
,
772 "couldn't set child process attributes: %s", r
->filename
);
774 procnew
->pid
= 0; /* no process to clean up */
777 apr_pool_userdata_set(r
, ERRFN_USERDATA_KEY
, apr_pool_cleanup_null
, ptrans
);
779 argv
= (const char * const *)create_argv(r
->pool
, NULL
, NULL
, NULL
, argv0
, r
->args
);
781 /* We want to close sd2 for the new CGI process too.
782 * If it is left open it'll make ap_pass_brigade() block
783 * waiting for EOF if CGI forked something running long.
784 * close(sd2) here should be okay, as CGI channel
785 * is already dup()ed by apr_procattr_child_{in,out}_set()
790 if (memcmp(&empty_ugid
, &cgid_req
.ugid
, sizeof(empty_ugid
))) {
791 /* We have a valid identity, and can be sure that
792 * cgid_suexec_id_doer will return a valid ugid
794 rc
= ap_os_create_privileged_process(r
, procnew
, argv0
, argv
,
795 (const char * const *)env
,
798 rc
= apr_proc_create(procnew
, argv0
, argv
,
799 (const char * const *)env
,
803 if (rc
!= APR_SUCCESS
) {
804 /* Bad things happened. Everyone should have cleaned up.
805 * ap_log_rerror() won't work because the header table used by
806 * ap_log_rerror() hasn't been replicated in the phony r
808 ap_log_error(APLOG_MARK
, APLOG_ERR
, rc
, r
->server
,
809 "couldn't create child process: %d: %s", rc
,
810 apr_filepath_name_get(r
->filename
));
812 procnew
->pid
= 0; /* no process to clean up */
816 /* If the script process was created, remember the pid for
817 * later cleanup. If the script process wasn't created, clear
818 * out any prior pid with the same key.
820 * We don't want to leak storage for the key, so only allocate
821 * a key if the key doesn't exist yet in the hash; there are
822 * only a limited number of possible keys (one for each
823 * possible thread in the server), so we can allocate a copy
824 * of the key the first time a thread has a cgid request.
825 * Note that apr_hash_set() only uses the storage passed in
826 * for the key if it is adding the key to the hash for the
827 * first time; new key storage isn't needed for replacing the
828 * existing value of a key.
831 if (apr_hash_get(script_hash
, &cgid_req
.conn_id
, sizeof(cgid_req
.conn_id
))) {
832 key
= &cgid_req
.conn_id
;
835 key
= apr_pcalloc(pcgi
, sizeof(cgid_req
.conn_id
));
836 memcpy(key
, &cgid_req
.conn_id
, sizeof(cgid_req
.conn_id
));
838 apr_hash_set(script_hash
, key
, sizeof(cgid_req
.conn_id
),
839 (void *)((long)procnew
->pid
));
841 return -1; /* should be <= 0 to distinguish from startup errors */
844 static int cgid_start(apr_pool_t
*p
, server_rec
*main_server
,
848 daemon_should_exit
= 0; /* clear setting from previous generation */
849 if ((daemon_pid
= fork()) < 0) {
850 ap_log_error(APLOG_MARK
, APLOG_ERR
, errno
, main_server
,
851 "mod_cgid: Couldn't spawn cgid daemon process");
854 else if (daemon_pid
== 0) {
856 apr_pool_create(&pcgi
, p
);
858 exit(cgid_server(main_server
) > 0 ? DAEMON_STARTUP_ERROR
: -1);
860 procnew
->pid
= daemon_pid
;
861 procnew
->err
= procnew
->in
= procnew
->out
= NULL
;
862 apr_pool_note_subprocess(p
, procnew
, APR_KILL_AFTER_TIMEOUT
);
863 #if APR_HAS_OTHER_CHILD
864 apr_proc_other_child_register(procnew
, cgid_maint
, procnew
, NULL
, p
);
869 static int cgid_pre_config(apr_pool_t
*pconf
, apr_pool_t
*plog
,
872 sockname
= ap_append_pid(pconf
, DEFAULT_SOCKET
, ".");
876 static int cgid_init(apr_pool_t
*p
, apr_pool_t
*plog
, apr_pool_t
*ptemp
,
877 server_rec
*main_server
)
879 apr_proc_t
*procnew
= NULL
;
881 const char *userdata_key
= "cgid_init";
886 root_server
= main_server
;
889 apr_pool_userdata_get(&data
, userdata_key
, main_server
->process
->pool
);
892 procnew
= apr_pcalloc(main_server
->process
->pool
, sizeof(*procnew
));
894 procnew
->err
= procnew
->in
= procnew
->out
= NULL
;
895 apr_pool_userdata_set((const void *)procnew
, userdata_key
,
896 apr_pool_cleanup_null
, main_server
->process
->pool
);
904 for (m
= ap_preloaded_modules
; *m
!= NULL
; m
++)
907 parent_pid
= getpid();
908 sockname
= ap_server_root_relative(p
, sockname
);
909 ret
= cgid_start(p
, main_server
, procnew
);
913 cgid_pfn_reg_with_ssi
= APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler
);
914 cgid_pfn_gtv
= APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value
);
915 cgid_pfn_ps
= APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string
);
917 if ((cgid_pfn_reg_with_ssi
) && (cgid_pfn_gtv
) && (cgid_pfn_ps
)) {
918 /* Required by mod_include filter. This is how mod_cgid registers
919 * with mod_include to provide processing of the exec directive.
921 cgid_pfn_reg_with_ssi("exec", handle_exec
);
927 static void *create_cgid_config(apr_pool_t
*p
, server_rec
*s
)
929 cgid_server_conf
*c
=
930 (cgid_server_conf
*) apr_pcalloc(p
, sizeof(cgid_server_conf
));
933 c
->logbytes
= DEFAULT_LOGBYTES
;
934 c
->bufbytes
= DEFAULT_BUFBYTES
;
938 static void *merge_cgid_config(apr_pool_t
*p
, void *basev
, void *overridesv
)
940 cgid_server_conf
*base
= (cgid_server_conf
*) basev
, *overrides
= (cgid_server_conf
*) overridesv
;
942 return overrides
->logname
? overrides
: base
;
945 static const char *set_scriptlog(cmd_parms
*cmd
, void *dummy
, const char *arg
)
947 server_rec
*s
= cmd
->server
;
948 cgid_server_conf
*conf
= ap_get_module_config(s
->module_config
,
951 conf
->logname
= ap_server_root_relative(cmd
->pool
, arg
);
953 if (!conf
->logname
) {
954 return apr_pstrcat(cmd
->pool
, "Invalid ScriptLog path ",
960 static const char *set_scriptlog_length(cmd_parms
*cmd
, void *dummy
, const char *arg
)
962 server_rec
*s
= cmd
->server
;
963 cgid_server_conf
*conf
= ap_get_module_config(s
->module_config
,
966 conf
->logbytes
= atol(arg
);
970 static const char *set_scriptlog_buffer(cmd_parms
*cmd
, void *dummy
, const char *arg
)
972 server_rec
*s
= cmd
->server
;
973 cgid_server_conf
*conf
= ap_get_module_config(s
->module_config
,
976 conf
->bufbytes
= atoi(arg
);
980 static const char *set_script_socket(cmd_parms
*cmd
, void *dummy
, const char *arg
)
982 const char *err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
987 /* Make sure the pid is appended to the sockname */
988 sockname
= ap_append_pid(cmd
->pool
, arg
, ".");
989 sockname
= ap_server_root_relative(cmd
->pool
, sockname
);
992 return apr_pstrcat(cmd
->pool
, "Invalid ScriptSock path",
999 static const command_rec cgid_cmds
[] =
1001 AP_INIT_TAKE1("ScriptLog", set_scriptlog
, NULL
, RSRC_CONF
,
1002 "the name of a log for script debugging info"),
1003 AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length
, NULL
, RSRC_CONF
,
1004 "the maximum length (in bytes) of the script debug log"),
1005 AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer
, NULL
, RSRC_CONF
,
1006 "the maximum size (in bytes) to record of a POST request"),
1007 AP_INIT_TAKE1("ScriptSock", set_script_socket
, NULL
, RSRC_CONF
,
1008 "the name of the socket to use for communication with "
1013 static int log_scripterror(request_rec
*r
, cgid_server_conf
* conf
, int ret
,
1014 apr_status_t rv
, char *error
)
1016 apr_file_t
*f
= NULL
;
1018 char time_str
[APR_CTIME_LEN
];
1019 int log_flags
= rv
? APLOG_ERR
: APLOG_ERR
;
1021 ap_log_rerror(APLOG_MARK
, log_flags
, rv
, r
,
1022 "%s: %s", error
, r
->filename
);
1024 /* XXX Very expensive mainline case! Open, then getfileinfo! */
1025 if (!conf
->logname
||
1026 ((stat(conf
->logname
, &finfo
) == 0)
1027 && (finfo
.st_size
> conf
->logbytes
)) ||
1028 (apr_file_open(&f
, conf
->logname
,
1029 APR_APPEND
|APR_WRITE
|APR_CREATE
, APR_OS_DEFAULT
, r
->pool
) != APR_SUCCESS
)) {
1033 /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */
1034 apr_ctime(time_str
, apr_time_now());
1035 apr_file_printf(f
, "%%%% [%s] %s %s%s%s %s\n", time_str
, r
->method
, r
->uri
,
1036 r
->args
? "?" : "", r
->args
? r
->args
: "", r
->protocol
);
1037 /* "%% 500 /usr/local/apache/cgid-bin */
1038 apr_file_printf(f
, "%%%% %d %s\n", ret
, r
->filename
);
1040 apr_file_printf(f
, "%%error\n%s\n", error
);
1046 static int log_script(request_rec
*r
, cgid_server_conf
* conf
, int ret
,
1047 char *dbuf
, const char *sbuf
, apr_bucket_brigade
*bb
,
1048 apr_file_t
*script_err
)
1050 const apr_array_header_t
*hdrs_arr
= apr_table_elts(r
->headers_in
);
1051 const apr_table_entry_t
*hdrs
= (apr_table_entry_t
*) hdrs_arr
->elts
;
1052 char argsbuffer
[HUGE_STRING_LEN
];
1053 apr_file_t
*f
= NULL
;
1061 char time_str
[APR_CTIME_LEN
];
1063 /* XXX Very expensive mainline case! Open, then getfileinfo! */
1064 if (!conf
->logname
||
1065 ((stat(conf
->logname
, &finfo
) == 0)
1066 && (finfo
.st_size
> conf
->logbytes
)) ||
1067 (apr_file_open(&f
, conf
->logname
,
1068 APR_APPEND
|APR_WRITE
|APR_CREATE
, APR_OS_DEFAULT
, r
->pool
) != APR_SUCCESS
)) {
1069 /* Soak up script output */
1070 discard_script_output(bb
);
1072 while (apr_file_gets(argsbuffer
, HUGE_STRING_LEN
,
1073 script_err
) == APR_SUCCESS
)
1079 /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */
1080 apr_ctime(time_str
, apr_time_now());
1081 apr_file_printf(f
, "%%%% [%s] %s %s%s%s %s\n", time_str
, r
->method
, r
->uri
,
1082 r
->args
? "?" : "", r
->args
? r
->args
: "", r
->protocol
);
1083 /* "%% 500 /usr/local/apache/cgid-bin" */
1084 apr_file_printf(f
, "%%%% %d %s\n", ret
, r
->filename
);
1086 apr_file_puts("%request\n", f
);
1087 for (i
= 0; i
< hdrs_arr
->nelts
; ++i
) {
1090 apr_file_printf(f
, "%s: %s\n", hdrs
[i
].key
, hdrs
[i
].val
);
1092 if ((r
->method_number
== M_POST
|| r
->method_number
== M_PUT
)
1094 apr_file_printf(f
, "\n%s\n", dbuf
);
1097 apr_file_puts("%response\n", f
);
1098 hdrs_arr
= apr_table_elts(r
->err_headers_out
);
1099 hdrs
= (const apr_table_entry_t
*) hdrs_arr
->elts
;
1101 for (i
= 0; i
< hdrs_arr
->nelts
; ++i
) {
1104 apr_file_printf(f
, "%s: %s\n", hdrs
[i
].key
, hdrs
[i
].val
);
1108 apr_file_printf(f
, "%s\n", sbuf
);
1112 for (e
= APR_BRIGADE_FIRST(bb
);
1113 e
!= APR_BRIGADE_SENTINEL(bb
);
1114 e
= APR_BUCKET_NEXT(e
))
1116 if (APR_BUCKET_IS_EOS(e
)) {
1119 rv
= apr_bucket_read(e
, &buf
, &len
, APR_BLOCK_READ
);
1120 if (rv
!= APR_SUCCESS
|| (len
== 0)) {
1124 apr_file_puts("%stdout\n", f
);
1127 apr_file_write(f
, buf
, &len
);
1128 apr_file_puts("\n", f
);
1132 if (apr_file_gets(argsbuffer
, HUGE_STRING_LEN
,
1133 script_err
) == APR_SUCCESS
) {
1134 apr_file_puts("%stderr\n", f
);
1135 apr_file_puts(argsbuffer
, f
);
1136 while (apr_file_gets(argsbuffer
, HUGE_STRING_LEN
,
1137 script_err
) == APR_SUCCESS
)
1138 apr_file_puts(argsbuffer
, f
);
1139 apr_file_puts("\n", f
);
1144 apr_file_close(script_err
);
1151 static apr_status_t
close_unix_socket(void *thefd
)
1153 int fd
= (int)((long)thefd
);
1158 static int connect_to_daemon(int *sdptr
, request_rec
*r
,
1159 cgid_server_conf
*conf
)
1161 struct sockaddr_un unix_addr
;
1164 apr_interval_time_t sliding_timer
;
1166 memset(&unix_addr
, 0, sizeof(unix_addr
));
1167 unix_addr
.sun_family
= AF_UNIX
;
1168 apr_cpystrn(unix_addr
.sun_path
, sockname
, sizeof unix_addr
.sun_path
);
1171 sliding_timer
= 100000; /* 100 milliseconds */
1174 if ((sd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0) {
1175 return log_scripterror(r
, conf
, HTTP_INTERNAL_SERVER_ERROR
, errno
,
1176 "unable to create socket to cgi daemon");
1178 if (connect(sd
, (struct sockaddr
*)&unix_addr
, sizeof(unix_addr
)) < 0) {
1179 if (errno
== ECONNREFUSED
&& connect_tries
< DEFAULT_CONNECT_ATTEMPTS
) {
1180 ap_log_rerror(APLOG_MARK
, APLOG_DEBUG
, errno
, r
,
1181 "connect #%d to cgi daemon failed, sleeping before retry",
1184 apr_sleep(sliding_timer
);
1185 if (sliding_timer
< apr_time_from_sec(2)) {
1191 return log_scripterror(r
, conf
, HTTP_SERVICE_UNAVAILABLE
, errno
,
1192 "unable to connect to cgi daemon after multiple tries");
1196 apr_pool_cleanup_register(r
->pool
, (void *)((long)sd
),
1197 close_unix_socket
, apr_pool_cleanup_null
);
1198 break; /* we got connected! */
1200 /* gotta try again, but make sure the cgid daemon is still around */
1201 if (kill(daemon_pid
, 0) != 0) {
1202 return log_scripterror(r
, conf
, HTTP_SERVICE_UNAVAILABLE
, errno
,
1203 "cgid daemon is gone; is Apache terminating?");
1210 static void discard_script_output(apr_bucket_brigade
*bb
)
1217 for (e
= APR_BRIGADE_FIRST(bb
);
1218 e
!= APR_BRIGADE_SENTINEL(bb
);
1219 e
= APR_BUCKET_NEXT(e
))
1221 if (APR_BUCKET_IS_EOS(e
)) {
1224 rv
= apr_bucket_read(e
, &buf
, &len
, APR_BLOCK_READ
);
1225 if (rv
!= APR_SUCCESS
) {
1231 /****************************************************************
1233 * Actual cgid handling...
1236 struct cleanup_script_info
{
1238 unsigned long conn_id
;
1239 cgid_server_conf
*conf
;
1242 static apr_status_t
dead_yet(pid_t pid
, apr_interval_time_t max_wait
)
1244 apr_interval_time_t interval
= 10000; /* 10 ms */
1245 apr_interval_time_t total
= 0;
1249 /* On AIX, for processes like mod_cgid's script children where
1250 * SIGCHLD is ignored, kill(pid,0) returns success for up to
1251 * one second after the script child exits, based on when a
1252 * daemon runs to clean up unnecessary process table entries.
1253 * getpgid() can report the proper info (-1/ESRCH) immediately.
1255 if (getpgid(pid
) < 0) {
1257 if (kill(pid
, 0) < 0) {
1261 apr_sleep(interval
);
1262 total
= total
+ interval
;
1263 if (interval
< 500000) {
1266 } while (total
< max_wait
);
1267 return APR_EGENERAL
;
1270 static apr_status_t
cleanup_nonchild_process(request_rec
*r
, pid_t pid
)
1272 kill(pid
, SIGTERM
); /* in case it isn't dead yet */
1273 if (dead_yet(pid
, apr_time_from_sec(3)) == APR_SUCCESS
) {
1276 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, 0, r
,
1277 "CGI process %" APR_PID_T_FMT
" didn't exit, sending SIGKILL",
1280 if (dead_yet(pid
, apr_time_from_sec(3)) == APR_SUCCESS
) {
1283 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, 0, r
,
1284 "CGI process %" APR_PID_T_FMT
" didn't exit, sending SIGKILL again",
1288 return APR_EGENERAL
;
1291 static apr_status_t
cleanup_script(void *vptr
)
1293 struct cleanup_script_info
*info
= vptr
;
1296 cgid_req_t req
= {0};
1300 rc
= connect_to_daemon(&sd
, info
->r
, info
->conf
);
1302 return APR_EGENERAL
;
1305 /* we got a socket, and there is already a cleanup registered for it */
1307 req
.req_type
= GETPID_REQ
;
1308 req
.ppid
= parent_pid
;
1309 req
.conn_id
= info
->r
->connection
->id
;
1311 stat
= sock_write(sd
, &req
, sizeof(req
));
1312 if (stat
!= APR_SUCCESS
) {
1316 /* wait for pid of script */
1317 stat
= sock_read(sd
, &pid
, sizeof(pid
));
1318 if (stat
!= APR_SUCCESS
) {
1323 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, 0, info
->r
,
1324 "daemon couldn't find CGI process for connection %lu",
1326 return APR_EGENERAL
;
1328 return cleanup_nonchild_process(info
->r
, pid
);
1331 static int cgid_handler(request_rec
*r
)
1333 conn_rec
*c
= r
->connection
;
1334 int retval
, nph
, dbpos
= 0;
1335 char *argv0
, *dbuf
= NULL
;
1336 apr_bucket_brigade
*bb
;
1338 cgid_server_conf
*conf
;
1340 int seen_eos
, child_stopped_reading
;
1343 apr_file_t
*tempsock
;
1344 struct cleanup_script_info
*info
;
1347 if (strcmp(r
->handler
,CGI_MAGIC_TYPE
) && strcmp(r
->handler
,"cgi-script"))
1350 conf
= ap_get_module_config(r
->server
->module_config
, &cgid_module
);
1351 is_included
= !strcmp(r
->protocol
, "INCLUDED");
1353 if ((argv0
= strrchr(r
->filename
, '/')) != NULL
)
1356 argv0
= r
->filename
;
1358 nph
= !(strncmp(argv0
, "nph-", 4));
1360 argv0
= r
->filename
;
1362 if (!(ap_allow_options(r
) & OPT_EXECCGI
) && !is_scriptaliased(r
))
1363 return log_scripterror(r
, conf
, HTTP_FORBIDDEN
, 0,
1364 "Options ExecCGI is off in this directory");
1365 if (nph
&& is_included
)
1366 return log_scripterror(r
, conf
, HTTP_FORBIDDEN
, 0,
1367 "attempt to include NPH CGI script");
1369 #if defined(OS2) || defined(WIN32)
1370 #error mod_cgid does not work on this platform. If you teach it to, look
1371 #error at mod_cgi.c for required code in this path.
1373 if (r
->finfo
.filetype
== 0)
1374 return log_scripterror(r
, conf
, HTTP_NOT_FOUND
, 0,
1375 "script not found or unable to stat");
1377 if (r
->finfo
.filetype
== APR_DIR
)
1378 return log_scripterror(r
, conf
, HTTP_FORBIDDEN
, 0,
1379 "attempt to invoke directory as script");
1381 if ((r
->used_path_info
== AP_REQ_REJECT_PATH_INFO
) &&
1382 r
->path_info
&& *r
->path_info
)
1384 /* default to accept */
1385 return log_scripterror(r
, conf
, HTTP_NOT_FOUND
, 0,
1386 "AcceptPathInfo off disallows user's path");
1389 if (!ap_suexec_enabled) {
1390 if (!ap_can_exec(&r->finfo))
1391 return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
1392 "file permissions deny server execution");
1395 ap_add_common_vars(r
);
1397 env
= ap_create_environment(r
->pool
, r
->subprocess_env
);
1399 if ((retval
= connect_to_daemon(&sd
, r
, conf
)) != OK
) {
1403 rv
= send_req(sd
, r
, argv0
, env
, CGI_REQ
);
1404 if (rv
!= APR_SUCCESS
) {
1405 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, rv
, r
,
1406 "write to cgi daemon process");
1409 info
= apr_palloc(r
->pool
, sizeof(struct cleanup_script_info
));
1411 info
->conn_id
= r
->connection
->id
;
1413 apr_pool_cleanup_register(r
->pool
, info
,
1415 apr_pool_cleanup_null
);
1416 /* We are putting the socket discriptor into an apr_file_t so that we can
1417 * use a pipe bucket to send the data to the client. APR will create
1418 * a cleanup for the apr_file_t which will close the socket, so we'll
1419 * get rid of the cleanup we registered when we created the socket.
1422 apr_os_pipe_put_ex(&tempsock
, &sd
, 1, r
->pool
);
1423 apr_pool_cleanup_kill(r
->pool
, (void *)((long)sd
), close_unix_socket
);
1425 if ((argv0
= strrchr(r
->filename
, '/')) != NULL
)
1428 argv0
= r
->filename
;
1430 /* Transfer any put/post args, CERN style...
1431 * Note that we already ignore SIGPIPE in the core server.
1433 bb
= apr_brigade_create(r
->pool
, r
->connection
->bucket_alloc
);
1435 child_stopped_reading
= 0;
1436 if (conf
->logname
) {
1437 dbuf
= apr_palloc(r
->pool
, conf
->bufbytes
+ 1);
1443 rv
= ap_get_brigade(r
->input_filters
, bb
, AP_MODE_READBYTES
,
1444 APR_BLOCK_READ
, HUGE_STRING_LEN
);
1446 if (rv
!= APR_SUCCESS
) {
1447 if (APR_STATUS_IS_TIMEUP(rv
)) {
1448 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, rv
, r
,
1449 "Timeout during reading request entity data");
1450 return HTTP_REQUEST_TIME_OUT
;
1452 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, rv
, r
,
1453 "Error reading request entity data");
1454 return HTTP_INTERNAL_SERVER_ERROR
;
1457 for (bucket
= APR_BRIGADE_FIRST(bb
);
1458 bucket
!= APR_BRIGADE_SENTINEL(bb
);
1459 bucket
= APR_BUCKET_NEXT(bucket
))
1464 if (APR_BUCKET_IS_EOS(bucket
)) {
1469 /* We can't do much with this. */
1470 if (APR_BUCKET_IS_FLUSH(bucket
)) {
1474 /* If the child stopped, we still must read to EOS. */
1475 if (child_stopped_reading
) {
1480 apr_bucket_read(bucket
, &data
, &len
, APR_BLOCK_READ
);
1482 if (conf
->logname
&& dbpos
< conf
->bufbytes
) {
1485 if ((dbpos
+ len
) > conf
->bufbytes
) {
1486 cursize
= conf
->bufbytes
- dbpos
;
1491 memcpy(dbuf
+ dbpos
, data
, cursize
);
1495 /* Keep writing data to the child until done or too much time
1496 * elapses with no progress or an error occurs.
1498 rv
= apr_file_write_full(tempsock
, data
, len
, NULL
);
1500 if (rv
!= APR_SUCCESS
) {
1501 /* silly script stopped reading, soak up remaining message */
1502 child_stopped_reading
= 1;
1505 apr_brigade_cleanup(bb
);
1509 if (conf
->logname
) {
1513 /* we're done writing, or maybe we didn't write at all;
1514 * force EOF on child's stdin so that the cgi detects end (or
1519 /* Handle script return... */
1521 const char *location
;
1522 char sbuf
[MAX_STRING_LEN
];
1525 bb
= apr_brigade_create(r
->pool
, c
->bucket_alloc
);
1526 b
= apr_bucket_pipe_create(tempsock
, c
->bucket_alloc
);
1527 APR_BRIGADE_INSERT_TAIL(bb
, b
);
1528 b
= apr_bucket_eos_create(c
->bucket_alloc
);
1529 APR_BRIGADE_INSERT_TAIL(bb
, b
);
1531 if ((ret
= ap_scan_script_header_err_brigade(r
, bb
, sbuf
))) {
1532 ret
= log_script(r
, conf
, ret
, dbuf
, sbuf
, bb
, NULL
);
1535 * ret could be HTTP_NOT_MODIFIED in the case that the CGI script
1536 * does not set an explicit status and ap_meets_conditions, which
1537 * is called by ap_scan_script_header_err_brigade, detects that
1538 * the conditions of the requests are met and the response is
1540 * In this case set r->status and return OK in order to prevent
1541 * running through the error processing stack as this would
1542 * break with mod_cache, if the conditions had been set by
1543 * mod_cache itself to validate a stale entity.
1544 * BTW: We circumvent the error processing stack anyway if the
1545 * CGI script set an explicit status code (whatever it is) and
1546 * the only possible values for ret here are:
1548 * HTTP_NOT_MODIFIED (set by ap_meets_conditions)
1549 * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions)
1550 * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the
1551 * processing of the response of the CGI script, e.g broken headers
1552 * or a crashed CGI process).
1554 if (ret
== HTTP_NOT_MODIFIED
) {
1562 location
= apr_table_get(r
->headers_out
, "Location");
1564 if (location
&& location
[0] == '/' && r
->status
== 200) {
1566 /* Soak up all the script output */
1567 discard_script_output(bb
);
1568 apr_brigade_destroy(bb
);
1569 /* This redirect needs to be a GET no matter what the original
1572 r
->method
= apr_pstrdup(r
->pool
, "GET");
1573 r
->method_number
= M_GET
;
1575 /* We already read the message body (if any), so don't allow
1576 * the redirected request to think it has one. We can ignore
1577 * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
1579 apr_table_unset(r
->headers_in
, "Content-Length");
1581 ap_internal_redirect_handler(location
, r
);
1584 else if (location
&& r
->status
== 200) {
1585 /* XX Note that if a script wants to produce its own Redirect
1586 * body, it now has to explicitly *say* "Status: 302"
1588 discard_script_output(bb
);
1589 apr_brigade_destroy(bb
);
1590 return HTTP_MOVED_TEMPORARILY
;
1593 ap_pass_brigade(r
->output_filters
, bb
);
1597 struct ap_filter_t
*cur
;
1599 /* get rid of all filters up through protocol... since we
1600 * haven't parsed off the headers, there is no way they can
1604 cur
= r
->proto_output_filters
;
1605 while (cur
&& cur
->frec
->ftype
< AP_FTYPE_CONNECTION
) {
1608 r
->output_filters
= r
->proto_output_filters
= cur
;
1610 bb
= apr_brigade_create(r
->pool
, c
->bucket_alloc
);
1611 b
= apr_bucket_pipe_create(tempsock
, c
->bucket_alloc
);
1612 APR_BRIGADE_INSERT_TAIL(bb
, b
);
1613 b
= apr_bucket_eos_create(c
->bucket_alloc
);
1614 APR_BRIGADE_INSERT_TAIL(bb
, b
);
1615 ap_pass_brigade(r
->output_filters
, bb
);
1618 return OK
; /* NOT r->status, even if it has changed. */
1624 /*============================================================================
1625 *============================================================================
1626 * This is the beginning of the cgi filter code moved from mod_include. This
1627 * is the code required to handle the "exec" SSI directive.
1628 *============================================================================
1629 *============================================================================*/
1630 static apr_status_t
include_cgi(include_ctx_t
*ctx
, ap_filter_t
*f
,
1631 apr_bucket_brigade
*bb
, char *s
)
1633 request_rec
*r
= f
->r
;
1634 request_rec
*rr
= ap_sub_req_lookup_uri(s
, r
, f
->next
);
1637 if (rr
->status
!= HTTP_OK
) {
1638 ap_destroy_sub_req(rr
);
1639 return APR_EGENERAL
;
1642 /* No hardwired path info or query allowed */
1643 if ((rr
->path_info
&& rr
->path_info
[0]) || rr
->args
) {
1644 ap_destroy_sub_req(rr
);
1645 return APR_EGENERAL
;
1647 if (rr
->finfo
.filetype
!= APR_REG
) {
1648 ap_destroy_sub_req(rr
);
1649 return APR_EGENERAL
;
1652 /* Script gets parameters of the *document*, for back compatibility */
1653 rr
->path_info
= r
->path_info
; /* hard to get right; see mod_cgi.c */
1656 /* Force sub_req to be treated as a CGI request, even if ordinary
1657 * typing rules would have called it something else.
1659 ap_set_content_type(rr
, CGI_MAGIC_TYPE
);
1662 rr_status
= ap_run_sub_req(rr
);
1663 if (ap_is_HTTP_REDIRECT(rr_status
)) {
1664 const char *location
= apr_table_get(rr
->headers_out
, "Location");
1669 location
= ap_escape_html(rr
->pool
, location
);
1670 buffer
= apr_pstrcat(ctx
->pool
, "<a href=\"", location
, "\">",
1671 location
, "</a>", NULL
);
1673 APR_BRIGADE_INSERT_TAIL(bb
, apr_bucket_pool_create(buffer
,
1674 strlen(buffer
), ctx
->pool
,
1675 f
->c
->bucket_alloc
));
1679 ap_destroy_sub_req(rr
);
1684 /* This is the special environment used for running the "exec cmd="
1685 * variety of SSI directives.
1687 static void add_ssi_vars(request_rec
*r
)
1689 apr_table_t
*e
= r
->subprocess_env
;
1691 if (r
->path_info
&& r
->path_info
[0] != '\0') {
1692 request_rec
*pa_req
;
1694 apr_table_setn(e
, "PATH_INFO", ap_escape_shell_cmd(r
->pool
, r
->path_info
));
1696 pa_req
= ap_sub_req_lookup_uri(ap_escape_uri(r
->pool
, r
->path_info
), r
, NULL
);
1697 if (pa_req
->filename
) {
1698 apr_table_setn(e
, "PATH_TRANSLATED",
1699 apr_pstrcat(r
->pool
, pa_req
->filename
, pa_req
->path_info
, NULL
));
1701 ap_destroy_sub_req(pa_req
);
1705 char *arg_copy
= apr_pstrdup(r
->pool
, r
->args
);
1707 apr_table_setn(e
, "QUERY_STRING", r
->args
);
1708 ap_unescape_url(arg_copy
);
1709 apr_table_setn(e
, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r
->pool
, arg_copy
));
1713 static int include_cmd(include_ctx_t
*ctx
, ap_filter_t
*f
,
1714 apr_bucket_brigade
*bb
, char *command
)
1719 apr_file_t
*tempsock
= NULL
;
1720 request_rec
*r
= f
->r
;
1721 cgid_server_conf
*conf
= ap_get_module_config(r
->server
->module_config
,
1723 struct cleanup_script_info
*info
;
1726 env
= ap_create_environment(r
->pool
, r
->subprocess_env
);
1728 if ((retval
= connect_to_daemon(&sd
, r
, conf
)) != OK
) {
1732 send_req(sd
, r
, command
, env
, SSI_REQ
);
1734 info
= apr_palloc(r
->pool
, sizeof(struct cleanup_script_info
));
1736 info
->conn_id
= r
->connection
->id
;
1738 /* for this type of request, the script is invoked through an
1739 * intermediate shell process... cleanup_script is only able
1740 * to knock out the shell process, not the actual script
1742 apr_pool_cleanup_register(r
->pool
, info
,
1744 apr_pool_cleanup_null
);
1746 /* We are putting the socket discriptor into an apr_file_t so that we can
1747 * use a pipe bucket to send the data to the client. APR will create
1748 * a cleanup for the apr_file_t which will close the socket, so we'll
1749 * get rid of the cleanup we registered when we created the socket.
1751 apr_os_pipe_put_ex(&tempsock
, &sd
, 1, r
->pool
);
1752 apr_pool_cleanup_kill(r
->pool
, (void *)((long)sd
), close_unix_socket
);
1754 APR_BRIGADE_INSERT_TAIL(bb
, apr_bucket_pipe_create(tempsock
,
1755 f
->c
->bucket_alloc
));
1761 static apr_status_t
handle_exec(include_ctx_t
*ctx
, ap_filter_t
*f
,
1762 apr_bucket_brigade
*bb
)
1765 char *tag_val
= NULL
;
1766 request_rec
*r
= f
->r
;
1767 char *file
= r
->filename
;
1768 char parsed_string
[MAX_STRING_LEN
];
1771 ap_log_rerror(APLOG_MARK
,
1772 (ctx
->flags
& SSI_FLAG_PRINTING
)
1773 ? APLOG_ERR
: APLOG_WARNING
,
1774 0, r
, "missing argument for exec element in %s",
1778 if (!(ctx
->flags
& SSI_FLAG_PRINTING
)) {
1783 SSI_CREATE_ERROR_BUCKET(ctx
, f
, bb
);
1787 if (ctx
->flags
& SSI_FLAG_NO_EXEC
) {
1788 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, 0, r
, "exec used but not allowed "
1789 "in %s", r
->filename
);
1790 SSI_CREATE_ERROR_BUCKET(ctx
, f
, bb
);
1795 cgid_pfn_gtv(ctx
, &tag
, &tag_val
, SSI_VALUE_DECODED
);
1796 if (!tag
|| !tag_val
) {
1800 if (!strcmp(tag
, "cmd")) {
1803 cgid_pfn_ps(ctx
, tag_val
, parsed_string
, sizeof(parsed_string
),
1804 SSI_EXPAND_LEAVE_NAME
);
1806 rv
= include_cmd(ctx
, f
, bb
, parsed_string
);
1807 if (rv
!= APR_SUCCESS
) {
1808 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, 0, r
,
1809 "execution failure for parameter \"%s\" "
1810 "to tag exec in file %s", tag
, r
->filename
);
1811 SSI_CREATE_ERROR_BUCKET(ctx
, f
, bb
);
1815 else if (!strcmp(tag
, "cgi")) {
1818 cgid_pfn_ps(ctx
, tag_val
, parsed_string
, sizeof(parsed_string
),
1819 SSI_EXPAND_DROP_NAME
);
1821 rv
= include_cgi(ctx
, f
, bb
, parsed_string
);
1822 if (rv
!= APR_SUCCESS
) {
1823 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, 0, r
, "invalid CGI ref "
1824 "\"%s\" in %s", tag_val
, file
);
1825 SSI_CREATE_ERROR_BUCKET(ctx
, f
, bb
);
1830 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, 0, r
, "unknown parameter "
1831 "\"%s\" to tag exec in %s", tag
, file
);
1832 SSI_CREATE_ERROR_BUCKET(ctx
, f
, bb
);
1839 /*============================================================================
1840 *============================================================================
1841 * This is the end of the cgi filter code moved from mod_include.
1842 *============================================================================
1843 *============================================================================*/
1846 static void register_hook(apr_pool_t
*p
)
1848 static const char * const aszPre
[] = { "mod_include.c", NULL
};
1850 ap_hook_pre_config(cgid_pre_config
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1851 ap_hook_post_config(cgid_init
, aszPre
, NULL
, APR_HOOK_MIDDLE
);
1852 ap_hook_handler(cgid_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1855 module AP_MODULE_DECLARE_DATA cgid_module
= {
1856 STANDARD20_MODULE_STUFF
,
1857 NULL
, /* dir config creater */
1858 NULL
, /* dir merger --- default is to override */
1859 create_cgid_config
, /* server config */
1860 merge_cgid_config
, /* merge server config */
1861 cgid_cmds
, /* command table */
1862 register_hook
/* register_handlers */