49
49
char argsbuffer[HUGE_STRING_LEN];
53
53
while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN,
54
54
script_err)) == APR_SUCCESS) {
55
55
newline = strchr(argsbuffer, '\n');
140
140
cfg->target_user = NULL;
141
141
cfg->target_group = NULL;
144
144
/* Create table with 0 initial elements */
145
145
/* This size may be increased for performance reasons */
146
146
cfg->handlers = apr_table_make(p, 0);
148
148
return (void *) cfg;
152
static void *suphp_merge_dir_config(apr_pool_t *p, void *base,
152
static void *suphp_merge_dir_config(apr_pool_t *p, void *base,
155
155
suphp_conf *parent = (suphp_conf *) base;
156
156
suphp_conf *child = (suphp_conf *) overrides;
157
157
suphp_conf *merged = (suphp_conf *) apr_pcalloc(p, sizeof(suphp_conf));
159
159
merged->cmode = SUPHP_CONFIG_MODE_DIRECTORY;
161
161
if (child->php_config)
162
162
merged->php_config = apr_pstrdup(p, child->php_config);
163
163
else if (parent->php_config)
164
164
merged->php_config = apr_pstrdup(p, parent->php_config);
166
166
merged->php_config = NULL;
168
168
if (child->engine != SUPHP_ENGINE_UNDEFINED)
169
169
merged->engine = child->engine;
177
177
merged->target_user = apr_pstrdup(p, parent->target_user);
179
179
merged->target_user = NULL;
181
181
if (child->target_group)
182
182
merged->target_group = apr_pstrdup(p, child->target_group);
183
183
else if (parent->target_group)
186
186
merged->target_group = NULL;
189
189
merged->handlers = apr_table_overlay(p, child->handlers, parent->handlers);
191
return (void *) merged;
191
return (void *) merged;
195
195
static void *suphp_create_server_config(apr_pool_t *p, server_rec *s)
197
197
suphp_conf *cfg = (suphp_conf *) apr_pcalloc(p, sizeof(suphp_conf));
199
199
cfg->engine = SUPHP_ENGINE_UNDEFINED;
200
200
cfg->php_path = NULL;
201
201
cfg->cmode = SUPHP_CONFIG_MODE_SERVER;
203
203
/* Create table with 0 initial elements */
204
204
/* This size may be increased for performance reasons */
205
205
cfg->handlers = apr_table_make(p, 0);
207
207
return (void *) cfg;
214
214
suphp_conf *parent = (suphp_conf *) base;
215
215
suphp_conf *child = (suphp_conf *) overrides;
216
216
suphp_conf *merged = (suphp_conf *) apr_pcalloc(p, sizeof(suphp_conf));
218
218
if (child->engine != SUPHP_ENGINE_UNDEFINED)
219
219
merged->engine = child->engine;
221
221
merged->engine = parent->engine;
223
223
if (child->php_path != NULL)
224
224
merged->php_path = apr_pstrdup(p, child->php_path);
226
226
merged->php_path = apr_pstrdup(p, parent->php_path);
228
228
#ifdef SUPHP_USE_USERGROUP
229
229
if (child->target_user)
230
230
merged->target_user = apr_pstrdup(p, child->target_user);
232
232
merged->target_user = apr_pstrdup(p, parent->target_user);
234
234
merged->target_user = NULL;
236
236
if (child->target_group)
237
237
merged->target_group = apr_pstrdup(p, child->target_group);
238
238
else if (parent->target_group)
257
257
server_rec *s = cmd->server;
261
261
cfg = (suphp_conf *) mconfig;
263
263
cfg = (suphp_conf *) ap_get_module_config(s->module_config, &suphp_module);
266
266
cfg->engine = SUPHP_ENGINE_ON;
268
268
cfg->engine = SUPHP_ENGINE_OFF;
277
277
server_rec *s = cmd->server;
281
281
cfg = (suphp_conf *) mconfig;
283
283
cfg = (suphp_conf *) ap_get_module_config(s->module_config, &suphp_module);
285
285
cfg->php_config = apr_pstrdup(cmd->pool, arg);
293
293
const char *arg1, const char *arg2)
295
295
suphp_conf *cfg = (suphp_conf *) mconfig;
297
297
cfg->target_user = apr_pstrdup(cmd->pool, arg1);
298
298
cfg->target_group = apr_pstrdup(cmd->pool, arg2);
310
310
cfg = (suphp_conf *) mconfig;
312
312
cfg = (suphp_conf *) ap_get_module_config(cmd->server->module_config, &suphp_module);
314
314
// Mark active handler with '1'
315
315
apr_table_set(cfg->handlers, arg, "1");
327
327
cfg = (suphp_conf *) mconfig;
329
329
cfg = (suphp_conf *) ap_get_module_config(cmd->server->module_config, &suphp_module);
331
331
// Mark deactivated handler with '0'
332
332
apr_table_set(cfg->handlers, arg, "0");
386
386
struct suphp_bucket_data *data = apr_palloc(r->pool, sizeof(*data));
388
388
APR_BUCKET_INIT(b);
389
389
b->free = apr_bucket_free;
391
391
b->type = &bucket_type_suphp;
392
392
b->length = (apr_size_t) (-1);
395
395
/* Create the pollset */
396
396
rv = apr_pollset_create(&data->pollset, 2, r->pool, 0);
397
397
AP_DEBUG_ASSERT(rv == APR_SUCCESS);
399
399
fd.desc_type = APR_POLL_FILE;
400
400
fd.reqevents = APR_POLLIN;
403
403
fd.client_data = (void *) 1;
404
404
rv = apr_pollset_add(data->pollset, &fd);
405
405
AP_DEBUG_ASSERT(rv == APR_SUCCESS);
407
407
fd.desc.f = err; /* script's stderr */
408
408
fd.client_data = (void *) 2;
409
409
rv = apr_pollset_add(data->pollset, &fd);
410
410
AP_DEBUG_ASSERT(rv == APR_SUCCESS);
438
438
*len = APR_BUCKET_BUFF_SIZE;
439
439
buf = apr_bucket_alloc(*len, b->list);
441
441
rv = apr_file_read(fd, buf, len);
445
445
struct suphp_bucket_data *data = b->data;
446
446
apr_bucket_heap *h;
448
448
/* Change the current bucket to refer to what we read
449
449
and append the pipe bucket after it */
450
450
b = apr_bucket_heap_make(b, buf, *len, apr_bucket_free);
470
470
apr_interval_time_t timeout;
474
474
timeout = (block == APR_NONBLOCK_READ) ? 0 : data->r->server->timeout;
477
477
const apr_pollfd_t *results;
480
480
rv = apr_pollset_poll(data->pollset, timeout, &num, &results);
481
481
if (APR_STATUS_IS_TIMEUP(rv)) {
482
482
return (timeout == 0) ? APR_EAGAIN : rv;
548
548
static int suphp_handler(request_rec *r)
550
550
suphp_conf *sconf, *dconf;
552
552
sconf = ap_get_module_config(r->server->module_config, &suphp_module);
553
553
dconf = ap_get_module_config(r->per_dir_config, &suphp_module);
555
555
/* only handle request if mod_suphp is active for this handler */
556
556
/* check only first byte of value (second has to be \0) */
557
557
if (apr_table_get(dconf->handlers, r->handler) != NULL)
569
569
return suphp_script_handler(r);
573
if (!strcmp(r->handler, "x-httpd-php-source")
573
if (!strcmp(r->handler, "x-httpd-php-source")
574
574
|| !strcmp(r->handler, "application/x-httpd-php-source"))
576
576
return suphp_source_handler(r);
592
592
apr_bucket_brigade *bb;
596
p = r->main ? r->main->pool : r->pool;
595
apr_table_t *empty_table = apr_table_make(p, 0);
598
597
if (strcmp(r->method, "GET"))
603
602
conf = ap_get_module_config(r->server->module_config, &suphp_module);
604
603
phpexec = apr_pstrdup(p, conf->php_path);
605
604
if (phpexec == NULL)
610
609
// Try to open file for reading to see whether is is accessible
611
610
rv = apr_file_open(&file, apr_pstrdup(p, r->filename), APR_READ, APR_OS_DEFAULT, p);
612
611
if (rv == APR_SUCCESS)
629
628
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Could not open file: %s", r->filename);
630
629
return HTTP_INTERNAL_SERVER_ERROR;
633
env = ap_create_environment(p, r->subprocess_env);
635
632
/* set attributes for new process */
637
634
if (((rv = apr_procattr_create(&procattr, p)) != APR_SUCCESS)
638
635
|| ((rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK)) != APR_SUCCESS)
639
636
|| ((rv = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS)
646
643
return HTTP_INTERNAL_SERVER_ERROR;
650
647
/* create new process */
652
649
argv = apr_palloc(p, 4 * sizeof(char *));
653
650
argv[0] = phpexec;
655
652
argv[2] = apr_pstrdup(p, r->filename);
658
env = ap_create_environment(p, r->subprocess_env);
655
env = ap_create_environment(p, empty_table);
660
657
proc = apr_pcalloc(p, sizeof(*proc));
661
658
rv = apr_proc_create(proc, phpexec, (const char *const *)argv, (const char *const *)env, procattr, p);
662
659
if (rv != APR_SUCCESS)
671
668
return APR_EBADF;
672
669
apr_file_pipe_timeout_set(proc->out, r->server->timeout);
675
672
return APR_EBADF;
676
673
apr_file_pipe_timeout_set(proc->in, r->server->timeout);
679
676
return APR_EBADF;
680
677
apr_file_pipe_timeout_set(proc->err, r->server->timeout);
682
679
/* discard input */
684
681
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
686
683
apr_file_flush(proc->in);
687
684
apr_file_close(proc->in);
689
686
rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN);
690
687
if (rv != APR_SUCCESS)
696
693
suphp_discard_output(bb);
697
694
apr_brigade_cleanup(bb);
699
696
/* get output from script */
701
698
#if APR_FILES_AS_SOCKETS
702
699
apr_file_pipe_timeout_set(proc->out, 0);
703
700
apr_file_pipe_timeout_set(proc->err, 0);
706
703
b = apr_bucket_pipe_create(proc->out, r->connection->bucket_alloc);
708
705
APR_BRIGADE_INSERT_TAIL(bb, b);
710
707
b = apr_bucket_eos_create(r->connection->bucket_alloc);
711
708
APR_BRIGADE_INSERT_TAIL(bb, b);
713
710
/* send output to browser (through filters) */
715
712
r->content_type = "text/html";
716
713
rv = ap_pass_brigade(r->output_filters, bb);
718
715
/* write errors to logfile */
720
717
if (rv == APR_SUCCESS && !r->connection->aborted)
722
719
suphp_log_script_err(r, proc->err);
723
720
apr_file_close(proc->err);
758
755
char *ud_user = NULL;
759
756
char *ud_group = NULL;
762
759
apr_bucket_brigade *bb;
765
762
/* load configuration */
767
764
p = r->main ? r->main->pool : r->pool;
768
765
sconf = ap_get_module_config(r->server->module_config, &suphp_module);
769
766
dconf = ap_get_module_config(r->per_dir_config, &suphp_module);
770
767
core_conf = (core_dir_config *) ap_get_module_config(r->per_dir_config, &core_module);
772
769
/* check if suPHP is enabled for this request */
774
771
if (((sconf->engine != SUPHP_ENGINE_ON)
775
772
&& (dconf->engine != SUPHP_ENGINE_ON))
776
773
|| ((sconf->engine == SUPHP_ENGINE_ON)
777
774
&& (dconf->engine == SUPHP_ENGINE_OFF)))
780
777
/* check if file is existing and acessible */
782
779
rv = apr_stat(&finfo, apr_pstrdup(p, r->filename), APR_FINFO_NORM, p);
784
781
if (rv == APR_SUCCESS)
785
782
; /* do nothing */
786
783
else if (rv == EACCES)
798
795
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "could not get fileinfo: %s", r->filename);
799
796
return HTTP_NOT_FOUND;
802
799
if (!(r->finfo.protection & APR_UREAD))
804
801
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Insufficient permissions: %s", r->filename);
805
802
return HTTP_FORBIDDEN;
808
805
#ifdef SUPHP_USE_USERGROUP
809
806
if ((sconf->target_user == NULL || sconf->target_group == NULL)
810
807
&& (dconf->target_user == NULL || dconf->target_group == NULL))
816
813
ud_user = apr_psprintf(r->pool, "#%ld", (long) userdir_id->uid);
817
814
ud_group = apr_psprintf(r->pool, "#%ld", (long) userdir_id->gid);
819
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
816
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
820
817
"No user or group set - set suPHP_UserGroup");
821
818
return HTTP_INTERNAL_SERVER_ERROR;
826
823
/* prepare argv for new process */
828
825
argv = apr_palloc(p, 2 * sizeof(char *));
829
826
argv[0] = SUPHP_PATH_TO_SUPHP;
832
829
/* prepare environment for new process */
834
831
ap_add_common_vars(r);
835
832
ap_add_cgi_vars(r);
837
834
apr_table_unset(r->subprocess_env, "SUPHP_PHP_CONFIG");
838
835
apr_table_unset(r->subprocess_env, "SUPHP_AUTH_USER");
839
836
apr_table_unset(r->subprocess_env, "SUPHP_AUTH_PW");
841
838
#ifdef SUPHP_USE_USERGROUP
842
839
apr_table_unset(r->subprocess_env, "SUPHP_USER");
843
840
apr_table_unset(r->subprocess_env, "SUPHP_GROUP");
846
843
if (dconf->php_config)
848
845
apr_table_setn(r->subprocess_env, "SUPHP_PHP_CONFIG", apr_pstrdup(p, dconf->php_config));
851
848
apr_table_setn(r->subprocess_env, "SUPHP_HANDLER", r->handler);
853
850
if (r->headers_in)
855
852
const char *auth = NULL;
894
891
apr_table_setn(r->subprocess_env, "SUPHP_USER",
895
892
apr_pstrdup(r->pool, ud_user));
898
895
if (dconf->target_group)
900
897
apr_table_setn(r->subprocess_env, "SUPHP_GROUP",
911
908
apr_pstrdup(r->pool, ud_group));
915
912
env = ap_create_environment(p, r->subprocess_env);
917
914
/* set attributes for new process */
919
916
if (((rv = apr_procattr_create(&procattr, p)) != APR_SUCCESS)
920
917
|| ((rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK)) != APR_SUCCESS)
921
918
|| ((rv = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS)
923
920
/* set resource limits */
925
922
#ifdef RLIMIT_CPU
940
937
"couldn't set child process attributes: %s", r->filename);
941
938
return HTTP_INTERNAL_SERVER_ERROR;
944
941
/* create new process */
947
944
proc = apr_pcalloc(p, sizeof(*proc));
948
945
rv = apr_proc_create(proc, SUPHP_PATH_TO_SUPHP, (const char *const *)argv, (const char *const *)env, procattr, p);
958
955
return APR_EBADF;
959
956
apr_file_pipe_timeout_set(proc->out, r->server->timeout);
962
959
return APR_EBADF;
963
960
apr_file_pipe_timeout_set(proc->in, r->server->timeout);
966
963
return APR_EBADF;
967
964
apr_file_pipe_timeout_set(proc->err, r->server->timeout);
969
966
/* send request body to script */
971
968
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
974
971
apr_bucket *bucket;
975
972
rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN);
977
974
if (rv != APR_SUCCESS)
982
979
for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket))
984
981
const char *data;
986
983
int child_stopped_reading = 0;
988
985
if (APR_BUCKET_IS_EOS(bucket))
994
991
if (APR_BUCKET_IS_FLUSH(bucket) || child_stopped_reading)
999
996
apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
1001
998
rv = apr_file_write_full(proc->in, data, len, NULL);
1002
999
if (rv != APR_SUCCESS)
1007
1004
apr_brigade_cleanup(bb);
1009
1006
while (!eos_reached);
1011
1008
apr_file_flush(proc->in);
1012
1009
apr_file_close(proc->in);
1014
1011
/* get output from script and check if non-parsed headers are used */
1016
1013
#if APR_FILES_AS_SOCKETS
1017
1014
apr_file_pipe_timeout_set(proc->out, 0);
1018
1015
apr_file_pipe_timeout_set(proc->err, 0);
1037
1034
/* normal cgi headers, so we have to create the real headers ourselves */
1040
1037
const char *location;
1042
1039
ret = ap_scan_script_header_err_brigade(r, bb, strbuf);
1043
1040
if (ret == HTTP_NOT_MODIFIED)
1049
1046
suphp_discard_output(bb);
1050
1047
apr_brigade_destroy(bb);
1051
1048
suphp_log_script_err(r, proc->err);
1053
1050
/* ap_scan_script_header_err_brigade does logging itself,
1054
1051
so simply return */
1056
1053
return HTTP_INTERNAL_SERVER_ERROR;
1059
1056
location = apr_table_get(r->headers_out, "Location");
1060
1057
if (location && location[0] == '/' && r->status == 200)
1062
1059
/* empty brigade (script output) and modify headers */
1064
1061
suphp_discard_output(bb);
1065
1062
apr_brigade_destroy(bb);
1066
1063
suphp_log_script_err(r, proc->err);
1067
1064
r->method = apr_pstrdup(r->pool, "GET");
1068
1065
r->method_number = M_GET;
1069
1066
apr_table_unset(r->headers_in, "Content-Length");
1071
1068
ap_internal_redirect_handler(location, r);
1079
1076
suphp_log_script_err(r, proc->err);
1080
1077
return HTTP_MOVED_TEMPORARILY;
1083
1080
/* send output to browser (through filters) */
1085
1082
rv = ap_pass_brigade(r->output_filters, bb);
1087
1084
/* write errors to logfile */
1089
1086
if (rv == APR_SUCCESS && !r->connection->aborted)
1090
1087
suphp_log_script_err(r, proc->err);
1092
1089
apr_file_close(proc->err);
1095
1092
if (proc->out && nph)
1097
1094
/* use non-parsed headers (direct output) */
1099
1096
struct ap_filter_t *cur;
1101
1098
/* get rid of output filters */
1103
1100
cur = r->proto_output_filters;
1104
1101
while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION)
1106
1103
cur = cur->next;
1108
1105
r->output_filters = r->proto_output_filters = cur;
1110
1107
/* send output to browser (directly) */
1112
1109
rv = ap_pass_brigade(r->output_filters, bb);
1114
1111
/* log errors */
1115
1112
if (rv == APR_SUCCESS && !r->connection->aborted)
1116
1113
suphp_log_script_err(r, proc->err);
1118
1115
apr_file_close(proc->err);