0
0
mirror of https://github.com/postfixadmin/postfixadmin.git synced 2024-09-19 19:22:14 +02:00

bump smarty to 4.5.3 (the smarty release is regarded as a security fix ( CVE-2024-35226 ). PostfixAdmin should not be vulnerable as it does not use the extends tag.

This commit is contained in:
David Goodwin 2024-06-09 10:20:44 +01:00
parent 37fe4d993a
commit 2694adbc27
No known key found for this signature in database
27 changed files with 145 additions and 105 deletions

View File

@ -107,7 +107,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/**
* smarty version
*/
const SMARTY_VERSION = '4.3.0';
const SMARTY_VERSION = '4.5.3';
/**
* define variable scopes
*/
@ -1386,8 +1386,7 @@ class Smarty extends Smarty_Internal_TemplateBase
}
/**
* Activates PHP7 compatibility mode:
* - converts E_WARNINGS for "undefined array key" and "trying to read property of null" errors to E_NOTICE
* Mutes errors for "undefined index", "undefined array key" and "trying to read property of null".
*
* @void
*/
@ -1396,7 +1395,7 @@ class Smarty extends Smarty_Internal_TemplateBase
}
/**
* Indicates if PHP7 compatibility mode is set.
* Indicates if Smarty will mute errors for "undefined index", "undefined array key" and "trying to read property of null".
* @bool
*/
public function isMutingUndefinedOrNullWarnings(): bool {

View File

@ -167,9 +167,7 @@
</html>
{/capture}
<script type="text/javascript">
{$id = '__Smarty__'}
{if $display_mode}{$id = "$offset$template_name"|md5}{/if}
_smarty_console = window.open("", "console{$id}", "width=1024,height=600,left={$offset},top={$offset},resizable,scrollbars=yes");
_smarty_console = window.open("", "console{$targetWindow}", "width=1024,height=600,left={$offset},top={$offset},resizable,scrollbars=yes");
_smarty_console.document.write("{$debug_output|escape:'javascript' nofilter}");
_smarty_console.document.close();
</script>

View File

@ -67,7 +67,7 @@ function smarty_function_math($params, $template)
$equation = preg_replace('/\s+/', '', $equation);
// Adapted from https://www.php.net/manual/en/function.eval.php#107377
$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
$number = '-?(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
$functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
$operators = '[,+\/*\^%-]'; // Allowed math operators
$regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)*\)|\((?1)*\)))(?:'.$operators.'(?1))?)+$/';

View File

@ -115,7 +115,9 @@ function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $
// see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements
'<!--' => '<\!--',
'<s' => '<\s',
'<S' => '<\S'
'<S' => '<\S',
"`" => "\\\\`",
"\${" => "\\\\\\$\\{"
)
);
case 'mail':

View File

@ -0,0 +1,15 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifier
*/
function smarty_modifier_implode($values, $separator = '')
{
if (is_array($separator)) {
return implode((string) ($values ?? ''), (array) $separator);
}
return implode((string) ($separator ?? ''), (array) $values);
}

View File

@ -26,7 +26,7 @@
*/
function smarty_modifier_truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false)
{
if ($length === 0) {
if ($length === 0 || $string === null) {
return '';
}
if (Smarty::$_MBSTRING) {

View File

@ -25,8 +25,8 @@ function smarty_modifiercompiler_count_characters($params)
return 'preg_match_all(\'/[^\s]/' . Smarty::$_UTF8_MODIFIER . '\',' . $params[ 0 ] . ', $tmp)';
}
if (Smarty::$_MBSTRING) {
return 'mb_strlen(' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
return 'mb_strlen((string) ' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
}
// no MBString fallback
return 'strlen(' . $params[ 0 ] . ')';
return 'strlen((string) ' . $params[ 0 ] . ')';
}

View File

@ -27,5 +27,5 @@ function smarty_modifiercompiler_count_words($params)
$params[ 0 ] . ', $tmp)';
}
// no MBString fallback
return 'str_word_count(' . $params[ 0 ] . ')';
return 'str_word_count((string) ' . $params[ 0 ] . ')';
}

View File

