From be5debc65a28a15334ade0c7d3292ca5a9a007c0 Mon Sep 17 00:00:00 2001 From: Sara Golemon Date: Tue, 17 Oct 2006 21:54:17 +0000 Subject: [PATCH] Extend open_basedir functionality to allow runtime tightening --- NEWS | 1 + main/fopen_wrappers.c | 58 +++++++++++++++++++++++++++++++++++++++++++ main/fopen_wrappers.h | 3 +++ main/main.c | 3 ++- 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index b91ea39c326dc..bc6b7b26a079f 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ PHP NEWS functions to not call __autoload(). (Dmitry) - Changed opendir/dir/scandir to use default context when no context argument is passed. (Sara) +- Changed open_basedir to allow tightening in runtime contexts. (Sara) - Removed old legacy: . "register_globals" support. (Pierre) diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c index 265097d8baa86..7f22be32bab88 100644 --- a/main/fopen_wrappers.c +++ b/main/fopen_wrappers.c @@ -82,6 +82,64 @@ #endif /* }}} */ +/* {{{ OnUpdateBaseDir +Allows any change to open_basedir setting in during Startup and Shutdown events, +or a tightening during activation/runtime/deactivation */ +PHPAPI ZEND_INI_MH(OnUpdateBaseDir) +{ + char **p, *pathbuf, *ptr, *end; +#ifndef ZTS + char *base = (char *) mh_arg2; +#else + char *base = (char *) ts_resource(*((int *) mh_arg2)); +#endif + + p = (char **) (base+(size_t) mh_arg1); + + if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN) { + /* We're in a PHP_INI_SYSTEM context, no restrictions */ + *p = new_value; + return SUCCESS; + } + + + /* Elsewise, we're in runtime */ + if (!*p || !**p) { + /* open_basedir not set yet, go ahead and give it a value */ + *p = new_value; + return SUCCESS; + } + + /* Shortcut: When we have a open_basedir and someone tries to unset, we know it'll fail */ + if (!new_value || !*new_value) { + return FAILURE; + } + + /* Is the proposed open_basedir at least as restrictive as the current setting? */ + ptr = pathbuf = estrdup(new_value); + while (ptr && *ptr) { + end = strchr(ptr, DEFAULT_DIR_SEPARATOR); + if (end != NULL) { + *end = '\0'; + end++; + } + if (php_check_open_basedir_ex(ptr, 0 TSRMLS_CC) != 0) { + /* At least one portion of this open_basedir is less restrictive than the prior one, FAIL */ + efree(pathbuf); + return FAILURE; + } + ptr = end; + } + efree(pathbuf); + + /* Everything checks out, set it */ + *p = new_value; + + return SUCCESS; +} +/* }}} */ + + /* {{{ php_check_specific_open_basedir When open_basedir is not NULL, check if the given filename is located in open_basedir. Returns -1 if error or not in the open_basedir, else 0 diff --git a/main/fopen_wrappers.h b/main/fopen_wrappers.h index fc46f92a6c187..9a7bfa562b448 100644 --- a/main/fopen_wrappers.h +++ b/main/fopen_wrappers.h @@ -23,6 +23,7 @@ BEGIN_EXTERN_C() #include "php_globals.h" +#include "php_ini.h" PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC); PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC); @@ -35,6 +36,8 @@ PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const c PHPAPI int php_is_url(char *path); PHPAPI char *php_strip_url_passwd(char *path); + +PHPAPI ZEND_INI_MH(OnUpdateBaseDir); END_EXTERN_C() #endif diff --git a/main/main.c b/main/main.c index d70451866eed4..e26a740aa85df 100644 --- a/main/main.c +++ b/main/main.c @@ -339,6 +339,7 @@ static PHP_INI_MH(OnUpdateDefaultMimetype) #else # define DEFAULT_SENDMAIL_PATH NULL #endif + /* {{{ PHP_INI */ PHP_INI_BEGIN() @@ -392,7 +393,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("extension_dir", PHP_EXTENSION_DIR, PHP_INI_SYSTEM, OnUpdateStringUnempty, extension_dir, php_core_globals, core_globals) STD_PHP_INI_ENTRY("include_path", PHP_INCLUDE_PATH, PHP_INI_ALL, OnUpdateStringUnempty, include_path, php_core_globals, core_globals) PHP_INI_ENTRY("max_execution_time", "30", PHP_INI_ALL, OnUpdateTimeout) - STD_PHP_INI_ENTRY("open_basedir", NULL, PHP_INI_SYSTEM, OnUpdateString, open_basedir, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("open_basedir", NULL, PHP_INI_ALL, OnUpdateBaseDir, open_basedir, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("file_uploads", "1", PHP_INI_SYSTEM, OnUpdateBool, file_uploads, php_core_globals, core_globals) STD_PHP_INI_ENTRY("upload_max_filesize", "2M", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, upload_max_filesize, php_core_globals, core_globals)