diff options
author | emkael <emkael@tlen.pl> | 2018-10-18 02:40:38 +0200 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2018-10-18 02:40:38 +0200 |
commit | eab8a101e7a3fcbb41e01a574985e06c5a3775de (patch) | |
tree | 60f201da5984b0c3638d10da02bba42b61aa3177 /lib/smarty3/sysplugins/smarty_security.php | |
parent | 7f38be342c1495aeca418286c15c25c18ac9e142 (diff) |
Updating Smarty
Diffstat (limited to 'lib/smarty3/sysplugins/smarty_security.php')
-rw-r--r-- | lib/smarty3/sysplugins/smarty_security.php | 293 |
1 files changed, 142 insertions, 151 deletions
diff --git a/lib/smarty3/sysplugins/smarty_security.php b/lib/smarty3/sysplugins/smarty_security.php index f2f98f4..441a7e2 100644 --- a/lib/smarty3/sysplugins/smarty_security.php +++ b/lib/smarty3/sysplugins/smarty_security.php @@ -6,12 +6,12 @@ * @subpackage Security * @author Uwe Tews */ - -/* +/** * FIXME: Smarty_Security API * - getter and setter instead of public properties would allow cultivating an internal cache properly - * - current implementation of isTrustedResourceDir() assumes that Smarty::$template_dir and Smarty::$config_dir are immutable - * the cache is killed every time either of the variables change. That means that two distinct Smarty objects with differing + * - current implementation of isTrustedResourceDir() assumes that Smarty::$template_dir and Smarty::$config_dir + * are immutable the cache is killed every time either of the variables change. That means that two distinct + * Smarty objects with differing * $template_dir or $config_dir should NOT share the same Smarty_Security instance, * as this would lead to (severe) performance penalty! how should this be handled? */ @@ -258,63 +258,54 @@ class Smarty_Security public function __construct($smarty) { $this->smarty = $smarty; - $this->smarty->_cache[ 'template_dir_new' ] = true; - $this->smarty->_cache[ 'config_dir_new' ] = true; } /** * Check if PHP function is trusted. * - * @param string $function_name - * @param object $compiler compiler object + * @param string $function_name + * @param object $compiler compiler object * * @return boolean true if function is trusted - * @throws SmartyCompilerException if php function is not trusted */ public function isTrustedPhpFunction($function_name, $compiler) { - if (isset($this->php_functions) && - (empty($this->php_functions) || in_array($function_name, $this->php_functions)) + if (isset($this->php_functions) + && (empty($this->php_functions) || in_array($function_name, $this->php_functions)) ) { return true; } - $compiler->trigger_template_error("PHP function '{$function_name}' not allowed by security setting"); - return false; // should not, but who knows what happens to the compiler in the future? } /** * Check if static class is trusted. * - * @param string $class_name - * @param object $compiler compiler object + * @param string $class_name + * @param object $compiler compiler object * * @return boolean true if class is trusted - * @throws SmartyCompilerException if static class is not trusted */ public function isTrustedStaticClass($class_name, $compiler) { - if (isset($this->static_classes) && - (empty($this->static_classes) || in_array($class_name, $this->static_classes)) + if (isset($this->static_classes) + && (empty($this->static_classes) || in_array($class_name, $this->static_classes)) ) { return true; } - $compiler->trigger_template_error("access to static class '{$class_name}' not allowed by security setting"); - return false; // should not, but who knows what happens to the compiler in the future? } /** * Check if static class method/property is trusted. * - * @param string $class_name - * @param string $params - * @param object $compiler compiler object + * @param string $class_name + * @param string $params + * @param object $compiler compiler object * * @return boolean true if class method is trusted - * @throws SmartyCompilerException if static class method is not trusted */ public function isTrustedStaticClassAccess($class_name, $params, $compiler) { @@ -322,7 +313,7 @@ class Smarty_Security // fall back return $this->isTrustedStaticClass($class_name, $compiler); } - if ($params[ 2 ] == 'method') { + if ($params[ 2 ] === 'method') { $allowed = $this->trusted_static_methods; $name = substr($params[ 0 ], 0, strpos($params[ 0 ], '(')); } else { @@ -335,8 +326,8 @@ class Smarty_Security // fall back return $this->isTrustedStaticClass($class_name, $compiler); } - if (isset($allowed[ $class_name ]) && - (empty($allowed[ $class_name ]) || in_array($name, $allowed[ $class_name ])) + if (isset($allowed[ $class_name ]) + && (empty($allowed[ $class_name ]) || in_array($name, $allowed[ $class_name ])) ) { return true; } @@ -348,42 +339,43 @@ class Smarty_Security /** * Check if PHP modifier is trusted. * - * @param string $modifier_name - * @param object $compiler compiler object + * @param string $modifier_name + * @param object $compiler compiler object * * @return boolean true if modifier is trusted - * @throws SmartyCompilerException if modifier is not trusted */ public function isTrustedPhpModifier($modifier_name, $compiler) { - if (isset($this->php_modifiers) && - (empty($this->php_modifiers) || in_array($modifier_name, $this->php_modifiers)) + if (isset($this->php_modifiers) + && (empty($this->php_modifiers) || in_array($modifier_name, $this->php_modifiers)) ) { return true; } - $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting"); - return false; // should not, but who knows what happens to the compiler in the future? } /** * Check if tag is trusted. * - * @param string $tag_name - * @param object $compiler compiler object + * @param string $tag_name + * @param object $compiler compiler object * * @return boolean true if tag is trusted - * @throws SmartyCompilerException if modifier is not trusted */ public function isTrustedTag($tag_name, $compiler) { // check for internal always required tags - if (in_array($tag_name, - array('assign', 'call', 'private_filter', 'private_block_plugin', 'private_function_plugin', - 'private_object_block_function', 'private_object_function', 'private_registered_function', - 'private_registered_block', 'private_special_variable', 'private_print_expression', - 'private_modifier'))) { + if (in_array( + $tag_name, + array( + 'assign', 'call', 'private_filter', 'private_block_plugin', 'private_function_plugin', + 'private_object_block_function', 'private_object_function', 'private_registered_function', + 'private_registered_block', 'private_special_variable', 'private_print_expression', + 'private_modifier' + ) + ) + ) { return true; } // check security settings @@ -398,39 +390,38 @@ class Smarty_Security } else { $compiler->trigger_template_error("tag '{$tag_name}' not allowed by security setting", null, true); } - return false; // should not, but who knows what happens to the compiler in the future? } /** * Check if special $smarty variable is trusted. * - * @param string $var_name - * @param object $compiler compiler object + * @param string $var_name + * @param object $compiler compiler object * * @return boolean true if tag is trusted - * @throws SmartyCompilerException if modifier is not trusted */ public function isTrustedSpecialSmartyVar($var_name, $compiler) { if (!in_array($var_name, $this->disabled_special_smarty_vars)) { return true; } else { - $compiler->trigger_template_error("special variable '\$smarty.{$var_name}' not allowed by security setting", - null, true); + $compiler->trigger_template_error( + "special variable '\$smarty.{$var_name}' not allowed by security setting", + null, + true + ); } - return false; // should not, but who knows what happens to the compiler in the future? } /** * Check if modifier plugin is trusted. * - * @param string $modifier_name - * @param object $compiler compiler object + * @param string $modifier_name + * @param object $compiler compiler object * * @return boolean true if tag is trusted - * @throws SmartyCompilerException if modifier is not trusted */ public function isTrustedModifier($modifier_name, $compiler) { @@ -443,26 +434,31 @@ class Smarty_Security if (empty($this->disabled_modifiers) || !in_array($modifier_name, $this->disabled_modifiers)) { return true; } else { - $compiler->trigger_template_error("modifier '{$modifier_name}' disabled by security setting", null, - true); + $compiler->trigger_template_error( + "modifier '{$modifier_name}' disabled by security setting", + null, + true + ); } - } elseif (in_array($modifier_name, $this->allowed_modifiers) && - !in_array($modifier_name, $this->disabled_modifiers) + } elseif (in_array($modifier_name, $this->allowed_modifiers) + && !in_array($modifier_name, $this->disabled_modifiers) ) { return true; } else { - $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting", null, - true); + $compiler->trigger_template_error( + "modifier '{$modifier_name}' not allowed by security setting", + null, + true + ); } - return false; // should not, but who knows what happens to the compiler in the future? } /** * Check if constants are enabled or trusted * - * @param string $const constant name - * @param object $compiler compiler object + * @param string $const constant name + * @param object $compiler compiler object * * @return bool */ @@ -472,7 +468,7 @@ class Smarty_Security return true; } if (!empty($this->trusted_constants)) { - if (!in_array($const, $this->trusted_constants)) { + if (!in_array(strtolower($const), $this->trusted_constants)) { $compiler->trigger_template_error("Security: access to constant '{$const}' not permitted"); return false; } @@ -488,7 +484,7 @@ class Smarty_Security /** * Check if stream is trusted. * - * @param string $stream_name + * @param string $stream_name * * @return boolean true if stream is trusted * @throws SmartyException if stream is not trusted @@ -498,14 +494,13 @@ class Smarty_Security if (isset($this->streams) && (empty($this->streams) || in_array($stream_name, $this->streams))) { return true; } - throw new SmartyException("stream '{$stream_name}' not allowed by security setting"); } /** * Check if directory of file resource is trusted. * - * @param string $filepath + * @param string $filepath * @param null|bool $isConfig * * @return bool true if directory is trusted @@ -514,60 +509,36 @@ class Smarty_Security public function isTrustedResourceDir($filepath, $isConfig = null) { if ($this->_include_path_status !== $this->smarty->use_include_path) { - foreach ($this->_include_dir as $directory) { - unset($this->_resource_dir[ $directory ]); - } - if ($this->smarty->use_include_path) { - $this->_include_dir = array(); - $_dirs = $this->smarty->ext->_getIncludePath->getIncludePathDirs($this->smarty); - foreach ($_dirs as $directory) { - $this->_include_dir[] = $directory; - $this->_resource_dir[ $directory ] = true; - } + $_dir = + $this->smarty->use_include_path ? $this->smarty->ext->_getIncludePath->getIncludePathDirs($this->smarty) : array(); + if ($this->_include_dir !== $_dir) { + $this->_updateResourceDir($this->_include_dir, $_dir); + $this->_include_dir = $_dir; } $this->_include_path_status = $this->smarty->use_include_path; } - if ($isConfig !== true && - (!isset($this->smarty->_cache[ 'template_dir_new' ]) || $this->smarty->_cache[ 'template_dir_new' ]) - ) { - $_dir = $this->smarty->getTemplateDir(); - if ($this->_template_dir !== $_dir) { - foreach ($this->_template_dir as $directory) { - unset($this->_resource_dir[ $directory ]); - } - foreach ($_dir as $directory) { - $this->_resource_dir[ $directory ] = true; - } - $this->_template_dir = $_dir; - } - $this->smarty->_cache[ 'template_dir_new' ] = false; + $_dir = $this->smarty->getTemplateDir(); + if ($this->_template_dir !== $_dir) { + $this->_updateResourceDir($this->_template_dir, $_dir); + $this->_template_dir = $_dir; } - if ($isConfig !== false && - (!isset($this->smarty->_cache[ 'config_dir_new' ]) || $this->smarty->_cache[ 'config_dir_new' ]) - ) { - $_dir = $this->smarty->getConfigDir(); - if ($this->_config_dir !== $_dir) { - foreach ($this->_config_dir as $directory) { - unset($this->_resource_dir[ $directory ]); - } - foreach ($_dir as $directory) { - $this->_resource_dir[ $directory ] = true; - } - $this->_config_dir = $_dir; - } - $this->smarty->_cache[ 'config_dir_new' ] = false; + $_dir = $this->smarty->getConfigDir(); + if ($this->_config_dir !== $_dir) { + $this->_updateResourceDir($this->_config_dir, $_dir); + $this->_config_dir = $_dir; } - if ($this->_secure_dir !== (array) $this->secure_dir) { - foreach ($this->_secure_dir as $directory) { - unset($this->_resource_dir[ $directory ]); - } - foreach ((array) $this->secure_dir as $directory) { - $directory = $this->smarty->_realpath($directory . DS, true); - $this->_resource_dir[ $directory ] = true; + if ($this->_secure_dir !== $this->secure_dir) { + $this->secure_dir = (array)$this->secure_dir; + foreach ($this->secure_dir as $k => $d) { + $this->secure_dir[ $k ] = $this->smarty->_realpath($d . DIRECTORY_SEPARATOR, true); } - $this->_secure_dir = (array) $this->secure_dir; + $this->_updateResourceDir($this->_secure_dir, $this->secure_dir); + $this->_secure_dir = $this->secure_dir; + } + $addPath = $this->_checkDir($filepath, $this->_resource_dir); + if ($addPath !== false) { + $this->_resource_dir = array_merge($this->_resource_dir, $addPath); } - $this->_resource_dir = $this->_checkDir($filepath, $this->_resource_dir); return true; } @@ -577,11 +548,11 @@ class Smarty_Security * So "http://username:password@hello.world.example.org:8080/some-path?some=query-string" * is reduced to "http://hello.world.example.org" prior to applying the patters from {@link $trusted_uri}. * - * @param string $uri + * @param string $uri * * @return boolean true if URI is trusted * @throws SmartyException if URI is not trusted - * @uses $trusted_uri for list of patterns to match against $uri + * @uses $trusted_uri for list of patterns to match against $uri */ public function isTrustedUri($uri) { @@ -594,14 +565,13 @@ class Smarty_Security } } } - throw new SmartyException("URI '{$uri}' not allowed by security setting"); } /** * Check if directory of file resource is trusted. * - * @param string $filepath + * @param string $filepath * * @return boolean true if directory is trusted * @throws SmartyException if PHP directory is not trusted @@ -611,63 +581,84 @@ class Smarty_Security if (empty($this->trusted_dir)) { throw new SmartyException("directory '{$filepath}' not allowed by security setting (no trusted_dir specified)"); } - // check if index is outdated if (!$this->_trusted_dir || $this->_trusted_dir !== $this->trusted_dir) { $this->_php_resource_dir = array(); - $this->_trusted_dir = $this->trusted_dir; - foreach ((array) $this->trusted_dir as $directory) { - $directory = $this->smarty->_realpath($directory . DS, true); + foreach ((array)$this->trusted_dir as $directory) { + $directory = $this->smarty->_realpath($directory . '/', true); $this->_php_resource_dir[ $directory ] = true; } } - - $this->_php_resource_dir = - $this->_checkDir($this->smarty->_realpath($filepath, true), $this->_php_resource_dir); + $addPath = $this->_checkDir($filepath, $this->_php_resource_dir); + if ($addPath !== false) { + $this->_php_resource_dir = array_merge($this->_php_resource_dir, $addPath); + } return true; } - + + /** + * Remove old directories and its sub folders, add new directories + * + * @param array $oldDir + * @param array $newDir + */ + private function _updateResourceDir($oldDir, $newDir) + { + foreach ($oldDir as $directory) { + // $directory = $this->smarty->_realpath($directory, true); + $length = strlen($directory); + foreach ($this->_resource_dir as $dir) { + if (substr($dir, 0, $length) === $directory) { + unset($this->_resource_dir[ $dir ]); + } + } + } + foreach ($newDir as $directory) { + // $directory = $this->smarty->_realpath($directory, true); + $this->_resource_dir[ $directory ] = true; + } + } + /** * Check if file is inside a valid directory * * @param string $filepath * @param array $dirs valid directories * - * @return array + * @return array|bool * @throws \SmartyException */ private function _checkDir($filepath, $dirs) { - $directory = dirname($filepath) . DS; + $directory = dirname($this->smarty->_realpath($filepath, true)) . DIRECTORY_SEPARATOR; $_directory = array(); - while (true) { - // remember the directory to add it to _resource_dir in case we're successful - $_directory[ $directory ] = true; - // test if the directory is trusted - if (isset($dirs[ $directory ])) { - // merge sub directories of current $directory into _resource_dir to speed up subsequent lookup - $dirs = array_merge($dirs, $_directory); - - return $dirs; - } - // abort if we've reached root - if (!preg_match('#[\\\/][^\\\/]+[\\\/]$#', $directory)) { - break; + if (!preg_match('#[\\\\/][.][.][\\\\/]#', $directory)) { + while (true) { + // test if the directory is trusted + if (isset($dirs[ $directory ])) { + return $_directory; + } + // abort if we've reached root + if (!preg_match('#[\\\\/][^\\\\/]+[\\\\/]$#', $directory)) { + // give up + break; + } + // remember the directory to add it to _resource_dir in case we're successful + $_directory[ $directory ] = true; + // bubble up one level + $directory = preg_replace('#[\\\\/][^\\\\/]+[\\\\/]$#', DIRECTORY_SEPARATOR, $directory); } - // bubble up one level - $directory = preg_replace('#[\\\/][^\\\/]+[\\\/]$#', DS, $directory); } - // give up - throw new SmartyException("directory '{$filepath}' not allowed by security setting"); + throw new SmartyException(sprintf('Smarty Security: not trusted file path \'%s\' ', $filepath)); } /** * Loads security class and enables security * - * @param \Smarty $smarty - * @param string|Smarty_Security $security_class if a string is used, it must be class-name + * @param \Smarty $smarty + * @param string|Smarty_Security $security_class if a string is used, it must be class-name * * @return \Smarty current Smarty instance for chaining * @throws \SmartyException when an invalid class name is provided @@ -676,11 +667,11 @@ class Smarty_Security { if ($security_class instanceof Smarty_Security) { $smarty->security_policy = $security_class; - return; + return $smarty; } elseif (is_object($security_class)) { throw new SmartyException("Class '" . get_class($security_class) . "' must extend Smarty_Security."); } - if ($security_class == null) { + if ($security_class === null) { $security_class = $smarty->security_class; } if (!class_exists($security_class)) { @@ -690,8 +681,9 @@ class Smarty_Security } else { $smarty->security_policy = new $security_class($smarty); } - return; + return $smarty; } + /** * Start template processing * @@ -701,19 +693,18 @@ class Smarty_Security */ public function startTemplate($template) { - if ($this->max_template_nesting > 0 && $this->_current_template_nesting ++ >= $this->max_template_nesting) { + if ($this->max_template_nesting > 0 && $this->_current_template_nesting++ >= $this->max_template_nesting) { throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'"); } } /** * Exit template processing - * */ public function endTemplate() { if ($this->max_template_nesting > 0) { - $this->_current_template_nesting --; + $this->_current_template_nesting--; } } |