@ -64,7 +64,9 @@ function smarty_modifiercompiler_escape($params, Smarty_Internal_TemplateCompile
// see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements
return 'strtr((string)' .
$params[ 0 ] .
', array("\\\\" => "\\\\\\\\", "\'" => "\\\\\'", "\"" => "\\\\\"", "\\r" => "\\\\r", "\\n" => "\\\n", "</" => "<\/", "<!--" => "<\!--", "<s" => "<\s", "<S" => "<\S" ))';
', array("\\\\" => "\\\\\\\\", "\'" => "\\\\\'", "\"" => "\\\\\"", "\\r" => "\\\\r",
"\\n" => "\\\n", "</" => "<\/", "<!--" => "<\!--", "<s" => "<\s", "<S" => "<\S",
"`" => "\\\\`", "\${" => "\\\\\\$\\{"))';
}
} catch (SmartyException $e) {
// pass through to regular plugin fallback

View File

@ -0,0 +1,11 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
function smarty_modifiercompiler_json_encode($params) {
return 'json_encode(' . $params[0] . (isset($params[1]) ? ', (int) ' . $params[1] : '') . ')';
}

View File

@ -22,8 +22,8 @@
function smarty_modifiercompiler_lower($params)
{
if (Smarty::$_MBSTRING) {
return 'mb_strtolower(' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
return 'mb_strtolower((string) ' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
}
// no MBString fallback
return 'strtolower(' . $params[ 0 ] . ')';
return 'strtolower((string) ' . $params[ 0 ] . ')';
}

View File

@ -21,7 +21,7 @@
function smarty_modifiercompiler_strip_tags($params)
{
if (!isset($params[ 1 ]) || $params[ 1 ] === true || trim($params[ 1 ], '"') === 'true') {
return "preg_replace('!<[^>]*?>!', ' ', {$params[0]} ?: '')";
return "preg_replace('!<[^>]*?>!', ' ', (string) {$params[0]})";
} else {
return 'strip_tags((string) ' . $params[ 0 ] . ')';
}

View File

@ -0,0 +1,12 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
function smarty_modifiercompiler_substr($params) {
return 'substr((string) ' . $params[0] . ', (int) ' . $params[1] .
(isset($params[2]) ? ', (int) ' . $params[2] : '') . ')';
}

View File

@ -21,8 +21,8 @@
function smarty_modifiercompiler_upper($params)
{
if (Smarty::$_MBSTRING) {
return 'mb_strtoupper(' . $params[ 0 ] . ' ?? \'\', \'' . addslashes(Smarty::$_CHARSET) . '\')';
return 'mb_strtoupper((string) ' . $params[ 0 ] . ' ?? \'\', \'' . addslashes(Smarty::$_CHARSET) . '\')';
}
// no MBString fallback
return 'strtoupper(' . $params[ 0 ] . ' ?? \'\')';
return 'strtoupper((string) ' . $params[ 0 ] . ' ?? \'\')';
}

View File

@ -62,7 +62,7 @@ function smarty_outputfilter_trimwhitespace($source)
}
}
$expressions = array(// replace multiple spaces between tags by a single space
// can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements
// can't remove them entirely, because that might break poorly implemented CSS display:inline-block elements
'#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2',
// remove spaces between attributes (but not in attribute values!)
'#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',

View File

@ -20,7 +20,7 @@
function smarty_function_escape_special_chars($string)
{
if (!is_array($string)) {
$string = htmlspecialchars($string, ENT_COMPAT, Smarty::$_CHARSET, false);
$string = htmlspecialchars((string) $string, ENT_COMPAT, Smarty::$_CHARSET, false);
}
return $string;
}

View File

@ -15,5 +15,5 @@
*/
function smarty_variablefilter_htmlspecialchars($source, Smarty_Internal_Template $template)
{
return htmlspecialchars($source, ENT_QUOTES, Smarty::$_CHARSET);
return htmlspecialchars((string) $source, ENT_QUOTES, Smarty::$_CHARSET);
}

View File

@ -30,7 +30,7 @@ class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inh
*
* @var array
*/
public $optional_attributes = array('extends_resource');
public $optional_attributes = array();
/**
* Attribute definition: Overwrites base class.
@ -62,29 +62,7 @@ class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inh
}
// add code to initialize inheritance
$this->registerInit($compiler, true);
$file = trim($_attr[ 'file' ], '\'"');
if (strlen($file) > 8 && substr($file, 0, 8) === 'extends:') {
// generate code for each template
$files = array_reverse(explode('|', substr($file, 8)));
$i = 0;
foreach ($files as $file) {
if ($file[ 0 ] === '"') {
$file = trim($file, '".');
} else {
$file = "'{$file}'";
}
$i++;
if ($i === count($files) && isset($_attr[ 'extends_resource' ])) {
$this->compileEndChild($compiler);
}
$this->compileInclude($compiler, $file);
}
if (!isset($_attr[ 'extends_resource' ])) {
$this->compileEndChild($compiler);
}
} else {
$this->compileEndChild($compiler, $_attr[ 'file' ]);
}
$this->compileEndChild($compiler, $_attr[ 'file' ]);
$compiler->has_code = false;
return '';
}
@ -115,44 +93,4 @@ class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inh
'') . ");\n?>"
);
}
/**
* Add code for including subtemplate to end of template
*
* @param \Smarty_Internal_TemplateCompilerBase $compiler
* @param string $template subtemplate name
*
* @throws \SmartyCompilerException
* @throws \SmartyException
*/
private function compileInclude(Smarty_Internal_TemplateCompilerBase $compiler, $template)
{
$compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag(
$compiler->parser,
$compiler->compileTag(
'include',
array(
$template,
array('scope' => 'parent')
)
)
);
}
/**
* Create source code for {extends} from source components array
*
* @param \Smarty_Internal_Template $template
*
* @return string
*/
public static function extendsSourceArrayCode(Smarty_Internal_Template $template)
{
$resources = array();
foreach ($template->source->components as $source) {
$resources[] = $source->resource;
}
return $template->smarty->left_delimiter . 'extends file=\'extends:' . join('|', $resources) .
'\' extends_resource=true' . $template->smarty->right_delimiter;
}
}

