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