- update for security fixes

- make modifier plugins always trusted
This commit is contained in:
Uwe.Tews
2009-12-28 15:27:13 +00:00
parent f908aa0a27
commit de4957a151
6 changed files with 70 additions and 46 deletions

View File

@@ -1,3 +1,7 @@
12/28/2009
- update for security fixes
- make modifier plugins always trusted
12/27/2009
--- this is a major update with a couple of internal changes ---
- new config file lexer/parser (thanks to Thue Jnaus Kristensen)

View File

@@ -68,7 +68,6 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase {
$_tpl->forceNocache = true;
$_tpl->suppressHeader = true;
$_tpl->suppressFileDependency = true;
if (strpos($this->smarty->block_data[$_name]['source'], '%%%%SMARTY_PARENT%%%%') !== false) {
$_output = str_replace('%%%%SMARTY_PARENT%%%%', $compiler->template->extracted_compiled_code, $_tpl->getCompiledTemplate());
} elseif ($this->smarty->block_data[$_name]['mode'] == 'prepend') {
@@ -78,7 +77,8 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase {
} elseif (!empty($this->smarty->block_data[$_name])) {
$_output = $_tpl->getCompiledTemplate();
}
$compiler->template->properties = array_merge_recursive($compiler->template->properties, $_tpl->properties);
$compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $_tpl->properties['file_dependency']);
$compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $_tpl->properties['function']);
unset($_tpl);
} else {
$_output = $compiler->template->extracted_compiled_code;

View File

@@ -46,7 +46,9 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
// get compiled code
$compiled_tpl = $tpl->getCompiledTemplate();
// remove header code
$compiled_tpl = preg_replace('/(<\?php \/\*%%SmartyHeaderCode%%\*\/(.+?)\/\*\/%%SmartyHeaderCode%%\*\/\?>\n)/s', '', $compiled_tpl);
$compiled_tpl = preg_replace("/(<\?php \/\*%%SmartyHeaderCode:{$tpl->properties['nocache_hash']}%%\*\/(.+?)\/\*\/%%SmartyHeaderCode%%\*\/\?>\n)/s", '', $compiled_tpl);
// replace nocache_hash
$compiled_tpl = preg_replace("/{$tpl->properties['nocache_hash']}/", $compiler->template->properties['nocache_hash'], $compiled_tpl);
$has_compiled_template = true;
}
}

View File

@@ -26,32 +26,33 @@ class Smarty_Internal_Compile_Private_Modifier extends Smarty_Internal_CompileBa
$this->required_attributes = array('modifier', 'params');
// check and get attributes
$_attr = $this->_get_attributes($args);
// check if modifier allowed
if (!$this->compiler->template->security || $this->smarty->security_handler->isTrustedModifier($_attr['modifier'], $this->compiler)) {
// check for registered or plugin modifier
if (isset($compiler->smarty->registered_plugins['modifier'][$_attr['modifier']])) {
$function = $compiler->smarty->registered_plugins['modifier'][$_attr['modifier']][0];
if (!is_array($function)) {
$output = "{$function}({$_attr['params']})";
} else if (is_object($function[0])) {
$output = 'call_user_func_array($_smarty_tpl->smarty->registered_plugins[\'modifier\'][\'' . $_attr['modifier'] . '\'][0],array(' . $_attr['params'] . '))';
} else {
$output = 'call_user_func_array(array(\'' . $function[0] . '\',\'' . $function[1] . '\'),array(' . $_attr['params'] . '))';
}
} else if ($function = $this->compiler->getPlugin($_attr['modifier'], 'modifier')) {
if (!is_array($function)) {
$output = "{$function}({$_attr['params']})";
} else {
$output = 'call_user_func_array(array(\'' . $function[0] . '\',\'' . $function[1] . '\'),array(' . $_attr['params'] . '))';
}
// check if trusted PHP function
} else if (is_callable($_attr['modifier'])) {
$output = "{$_attr['modifier']}({$_attr['params']})";
// check for registered modifier
if (isset($compiler->smarty->registered_plugins['modifier'][$_attr['modifier']])) {
$function = $compiler->smarty->registered_plugins['modifier'][$_attr['modifier']][0];
if (!is_array($function)) {
$output = "{$function}({$_attr['params']})";
} else if (is_object($function[0])) {
$output = 'call_user_func_array($_smarty_tpl->smarty->registered_plugins[\'modifier\'][\'' . $_attr['modifier'] . '\'][0],array(' . $_attr['params'] . '))';
} else {
$this->compiler->trigger_template_error ("unknown modifier \"" . $_attr['modifier'] . "\"");
$output = 'call_user_func_array(array(\'' . $function[0] . '\',\'' . $function[1] . '\'),array(' . $_attr['params'] . '))';
}
return $output;
// check for plugin modifier
} else if ($function = $this->compiler->getPlugin($_attr['modifier'], 'modifier')) {
if (!is_array($function)) {
$output = "{$function}({$_attr['params']})";
} else {
$output = 'call_user_func_array(array(\'' . $function[0] . '\',\'' . $function[1] . '\'),array(' . $_attr['params'] . '))';
}
// check if trusted PHP function
} else if (is_callable($_attr['modifier'])) {
// check if modifier allowed
if (!$this->compiler->template->security || $this->smarty->security_handler->isTrustedModifier($_attr['modifier'], $this->compiler)) {
$output = "{$_attr['modifier']}({$_attr['params']})";
}
} else {
$this->compiler->trigger_template_error ("unknown modifier \"" . $_attr['modifier'] . "\"");
}
return $output;
}
}

