X-Git-Url: http://git.home-dn.net/?p=manu%2Fsuphp.git;a=blobdiff_plain;f=src%2Fapache2%2Fmod_suphp.c;h=35b22926d3febe96f1d10ee17b58ea38dee664ad;hp=4b26a7a8a1f8b0864d947c1b35a1d023e9cfc4a6;hb=849f4a7977b5780eacae8fad7a078d05f4a615ee;hpb=b0eaa3f1fbf491fdc8a3044cf20754f14254338a diff --git a/src/apache2/mod_suphp.c b/src/apache2/mod_suphp.c index 4b26a7a..35b2292 100644 --- a/src/apache2/mod_suphp.c +++ b/src/apache2/mod_suphp.c @@ -123,6 +123,7 @@ typedef struct { char *target_group; #endif apr_table_t *handlers; + char *php_path; } suphp_conf; @@ -132,6 +133,7 @@ static void *suphp_create_dir_config(apr_pool_t *p, char *dir) cfg->php_config = NULL; cfg->engine = SUPHP_ENGINE_UNDEFINED; + cfg->php_path = NULL; cfg->cmode = SUPHP_CONFIG_MODE_DIRECTORY; #ifdef SUPHP_USE_USERGROUP @@ -195,8 +197,13 @@ static void *suphp_create_server_config(apr_pool_t *p, server_rec *s) suphp_conf *cfg = (suphp_conf *) apr_pcalloc(p, sizeof(suphp_conf)); cfg->engine = SUPHP_ENGINE_UNDEFINED; + cfg->php_path = NULL; cfg->cmode = SUPHP_CONFIG_MODE_SERVER; + /* Create table with 0 initial elements */ + /* This size may be increased for performance reasons */ + cfg->handlers = apr_table_make(p, 0); + return (void *) cfg; } @@ -212,7 +219,12 @@ static void *suphp_merge_server_config(apr_pool_t *p, void *base, merged->engine = child->engine; else merged->engine = parent->engine; - + + if (child->php_path != NULL) + merged->php_path = apr_pstrdup(p, child->php_path); + else + merged->php_path = apr_pstrdup(p, parent->php_path); + #ifdef SUPHP_USE_USERGROUP if (child->target_user) merged->target_user = apr_pstrdup(p, child->target_user); @@ -229,6 +241,8 @@ static void *suphp_merge_server_config(apr_pool_t *p, void *base, merged->target_group = NULL; #endif + merged->handlers = apr_table_overlay(p, child->handlers, parent->handlers); + return (void*) merged; } @@ -289,9 +303,14 @@ static const char *suphp_handle_cmd_user_group(cmd_parms *cmd, void *mconfig, static const char *suphp_handle_cmd_add_handler(cmd_parms *cmd, void *mconfig, - const char *arg) + const char *arg) { - suphp_conf *cfg = (suphp_conf *) mconfig; + suphp_conf *cfg; + if (mconfig) + cfg = (suphp_conf *) mconfig; + else + cfg = (suphp_conf *) ap_get_module_config(cmd->server->module_config, &suphp_module); + // Mark active handler with '1' apr_table_set(cfg->handlers, arg, "1"); @@ -300,10 +319,15 @@ static const char *suphp_handle_cmd_add_handler(cmd_parms *cmd, void *mconfig, static const char *suphp_handle_cmd_remove_handler(cmd_parms *cmd, - void *mconfig, - const char *arg) + void *mconfig, + const char *arg) { - suphp_conf *cfg = (suphp_conf *) mconfig; + suphp_conf *cfg; + if (mconfig) + cfg = (suphp_conf *) mconfig; + else + cfg = (suphp_conf *) ap_get_module_config(cmd->server->module_config, &suphp_module); + // Mark deactivated handler with '0' apr_table_set(cfg->handlers, arg, "0"); @@ -311,6 +335,19 @@ static const char *suphp_handle_cmd_remove_handler(cmd_parms *cmd, } +static const char *suphp_handle_cmd_phppath(cmd_parms *cmd, void* mconfig, const char *arg) +{ + server_rec *s = cmd->server; + suphp_conf *cfg; + + cfg = (suphp_conf *) ap_get_module_config(s->module_config, &suphp_module); + + cfg->php_path = apr_pstrdup(cmd->pool, arg); + + return NULL; +} + + static const command_rec suphp_cmds[] = { AP_INIT_FLAG("suPHP_Engine", suphp_handle_cmd_engine, NULL, RSRC_CONF | ACCESS_CONF, @@ -321,8 +358,9 @@ static const command_rec suphp_cmds[] = AP_INIT_TAKE2("suPHP_UserGroup", suphp_handle_cmd_user_group, NULL, RSRC_CONF | ACCESS_CONF, "User and group scripts shall be run as"), #endif - AP_INIT_ITERATE("suPHP_AddHandler", suphp_handle_cmd_add_handler, NULL, ACCESS_CONF, "Tells mod_suphp to handle these MIME-types"), - AP_INIT_ITERATE("suPHP_RemoveHandler", suphp_handle_cmd_remove_handler, NULL, ACCESS_CONF, "Tells mod_suphp not to handle these MIME-types"), + AP_INIT_ITERATE("suPHP_AddHandler", suphp_handle_cmd_add_handler, NULL, RSRC_CONF | ACCESS_CONF, "Tells mod_suphp to handle these MIME-types"), + AP_INIT_ITERATE("suPHP_RemoveHandler", suphp_handle_cmd_remove_handler, NULL, RSRC_CONF | ACCESS_CONF, "Tells mod_suphp not to handle these MIME-types"), + AP_INIT_TAKE1("suPHP_PHPPath", suphp_handle_cmd_phppath, NULL, RSRC_CONF, "Path to the PHP binary used to render source view"), {NULL} }; @@ -504,8 +542,192 @@ static void suphp_discard_output(apr_bucket_brigade *bb) { Hooks / handlers ******************/ +static int suphp_script_handler(request_rec *r); +static int suphp_source_handler(request_rec *r); + static int suphp_handler(request_rec *r) { + suphp_conf *sconf, *dconf; + + sconf = ap_get_module_config(r->server->module_config, &suphp_module); + dconf = ap_get_module_config(r->per_dir_config, &suphp_module); + + /* only handle request if mod_suphp is active for this handler */ + /* check only first byte of value (second has to be \0) */ + if (apr_table_get(dconf->handlers, r->handler) != NULL) + { + if (*(apr_table_get(dconf->handlers, r->handler)) != '0') + { + return suphp_script_handler(r); + } + } + else + { + if ((apr_table_get(sconf->handlers, r->handler) != NULL) + && (*(apr_table_get(sconf->handlers, r->handler)) != '0')) + { + return suphp_script_handler(r); + } + } + + if (!strcmp(r->handler, "x-httpd-php-source") + || !strcmp(r->handler, "application/x-httpd-php-source")) + { + return suphp_source_handler(r); + } + + return DECLINED; +} + +static int suphp_source_handler(request_rec *r) +{ + suphp_conf *conf; + apr_status_t rv; + apr_pool_t *p; + apr_file_t *file; + apr_proc_t *proc; + apr_procattr_t *procattr; + char **argv; + char **env; + apr_bucket_brigade *bb; + apr_bucket *b; + char *phpexec; + + p = r->main ? r->main->pool : r->pool; + + if (strcmp(r->method, "GET")) + { + return DECLINED; + } + + conf = ap_get_module_config(r->server->module_config, &suphp_module); + phpexec = apr_pstrdup(p, conf->php_path); + if (phpexec == NULL) + { + return DECLINED; + } + + // Try to open file for reading to see whether is is accessible + rv = apr_file_open(&file, apr_pstrdup(p, r->filename), APR_READ, APR_OS_DEFAULT, p); + if (rv == APR_SUCCESS) + { + apr_file_close(file); + file = NULL; + } + else if (rv == EACCES) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "access to %s denied", r->filename); + return HTTP_FORBIDDEN; + } + else if (rv == ENOENT) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "File does not exist: %s", r->filename); + return HTTP_NOT_FOUND; + } + else + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Could not open file: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + env = ap_create_environment(p, r->subprocess_env); + + /* set attributes for new process */ + + if (((rv = apr_procattr_create(&procattr, p)) != APR_SUCCESS) + || ((rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK)) != APR_SUCCESS) + || ((rv = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) + || ((apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) != APR_SUCCESS) + || ((apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS) + || ((apr_procattr_detach_set(procattr, 0)) != APR_SUCCESS)) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "couldn't set child process attributes: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + + /* create new process */ + + argv = apr_palloc(p, 4 * sizeof(char *)); + argv[0] = phpexec; + argv[1] = "-s"; + argv[2] = apr_pstrdup(p, r->filename); + argv[3] = NULL; + + env = ap_create_environment(p, r->subprocess_env); + + proc = apr_pcalloc(p, sizeof(*proc)); + rv = apr_proc_create(proc, phpexec, (const char *const *)argv, (const char *const *)env, procattr, p); + if (rv != APR_SUCCESS) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "couldn't create child process: %s for %s", phpexec, r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + apr_pool_note_subprocess(p, proc, APR_KILL_AFTER_TIMEOUT); + + if (!proc->out) + return APR_EBADF; + apr_file_pipe_timeout_set(proc->out, r->server->timeout); + + if (!proc->in) + return APR_EBADF; + apr_file_pipe_timeout_set(proc->in, r->server->timeout); + + if (!proc->err) + return APR_EBADF; + apr_file_pipe_timeout_set(proc->err, r->server->timeout); + + /* discard input */ + + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + + apr_file_flush(proc->in); + apr_file_close(proc->in); + + rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); + if (rv != APR_SUCCESS) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "couldn't get input from filters: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + suphp_discard_output(bb); + apr_brigade_cleanup(bb); + + /* get output from script */ + +#if APR_FILES_AS_SOCKETS + apr_file_pipe_timeout_set(proc->out, 0); + apr_file_pipe_timeout_set(proc->err, 0); + b = suphp_bucket_create(r, proc->out, proc->err, r->connection->bucket_alloc); +#else + b = apr_bucket_pipe_create(proc->out, r->connection->bucket_alloc); +#endif + APR_BRIGADE_INSERT_TAIL(bb, b); + + b = apr_bucket_eos_create(r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + + /* send output to browser (through filters) */ + + r->content_type = "text/html"; + rv = ap_pass_brigade(r->output_filters, bb); + + /* write errors to logfile */ + + if (rv == APR_SUCCESS && !r->connection->aborted) + { + suphp_log_script_err(r, proc->err); + apr_file_close(proc->err); + } + + return OK; +} + +static int suphp_script_handler(request_rec *r) +{ apr_pool_t *p; suphp_conf *sconf; suphp_conf *dconf; @@ -547,12 +769,6 @@ static int suphp_handler(request_rec *r) dconf = ap_get_module_config(r->per_dir_config, &suphp_module); core_conf = (core_dir_config *) ap_get_module_config(r->per_dir_config, &core_module); - /* only handle request if mod_suphp is active for this handler */ - /* check only first byte of value (second has to be \0) */ - if ((apr_table_get(dconf->handlers, r->handler) == NULL) - || (*(apr_table_get(dconf->handlers, r->handler)) == '0')) - return DECLINED; - /* check if suPHP is enabled for this request */ if (((sconf->engine != SUPHP_ENGINE_ON) @@ -585,25 +801,25 @@ static int suphp_handler(request_rec *r) if (!(r->finfo.protection & APR_UREAD)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Insufficient permissions: %s", r->filename); - return HTTP_FORBIDDEN; + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Insufficient permissions: %s", r->filename); + return HTTP_FORBIDDEN; } #ifdef SUPHP_USE_USERGROUP if ((sconf->target_user == NULL || sconf->target_group == NULL) && (dconf->target_user == NULL || dconf->target_group == NULL)) { - /* Check for userdir request */ - ap_unix_identity_t *userdir_id = NULL; - userdir_id = ap_run_get_suexec_identity(r); - if (userdir_id != NULL && userdir_id->userdir) { - ud_user = apr_psprintf(r->pool, "#%ld", (long) userdir_id->uid); - ud_group = apr_psprintf(r->pool, "#%ld", (long) userdir_id->gid); - } else { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "No user or group set - set suPHP_UserGroup"); - return HTTP_INTERNAL_SERVER_ERROR; - } + /* Check for userdir request */ + ap_unix_identity_t *userdir_id = NULL; + userdir_id = ap_run_get_suexec_identity(r); + if (userdir_id != NULL && userdir_id->userdir) { + ud_user = apr_psprintf(r->pool, "#%ld", (long) userdir_id->uid); + ud_group = apr_psprintf(r->pool, "#%ld", (long) userdir_id->gid); + } else { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "No user or group set - set suPHP_UserGroup"); + return HTTP_INTERNAL_SERVER_ERROR; + } } #endif @@ -675,8 +891,8 @@ static int suphp_handler(request_rec *r) } else { - apr_table_setn(r->subprocess_env, "SUPHP_USER", - apr_pstrdup(r->pool, ud_user)); + apr_table_setn(r->subprocess_env, "SUPHP_USER", + apr_pstrdup(r->pool, ud_user)); } if (dconf->target_group) @@ -691,8 +907,8 @@ static int suphp_handler(request_rec *r) } else { - apr_table_setn(r->subprocess_env, "SUPHP_GROUP", - apr_pstrdup(r->pool, ud_group)); + apr_table_setn(r->subprocess_env, "SUPHP_GROUP", + apr_pstrdup(r->pool, ud_group)); } #endif @@ -823,11 +1039,11 @@ static int suphp_handler(request_rec *r) int ret; const char *location; - ret = ap_scan_script_header_err_brigade(r, bb, strbuf); - if (ret == HTTP_NOT_MODIFIED) - { - return ret; - } + ret = ap_scan_script_header_err_brigade(r, bb, strbuf); + if (ret == HTTP_NOT_MODIFIED) + { + return ret; + } else if (ret != APR_SUCCESS) { suphp_discard_output(bb);