View File

@ -109,9 +109,11 @@ class Smarty_Internal_Compile_Private_Modifier extends Smarty_Internal_CompileBa
if (!is_object($compiler->smarty->security_policy)
|| $compiler->smarty->security_policy->isTrustedPhpModifier($modifier, $compiler)
) {
trigger_error('Using php-function "' . $modifier . '" as a modifier is deprecated and will be ' .
'removed in a future release. Use Smarty::registerPlugin to explicitly register ' .
'a custom modifier.', E_USER_DEPRECATED);
if (!in_array($modifier, ['time', 'join', 'is_array', 'in_array'])) {
trigger_error('Using unregistered function "' . $modifier . '" in a template is deprecated and will be ' .
'removed in a future release. Use Smarty::registerPlugin to explicitly register ' .
'a custom modifier.', E_USER_DEPRECATED);
}
$output = "{$modifier}({$params})";
}
$compiler->known_modifier_type[ $modifier ] = $type;

View File

@ -93,7 +93,7 @@ class Smarty_Internal_Compile_Private_Print_Expression extends Smarty_Internal_C
}
// autoescape html
if ($compiler->template->smarty->escape_html) {
$output = "htmlspecialchars((string) {$output}, ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')";
$output = "htmlspecialchars((string) ({$output}), ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')";
}
// loop over registered filters
if (!empty($compiler->template->smarty->registered_filters[ Smarty::FILTER_VARIABLE ])) {

View File

@ -238,9 +238,12 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data
$_config_vars = $ptr->config_vars;
ksort($_config_vars);
$debugging = $smarty->debugging;
$templateName = $obj->source->type . ':' . $obj->source->name;
$displayMode = $debugging === 2 || !$full;
$offset = $this->offset * 50;
$_template = new Smarty_Internal_Template($debObj->debug_tpl, $debObj);
if ($obj->_isTplObj()) {
$_template->assign('template_name', $obj->source->type . ':' . $obj->source->name);
$_template->assign('template_name', $templateName);
}
if ($obj->_objType === 1 || $full) {
$_template->assign('template_data', $this->template_data[ $this->index ]);
@ -250,8 +253,8 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data
$_template->assign('assigned_vars', $_assigned_vars);
$_template->assign('config_vars', $_config_vars);
$_template->assign('execution_time', microtime(true) - $smarty->start_time);
$_template->assign('display_mode', $debugging === 2 || !$full);
$_template->assign('offset', $this->offset * 50);
$_template->assign('targetWindow', $displayMode ? md5("$offset$templateName") : '__Smarty__');
$_template->assign('offset', $offset);
echo $_template->fetch();
if (isset($full)) {
$this->index--;

View File

@ -17,12 +17,24 @@ class Smarty_Internal_ErrorHandler
*/
public $allowUndefinedVars = true;
/**
* Allows {$foo->propName} where propName is undefined.
* @var bool
*/
public $allowUndefinedProperties = true;
/**
* Allows {$foo.bar} where bar is unset and {$foo.bar1.bar2} where either bar1 or bar2 is unset.
* @var bool
*/
public $allowUndefinedArrayKeys = true;
/**
* Allows {$foo->bar} where bar is not an object (e.g. null or false).
* @var bool
*/
public $allowDereferencingNonObjects = true;
private $previousErrorHandler = null;
/**
@ -66,17 +78,35 @@ class Smarty_Internal_ErrorHandler
*/
public function handleError($errno, $errstr, $errfile, $errline, $errcontext = [])
{
if ($this->allowUndefinedVars && $errstr == 'Attempt to read property "value" on null') {
if ($this->allowUndefinedVars && preg_match(
'/^(Attempt to read property "value" on null|Trying to get property (\'value\' )?of non-object)/',
$errstr
)) {
return; // suppresses this error
}
if ($this->allowUndefinedProperties && preg_match(
'/^(Undefined property)/',
$errstr
)) {
return; // suppresses this error
}
if ($this->allowUndefinedArrayKeys && preg_match(
'/^(Undefined array key|Trying to access array offset on value of type null)/',
'/^(Undefined index|Undefined array key|Trying to access array offset on)/',
$errstr
)) {
return; // suppresses this error
}
if ($this->allowDereferencingNonObjects && preg_match(
'/^Attempt to read property ".+?" on/',
$errstr
)) {
return; // suppresses this error
}
// pass all other errors through to the previous error handler or to the default PHP error handler
return $this->previousErrorHandler ?
call_user_func($this->previousErrorHandler, $errno, $errstr, $errfile, $errline, $errcontext) : false;

View File

@ -455,15 +455,29 @@ abstract class Smarty_Internal_TemplateCompilerBase
$this->smarty->_current_file = $this->template->source->filepath;
// get template source
if (!empty($this->template->source->components)) {
// we have array of inheritance templates by extends: resource
// generate corresponding source code sequence
$_content =
Smarty_Internal_Compile_Extends::extendsSourceArrayCode($this->template);
$_compiled_code = '<?php $_smarty_tpl->_loadInheritance(); $_smarty_tpl->inheritance->init($_smarty_tpl, true); ?>';
$i = 0;
$reversed_components = array_reverse($this->template->getSource()->components);
foreach ($reversed_components as $source) {
$i++;
if ($i === count($reversed_components)) {
$_compiled_code .= '<?php $_smarty_tpl->inheritance->endChild($_smarty_tpl); ?>';
}
$_compiled_code .= $this->compileTag(
'include',
[
var_export($source->resource, true),
['scope' => 'parent'],
]
);
}
$_compiled_code = $this->postFilter($_compiled_code, $this->template);
} else {
// get template source
$_content = $this->template->source->getContent();
$_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true));
}
$_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true));
if (!empty($this->required_plugins[ 'compiled' ]) || !empty($this->required_plugins[ 'nocache' ])) {
$_compiled_code = '<?php ' . $this->compileRequiredPlugins() . "?>\n" . $_compiled_code;
}
@ -640,7 +654,18 @@ abstract class Smarty_Internal_TemplateCompilerBase
return $func_name . '(' . $parameter[ 0 ] . ')';
}
} else {
return $name . '(' . implode(',', $parameter) . ')';
if (
!$this->smarty->loadPlugin('smarty_modifiercompiler_' . $name)
&& !isset($this->smarty->registered_plugins[Smarty::PLUGIN_MODIFIER][$name])
&& !in_array($name, ['time', 'join', 'is_array', 'in_array'])
) {
trigger_error('Using unregistered function "' . $name . '" in a template is deprecated and will be ' .
'removed in a future release. Use Smarty::registerPlugin to explicitly register ' .
'a custom modifier.', E_USER_DEPRECATED);
}
return $name . '(' . implode(',', $parameter) . ')';
}
} else {
$this->trigger_template_error("unknown function '{$name}'");

View File

@ -2425,6 +2425,9 @@ public static $yy_action = array(
if (isset($this->smarty->registered_classes[$this->yystack[$this->yyidx + -2]->minor])) {
$this->_retvalue = $this->smarty->registered_classes[$this->yystack[$this->yyidx + -2]->minor].'::'.$this->yystack[$this->yyidx + 0]->minor[0].$this->yystack[$this->yyidx + 0]->minor[1];
} else {
trigger_error('Using unregistered static method "' . $this->yystack[$this->yyidx + -2]->minor.'::'.$this->yystack[$this->yyidx + 0]->minor[0] . '" in a template is deprecated and will be ' .
'removed in a future release. Use Smarty::registerClass to explicitly register ' .
'a class for access.', E_USER_DEPRECATED);
$this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.'::'.$this->yystack[$this->yyidx + 0]->minor[0].$this->yystack[$this->yyidx + 0]->minor[1];
}
} else {

View File

@ -253,7 +253,7 @@ class Smarty_Security
*
* @param string $function_name
* @param object $compiler compiler object
*
* @deprecated
* @return boolean true if function is trusted
*/
public function isTrustedPhpFunction($function_name, $compiler)

View File

@ -85,7 +85,7 @@ class Smarty_Template_Compiled extends Smarty_Template_Resource_Base
*
* @param Smarty_Internal_Template $_template
*
* @return string
* @return void
* @throws Exception
*/
public function render(Smarty_Internal_Template $_template)

View File

@ -1,5 +1,5 @@
$Id$
Smarty version: 4.3.0 (released: 2022/11/22)
Smarty version: 4.5.3 (released: 2024/05/28)
https://github.com/smarty-php/smarty/archive/refs/tags/v4.3.0.tar.gz
https://github.com/smarty-php/smarty/archive/refs/tags/v4.5.3.tar.gz