- added trusted stream checking to security

- internal changes at file dependency check for caching
This commit is contained in:
Uwe.Tews
2009-04-26 16:56:17 +00:00
parent 4f4f2d3dd3
commit c724b720be
9 changed files with 112 additions and 43 deletions

View File

@@ -1,3 +1,7 @@
04/26/2009
- added trusted stream checking to security
- internal changes at file dependency check for caching
04/24/2009
- changed name of {template} tag to {function}
- added new {template} tag

View File

@@ -47,6 +47,13 @@ define('SMARTY_PARENT_SCOPE', 1);
define('SMARTY_ROOT_SCOPE', 2);
define('SMARTY_GLOBAL_SCOPE', 3);
/**
* define caching modes
*/
define('SMARTY_CACHING_OFF', 0);
define('SMARTY_CACHING_LIFETIME_CURRENT', 1);
define('SMARTY_CACHING_LIVETIME_SAVED', 2);
/**
* load required base class for creation of the smarty object
*/
@@ -111,7 +118,7 @@ class Smarty extends Smarty_Internal_TemplateBase {
// config var settings
public $config_overwrite = true; //Controls whether variables with the same name overwrite each other.
public $config_booleanize = true; //Controls whether config values of on/true/yes and off/false/no get converted to boolean
public $config_read_hidden = true; //Controls whether hidden config sections/vars are read from the file.
public $config_read_hidden = true; //Controls whether hidden config sections/vars are read from the file.
// config vars
public $config_vars = array();
// assigned tpl vars
@@ -172,9 +179,9 @@ class Smarty extends Smarty_Internal_TemplateBase {
* Class constructor, initializes basic smarty properties
*/
public function __construct()
{
{
// set instance object
self::instance($this);
self::instance($this);
if (is_callable('mb_internal_encoding')) {
$this->has_mb = true;
@@ -204,7 +211,11 @@ class Smarty extends Smarty_Internal_TemplateBase {
$this->loadPlugin('Smarty_Internal_Run_Filter');
$this->filter_handler = new Smarty_Internal_Run_Filter;
if (!$this->debugging && $this->debugging_ctrl == 'URL') {
$_query_string = $this->request_use_auto_globals ? isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING']:'' : isset($GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']) ? $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']:'';
if (isset($_SERVER['QUERY_STRING'])) {
$_query_string = $_SERVER['QUERY_STRING'];
} else {
$_query_string = '';
}
if (false !== strpos($_query_string, $this->smarty_debug_id)) {
if (false !== strpos($_query_string, $this->smarty_debug_id . '=on')) {
// enable debugging for this browser session

View File

@@ -65,6 +65,15 @@ class Smarty_Security_Policy {
* @var array
*/
public $modifiers = array('escape','count');
/**
* This is an array of trusted streams.
*
* If empty all streams are allowed.
* If set to 'none' none is allowed.
* @var array
*/
public $streams = array('file');
/**
+ flag if constants can be accessed from template
*/

View File

@@ -44,7 +44,8 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
$_parent_scope = SMARTY_GLOBAL_SCOPE;
}
}
// default for included templates
$_caching = SMARTY_CACHING_OFF;
/*
* if the {include} tag provides individual parameter for caching
* it will not be included into the common cache file and treated like
@@ -56,21 +57,14 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
}
if (isset($_attr['nocache'])) {
if ($_attr['nocache'] == 'true') {
$_caching = 'false';
$this->compiler->tag_nocache = true;
}
}
if (isset($_attr['caching'])) {
if ($_attr['caching'] == 'true') {
$_caching = 'true';
$_caching = SMARTY_CACHING_LIFETIME_CURRENT;
}
}
// if ($this->compiler->tag_nocache == false) {
// save file dependency
// $compiler->template->properties['file_dependency'][] = array($_template->getTemplateFilepath(), $_template->getTemplateTimestamp());
// unset ($_template);
// }
// create template object
$_output = "<?php \$_template = new Smarty_Template ($include_file, \$_smarty_tpl, \$_smarty_tpl->cache_id, \$_smarty_tpl->compile_id);";
// delete {include} standard attributes
@@ -90,11 +84,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
if (isset($_caching_lifetime)) {
$_output .= "\$_template->caching_lifetime = $_caching_lifetime;";
}
if (isset($_caching)) {
$_output .= "\$_template->caching = $_caching;";
} elseif (isset($_caching_lifetime)) {
$_output .= "\$_template->caching = true;";
}
$_output .= "\$_template->caching = $_caching;";
// was there an assign attribute
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign($_assign,\$_smarty_tpl->smarty->fetch(\$_template)); ?>";

View File

@@ -1,20 +1,20 @@
<?php
/**
* Smarty Internal Plugin Compile Internalfunctioncall
* Smarty Internal Plugin Compile Internal_Function_Call
*
* Compiles the {internalfunctioncall} tag
* Compiles the {internal_function_call} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Internalfunctioncall Class
* Smarty Internal Plugin Compile Internal_Function_Call Class
*/
class Smarty_Internal_Compile_Internalfunctioncall extends Smarty_Internal_CompileBase {
class Smarty_Internal_Compile_Internal_Function_Call extends Smarty_Internal_CompileBase {
/**
* Compiles code for the {internalfunctioncall} tag
* Compiles code for the {internal_function_call} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
@@ -31,8 +31,8 @@ class Smarty_Internal_Compile_Internalfunctioncall extends Smarty_Internal_Compi
if (isset($_attr['assign'])) {
// output will be stored in a smarty variable instead of beind displayed
$_assign = $_attr['assign'];
}
$_name = trim( $_attr['name'],"'");
}
$_name = trim($_attr['name'], "'");
// create template object
$_output = "<?php \$_template = new Smarty_Template ('string:', \$_smarty_tpl);\n";
// assign default paramter
@@ -51,14 +51,14 @@ class Smarty_Internal_Compile_Internalfunctioncall extends Smarty_Internal_Compi
foreach ($_attr as $_key => $_value) {
$_output .= "\$_template->assign('$_key',$_value);\n";
}
}
}
if (isset($compiler->template->properties['function'][$_name]['compiled'])) {
$_compiled = str_replace(array('_%n',"'"), array("\n","\'"), $compiler->template->properties['function'][$_name]['compiled']);
$_compiled = str_replace(array('_%n', "'"), array("\n", "\'"), $compiler->template->properties['function'][$_name]['compiled']);
$_output .= "\$_template->compiled_template = '$_compiled';\n \$_template->mustCompile = false;\n";
} else {
// for recursion
// for recursion
$_output .= "\$_template->compiled_template = \$_smarty_tpl->compiled_template;\n \$_template->mustCompile = false;\n";
}
}
// was there an assign attribute
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign($_assign,\$_smarty_tpl->smarty->fetch(\$_template)); ?>";

View File

@@ -18,8 +18,7 @@ class Smarty_Internal_Debug extends Smarty_Internal_TemplateBase {
*/
public function display_debug()
{
$this->smarty = Smarty::instance();
$this->smarty = Smarty::instance();
// get template names
$i = 0;
$_template_data = array();
@@ -32,6 +31,15 @@ class Smarty_Internal_Debug extends Smarty_Internal_TemplateBase {
$_template_data[$i]['render_time'] = $_template_obj->render_time;
$_template_data[$i]['cache_time'] = $_template_obj->cache_time;
$i++;
if (false && $i == 1) {
foreach ($_template_obj->properties['file_dependency'] as $_file) {
$_template_data[$i]['name'] = $_file[0];
$_template_data[$i]['compile_time'] = 0;
$_template_data[$i]['render_time'] = 0;
$_template_data[$i]['cache_time'] = 0;
$i++;
}
}
}
}
}

View File

@@ -10,7 +10,6 @@
* This class contains all methods for security checking
*/
class Smarty_Internal_Security_Handler extends Smarty_Internal_Base {
/**
* Check if PHP function is trusted.
*
@@ -44,6 +43,22 @@ class Smarty_Internal_Security_Handler extends Smarty_Internal_Base {
return false;
}
}
/**
* Check if stream is trusted.
*
* @param string $stream_name
* @param object $compiler compiler object
* @return boolean true if stream is trusted
*/
function isTrustedStream($stream_name)
{
if (empty($this->smarty->security_policy->streams) || in_array($stream_name, $this->smarty->security_policy->streams)) {
return true;
} else {
throw new Exception ("stream \"" . $stream_name . "\" not allowed by security setting");
return false;
}
}
/**
* Check if directory of file resource is trusted.
@@ -70,7 +85,7 @@ class Smarty_Internal_Security_Handler extends Smarty_Internal_Base {
if ($_cd == $_rp) {
return true;
} elseif (strncmp($_rp, $_cd, strlen($_cd)) == 0 &&
(strlen($_rp) == strlen($_cd) || substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR)) {
(strlen($_rp) == strlen($_cd) || substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR)) {
return true;
}
}
@@ -90,7 +105,7 @@ class Smarty_Internal_Security_Handler extends Smarty_Internal_Base {
function isTrustedPHPDir($filepath)
{
$_rp = realpath($filepath);
if (!empty($this->smarty->security_policy->trusted_dir)) {
if (!empty($this->smarty->security_policy->trusted_dir)) {
foreach ((array)$this->smarty->security_policy->trusted_dir as $curr_dir) {
if (($_cd = realpath($curr_dir)) !== false) {
if ($_cd == $_rp) {

View File

@@ -89,7 +89,8 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
$this->caching_type = $this->smarty->default_caching_type;
$this->security = $this->smarty->security;
$this->cache_resource_class = 'Smarty_Internal_CacheResource_' . ucfirst($this->caching_type);
$this->parent = $_parent;
$this->parent = $_parent;
$this->properties['file_dependency'] = array();
// Template resource
$this->template_resource = $template_resource;
// parse resource name
@@ -286,7 +287,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
if ($this->compiler_object->compileTemplate($this)) {
// compiling succeded
if (!$this->isEvaluated()) {
// build file dependency string
// build template property string
$this->properties_string = '<?php /*' . serialize($this->properties) . "*/ ?>\n";
// write compiled template
$this->smarty->write_file_object->writeFile($this->getCompiledFilepath(), $this->properties_string . $this->dir_acc_sec_string . $this->getCompiledTemplate());
@@ -298,7 +299,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
throw new Exception("Error compiling template {$this->getTemplateFilepath ()}");
return false;
}
$this->compile_time = $this->_get_time() - $_start_time;
$this->compile_time += $this->_get_time() - $_start_time;
}
/**
@@ -347,6 +348,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
public function writeCachedContent ()
{
// build file dependency string
$this->properties['caching_lifetime'] = $this->caching_lifetime;
$this->properties_string = '<?php /*' . serialize($this->properties) . "*/ ?>\n";
$this->rendered_content = $this->properties_string . $this->dir_acc_sec_string . $this->rendered_content;
return ($this->isEvaluated() || !$this->caching) ? false : $this->cacher_object->writeCachedContent($this);
@@ -363,9 +365,29 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
{
if ($this->isCached === null) {
$this->isCached = false;
if ($this->caching && !$this->isEvaluated()) {
if (!$this->mustCompile() && $this->getTemplateTimestamp() <= $this->getCachedTimestamp() && ((time() <= $this->getCachedTimestamp() + $this->caching_lifetime) || $this->caching_lifetime < 0)) {
if ($this->caching && !$this->isEvaluated() && !$this->force_compile) {
if ($this->getCachedTimestamp() === false) {
return $this->isCached;
}
if (/*$this->getTemplateTimestamp() <= $this->getCachedTimestamp() && */
($this->caching == SMARTY_CACHING_LIVETIME_SAVED || ($this->caching == SMARTY_CACHING_LIFETIME_CURRENT && (time() <= ($this->getCachedTimestamp() + $this->caching_lifetime) || $this->caching_lifetime < 0)))) {
$this->rendered_content = $this->cacher_object->getCachedContents($this);
$_found = preg_match('~\<\?php /\*(.*)\*/ \?\>~', $this->rendered_content, $_matches);
if ($_found) {
$this->properties = unserialize($_matches[1]);
if ($this->caching == SMARTY_CACHING_LIVETIME_SAVED && (time() > ($this->getCachedTimestamp() + $this->properties['caching_lifetime']) || $this->properties['caching_lifetime'] < 0)) {
$this->rendered_content = null;
return $this->isCached;
}
if (!empty($this->properties['file_dependency'])) {
foreach ($this->properties['file_dependency'] as $file_to_check) {
If (filemtime($file_to_check[0]) > $this->getCachedTimestamp()) {
$this->rendered_content = null;
return $this->isCached;
}
}
}
}
$this->isCached = true;
}
}
@@ -415,10 +437,17 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
// include PHP template
include($this->getTemplateFilepath ());
}
$this->render_time = $this->_get_time() - $_start_time;
$this->rendered_content = ob_get_clean();
$this->render_time += $this->_get_time() - $_start_time;
$this->rendered_content = ob_get_clean();
if (!$this->isEvaluated) {
$this->properties['file_dependency'][] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp());
}
if ($this->parent instanceof Smarty_Template or $this->parent instanceof Smarty_Internal_Template) {
$this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']);
}
// write to cache when nessecary
if (!$this->isEvaluated() && $this->caching) {
$this->properties['file_dependency'] = array_unique($this->properties['file_dependency']);
// write rendered template
$this->writeCachedContent($this);
}
@@ -452,7 +481,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
ob_start();
eval("?>" . $this->rendered_content);
$this->updateParentVariables();
$this->cache_time = $this->_get_time() - $_start_time;
$this->cache_time += $this->_get_time() - $_start_time;
return (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))?
$this->smarty->filter_handler->execute('output', ob_get_clean()) : ob_get_clean();
} else {
@@ -502,6 +531,9 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase {
$_known_stream = stream_get_wrappers();
if (in_array($this->resource_type, $_known_stream)) {
// is known stream
if ($this->smarty->security) {
$this->smarty->security_handler->isTrustedStream($this->resource_type);
}
if (!isset($this->resource_objects['stream'])) {
$this->smarty->loadPlugin('Smarty_Internal_Resource_Stream');
$this->resource_objects['stream'] = new Smarty_Internal_Resource_Stream;

View File

@@ -115,7 +115,7 @@ class Smarty_Internal_TemplateCompilerBase extends Smarty_Internal_Base {
if (isset($this->template->properties['function'][$tag])) {
// template defined by {template} tag
$args['name'] = $tag;
$tag = 'internalfunctioncall';
$tag = 'internal_function_call';
}
if (!($_output = $this->$tag($args, $this)) === false) {
if ($_output !== true) {