upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / modules / generators / mod_cgi.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.h"
31 #include "apr_strings.h"
32 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
33 #include "apr_optional.h"
34 #include "apr_buckets.h"
35 #include "apr_lib.h"
36 #include "apr_poll.h"
37
38 #define APR_WANT_STRFUNC
39 #include "apr_want.h"
40
41 #define CORE_PRIVATE
42
43 #include "util_filter.h"
44 #include "ap_config.h"
45 #include "httpd.h"
46 #include "http_config.h"
47 #include "http_request.h"
48 #include "http_core.h"
49 #include "http_protocol.h"
50 #include "http_main.h"
51 #include "http_log.h"
52 #include "util_script.h"
53 #include "ap_mpm.h"
54 #include "mod_core.h"
55 #include "mod_cgi.h"
56
57 module AP_MODULE_DECLARE_DATA cgi_module;
58
59 static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgi_pfn_reg_with_ssi;
60 static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgi_pfn_gtv;
61 static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgi_pfn_ps;
62 static APR_OPTIONAL_FN_TYPE(ap_cgi_build_command) *cgi_build_command;
63
64 /* Read and discard the data in the brigade produced by a CGI script */
65 static void discard_script_output(apr_bucket_brigade *bb);
66
67 /* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
68  * in ScriptAliased directories, which means we need to know if this
69  * request came through ScriptAlias or not... so the Alias module
70  * leaves a note for us.
71  */
72
73 static int is_scriptaliased(request_rec *r)
74 {
75     const char *t = apr_table_get(r->notes, "alias-forced-type");
76     return t && (!strcasecmp(t, "cgi-script"));
77 }
78
79 /* Configuration stuff */
80
81 #define DEFAULT_LOGBYTES 10385760
82 #define DEFAULT_BUFBYTES 1024
83
84 typedef struct {
85     const char *logname;
86     long        logbytes;
87     apr_size_t  bufbytes;
88 } cgi_server_conf;
89
90 static void *create_cgi_config(apr_pool_t *p, server_rec *s)
91 {
92     cgi_server_conf *c =
93     (cgi_server_conf *) apr_pcalloc(p, sizeof(cgi_server_conf));
94
95     c->logname = NULL;
96     c->logbytes = DEFAULT_LOGBYTES;
97     c->bufbytes = DEFAULT_BUFBYTES;
98
99     return c;
100 }
101
102 static void *merge_cgi_config(apr_pool_t *p, void *basev, void *overridesv)
103 {
104     cgi_server_conf *base = (cgi_server_conf *) basev,
105                     *overrides = (cgi_server_conf *) overridesv;
106
107     return overrides->logname ? overrides : base;
108 }
109
110 static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg)
111 {
112     server_rec *s = cmd->server;
113     cgi_server_conf *conf = ap_get_module_config(s->module_config,
114                                                  &cgi_module);
115
116     conf->logname = ap_server_root_relative(cmd->pool, arg);
117
118     if (!conf->logname) {
119         return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ",
120                            arg, NULL);
121     }
122
123     return NULL;
124 }
125
126 static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy,
127                                         const char *arg)
128 {
129     server_rec *s = cmd->server;
130     cgi_server_conf *conf = ap_get_module_config(s->module_config,
131                                                  &cgi_module);
132
133     conf->logbytes = atol(arg);
134     return NULL;
135 }
136
137 static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy,
138                                         const char *arg)
139 {
140     server_rec *s = cmd->server;
141     cgi_server_conf *conf = ap_get_module_config(s->module_config,
142                                                  &cgi_module);
143
144     conf->bufbytes = atoi(arg);
145     return NULL;
146 }
147
148 static const command_rec cgi_cmds[] =
149 {
150 AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF,
151      "the name of a log for script debugging info"),
152 AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF,
153      "the maximum length (in bytes) of the script debug log"),
154 AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF,
155      "the maximum size (in bytes) to record of a POST request"),
156     {NULL}
157 };
158
159 static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret,
160                            apr_status_t rv, char *error)
161 {
162     apr_file_t *f = NULL;
163     apr_finfo_t finfo;
164     char time_str[APR_CTIME_LEN];
165     int log_flags = rv ? APLOG_ERR : APLOG_ERR;
166
167     ap_log_rerror(APLOG_MARK, log_flags, rv, r, 
168                   "%s: %s", error, r->filename);
169
170     /* XXX Very expensive mainline case! Open, then getfileinfo! */
171     if (!conf->logname ||
172         ((apr_stat(&finfo, conf->logname,
173                    APR_FINFO_SIZE, r->pool) == APR_SUCCESS) &&
174          (finfo.size > conf->logbytes)) ||
175         (apr_file_open(&f, conf->logname,
176                        APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT,
177                        r->pool) != APR_SUCCESS)) {
178         return ret;
179     }
180
181     /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
182     apr_ctime(time_str, apr_time_now());
183     apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
184                     r->args ? "?" : "", r->args ? r->args : "", r->protocol);
185     /* "%% 500 /usr/local/apache/cgi-bin */
186     apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
187
188     apr_file_printf(f, "%%error\n%s\n", error);
189
190     apr_file_close(f);
191     return ret;
192 }
193
194 /* Soak up stderr from a script and redirect it to the error log. 
195  */
196 static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err)
197 {
198     char argsbuffer[HUGE_STRING_LEN];
199     char *newline;
200     apr_status_t rv;
201
202     while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN,
203                                script_err)) == APR_SUCCESS) {
204         newline = strchr(argsbuffer, '\n');
205         if (newline) {
206             *newline = '\0';
207         }
208         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, 
209                       "%s", argsbuffer);            
210     }
211
212     return rv;
213 }
214
215 static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
216                       char *dbuf, const char *sbuf, apr_bucket_brigade *bb, 
217                       apr_file_t *script_err)
218 {
219     const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in);
220     const apr_table_entry_t *hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
221     char argsbuffer[HUGE_STRING_LEN];
222     apr_file_t *f = NULL;
223     apr_bucket *e;
224     const char *buf;
225     apr_size_t len;
226     apr_status_t rv;
227     int first;
228     int i;
229     apr_finfo_t finfo;
230     char time_str[APR_CTIME_LEN];
231
232     /* XXX Very expensive mainline case! Open, then getfileinfo! */
233     if (!conf->logname ||
234         ((apr_stat(&finfo, conf->logname,
235                    APR_FINFO_SIZE, r->pool) == APR_SUCCESS) &&
236          (finfo.size > conf->logbytes)) ||
237         (apr_file_open(&f, conf->logname,
238                        APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT,
239                        r->pool) != APR_SUCCESS)) {
240         /* Soak up script output */
241         discard_script_output(bb);
242         log_script_err(r, script_err);
243         return ret;
244     }
245
246     /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
247     apr_ctime(time_str, apr_time_now());
248     apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
249                     r->args ? "?" : "", r->args ? r->args : "", r->protocol);
250     /* "%% 500 /usr/local/apache/cgi-bin" */
251     apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
252
253     apr_file_puts("%request\n", f);
254     for (i = 0; i < hdrs_arr->nelts; ++i) {
255         if (!hdrs[i].key)
256             continue;
257         apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
258     }
259     if ((r->method_number == M_POST || r->method_number == M_PUT) &&
260         *dbuf) {
261         apr_file_printf(f, "\n%s\n", dbuf);
262     }
263
264     apr_file_puts("%response\n", f);
265     hdrs_arr = apr_table_elts(r->err_headers_out);
266     hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
267
268     for (i = 0; i < hdrs_arr->nelts; ++i) {
269         if (!hdrs[i].key)
270             continue;
271         apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
272     }
273
274     if (sbuf && *sbuf)
275         apr_file_printf(f, "%s\n", sbuf);
276
277     first = 1;
278     APR_BRIGADE_FOREACH(e, bb) {
279         if (APR_BUCKET_IS_EOS(e)) {
280             break;
281         }
282         rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
283         if (rv != APR_SUCCESS || (len == 0)) {
284             break;
285         }
286         if (first) {
287             apr_file_puts("%stdout\n", f);
288             first = 0;
289         }
290         apr_file_write(f, buf, &len);
291         apr_file_puts("\n", f);
292     }
293
294     if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == APR_SUCCESS) {
295         apr_file_puts("%stderr\n", f);
296         apr_file_puts(argsbuffer, f);
297         while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
298                              script_err) == APR_SUCCESS) {
299             apr_file_puts(argsbuffer, f);
300         }
301         apr_file_puts("\n", f);
302     }
303
304     apr_brigade_destroy(bb);
305     apr_file_close(script_err);
306
307     apr_file_close(f);
308     return ret;
309 }
310
311
312 /* This is the special environment used for running the "exec cmd="
313  *   variety of SSI directives.
314  */
315 static void add_ssi_vars(request_rec *r)
316 {
317     apr_table_t *e = r->subprocess_env;
318
319     if (r->path_info && r->path_info[0] != '\0') {
320         request_rec *pa_req;
321
322         apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool,
323                                                            r->path_info));
324
325         pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info),
326                                        r, NULL);
327         if (pa_req->filename) {
328             apr_table_setn(e, "PATH_TRANSLATED",
329                            apr_pstrcat(r->pool, pa_req->filename,
330                                        pa_req->path_info, NULL));
331         }
332         ap_destroy_sub_req(pa_req);
333     }
334
335     if (r->args) {
336         char *arg_copy = apr_pstrdup(r->pool, r->args);
337
338         apr_table_setn(e, "QUERY_STRING", r->args);
339         ap_unescape_url(arg_copy);
340         apr_table_setn(e, "QUERY_STRING_UNESCAPED",
341                        ap_escape_shell_cmd(r->pool, arg_copy));
342     }
343 }
344
345 static void cgi_child_errfn(apr_pool_t *pool, apr_status_t err,
346                             const char *description)
347 {
348     apr_file_t *stderr_log;
349     char errbuf[200];
350
351     apr_file_open_stderr(&stderr_log, pool);
352     /* Escape the logged string because it may be something that
353      * came in over the network.
354      */
355     apr_file_printf(stderr_log,
356                     "(%d)%s: %s\n",
357                     err,
358                     apr_strerror(err, errbuf, sizeof(errbuf)),
359 #ifdef AP_UNSAFE_ERROR_LOG_UNESCAPED
360                     description
361 #else
362                     ap_escape_logitem(pool, description)
363 #endif
364                     );
365 }
366
367 static apr_status_t run_cgi_child(apr_file_t **script_out,
368                                   apr_file_t **script_in,
369                                   apr_file_t **script_err, 
370                                   const char *command,
371                                   const char * const argv[],
372                                   request_rec *r,
373                                   apr_pool_t *p,
374                                   cgi_exec_info_t *e_info)
375 {
376     const char * const *env;
377     apr_procattr_t *procattr;
378     apr_proc_t *procnew;
379     apr_status_t rc = APR_SUCCESS;
380
381 #if defined(RLIMIT_CPU)  || defined(RLIMIT_NPROC) || \
382     defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS)
383
384     core_dir_config *conf = ap_get_module_config(r->per_dir_config,
385                                                  &core_module);
386 #endif
387
388 #ifdef DEBUG_CGI
389 #ifdef OS2
390     /* Under OS/2 need to use device con. */
391     FILE *dbg = fopen("con", "w");
392 #else
393     FILE *dbg = fopen("/dev/tty", "w");
394 #endif
395     int i;
396 #endif
397
398     RAISE_SIGSTOP(CGI_CHILD);
399 #ifdef DEBUG_CGI
400     fprintf(dbg, "Attempting to exec %s as CGI child (argv0 = %s)\n",
401             r->filename, argv[0]);
402 #endif
403
404     env = (const char * const *)ap_create_environment(p, r->subprocess_env);
405
406 #ifdef DEBUG_CGI
407     fprintf(dbg, "Environment: \n");
408     for (i = 0; env[i]; ++i)
409         fprintf(dbg, "'%s'\n", env[i]);
410 #endif
411
412     /* Transmute ourselves into the script.
413      * NB only ISINDEX scripts get decoded arguments.
414      */
415     if (((rc = apr_procattr_create(&procattr, p)) != APR_SUCCESS) ||
416         ((rc = apr_procattr_io_set(procattr,
417                                    e_info->in_pipe,
418                                    e_info->out_pipe,
419                                    e_info->err_pipe)) != APR_SUCCESS) ||
420         ((rc = apr_procattr_dir_set(procattr, 
421                         ap_make_dirstr_parent(r->pool,
422                                               r->filename))) != APR_SUCCESS) ||
423 #ifdef RLIMIT_CPU
424         ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU,
425                                       conf->limit_cpu)) != APR_SUCCESS) ||
426 #endif
427 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
428         ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM,
429                                       conf->limit_mem)) != APR_SUCCESS) ||
430 #endif
431 #ifdef RLIMIT_NPROC
432         ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC,
433                                       conf->limit_nproc)) != APR_SUCCESS) ||
434 #endif
435         ((rc = apr_procattr_cmdtype_set(procattr,
436                                         e_info->cmd_type)) != APR_SUCCESS) ||
437
438         ((rc = apr_procattr_detach_set(procattr,
439                                         e_info->detached & AP_PROC_DETACHED)) != APR_SUCCESS) ||
440         ((rc = apr_procattr_addrspace_set(procattr,
441                                         (e_info->detached & AP_PROC_NEWADDRSPACE) ? 1 : 0)) != APR_SUCCESS) ||
442         ((rc = apr_procattr_child_errfn_set(procattr, cgi_child_errfn)) != APR_SUCCESS)) {
443         /* Something bad happened, tell the world. */
444         ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
445                       "couldn't set child process attributes: %s", r->filename);
446     }
447     else {
448         procnew = apr_pcalloc(p, sizeof(*procnew));
449         if (e_info->prog_type == RUN_AS_SSI) {
450             SPLIT_AND_PASS_PRETAG_BUCKETS(*(e_info->bb), e_info->ctx,
451                                           e_info->next, rc);
452             if (rc != APR_SUCCESS) {
453                 return rc;
454             }
455         }
456
457         rc = ap_os_create_privileged_process(r, procnew, command, argv, env,
458                                              procattr, p);
459     
460         if (rc != APR_SUCCESS) {
461             /* Bad things happened. Everyone should have cleaned up. */
462             ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, rc, r,
463                           "couldn't create child process: %d: %s", rc,
464                           apr_filename_of_pathname(r->filename));
465         }
466         else {
467             apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
468
469             *script_in = procnew->out;
470             if (!*script_in)
471                 return APR_EBADF;
472             apr_file_pipe_timeout_set(*script_in, r->server->timeout);
473
474             if (e_info->prog_type == RUN_AS_CGI) {
475                 *script_out = procnew->in;
476                 if (!*script_out)
477                     return APR_EBADF;
478                 apr_file_pipe_timeout_set(*script_out, r->server->timeout);
479
480                 *script_err = procnew->err;
481                 if (!*script_err)
482                     return APR_EBADF;
483                 apr_file_pipe_timeout_set(*script_err, r->server->timeout);
484             }
485         }
486     }
487 #ifdef DEBUG_CGI
488     fclose(dbg);
489 #endif
490     return (rc);
491 }
492
493
494 static apr_status_t default_build_command(const char **cmd, const char ***argv,
495                                           request_rec *r, apr_pool_t *p,
496                                           cgi_exec_info_t *e_info)
497 {
498     int numwords, x, idx;
499     char *w;
500     const char *args = NULL;
501
502     if (e_info->process_cgi) {
503         *cmd = r->filename;
504         /* Do not process r->args if they contain an '=' assignment 
505          */
506         if (r->args && r->args[0] && !ap_strchr_c(r->args, '=')) {
507             args = r->args;
508         }
509     }
510
511     if (!args) {
512         numwords = 1;
513     }
514     else {
515         /* count the number of keywords */
516         for (x = 0, numwords = 2; args[x]; x++) {
517             if (args[x] == '+') {
518                 ++numwords;
519             }
520         }
521     }
522     /* Everything is - 1 to account for the first parameter 
523      * which is the program name.
524      */ 
525     if (numwords > APACHE_ARG_MAX - 1) {
526         numwords = APACHE_ARG_MAX - 1;    /* Truncate args to prevent overrun */
527     }
528     *argv = apr_palloc(p, (numwords + 2) * sizeof(char *));
529     (*argv)[0] = *cmd;
530     for (x = 1, idx = 1; x < numwords; x++) {
531         w = ap_getword_nulls(p, &args, '+');
532         ap_unescape_url(w);
533         (*argv)[idx++] = ap_escape_shell_cmd(p, w);
534     }
535     (*argv)[idx] = NULL;
536
537     return APR_SUCCESS;
538 }
539
540 static void discard_script_output(apr_bucket_brigade *bb)
541 {
542     apr_bucket *e;
543     const char *buf;
544     apr_size_t len;
545     apr_status_t rv;
546     APR_BRIGADE_FOREACH(e, bb) {
547         if (APR_BUCKET_IS_EOS(e)) {
548             break;
549         }
550         rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
551         if (rv != APR_SUCCESS) {
552             break;
553         }
554     }
555 }
556
557 #if APR_FILES_AS_SOCKETS
558
559 /* A CGI bucket type is needed to catch any output to stderr from the
560  * script; see PR 22030. */
561 static const apr_bucket_type_t bucket_type_cgi;
562
563 struct cgi_bucket_data {
564     apr_pollset_t *pollset;
565     request_rec *r;
566 };
567
568 /* Create a CGI bucket using pipes from script stdout 'out'
569  * and stderr 'err', for request 'r'. */
570 static apr_bucket *cgi_bucket_create(request_rec *r,
571                                      apr_file_t *out, apr_file_t *err,
572                                      apr_bucket_alloc_t *list)
573 {
574     apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
575     apr_status_t rv;
576     apr_pollfd_t fd;
577     struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data);
578     
579     APR_BUCKET_INIT(b);
580     b->free = apr_bucket_free;
581     b->list = list;
582     b->type = &bucket_type_cgi;
583     b->length = (apr_size_t)(-1);
584     b->start = -1;
585
586     /* Create the pollset */
587     rv = apr_pollset_create(&data->pollset, 2, r->pool, 0);
588     AP_DEBUG_ASSERT(rv == APR_SUCCESS);
589
590     fd.desc_type = APR_POLL_FILE;
591     fd.reqevents = APR_POLLIN;
592     fd.p = r->pool;
593     fd.desc.f = out; /* script's stdout */
594     fd.client_data = (void *)1;
595     rv = apr_pollset_add(data->pollset, &fd);
596     AP_DEBUG_ASSERT(rv == APR_SUCCESS);
597     
598     fd.desc.f = err; /* script's stderr */
599     fd.client_data = (void *)2;
600     rv = apr_pollset_add(data->pollset, &fd);
601     AP_DEBUG_ASSERT(rv == APR_SUCCESS);
602     
603     data->r = r;
604     b->data = data;
605     return b;
606 }
607
608 /* Create a duplicate CGI bucket using given bucket data */
609 static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data,
610                                   apr_bucket_alloc_t *list)
611 {
612     apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
613     APR_BUCKET_INIT(b);
614     b->free = apr_bucket_free;
615     b->list = list;
616     b->type = &bucket_type_cgi;
617     b->length = (apr_size_t)(-1);
618     b->start = -1;
619     b->data = data;
620     return b;
621 }
622
623 /* Handle stdout from CGI child.  Duplicate of logic from the _read
624  * method of the real APR pipe bucket implementation. */
625 static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out,
626                                     const char **str, apr_size_t *len)
627 {
628     char *buf;
629     apr_status_t rv;
630
631     *str = NULL;
632     *len = APR_BUCKET_BUFF_SIZE;
633     buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */
634
635     rv = apr_file_read(out, buf, len);
636
637     if (rv != APR_SUCCESS && rv != APR_EOF) {
638         apr_bucket_free(buf);
639         return rv;
640     }
641
642     if (*len > 0) {
643         struct cgi_bucket_data *data = a->data;
644         apr_bucket_heap *h;
645
646         /* Change the current bucket to refer to what we read */
647         a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free);
648         h = a->data;
649         h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
650         *str = buf;
651         APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list));
652     }
653     else {
654         apr_bucket_free(buf);
655         a = apr_bucket_immortal_make(a, "", 0);
656         *str = a->data;
657     }
658     return rv;
659 }
660
661 /* Read method of CGI bucket: polls on stderr and stdout of the child,
662  * sending any stderr output immediately away to the error log. */
663 static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str,
664                                     apr_size_t *len, apr_read_type_e block)
665 {
666     struct cgi_bucket_data *data = b->data;
667     apr_interval_time_t timeout;
668     apr_status_t rv;
669     int gotdata = 0;
670
671     timeout = block == APR_NONBLOCK_READ ? 0 : data->r->server->timeout;
672
673     do {
674         const apr_pollfd_t *results;
675         apr_int32_t num;
676
677         rv = apr_pollset_poll(data->pollset, timeout, &num, &results);
678         if (APR_STATUS_IS_TIMEUP(rv)) {
679             return timeout == 0 ? APR_EAGAIN : rv;
680         }
681         else if (APR_STATUS_IS_EINTR(rv)) {
682             continue;
683         }
684         else if (rv != APR_SUCCESS) {
685             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r,
686                           "poll failed waiting for CGI child");
687             return rv;
688         }
689         
690         for (; num; num--, results++) {
691             if (results[0].client_data == (void *)1) {
692                 /* stdout */
693                 rv = cgi_read_stdout(b, results[0].desc.f, str, len);
694                 if (APR_STATUS_IS_EOF(rv)) {
695                     rv = APR_SUCCESS;
696                 }
697                 gotdata = 1;
698             } else {
699                 /* stderr */
700                 apr_status_t rv2 = log_script_err(data->r, results[0].desc.f);
701                 if (APR_STATUS_IS_EOF(rv2)) {
702                     apr_pollset_remove(data->pollset, &results[0]);
703                 }
704             }
705         }
706
707     } while (!gotdata);
708
709     return rv;
710 }
711
712 static const apr_bucket_type_t bucket_type_cgi = {
713     "CGI", 5, APR_BUCKET_DATA,
714     apr_bucket_destroy_noop,
715     cgi_bucket_read,
716     apr_bucket_setaside_notimpl,
717     apr_bucket_split_notimpl,
718     apr_bucket_copy_notimpl
719 };
720
721 #endif
722
723 static int cgi_handler(request_rec *r)
724 {
725     int nph;
726     apr_size_t dbpos = 0;
727     const char *argv0;
728     const char *command;
729     const char **argv;
730     char *dbuf = NULL;
731     apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL;
732     apr_bucket_brigade *bb;
733     apr_bucket *b;
734     int is_included;
735     int seen_eos, child_stopped_reading;
736     apr_pool_t *p;
737     cgi_server_conf *conf;
738     apr_status_t rv;
739     cgi_exec_info_t e_info;
740     conn_rec *c = r->connection;
741
742     if(strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script"))
743         return DECLINED;
744
745     is_included = !strcmp(r->protocol, "INCLUDED");
746
747     p = r->main ? r->main->pool : r->pool;
748
749     argv0 = apr_filename_of_pathname(r->filename);
750     nph = !(strncmp(argv0, "nph-", 4));
751     conf = ap_get_module_config(r->server->module_config, &cgi_module);
752
753     if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r))
754         return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
755                                "Options ExecCGI is off in this directory");
756     if (nph && is_included)
757         return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
758                                "attempt to include NPH CGI script");
759
760     if (r->finfo.filetype == 0)
761         return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,
762                                "script not found or unable to stat");
763     if (r->finfo.filetype == APR_DIR)
764         return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
765                                "attempt to invoke directory as script");
766
767     if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) &&
768         r->path_info && *r->path_info)
769     {
770         /* default to accept */
771         return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,
772                                "AcceptPathInfo off disallows user's path");
773     }
774 /*
775     if (!ap_suexec_enabled) {
776         if (!ap_can_exec(&r->finfo))
777             return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
778                                    "file permissions deny server execution");
779     }
780
781 */
782     ap_add_common_vars(r);
783     ap_add_cgi_vars(r);
784
785     e_info.process_cgi = 1;
786     e_info.cmd_type    = APR_PROGRAM;
787     e_info.detached    = 0;
788     e_info.in_pipe     = APR_CHILD_BLOCK;
789     e_info.out_pipe    = APR_CHILD_BLOCK;
790     e_info.err_pipe    = APR_CHILD_BLOCK;
791     e_info.prog_type   = RUN_AS_CGI;
792     e_info.bb          = NULL;
793     e_info.ctx         = NULL;
794     e_info.next        = NULL;
795
796     /* build the command line */
797     if ((rv = cgi_build_command(&command, &argv, r, p, &e_info)) != APR_SUCCESS) {
798         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
799                       "don't know how to spawn child process: %s", 
800                       r->filename);
801         return HTTP_INTERNAL_SERVER_ERROR;
802     }
803
804     /* run the script in its own process */
805     if ((rv = run_cgi_child(&script_out, &script_in, &script_err,
806                             command, argv, r, p, &e_info)) != APR_SUCCESS) {
807         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
808                       "couldn't spawn child process: %s", r->filename);
809         return HTTP_INTERNAL_SERVER_ERROR;
810     }
811
812     /* Transfer any put/post args, CERN style...
813      * Note that we already ignore SIGPIPE in the core server.
814      */
815     bb = apr_brigade_create(r->pool, c->bucket_alloc);
816     seen_eos = 0;
817     child_stopped_reading = 0;
818     if (conf->logname) {
819         dbuf = apr_palloc(r->pool, conf->bufbytes + 1);
820         dbpos = 0;
821     }
822     do {
823         apr_bucket *bucket;
824
825         rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
826                             APR_BLOCK_READ, HUGE_STRING_LEN);
827        
828         if (rv != APR_SUCCESS) {
829             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
830                           "Error reading request entity data");
831             return HTTP_INTERNAL_SERVER_ERROR;
832         }
833
834         APR_BRIGADE_FOREACH(bucket, bb) {
835             const char *data;
836             apr_size_t len;
837
838             if (APR_BUCKET_IS_EOS(bucket)) {
839                 seen_eos = 1;
840                 break;
841             }
842
843             /* We can't do much with this. */
844             if (APR_BUCKET_IS_FLUSH(bucket)) {
845                 continue;
846             }
847
848             /* If the child stopped, we still must read to EOS. */
849             if (child_stopped_reading) {
850                 continue;
851             } 
852
853             /* read */
854             apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
855             
856             if (conf->logname && dbpos < conf->bufbytes) {
857                 int cursize;
858
859                 if ((dbpos + len) > conf->bufbytes) {
860                     cursize = conf->bufbytes - dbpos;
861                 }
862                 else {
863                     cursize = len;
864                 }
865                 memcpy(dbuf + dbpos, data, cursize);
866                 dbpos += cursize;
867             }
868
869             /* Keep writing data to the child until done or too much time
870              * elapses with no progress or an error occurs.
871              */
872             rv = apr_file_write_full(script_out, data, len, NULL);
873
874             if (rv != APR_SUCCESS) {
875                 /* silly script stopped reading, soak up remaining message */
876                 child_stopped_reading = 1;
877             }
878         }
879         apr_brigade_cleanup(bb);
880     }
881     while (!seen_eos);
882
883     if (conf->logname) {
884         dbuf[dbpos] = '\0';
885     }
886     /* Is this flush really needed? */
887     apr_file_flush(script_out);
888     apr_file_close(script_out);
889
890     AP_DEBUG_ASSERT(script_in != NULL);
891
892     apr_brigade_cleanup(bb);
893
894 #if APR_FILES_AS_SOCKETS
895     apr_file_pipe_timeout_set(script_in, 0);
896     apr_file_pipe_timeout_set(script_err, 0);
897     
898     b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc);
899 #else
900     b = apr_bucket_pipe_create(script_in, c->bucket_alloc);
901 #endif
902     APR_BRIGADE_INSERT_TAIL(bb, b);
903     b = apr_bucket_eos_create(c->bucket_alloc);
904     APR_BRIGADE_INSERT_TAIL(bb, b);
905
906     /* Handle script return... */
907     if (!nph) {
908         const char *location;
909         char sbuf[MAX_STRING_LEN];
910         int ret;
911
912         if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) {
913             return log_script(r, conf, ret, dbuf, sbuf, bb, script_err);
914         }
915
916         location = apr_table_get(r->headers_out, "Location");
917
918         if (location && location[0] == '/' && r->status == 200) {
919             discard_script_output(bb);
920             apr_brigade_destroy(bb);
921             apr_file_pipe_timeout_set(script_err, r->server->timeout);
922             log_script_err(r, script_err);
923             /* This redirect needs to be a GET no matter what the original
924              * method was.
925              */
926             r->method = apr_pstrdup(r->pool, "GET");
927             r->method_number = M_GET;
928
929             /* We already read the message body (if any), so don't allow
930              * the redirected request to think it has one.  We can ignore 
931              * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
932              */
933             apr_table_unset(r->headers_in, "Content-Length");
934
935             ap_internal_redirect_handler(location, r);
936             return OK;
937         }
938         else if (location && r->status == 200) {
939             /* XX Note that if a script wants to produce its own Redirect
940              * body, it now has to explicitly *say* "Status: 302"
941              */
942             discard_script_output(bb);
943             apr_brigade_destroy(bb);
944             return HTTP_MOVED_TEMPORARILY;
945         }
946
947         rv = ap_pass_brigade(r->output_filters, bb);
948     }
949     else /* nph */ {
950         struct ap_filter_t *cur;
951         
952         /* get rid of all filters up through protocol...  since we
953          * haven't parsed off the headers, there is no way they can
954          * work
955          */
956
957         cur = r->proto_output_filters;
958         while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) {
959             cur = cur->next;
960         }
961         r->output_filters = r->proto_output_filters = cur;
962
963         rv = ap_pass_brigade(r->output_filters, bb);
964     }
965
966     /* don't soak up script output if errors occurred writing it
967      * out...  otherwise, we prolong the life of the script when the
968      * connection drops or we stopped sending output for some other
969      * reason */
970     if (rv == APR_SUCCESS && !r->connection->aborted) {
971         apr_file_pipe_timeout_set(script_err, r->server->timeout);
972         log_script_err(r, script_err);
973     }
974     
975     apr_file_close(script_err);
976
977     return OK;                      /* NOT r->status, even if it has changed. */
978 }
979
980 /*============================================================================
981  *============================================================================
982  * This is the beginning of the cgi filter code moved from mod_include. This
983  *   is the code required to handle the "exec" SSI directive.
984  *============================================================================
985  *============================================================================*/
986 static int include_cgi(char *s, request_rec *r, ap_filter_t *next,
987                        apr_bucket *head_ptr, apr_bucket **inserted_head)
988 {
989     request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
990     int rr_status;
991     apr_bucket  *tmp_buck, *tmp2_buck;
992
993     if (rr->status != HTTP_OK) {
994         ap_destroy_sub_req(rr);
995         return -1;
996     }
997
998     /* No hardwired path info or query allowed */
999
1000     if ((rr->path_info && rr->path_info[0]) || rr->args) {
1001         ap_destroy_sub_req(rr);
1002         return -1;
1003     }
1004     if (rr->finfo.filetype != APR_REG) {
1005         ap_destroy_sub_req(rr);
1006         return -1;
1007     }
1008
1009     /* Script gets parameters of the *document*, for back compatibility */
1010
1011     rr->path_info = r->path_info;       /* hard to get right; see mod_cgi.c */
1012     rr->args = r->args;
1013
1014     /* Force sub_req to be treated as a CGI request, even if ordinary
1015      * typing rules would have called it something else.
1016      */
1017
1018     ap_set_content_type(rr, CGI_MAGIC_TYPE);
1019
1020     /* Run it. */
1021
1022     rr_status = ap_run_sub_req(rr);
1023     if (ap_is_HTTP_REDIRECT(rr_status)) {
1024         apr_size_t len_loc;
1025         const char *location = apr_table_get(rr->headers_out, "Location");
1026         conn_rec *c = r->connection;
1027
1028         location = ap_escape_html(rr->pool, location);
1029         len_loc = strlen(location);
1030
1031         /* XXX: if most of this stuff is going to get copied anyway,
1032          * it'd be more efficient to pstrcat it into a single pool buffer
1033          * and a single pool bucket */
1034
1035         tmp_buck = apr_bucket_immortal_create("<A HREF=\"",
1036                                               sizeof("<A HREF=\"") - 1,
1037                                               c->bucket_alloc);
1038         APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
1039         tmp2_buck = apr_bucket_heap_create(location, len_loc, NULL,
1040                                            c->bucket_alloc);
1041         APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
1042         tmp2_buck = apr_bucket_immortal_create("\">", sizeof("\">") - 1,
1043                                                c->bucket_alloc);
1044         APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
1045         tmp2_buck = apr_bucket_heap_create(location, len_loc, NULL,
1046                                            c->bucket_alloc);
1047         APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
1048         tmp2_buck = apr_bucket_immortal_create("</A>", sizeof("</A>") - 1,
1049                                                c->bucket_alloc);
1050         APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
1051
1052         if (*inserted_head == NULL) {
1053             *inserted_head = tmp_buck;
1054         }
1055     }
1056
1057     ap_destroy_sub_req(rr);
1058
1059     return 0;
1060 }
1061
1062
1063 static int include_cmd(include_ctx_t *ctx, apr_bucket_brigade **bb,
1064                        const char *command, request_rec *r, ap_filter_t *f)
1065 {
1066     cgi_exec_info_t  e_info;
1067     const char   **argv;
1068     apr_file_t    *script_out = NULL, *script_in = NULL, *script_err = NULL;
1069     apr_bucket_brigade *bcgi;
1070     apr_bucket *b;
1071     apr_status_t rv;
1072
1073     add_ssi_vars(r);
1074
1075     e_info.process_cgi = 0;
1076     e_info.cmd_type    = APR_SHELLCMD;
1077     e_info.detached    = 0;
1078     e_info.in_pipe     = APR_NO_PIPE;
1079     e_info.out_pipe    = APR_FULL_BLOCK;
1080     e_info.err_pipe    = APR_NO_PIPE;
1081     e_info.prog_type   = RUN_AS_SSI;
1082     e_info.bb          = bb;
1083     e_info.ctx         = ctx;
1084     e_info.next        = f->next;
1085
1086     if ((rv = cgi_build_command(&command, &argv, r, r->pool, &e_info)) != APR_SUCCESS) {
1087         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
1088                       "don't know how to spawn cmd child process: %s", 
1089                       r->filename);
1090         return HTTP_INTERNAL_SERVER_ERROR;
1091     }
1092
1093     /* run the script in its own process */
1094     if ((rv = run_cgi_child(&script_out, &script_in, &script_err,
1095                             command, argv, r, r->pool,
1096                             &e_info)) != APR_SUCCESS) {
1097         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
1098                       "couldn't spawn child process: %s", r->filename);
1099         return HTTP_INTERNAL_SERVER_ERROR;
1100     }
1101
1102     bcgi = apr_brigade_create(r->pool, f->c->bucket_alloc);
1103     b = apr_bucket_pipe_create(script_in, f->c->bucket_alloc);
1104     APR_BRIGADE_INSERT_TAIL(bcgi, b);
1105     ap_pass_brigade(f->next, bcgi);
1106
1107     /* We can't close the pipe here, because we may return before the
1108      * full CGI has been sent to the network.  That's okay though,
1109      * because we can rely on the pool to close the pipe for us.
1110      */
1111
1112     return 0;
1113 }
1114
1115 static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb,
1116                        request_rec *r, ap_filter_t *f, apr_bucket *head_ptr,
1117                        apr_bucket **inserted_head)
1118 {
1119     char *tag     = NULL;
1120     char *tag_val = NULL;
1121     char *file = r->filename;
1122     apr_bucket  *tmp_buck;
1123     char parsed_string[MAX_STRING_LEN];
1124
1125     *inserted_head = NULL;
1126     if (ctx->flags & FLAG_PRINTING) {
1127         if (ctx->flags & FLAG_NO_EXEC) {
1128             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1129                           "exec used but not allowed in %s", r->filename);
1130             CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
1131         }
1132         else {
1133             while (1) {
1134                 cgi_pfn_gtv(ctx, &tag, &tag_val, 1);
1135                 if (tag_val == NULL) {
1136                     if (tag == NULL) {
1137                         return 0;
1138                     }
1139                     else {
1140                         return 1;
1141                     }
1142                 }
1143                 if (!strcmp(tag, "cmd")) {
1144                     cgi_pfn_ps(r, ctx, tag_val, parsed_string,
1145                                sizeof(parsed_string), 1);
1146                     if (include_cmd(ctx, bb, parsed_string, r, f) == -1) {
1147                         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1148                                     "execution failure for parameter \"%s\" "
1149                                     "to tag exec in file %s", tag, r->filename);
1150                         CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr,
1151                                             *inserted_head);
1152                     }
1153                 }
1154                 else if (!strcmp(tag, "cgi")) {
1155                     apr_status_t retval = APR_SUCCESS;
1156
1157                     cgi_pfn_ps(r, ctx, tag_val, parsed_string,
1158                                sizeof(parsed_string), 0);
1159
1160                     SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next, retval);
1161                     if (retval != APR_SUCCESS) {
1162                         return retval;
1163                     }
1164
1165                     if (include_cgi(parsed_string, r, f->next, head_ptr,
1166                                     inserted_head) == -1) {
1167                         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1168                                       "invalid CGI ref \"%s\" in %s",
1169                                       tag_val, file);
1170                         CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr,
1171                                             *inserted_head);
1172                     }
1173                 }
1174                 else {
1175                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1176                                   "unknown parameter \"%s\" to tag exec in %s",
1177                                   tag, file);
1178                     CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr,
1179                                         *inserted_head);
1180                 }
1181             }
1182         }
1183     }
1184     return 0;
1185 }
1186
1187
1188 /*============================================================================
1189  *============================================================================
1190  * This is the end of the cgi filter code moved from mod_include.
1191  *============================================================================
1192  *============================================================================*/
1193
1194
1195 static int cgi_post_config(apr_pool_t *p, apr_pool_t *plog,
1196                                 apr_pool_t *ptemp, server_rec *s)
1197 {
1198     cgi_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
1199     cgi_pfn_gtv          = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value);
1200     cgi_pfn_ps           = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string);
1201
1202     if ((cgi_pfn_reg_with_ssi) && (cgi_pfn_gtv) && (cgi_pfn_ps)) {
1203         /* Required by mod_include filter. This is how mod_cgi registers
1204          *   with mod_include to provide processing of the exec directive.
1205          */
1206         cgi_pfn_reg_with_ssi("exec", handle_exec);
1207     }
1208
1209     /* This is the means by which unusual (non-unix) os's may find alternate
1210      * means to run a given command (e.g. shebang/registry parsing on Win32)
1211      */
1212     cgi_build_command    = APR_RETRIEVE_OPTIONAL_FN(ap_cgi_build_command);
1213     if (!cgi_build_command) {
1214         cgi_build_command = default_build_command;
1215     }
1216     return OK;
1217 }
1218
1219 static void register_hooks(apr_pool_t *p)
1220 {
1221     static const char * const aszPre[] = { "mod_include.c", NULL };
1222     ap_hook_handler(cgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
1223     ap_hook_post_config(cgi_post_config, aszPre, NULL, APR_HOOK_REALLY_FIRST);
1224 }
1225
1226 module AP_MODULE_DECLARE_DATA cgi_module =
1227 {
1228     STANDARD20_MODULE_STUFF,
1229     NULL,                        /* dir config creater */
1230     NULL,                        /* dir merger --- default is to override */
1231     create_cgi_config,           /* server config */
1232     merge_cgi_config,            /* merge server config */
1233     cgi_cmds,                    /* command apr_table_t */
1234     register_hooks               /* register hooks */
1235 };