View File

@@ -61,7 +61,7 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
// storage for plugin
public $plugin_data = array();
// special properties
public $properties = array();
public $properties = null;
// storage for block data
public $block_data = array();
// required plugins
@@ -91,7 +91,9 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
$this->force_cache = $this->smarty->force_cache;
$this->security = $this->smarty->security;
$this->parent = $_parent;
$this->properties['file_dependency'] = array();
$this->properties['file_dependency'] = array();
$this->properties['nocache_hash'] = '';
$this->properties['function'] = array();;
// dummy local smarty variable
$this->tpl_vars['smarty'] = new Smarty_Variable;
// Template resource
@@ -329,19 +331,21 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
return false;
}
// build file dependency string
$this->properties['cache_lifetime'] = $this->cache_lifetime;
$this->properties['cache_lifetime'] = $this->cache_lifetime;
// get text between non-cached items
$cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s",$this->rendered_content);
$cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content);
// get non-cached items
preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s",$this->rendered_content,$cache_parts);
$output = '';
preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content, $cache_parts);
$output = '';
// loop over items, stitch back together
foreach($cache_split as $curr_idx => $curr_split) {
// escape PHP tags in template content
$output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php echo \'$1\'; ?>', $curr_split);
// remove nocache tags from cache output
$output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!",'',$cache_parts[0][$curr_idx]);
}
// escape PHP tags in template content
$output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php echo \'$1\'; ?>', $curr_split);
if (isset($cache_parts[0][$curr_idx])) {
// remove nocache tags from cache output
$output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);
}
}
return $this->cache_resource_object->writeCachedContent($this, $this->createPropertyHeader(true) . $output);
}
@@ -489,6 +493,12 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
if ($this->smarty->debugging) {
Smarty_Internal_Debug::end_cache($this);
}
} else {
if (!empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
// replace nocache_hash
// var_dump($this->properties['nocache_hash'],$this->parent->properties['nocache_hash'],$this->rendered_content);
$this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
}
}
}
@@ -711,9 +721,12 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
*/
public function createPropertyHeader ($cache = false)
{
$directory_security = $this->smarty->direct_access_security ? "<?php /*%%SmartyHeaderCode%%*/ if(!defined('SMARTY_DIR')) exit('no direct access allowed'); /*/%%SmartyHeaderCode%%*/?>\n" : '';
// $properties_string = "<?php \$_smarty_tpl->decodeProperties(" . preg_replace('/\s*/', '',var_export($this->properties, true)) . "); ? >\n";
$properties_string = "<?php /*%%SmartyHeaderCode%%*/ \$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n";
$this->properties['fullpath'] = realpath($this->getTemplateFilepath());
$properties_string = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/" ;
if ($this->smarty->direct_access_security) {
$properties_string .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n";
}
$properties_string .= "\$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n";
$plugins_string = '';
if (!$cache) {
if (!empty($this->required_plugins['compiled'])) {
@@ -725,15 +738,15 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
$plugins_string .= '?>';
}
if (!empty($this->required_plugins['cache'])) {
$plugins_string .= '<?php echo \'/*%%SmartyNocache%%*/<?php ';
$plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php ";
foreach($this->required_plugins['cache'] as $plugin_name => $data) {
$plugin = 'smarty_' . $data['type'] . '_' . $plugin_name;
$plugins_string .= "if (!is_callable(\'{$plugin}\')) include \'{$data['file']}\';\n";
}
$plugins_string .= "?>/*/%%SmartyNocache%%*/';?>\n";
$plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
}
}
return $directory_security . $properties_string . $plugins_string;
return $properties_string . $plugins_string;
}
/**
@@ -741,6 +754,10 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
*/
public function decodeProperties ($properties)
{
// if ($properties['fullpath'] != realpath($this->getTemplateFilepath())) {
// throw new Exception('CRC32 collision \'' . $properties['fullpath'] . '\'');
// } ;
$this->properties['nocache_hash'] = $properties['nocache_hash'];
if (isset($properties['cache_lifetime'])) {
$this->properties['cache_lifetime'] = $properties['cache_lifetime'];
}

View File

@@ -28,7 +28,7 @@ class Smarty_Internal_TemplateCompilerBase {
*/
public function __construct()
{
$this->nocache_hash = md5(uniqid(rand(),true));
$this->nocache_hash = uniqid(rand(),true);
}
// abstract function doCompile($_content);
/**
@@ -275,7 +275,7 @@ class Smarty_Internal_TemplateCompilerBase {
$this->template->required_plugins['compiled'][$plugin_name] = $this->template->required_plugins['compiled'][$plugin_name];
}
}
if ($type = 'modifier') {
if ($type == 'modifier') {
$this->template->saved_modifer[$plugin_name] = true;
}
return $this->template->required_plugins_call[$plugin_name][$type];
@@ -301,7 +301,7 @@ class Smarty_Internal_TemplateCompilerBase {
$this->template->required_plugins['compiled'][$plugin_name]['file'] = $file;
$this->template->required_plugins['compiled'][$plugin_name]['type'] = $type;
}
if ($type = 'modifier') {
if ($type == 'modifier') {
$this->template->saved_modifer[$plugin_name] = true;
}