|
Lines 32-39
Link Here
|
| 32 |
#include "apr_optional.h" |
32 |
#include "apr_optional.h" |
| 33 |
#include "apr_buckets.h" |
33 |
#include "apr_buckets.h" |
| 34 |
#include "apr_lib.h" |
34 |
#include "apr_lib.h" |
|
|
35 |
#include "apr_poll.h" |
| 35 |
|
36 |
|
| 36 |
#define APR_WANT_STRFUNC |
37 |
#define APR_WANT_STRFUNC |
|
|
38 |
#define APR_WANT_MEMFUNC |
| 37 |
#include "apr_want.h" |
39 |
#include "apr_want.h" |
| 38 |
|
40 |
|
| 39 |
#define CORE_PRIVATE |
41 |
#define CORE_PRIVATE |
|
Lines 191-203
Link Here
|
| 191 |
|
193 |
|
| 192 |
/* Soak up stderr from a script and redirect it to the error log. |
194 |
/* Soak up stderr from a script and redirect it to the error log. |
| 193 |
*/ |
195 |
*/ |
| 194 |
static void log_script_err(request_rec *r, apr_file_t *script_err) |
196 |
static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err) |
| 195 |
{ |
197 |
{ |
| 196 |
char argsbuffer[HUGE_STRING_LEN]; |
198 |
char argsbuffer[HUGE_STRING_LEN]; |
| 197 |
char *newline; |
199 |
char *newline; |
|
|
200 |
apr_status_t rv; |
| 198 |
|
201 |
|
| 199 |
while (apr_file_gets(argsbuffer, HUGE_STRING_LEN, |
202 |
while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN, |
| 200 |
script_err) == APR_SUCCESS) { |
203 |
script_err)) == APR_SUCCESS) { |
| 201 |
newline = strchr(argsbuffer, '\n'); |
204 |
newline = strchr(argsbuffer, '\n'); |
| 202 |
if (newline) { |
205 |
if (newline) { |
| 203 |
*newline = '\0'; |
206 |
*newline = '\0'; |
|
Lines 205-210
Link Here
|
| 205 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
208 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
| 206 |
"%s", argsbuffer); |
209 |
"%s", argsbuffer); |
| 207 |
} |
210 |
} |
|
|
211 |
|
| 212 |
return rv; |
| 208 |
} |
213 |
} |
| 209 |
|
214 |
|
| 210 |
static int log_script(request_rec *r, cgi_server_conf * conf, int ret, |
215 |
static int log_script(request_rec *r, cgi_server_conf * conf, int ret, |
|
Lines 270-276
Link Here
|
| 270 |
apr_file_printf(f, "%s\n", sbuf); |
275 |
apr_file_printf(f, "%s\n", sbuf); |
| 271 |
|
276 |
|
| 272 |
first = 1; |
277 |
first = 1; |
| 273 |
APR_BRIGADE_FOREACH(e, bb) { |
278 |
for (e = APR_BRIGADE_FIRST(bb); |
|
|
279 |
e != APR_BRIGADE_SENTINEL(bb); |
| 280 |
e = APR_BUCKET_NEXT(e)) |
| 281 |
{ |
| 274 |
if (APR_BUCKET_IS_EOS(e)) { |
282 |
if (APR_BUCKET_IS_EOS(e)) { |
| 275 |
break; |
283 |
break; |
| 276 |
} |
284 |
} |
|
Lines 431-444
Link Here
|
| 431 |
} |
439 |
} |
| 432 |
else { |
440 |
else { |
| 433 |
procnew = apr_pcalloc(p, sizeof(*procnew)); |
441 |
procnew = apr_pcalloc(p, sizeof(*procnew)); |
| 434 |
if (e_info->prog_type == RUN_AS_SSI) { |
|
|
| 435 |
SPLIT_AND_PASS_PRETAG_BUCKETS(*(e_info->bb), e_info->ctx, |
| 436 |
e_info->next, rc); |
| 437 |
if (rc != APR_SUCCESS) { |
| 438 |
return rc; |
| 439 |
} |
| 440 |
} |
| 441 |
|
| 442 |
rc = ap_os_create_privileged_process(r, procnew, command, argv, env, |
442 |
rc = ap_os_create_privileged_process(r, procnew, command, argv, env, |
| 443 |
procattr, p); |
443 |
procattr, p); |
| 444 |
|
444 |
|
|
Lines 446-452
Link Here
|
| 446 |
/* Bad things happened. Everyone should have cleaned up. */ |
446 |
/* Bad things happened. Everyone should have cleaned up. */ |
| 447 |
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, rc, r, |
447 |
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, rc, r, |
| 448 |
"couldn't create child process: %d: %s", rc, |
448 |
"couldn't create child process: %d: %s", rc, |
| 449 |
apr_filename_of_pathname(r->filename)); |
449 |
apr_filepath_name_get(r->filename)); |
| 450 |
} |
450 |
} |
| 451 |
else { |
451 |
else { |
| 452 |
apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); |
452 |
apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); |
|
Lines 528-534
Link Here
|
| 528 |
const char *buf; |
528 |
const char *buf; |
| 529 |
apr_size_t len; |
529 |
apr_size_t len; |
| 530 |
apr_status_t rv; |
530 |
apr_status_t rv; |
| 531 |
APR_BRIGADE_FOREACH(e, bb) { |
531 |
|
|
|
532 |
for (e = APR_BRIGADE_FIRST(bb); |
| 533 |
e != APR_BRIGADE_SENTINEL(bb); |
| 534 |
e = APR_BUCKET_NEXT(e)) |
| 535 |
{ |
| 532 |
if (APR_BUCKET_IS_EOS(e)) { |
536 |
if (APR_BUCKET_IS_EOS(e)) { |
| 533 |
break; |
537 |
break; |
| 534 |
} |
538 |
} |
|
Lines 539-544
Link Here
|
| 539 |
} |
543 |
} |
| 540 |
} |
544 |
} |
| 541 |
|
545 |
|
|
|
546 |
#if APR_FILES_AS_SOCKETS |
| 547 |
|
| 548 |
/* A CGI bucket type is needed to catch any output to stderr from the |
| 549 |
* script; see PR 22030. */ |
| 550 |
static const apr_bucket_type_t bucket_type_cgi; |
| 551 |
|
| 552 |
struct cgi_bucket_data { |
| 553 |
apr_pollset_t *pollset; |
| 554 |
request_rec *r; |
| 555 |
}; |
| 556 |
|
| 557 |
/* Create a CGI bucket using pipes from script stdout 'out' |
| 558 |
* and stderr 'err', for request 'r'. */ |
| 559 |
static apr_bucket *cgi_bucket_create(request_rec *r, |
| 560 |
apr_file_t *out, apr_file_t *err, |
| 561 |
apr_bucket_alloc_t *list) |
| 562 |
{ |
| 563 |
apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); |
| 564 |
apr_status_t rv; |
| 565 |
apr_pollfd_t fd; |
| 566 |
struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); |
| 567 |
|
| 568 |
APR_BUCKET_INIT(b); |
| 569 |
b->free = apr_bucket_free; |
| 570 |
b->list = list; |
| 571 |
b->type = &bucket_type_cgi; |
| 572 |
b->length = (apr_size_t)(-1); |
| 573 |
b->start = -1; |
| 574 |
|
| 575 |
/* Create the pollset */ |
| 576 |
rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); |
| 577 |
AP_DEBUG_ASSERT(rv == APR_SUCCESS); |
| 578 |
|
| 579 |
fd.desc_type = APR_POLL_FILE; |
| 580 |
fd.reqevents = APR_POLLIN; |
| 581 |
fd.p = r->pool; |
| 582 |
fd.desc.f = out; /* script's stdout */ |
| 583 |
fd.client_data = (void *)1; |
| 584 |
rv = apr_pollset_add(data->pollset, &fd); |
| 585 |
AP_DEBUG_ASSERT(rv == APR_SUCCESS); |
| 586 |
|
| 587 |
fd.desc.f = err; /* script's stderr */ |
| 588 |
fd.client_data = (void *)2; |
| 589 |
rv = apr_pollset_add(data->pollset, &fd); |
| 590 |
AP_DEBUG_ASSERT(rv == APR_SUCCESS); |
| 591 |
|
| 592 |
data->r = r; |
| 593 |
b->data = data; |
| 594 |
return b; |
| 595 |
} |
| 596 |
|
| 597 |
/* Create a duplicate CGI bucket using given bucket data */ |
| 598 |
static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, |
| 599 |
apr_bucket_alloc_t *list) |
| 600 |
{ |
| 601 |
apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); |
| 602 |
APR_BUCKET_INIT(b); |
| 603 |
b->free = apr_bucket_free; |
| 604 |
b->list = list; |
| 605 |
b->type = &bucket_type_cgi; |
| 606 |
b->length = (apr_size_t)(-1); |
| 607 |
b->start = -1; |
| 608 |
b->data = data; |
| 609 |
return b; |
| 610 |
} |
| 611 |
|
| 612 |
/* Handle stdout from CGI child. Duplicate of logic from the _read |
| 613 |
* method of the real APR pipe bucket implementation. */ |
| 614 |
static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, |
| 615 |
const char **str, apr_size_t *len) |
| 616 |
{ |
| 617 |
char *buf; |
| 618 |
apr_status_t rv; |
| 619 |
|
| 620 |
*str = NULL; |
| 621 |
*len = APR_BUCKET_BUFF_SIZE; |
| 622 |
buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ |
| 623 |
|
| 624 |
rv = apr_file_read(out, buf, len); |
| 625 |
|
| 626 |
if (rv != APR_SUCCESS && rv != APR_EOF) { |
| 627 |
apr_bucket_free(buf); |
| 628 |
return rv; |
| 629 |
} |
| 630 |
|
| 631 |
if (*len > 0) { |
| 632 |
struct cgi_bucket_data *data = a->data; |
| 633 |
apr_bucket_heap *h; |
| 634 |
|
| 635 |
/* Change the current bucket to refer to what we read */ |
| 636 |
a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); |
| 637 |
h = a->data; |
| 638 |
h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ |
| 639 |
*str = buf; |
| 640 |
APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list)); |
| 641 |
} |
| 642 |
else { |
| 643 |
apr_bucket_free(buf); |
| 644 |
a = apr_bucket_immortal_make(a, "", 0); |
| 645 |
*str = a->data; |
| 646 |
} |
| 647 |
return rv; |
| 648 |
} |
| 649 |
|
| 650 |
/* Read method of CGI bucket: polls on stderr and stdout of the child, |
| 651 |
* sending any stderr output immediately away to the error log. */ |
| 652 |
static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str, |
| 653 |
apr_size_t *len, apr_read_type_e block) |
| 654 |
{ |
| 655 |
struct cgi_bucket_data *data = b->data; |
| 656 |
apr_interval_time_t timeout; |
| 657 |
apr_status_t rv; |
| 658 |
int gotdata = 0; |
| 659 |
|
| 660 |
timeout = block == APR_NONBLOCK_READ ? 0 : data->r->server->timeout; |
| 661 |
|
| 662 |
do { |
| 663 |
const apr_pollfd_t *results; |
| 664 |
apr_int32_t num; |
| 665 |
|
| 666 |
rv = apr_pollset_poll(data->pollset, timeout, &num, &results); |
| 667 |
if (APR_STATUS_IS_TIMEUP(rv)) { |
| 668 |
return timeout == 0 ? APR_EAGAIN : rv; |
| 669 |
} |
| 670 |
else if (APR_STATUS_IS_EINTR(rv)) { |
| 671 |
continue; |
| 672 |
} |
| 673 |
else if (rv != APR_SUCCESS) { |
| 674 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, |
| 675 |
"poll failed waiting for CGI child"); |
| 676 |
return rv; |
| 677 |
} |
| 678 |
|
| 679 |
for (; num; num--, results++) { |
| 680 |
if (results[0].client_data == (void *)1) { |
| 681 |
/* stdout */ |
| 682 |
rv = cgi_read_stdout(b, results[0].desc.f, str, len); |
| 683 |
if (APR_STATUS_IS_EOF(rv)) { |
| 684 |
rv = APR_SUCCESS; |
| 685 |
} |
| 686 |
gotdata = 1; |
| 687 |
} else { |
| 688 |
/* stderr */ |
| 689 |
apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); |
| 690 |
if (APR_STATUS_IS_EOF(rv2)) { |
| 691 |
apr_pollset_remove(data->pollset, &results[0]); |
| 692 |
} |
| 693 |
} |
| 694 |
} |
| 695 |
|
| 696 |
} while (!gotdata); |
| 697 |
|
| 698 |
return rv; |
| 699 |
} |
| 700 |
|
| 701 |
static const apr_bucket_type_t bucket_type_cgi = { |
| 702 |
"CGI", 5, APR_BUCKET_DATA, |
| 703 |
apr_bucket_destroy_noop, |
| 704 |
cgi_bucket_read, |
| 705 |
apr_bucket_setaside_notimpl, |
| 706 |
apr_bucket_split_notimpl, |
| 707 |
apr_bucket_copy_notimpl |
| 708 |
}; |
| 709 |
|
| 710 |
#endif |
| 711 |
|
| 542 |
static int cgi_handler(request_rec *r) |
712 |
static int cgi_handler(request_rec *r) |
| 543 |
{ |
713 |
{ |
| 544 |
int nph; |
714 |
int nph; |
|
Lines 556-561
Link Here
|
| 556 |
cgi_server_conf *conf; |
726 |
cgi_server_conf *conf; |
| 557 |
apr_status_t rv; |
727 |
apr_status_t rv; |
| 558 |
cgi_exec_info_t e_info; |
728 |
cgi_exec_info_t e_info; |
|
|
729 |
conn_rec *c = r->connection; |
| 559 |
|
730 |
|
| 560 |
if(strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) |
731 |
if(strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) |
| 561 |
return DECLINED; |
732 |
return DECLINED; |
|
Lines 571-577
Link Here
|
| 571 |
return DECLINED; |
742 |
return DECLINED; |
| 572 |
} |
743 |
} |
| 573 |
|
744 |
|
| 574 |
argv0 = apr_filename_of_pathname(r->filename); |
745 |
argv0 = apr_filepath_name_get(r->filename); |
| 575 |
nph = !(strncmp(argv0, "nph-", 4)); |
746 |
nph = !(strncmp(argv0, "nph-", 4)); |
| 576 |
conf = ap_get_module_config(r->server->module_config, &cgi_module); |
747 |
conf = ap_get_module_config(r->server->module_config, &cgi_module); |
| 577 |
|
748 |
|
|
Lines 637-643
Link Here
|
| 637 |
/* Transfer any put/post args, CERN style... |
808 |
/* Transfer any put/post args, CERN style... |
| 638 |
* Note that we already ignore SIGPIPE in the core server. |
809 |
* Note that we already ignore SIGPIPE in the core server. |
| 639 |
*/ |
810 |
*/ |
| 640 |
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); |
811 |
bb = apr_brigade_create(r->pool, c->bucket_alloc); |
| 641 |
seen_eos = 0; |
812 |
seen_eos = 0; |
| 642 |
child_stopped_reading = 0; |
813 |
child_stopped_reading = 0; |
| 643 |
if (conf->logname) { |
814 |
if (conf->logname) { |
|
Lines 654-660
Link Here
|
| 654 |
return rv; |
825 |
return rv; |
| 655 |
} |
826 |
} |
| 656 |
|
827 |
|
| 657 |
APR_BRIGADE_FOREACH(bucket, bb) { |
828 |
for (bucket = APR_BRIGADE_FIRST(bb); |
|
|
829 |
bucket != APR_BRIGADE_SENTINEL(bb); |
| 830 |
bucket = APR_BUCKET_NEXT(bucket)) |
| 831 |
{ |
| 658 |
const char *data; |
832 |
const char *data; |
| 659 |
apr_size_t len; |
833 |
apr_size_t len; |
| 660 |
|
834 |
|
|
Lines 710-727
Link Here
|
| 710 |
apr_file_flush(script_out); |
884 |
apr_file_flush(script_out); |
| 711 |
apr_file_close(script_out); |
885 |
apr_file_close(script_out); |
| 712 |
|
886 |
|
|
|
887 |
AP_DEBUG_ASSERT(script_in != NULL); |
| 888 |
|
| 889 |
apr_brigade_cleanup(bb); |
| 890 |
|
| 891 |
#if APR_FILES_AS_SOCKETS |
| 892 |
apr_file_pipe_timeout_set(script_in, 0); |
| 893 |
apr_file_pipe_timeout_set(script_err, 0); |
| 894 |
|
| 895 |
b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc); |
| 896 |
#else |
| 897 |
b = apr_bucket_pipe_create(script_in, c->bucket_alloc); |
| 898 |
#endif |
| 899 |
APR_BRIGADE_INSERT_TAIL(bb, b); |
| 900 |
b = apr_bucket_eos_create(c->bucket_alloc); |
| 901 |
APR_BRIGADE_INSERT_TAIL(bb, b); |
| 902 |
|
| 713 |
/* Handle script return... */ |
903 |
/* Handle script return... */ |
| 714 |
if (script_in && !nph) { |
904 |
if (!nph) { |
| 715 |
conn_rec *c = r->connection; |
|
|
| 716 |
const char *location; |
905 |
const char *location; |
| 717 |
char sbuf[MAX_STRING_LEN]; |
906 |
char sbuf[MAX_STRING_LEN]; |
| 718 |
int ret; |
907 |
int ret; |
| 719 |
|
908 |
|
| 720 |
b = apr_bucket_pipe_create(script_in, c->bucket_alloc); |
|
|
| 721 |
APR_BRIGADE_INSERT_TAIL(bb, b); |
| 722 |
b = apr_bucket_eos_create(c->bucket_alloc); |
| 723 |
APR_BRIGADE_INSERT_TAIL(bb, b); |
| 724 |
|
| 725 |
if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) { |
909 |
if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) { |
| 726 |
return log_script(r, conf, ret, dbuf, sbuf, bb, script_err); |
910 |
return log_script(r, conf, ret, dbuf, sbuf, bb, script_err); |
| 727 |
} |
911 |
} |
|
Lines 731-736
Link Here
|
| 731 |
if (location && location[0] == '/' && r->status == 200) { |
915 |
if (location && location[0] == '/' && r->status == 200) { |
| 732 |
discard_script_output(bb); |
916 |
discard_script_output(bb); |
| 733 |
apr_brigade_destroy(bb); |
917 |
apr_brigade_destroy(bb); |
|
|
918 |
apr_file_pipe_timeout_set(script_err, r->server->timeout); |
| 734 |
log_script_err(r, script_err); |
919 |
log_script_err(r, script_err); |
| 735 |
/* This redirect needs to be a GET no matter what the original |
920 |
/* This redirect needs to be a GET no matter what the original |
| 736 |
* method was. |
921 |
* method was. |
|
Lines 757-778
Link Here
|
| 757 |
} |
942 |
} |
| 758 |
|
943 |
|
| 759 |
rv = ap_pass_brigade(r->output_filters, bb); |
944 |
rv = ap_pass_brigade(r->output_filters, bb); |
| 760 |
|
|
|
| 761 |
/* don't soak up script output if errors occurred |
| 762 |
* writing it out... otherwise, we prolong the |
| 763 |
* life of the script when the connection drops |
| 764 |
* or we stopped sending output for some other |
| 765 |
* reason |
| 766 |
*/ |
| 767 |
if (rv == APR_SUCCESS && !r->connection->aborted) { |
| 768 |
log_script_err(r, script_err); |
| 769 |
} |
| 770 |
|
| 771 |
apr_file_close(script_err); |
| 772 |
} |
945 |
} |
| 773 |
|
946 |
else /* nph */ { |
| 774 |
if (script_in && nph) { |
|
|
| 775 |
conn_rec *c = r->connection; |
| 776 |
struct ap_filter_t *cur; |
947 |
struct ap_filter_t *cur; |
| 777 |
|
948 |
|
| 778 |
/* get rid of all filters up through protocol... since we |
949 |
/* get rid of all filters up through protocol... since we |
|
Lines 786-799
Link Here
|
| 786 |
} |
957 |
} |
| 787 |
r->output_filters = r->proto_output_filters = cur; |
958 |
r->output_filters = r->proto_output_filters = cur; |
| 788 |
|
959 |
|
| 789 |
bb = apr_brigade_create(r->pool, c->bucket_alloc); |
960 |
rv = ap_pass_brigade(r->output_filters, bb); |
| 790 |
b = apr_bucket_pipe_create(script_in, c->bucket_alloc); |
|
|
| 791 |
APR_BRIGADE_INSERT_TAIL(bb, b); |
| 792 |
b = apr_bucket_eos_create(c->bucket_alloc); |
| 793 |
APR_BRIGADE_INSERT_TAIL(bb, b); |
| 794 |
ap_pass_brigade(r->output_filters, bb); |
| 795 |
} |
961 |
} |
| 796 |
|
962 |
|
|
|
963 |
/* don't soak up script output if errors occurred writing it |
| 964 |
* out... otherwise, we prolong the life of the script when the |
| 965 |
* connection drops or we stopped sending output for some other |
| 966 |
* reason */ |
| 967 |
if (rv == APR_SUCCESS && !r->connection->aborted) { |
| 968 |
apr_file_pipe_timeout_set(script_err, r->server->timeout); |
| 969 |
log_script_err(r, script_err); |
| 970 |
} |
| 971 |
|
| 972 |
apr_file_close(script_err); |
| 973 |
|
| 797 |
return OK; /* NOT r->status, even if it has changed. */ |
974 |
return OK; /* NOT r->status, even if it has changed. */ |
| 798 |
} |
975 |
} |
| 799 |
|
976 |
|
|
Lines 803-894
Link Here
|
| 803 |
* is the code required to handle the "exec" SSI directive. |
980 |
* is the code required to handle the "exec" SSI directive. |
| 804 |
*============================================================================ |
981 |
*============================================================================ |
| 805 |
*============================================================================*/ |
982 |
*============================================================================*/ |
| 806 |
static int include_cgi(char *s, request_rec *r, ap_filter_t *next, |
983 |
static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f, |
| 807 |
apr_bucket *head_ptr, apr_bucket **inserted_head) |
984 |
apr_bucket_brigade *bb, char *s) |
| 808 |
{ |
985 |
{ |
| 809 |
request_rec *rr = ap_sub_req_lookup_uri(s, r, next); |
986 |
request_rec *r = f->r; |
|
|
987 |
request_rec *rr = ap_sub_req_lookup_uri(s, r, f->next); |
| 810 |
int rr_status; |
988 |
int rr_status; |
| 811 |
apr_bucket *tmp_buck, *tmp2_buck; |
|
|
| 812 |
|
989 |
|
| 813 |
if (rr->status != HTTP_OK) { |
990 |
if (rr->status != HTTP_OK) { |
| 814 |
ap_destroy_sub_req(rr); |
991 |
ap_destroy_sub_req(rr); |
| 815 |
return -1; |
992 |
return APR_EGENERAL; |
| 816 |
} |
993 |
} |
| 817 |
|
994 |
|
| 818 |
/* No hardwired path info or query allowed */ |
995 |
/* No hardwired path info or query allowed */ |
| 819 |
|
|
|
| 820 |
if ((rr->path_info && rr->path_info[0]) || rr->args) { |
996 |
if ((rr->path_info && rr->path_info[0]) || rr->args) { |
| 821 |
ap_destroy_sub_req(rr); |
997 |
ap_destroy_sub_req(rr); |
| 822 |
return -1; |
998 |
return APR_EGENERAL; |
| 823 |
} |
999 |
} |
| 824 |
if (rr->finfo.filetype != APR_REG) { |
1000 |
if (rr->finfo.filetype != APR_REG) { |
| 825 |
ap_destroy_sub_req(rr); |
1001 |
ap_destroy_sub_req(rr); |
| 826 |
return -1; |
1002 |
return APR_EGENERAL; |
| 827 |
} |
1003 |
} |
| 828 |
|
1004 |
|
| 829 |
/* Script gets parameters of the *document*, for back compatibility */ |
1005 |
/* Script gets parameters of the *document*, for back compatibility */ |
| 830 |
|
|
|
| 831 |
rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */ |
1006 |
rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */ |
| 832 |
rr->args = r->args; |
1007 |
rr->args = r->args; |
| 833 |
|
1008 |
|
| 834 |
/* Force sub_req to be treated as a CGI request, even if ordinary |
1009 |
/* Force sub_req to be treated as a CGI request, even if ordinary |
| 835 |
* typing rules would have called it something else. |
1010 |
* typing rules would have called it something else. |
| 836 |
*/ |
1011 |
*/ |
| 837 |
|
|
|
| 838 |
ap_set_content_type(rr, CGI_MAGIC_TYPE); |
1012 |
ap_set_content_type(rr, CGI_MAGIC_TYPE); |
| 839 |
|
1013 |
|
| 840 |
/* Run it. */ |
1014 |
/* Run it. */ |
| 841 |
|
|
|
| 842 |
rr_status = ap_run_sub_req(rr); |
1015 |
rr_status = ap_run_sub_req(rr); |
| 843 |
if (ap_is_HTTP_REDIRECT(rr_status)) { |
1016 |
if (ap_is_HTTP_REDIRECT(rr_status)) { |
| 844 |
apr_size_t len_loc; |
|
|
| 845 |
const char *location = apr_table_get(rr->headers_out, "Location"); |
1017 |
const char *location = apr_table_get(rr->headers_out, "Location"); |
| 846 |
conn_rec *c = r->connection; |
|
|
| 847 |
|
1018 |
|
| 848 |
location = ap_escape_html(rr->pool, location); |
1019 |
if (location) { |
| 849 |
len_loc = strlen(location); |
1020 |
char *buffer; |
| 850 |
|
1021 |
|
| 851 |
/* XXX: if most of this stuff is going to get copied anyway, |
1022 |
location = ap_escape_html(rr->pool, location); |
| 852 |
* it'd be more efficient to pstrcat it into a single pool buffer |
1023 |
buffer = apr_pstrcat(ctx->pool, "<a href=\"", location, "\">", |
| 853 |
* and a single pool bucket */ |
1024 |
location, "</a>", NULL); |
| 854 |
|
1025 |
|
| 855 |
tmp_buck = apr_bucket_immortal_create("<A HREF=\"", |
1026 |
APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(buffer, |
| 856 |
sizeof("<A HREF=\"") - 1, |
1027 |
strlen(buffer), ctx->pool, |
| 857 |
c->bucket_alloc); |
1028 |
f->c->bucket_alloc)); |
| 858 |
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck); |
|
|
| 859 |
tmp2_buck = apr_bucket_heap_create(location, len_loc, NULL, |
| 860 |
c->bucket_alloc); |
| 861 |
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); |
| 862 |
tmp2_buck = apr_bucket_immortal_create("\">", sizeof("\">") - 1, |
| 863 |
c->bucket_alloc); |
| 864 |
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); |
| 865 |
tmp2_buck = apr_bucket_heap_create(location, len_loc, NULL, |
| 866 |
c->bucket_alloc); |
| 867 |
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); |
| 868 |
tmp2_buck = apr_bucket_immortal_create("</A>", sizeof("</A>") - 1, |
| 869 |
c->bucket_alloc); |
| 870 |
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck); |
| 871 |
|
| 872 |
if (*inserted_head == NULL) { |
| 873 |
*inserted_head = tmp_buck; |
| 874 |
} |
1029 |
} |
| 875 |
} |
1030 |
} |
| 876 |
|
1031 |
|
| 877 |
ap_destroy_sub_req(rr); |
1032 |
ap_destroy_sub_req(rr); |
| 878 |
|
1033 |
|
| 879 |
return 0; |
1034 |
return APR_SUCCESS; |
| 880 |
} |
1035 |
} |
| 881 |
|
1036 |
|
| 882 |
|
1037 |
static apr_status_t include_cmd(include_ctx_t *ctx, ap_filter_t *f, |
| 883 |
static int include_cmd(include_ctx_t *ctx, apr_bucket_brigade **bb, |
1038 |
apr_bucket_brigade *bb, const char *command) |
| 884 |
const char *command, request_rec *r, ap_filter_t *f) |
|
|
| 885 |
{ |
1039 |
{ |
| 886 |
cgi_exec_info_t e_info; |
1040 |
cgi_exec_info_t e_info; |
| 887 |
const char **argv; |
1041 |
const char **argv; |
| 888 |
apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL; |
1042 |
apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL; |
| 889 |
apr_bucket_brigade *bcgi; |
|
|
| 890 |
apr_bucket *b; |
| 891 |
apr_status_t rv; |
1043 |
apr_status_t rv; |
|
|
1044 |
request_rec *r = f->r; |
| 892 |
|
1045 |
|
| 893 |
add_ssi_vars(r); |
1046 |
add_ssi_vars(r); |
| 894 |
|
1047 |
|
|
Lines 899-913
Link Here
|
| 899 |
e_info.out_pipe = APR_FULL_BLOCK; |
1052 |
e_info.out_pipe = APR_FULL_BLOCK; |
| 900 |
e_info.err_pipe = APR_NO_PIPE; |
1053 |
e_info.err_pipe = APR_NO_PIPE; |
| 901 |
e_info.prog_type = RUN_AS_SSI; |
1054 |
e_info.prog_type = RUN_AS_SSI; |
| 902 |
e_info.bb = bb; |
1055 |
e_info.bb = &bb; |
| 903 |
e_info.ctx = ctx; |
1056 |
e_info.ctx = ctx; |
| 904 |
e_info.next = f->next; |
1057 |
e_info.next = f->next; |
| 905 |
|
1058 |
|
| 906 |
if ((rv = cgi_build_command(&command, &argv, r, r->pool, &e_info)) != APR_SUCCESS) { |
1059 |
if ((rv = cgi_build_command(&command, &argv, r, r->pool, |
|
|
1060 |
&e_info)) != APR_SUCCESS) { |
| 907 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, |
1061 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, |
| 908 |
"don't know how to spawn cmd child process: %s", |
1062 |
"don't know how to spawn cmd child process: %s", |
| 909 |
r->filename); |
1063 |
r->filename); |
| 910 |
return HTTP_INTERNAL_SERVER_ERROR; |
1064 |
return rv; |
| 911 |
} |
1065 |
} |
| 912 |
|
1066 |
|
| 913 |
/* run the script in its own process */ |
1067 |
/* run the script in its own process */ |
|
Lines 916-1007
Link Here
|
| 916 |
&e_info)) != APR_SUCCESS) { |
1070 |
&e_info)) != APR_SUCCESS) { |
| 917 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, |
1071 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, |
| 918 |
"couldn't spawn child process: %s", r->filename); |
1072 |
"couldn't spawn child process: %s", r->filename); |
| 919 |
return HTTP_INTERNAL_SERVER_ERROR; |
1073 |
return rv; |
| 920 |
} |
1074 |
} |
| 921 |
|
1075 |
|
| 922 |
bcgi = apr_brigade_create(r->pool, f->c->bucket_alloc); |
1076 |
APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pipe_create(script_in, |
| 923 |
b = apr_bucket_pipe_create(script_in, f->c->bucket_alloc); |
1077 |
f->c->bucket_alloc)); |
| 924 |
APR_BRIGADE_INSERT_TAIL(bcgi, b); |
1078 |
ctx->flush_now = 1; |
| 925 |
ap_pass_brigade(f->next, bcgi); |
|
|
| 926 |
|
1079 |
|
| 927 |
/* We can't close the pipe here, because we may return before the |
1080 |
/* We can't close the pipe here, because we may return before the |
| 928 |
* full CGI has been sent to the network. That's okay though, |
1081 |
* full CGI has been sent to the network. That's okay though, |
| 929 |
* because we can rely on the pool to close the pipe for us. |
1082 |
* because we can rely on the pool to close the pipe for us. |
| 930 |
*/ |
1083 |
*/ |
| 931 |
|
1084 |
return APR_SUCCESS; |
| 932 |
return 0; |
|
|
| 933 |
} |
1085 |
} |
| 934 |
|
1086 |
|
| 935 |
static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, |
1087 |
static apr_status_t handle_exec(include_ctx_t *ctx, ap_filter_t *f, |
| 936 |
request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, |
1088 |
apr_bucket_brigade *bb) |
| 937 |
apr_bucket **inserted_head) |
|
|
| 938 |
{ |
1089 |
{ |
| 939 |
char *tag = NULL; |
1090 |
char *tag = NULL; |
| 940 |
char *tag_val = NULL; |
1091 |
char *tag_val = NULL; |
|
|
1092 |
request_rec *r = f->r; |
| 941 |
char *file = r->filename; |
1093 |
char *file = r->filename; |
| 942 |
apr_bucket *tmp_buck; |
|
|
| 943 |
char parsed_string[MAX_STRING_LEN]; |
1094 |
char parsed_string[MAX_STRING_LEN]; |
| 944 |
|
1095 |
|
| 945 |
*inserted_head = NULL; |
1096 |
if (!ctx->argc) { |
| 946 |
if (ctx->flags & FLAG_PRINTING) { |
1097 |
ap_log_rerror(APLOG_MARK, |
| 947 |
if (ctx->flags & FLAG_NO_EXEC) { |
1098 |
(ctx->flags & SSI_FLAG_PRINTING) |
| 948 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
1099 |
? APLOG_ERR : APLOG_WARNING, |
| 949 |
"exec used but not allowed in %s", r->filename); |
1100 |
0, r, "missing argument for exec element in %s", |
| 950 |
CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); |
1101 |
r->filename); |
|
|
1102 |
} |
| 1103 |
|
| 1104 |
if (!(ctx->flags & SSI_FLAG_PRINTING)) { |
| 1105 |
return APR_SUCCESS; |
| 1106 |
} |
| 1107 |
|
| 1108 |
if (!ctx->argc) { |
| 1109 |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
| 1110 |
return APR_SUCCESS; |
| 1111 |
} |
| 1112 |
|
| 1113 |
if (ctx->flags & SSI_FLAG_NO_EXEC) { |
| 1114 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "exec used but not allowed " |
| 1115 |
"in %s", r->filename); |
| 1116 |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
| 1117 |
return APR_SUCCESS; |
| 1118 |
} |
| 1119 |
|
| 1120 |
while (1) { |
| 1121 |
cgi_pfn_gtv(ctx, &tag, &tag_val, SSI_VALUE_DECODED); |
| 1122 |
if (!tag || !tag_val) { |
| 1123 |
break; |
| 951 |
} |
1124 |
} |
| 952 |
else { |
|
|
| 953 |
while (1) { |
| 954 |
cgi_pfn_gtv(ctx, &tag, &tag_val, 1); |
| 955 |
if (tag_val == NULL) { |
| 956 |
if (tag == NULL) { |
| 957 |
return 0; |
| 958 |
} |
| 959 |
else { |
| 960 |
return 1; |
| 961 |
} |
| 962 |
} |
| 963 |
if (!strcmp(tag, "cmd")) { |
| 964 |
cgi_pfn_ps(r, ctx, tag_val, parsed_string, |
| 965 |
sizeof(parsed_string), 1); |
| 966 |
if (include_cmd(ctx, bb, parsed_string, r, f) == -1) { |
| 967 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
| 968 |
"execution failure for parameter \"%s\" " |
| 969 |
"to tag exec in file %s", tag, r->filename); |
| 970 |
CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, |
| 971 |
*inserted_head); |
| 972 |
} |
| 973 |
} |
| 974 |
else if (!strcmp(tag, "cgi")) { |
| 975 |
apr_status_t retval = APR_SUCCESS; |
| 976 |
|
1125 |
|
| 977 |
cgi_pfn_ps(r, ctx, tag_val, parsed_string, |
1126 |
if (!strcmp(tag, "cmd")) { |
| 978 |
sizeof(parsed_string), 0); |
1127 |
apr_status_t rv; |
| 979 |
|
1128 |
|
| 980 |
SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next, retval); |
1129 |
cgi_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string), |
| 981 |
if (retval != APR_SUCCESS) { |
1130 |
SSI_EXPAND_LEAVE_NAME); |
| 982 |
return retval; |
1131 |
|
| 983 |
} |
1132 |
rv = include_cmd(ctx, f, bb, parsed_string); |
| 984 |
|
1133 |
if (!APR_STATUS_IS_SUCCESS(rv)) { |
| 985 |
if (include_cgi(parsed_string, r, f->next, head_ptr, |
1134 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "execution failure " |
| 986 |
inserted_head) == -1) { |
1135 |
"for parameter \"%s\" to tag exec in file %s", |
| 987 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
1136 |
tag, r->filename); |
| 988 |
"invalid CGI ref \"%s\" in %s", |
1137 |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
| 989 |
tag_val, file); |
1138 |
break; |
| 990 |
CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, |
1139 |
} |
| 991 |
*inserted_head); |
1140 |
} |
| 992 |
} |
1141 |
else if (!strcmp(tag, "cgi")) { |
| 993 |
} |
1142 |
apr_status_t rv; |
| 994 |
else { |
1143 |
|
| 995 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
1144 |
cgi_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string), |
| 996 |
"unknown parameter \"%s\" to tag exec in %s", |
1145 |
SSI_EXPAND_DROP_NAME); |
| 997 |
tag, file); |
1146 |
|
| 998 |
CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, |
1147 |
rv = include_cgi(ctx, f, bb, parsed_string); |
| 999 |
*inserted_head); |
1148 |
if (!APR_STATUS_IS_SUCCESS(rv)) { |
| 1000 |
} |
1149 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "invalid CGI ref " |
|
|
1150 |
"\"%s\" in %s", tag_val, file); |
| 1151 |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
| 1152 |
break; |
| 1001 |
} |
1153 |
} |
| 1002 |
} |
1154 |
} |
|
|
1155 |
else { |
| 1156 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter " |
| 1157 |
"\"%s\" to tag exec in %s", tag, file); |
| 1158 |
SSI_CREATE_ERROR_BUCKET(ctx, f, bb); |
| 1159 |
break; |
| 1160 |
} |
| 1003 |
} |
1161 |
} |
| 1004 |
return 0; |
1162 |
|
|
|
1163 |
return APR_SUCCESS; |
| 1005 |
} |
1164 |
} |
| 1006 |
|
1165 |
|
| 1007 |
|
1166 |
|