summaryrefslogtreecommitdiff
path: root/lib/smarty3/sysplugins/smarty_security.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/smarty3/sysplugins/smarty_security.php')
-rw-r--r--lib/smarty3/sysplugins/smarty_security.php293
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--;
}
}