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