Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/Compile/ModifierCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =

$modifier_params[0] = $output;
$params = implode(',', $modifier_params);
$securityPolicy = $compiler->getSmarty()->getSecurityPolicy();

if (!is_object($compiler->getSmarty()->security_policy)
|| $compiler->getSmarty()->security_policy->isTrustedModifier($modifier, $compiler)
if ($securityPolicy === null
|| $securityPolicy->isTrustedModifier($modifier, $compiler)
) {

if ($handler = $compiler->getModifierCompiler($modifier)) {
Expand Down
19 changes: 10 additions & 9 deletions src/Compile/SpecialVariableCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =
if ($variable === false) {
$compiler->trigger_template_error("special \$Smarty variable name index can not be variable", null, true);
}
if (!isset($compiler->getSmarty()->security_policy)
|| $compiler->getSmarty()->security_policy->isTrustedSpecialSmartyVar($variable, $compiler)
$securityPolicy = $compiler->getSmarty()->getSecurityPolicy();
if ($securityPolicy === null
|| $securityPolicy->isTrustedSpecialSmartyVar($variable, $compiler)
) {
switch ($variable) {
case 'foreach':
Expand All @@ -58,8 +59,8 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =
case 'now':
return 'time()';
case 'cookies':
if (isset($compiler->getSmarty()->security_policy)
&& !$compiler->getSmarty()->security_policy->allow_super_globals
if ($securityPolicy !== null
&& !$securityPolicy->allow_super_globals
) {
$compiler->trigger_template_error("(secure mode) super globals not permitted");
break;
Expand All @@ -72,8 +73,8 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =
case 'server':
case 'session':
case 'request':
if (isset($compiler->getSmarty()->security_policy)
&& !$compiler->getSmarty()->security_policy->allow_super_globals
if ($securityPolicy !== null
&& !$securityPolicy->allow_super_globals
) {
$compiler->trigger_template_error("(secure mode) super globals not permitted");
break;
Expand All @@ -83,7 +84,7 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =
case 'template':
return '$_smarty_tpl->template_resource';
case 'template_object':
if (isset($compiler->getSmarty()->security_policy)) {
if ($securityPolicy !== null) {
$compiler->trigger_template_error("(secure mode) template_object not permitted");
break;
}
Expand All @@ -93,8 +94,8 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =
case 'version':
return "\\Smarty\\Smarty::SMARTY_VERSION";
case 'const':
if (isset($compiler->getSmarty()->security_policy)
&& !$compiler->getSmarty()->security_policy->allow_constants
if ($securityPolicy !== null
&& !$securityPolicy->allow_constants
) {
$compiler->trigger_template_error("(secure mode) constants not permitted");
break;
Expand Down
15 changes: 8 additions & 7 deletions src/Compiler/Template.php
Original file line number Diff line number Diff line change
Expand Up @@ -606,8 +606,8 @@ public function processText($text) {
*/
public function getTagCompiler($tag): ?\Smarty\Compile\CompilerInterface {
$tag = strtolower($tag);

if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->isTrustedTag($tag, $this)) {
$securityPolicy = $this->smarty->getSecurityPolicy();
if ($securityPolicy !== null && !$securityPolicy->isTrustedTag($tag, $this)) {
return null;
}

Expand All @@ -628,8 +628,8 @@ public function getTagCompiler($tag): ?\Smarty\Compile\CompilerInterface {
* @return bool|\Smarty\Compile\Modifier\ModifierCompilerInterface tag compiler object or false if not found or untrusted by security policy
*/
public function getModifierCompiler($modifier) {

if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->isTrustedModifier($modifier, $this)) {
$securityPolicy = $this->smarty->getSecurityPolicy();
if ($securityPolicy !== null && !$securityPolicy->isTrustedModifier($modifier, $this)) {
return false;
}

Expand Down Expand Up @@ -1111,10 +1111,11 @@ private function compileTag2($tag, $args, $parameter) {
// $args contains the attributes parsed and compiled by the lexer/parser

$this->handleNocacheFlag($args);
$securityPolicy = $this->smarty->getSecurityPolicy();

// compile built-in tags
if ($tagCompiler = $this->getTagCompiler($tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) {
if ($securityPolicy === null || $securityPolicy->isTrustedTag($tag, $this)) {
$this->tag_nocache = $this->tag_nocache | !$tagCompiler->isCacheable();
$_output = $tagCompiler->compile($args, $this, $parameter);
if (!empty($parameter['modifierlist'])) {
Expand Down Expand Up @@ -1147,7 +1148,7 @@ private function compileTag2($tag, $args, $parameter) {

// check if tag is a function
if ($this->smarty->getFunctionHandler($tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) {
if ($securityPolicy === null || $securityPolicy->isTrustedTag($tag, $this)) {
return (new \Smarty\Compile\PrintExpressionCompiler())->compile(
['nofilter'], // functions are never auto-escaped
$this,
Expand All @@ -1158,7 +1159,7 @@ private function compileTag2($tag, $args, $parameter) {

// check if tag is a block
if ($this->smarty->getBlockHandler($base_tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($base_tag, $this)) {
if ($securityPolicy === null || $securityPolicy->isTrustedTag($base_tag, $this)) {
return $this->blockCompiler->compile($args, $this, $parameter, $tag, $base_tag);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Debug.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public function display_debug($obj, bool $full = false)
// copy the working dirs from application
$debObj->setCompileDir($smarty->getCompileDir());
$debObj->compile_check = Smarty::COMPILECHECK_ON;
$debObj->security_policy = null;
$debObj->setSecurityPolicy(null);
$debObj->debugging = false;
$debObj->debugging_ctrl = 'NONE';
$debObj->error_reporting = E_ALL & ~E_NOTICE;
Expand Down
7 changes: 4 additions & 3 deletions src/FunctionHandler/Fetch.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,16 @@ public function handle($params, Template $template) {
if ($protocol !== false) {
$protocol = strtolower(substr($params['file'], 0, $protocol));
}
if (isset($template->getSmarty()->security_policy)) {
$securityPolicy = $template->getSmarty()->getSecurityPolicy();
if ($securityPolicy !== null) {
if ($protocol) {
// remote resource (or php stream, …)
if (!$template->getSmarty()->security_policy->isTrustedUri($params['file'])) {
if (!$securityPolicy->isTrustedUri($params['file'])) {
return;
}
} else {
// local file
if (!$template->getSmarty()->security_policy->isTrustedResourceDir($params['file'])) {
if (!$securityPolicy->isTrustedResourceDir($params['file'])) {
return;
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/FunctionHandler/HtmlImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,16 @@ public function handle($params, Template $template) {
if ($protocol !== false) {
$protocol = strtolower(substr($params['file'], 0, $protocol));
}
if (isset($template->getSmarty()->security_policy)) {
$securityPolicy = $template->getSmarty()->getSecurityPolicy();
if ($securityPolicy !== null) {
if ($protocol) {
// remote resource (or php stream, …)
if (!$template->getSmarty()->security_policy->isTrustedUri($params['file'])) {
if (!$securityPolicy->isTrustedUri($params['file'])) {
return;
}
} else {
// local file
if (!$template->getSmarty()->security_policy->isTrustedResourceDir($_image_path)) {
if (!$securityPolicy->isTrustedResourceDir($_image_path)) {
return;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Parser/TemplateParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public function __construct(Lexer $lex, TemplateCompiler $compiler)
$this->compiler = $compiler;
$this->template = $this->compiler->getTemplate();
$this->smarty = $this->template->getSmarty();
$this->security = $this->smarty->security_policy ?? false;
$this->security = $this->smarty->getSecurityPolicy() ?? false;
$this->current_buffer = $this->root_buffer = new TemplateParseTree();
}

Expand Down
2 changes: 1 addition & 1 deletion src/Parser/TemplateParser.y
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class TemplateParser
$this->compiler = $compiler;
$this->template = $this->compiler->getTemplate();
$this->smarty = $this->template->getSmarty();
$this->security = $this->smarty->security_policy ?? false;
$this->security = $this->smarty->getSecurityPolicy() ?? false;
$this->current_buffer = $this->root_buffer = new TemplateParseTree();
}

Expand Down
5 changes: 3 additions & 2 deletions src/Resource/BasePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ public static function load(Smarty $smarty, $type)
$_known_stream = stream_get_wrappers();
if (in_array($type, $_known_stream)) {
// is known stream
if (is_object($smarty->security_policy)) {
$smarty->security_policy->isTrustedStream($type);
$securityPolicy = $smarty->getSecurityPolicy();
if ($securityPolicy !== null) {
$securityPolicy->isTrustedStream($type);
}
return $smarty->_resource_handlers[ $type ] = new StreamPlugin();
}
Expand Down
5 changes: 3 additions & 2 deletions src/Resource/FilePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ public function populate(Source $source, ?Template $_template = null) {
);

if ($path = $this->getFilePath($source->name, $source->getSmarty(), $source->isConfig)) {
if (isset($source->getSmarty()->security_policy) && is_object($source->getSmarty()->security_policy)) {
$source->getSmarty()->security_policy->isTrustedResourceDir($path, $source->isConfig);
$securityPolicy = $source->getSmarty()->getSecurityPolicy();
if ($securityPolicy !== null) {
$securityPolicy->isTrustedResourceDir($path, $source->isConfig);
}
$source->exists = true;
$source->timestamp = filemtime($path);
Expand Down
4 changes: 2 additions & 2 deletions src/Security.php
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ private function _checkDir($filepath, $dirs) {
*/
public static function enableSecurity(Smarty $smarty, $security_class) {
if ($security_class instanceof Security) {
$smarty->security_policy = $security_class;
$smarty->setSecurityPolicy($security_class);
return $smarty;
} elseif (is_object($security_class)) {
throw new Exception("Class '" . get_class($security_class) . "' must extend \\Smarty\\Security.");
Expand All @@ -521,7 +521,7 @@ public static function enableSecurity(Smarty $smarty, $security_class) {
} elseif ($security_class !== Security::class && !is_subclass_of($security_class, Security::class)) {
throw new Exception("Class '$security_class' must extend " . Security::class . ".");
} else {
$smarty->security_policy = new $security_class($smarty);
$smarty->setSecurityPolicy(new $security_class($smarty));
}
return $smarty;
}
Expand Down
50 changes: 47 additions & 3 deletions src/Smarty.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ class Smarty extends \Smarty\TemplateBase {
/**
* implementation of security class
*
* @var \Smarty\Security
* @var \Smarty\Security|null
*/
public $security_policy = null;
private $security_policy = null;

/**
* debug mode
Expand Down Expand Up @@ -594,10 +594,31 @@ public function enableSecurity($security_class = null) {
* @return static current Smarty instance for chaining
*/
public function disableSecurity() {
$this->security_policy = null;
$this->setSecurityPolicy(null);
return $this;
}

/**
* Set security policy
*
* @param \Smarty\Security|null $policy Security policy instance or null to disable
*
* @return static current Smarty instance for chaining
*/
public function setSecurityPolicy(?\Smarty\Security $policy) {
$this->security_policy = $policy;
return $this;
}

/**
* Get security policy
*
* @return \Smarty\Security|null Current security policy instance or null if disabled
*/
public function getSecurityPolicy(): ?\Smarty\Security {
return $this->security_policy;
}

/**
* Add template directory(s)
*
Expand Down Expand Up @@ -2231,5 +2252,28 @@ public function setCacheModifiedCheck($cache_modified_check): void {
$this->cache_modified_check = (bool) $cache_modified_check;
}

/**
* Backward compatibility for security_policy property assignment with type validation
*
* @param string $name Property name
* @param mixed $value Property value
*
* @return void
* @throws \Smarty\Exception if security_policy value is invalid
*/
public function __set($name, $value) {
if ($name === 'security_policy') {
if ($value !== null && !($value instanceof \Smarty\Security)) {
$given = is_object($value) ? get_class($value) : gettype($value);
throw new \Smarty\Exception(
'security_policy must be null or \Smarty\Security, ' . $given . ' given'
);
}
$this->setSecurityPolicy($value);
return;
}
$this->$name = $value;
}

}

5 changes: 3 additions & 2 deletions src/Template.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@ public function __construct(
$this->source = $_isConfig ? Config::load($this) : Source::load($this);
$this->compiled = Compiled::load($this);

if ($smarty->security_policy) {
$smarty->security_policy->registerCallBacks($this);
$securityPolicy = $smarty->getSecurityPolicy();
if ($securityPolicy !== null) {
$securityPolicy->registerCallBacks($this);
}
}

Expand Down
Loading