[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Smarty plugin 4 * 5 * @package Smarty 6 * @subpackage Security 7 * @author Uwe Tews 8 */ 9 10 /* 11 * FIXME: Smarty_Security API 12 * - getter and setter instead of public properties would allow cultivating an internal cache properly 13 * - current implementation of isTrustedResourceDir() assumes that Smarty::$template_dir and Smarty::$config_dir are immutable 14 * the cache is killed every time either of the variables change. That means that two distinct Smarty objects with differing 15 * $template_dir or $config_dir should NOT share the same Smarty_Security instance, 16 * as this would lead to (severe) performance penalty! how should this be handled? 17 */ 18 19 /** 20 * This class does contain the security settings 21 */ 22 class Smarty_Security { 23 24 /** 25 * This determines how Smarty handles "<?php ... ?>" tags in templates. 26 * possible values: 27 * <ul> 28 * <li>Smarty::PHP_PASSTHRU -> echo PHP tags as they are</li> 29 * <li>Smarty::PHP_QUOTE -> escape tags as entities</li> 30 * <li>Smarty::PHP_REMOVE -> remove php tags</li> 31 * <li>Smarty::PHP_ALLOW -> execute php tags</li> 32 * </ul> 33 * 34 * @var integer 35 */ 36 public $php_handling = Smarty::PHP_PASSTHRU; 37 /** 38 * This is the list of template directories that are considered secure. 39 * $template_dir is in this list implicitly. 40 * 41 * @var array 42 */ 43 public $secure_dir = array(); 44 /** 45 * This is an array of directories where trusted php scripts reside. 46 * {@link $security} is disabled during their inclusion/execution. 47 * 48 * @var array 49 */ 50 public $trusted_dir = array(); 51 /** 52 * List of regular expressions (PCRE) that include trusted URIs 53 * 54 * @var array 55 */ 56 public $trusted_uri = array(); 57 /** 58 * This is an array of trusted static classes. 59 * 60 * If empty access to all static classes is allowed. 61 * If set to 'none' none is allowed. 62 * @var array 63 */ 64 public $static_classes = array(); 65 /** 66 * This is an array of trusted PHP functions. 67 * 68 * If empty all functions are allowed. 69 * To disable all PHP functions set $php_functions = null. 70 * @var array 71 */ 72 public $php_functions = array( 73 'isset', 'empty', 74 'count', 'sizeof', 75 'in_array', 'is_array', 76 'time', 77 'nl2br', 78 ); 79 /** 80 * This is an array of trusted PHP modifers. 81 * 82 * If empty all modifiers are allowed. 83 * To disable all modifier set $modifiers = null. 84 * @var array 85 */ 86 public $php_modifiers = array( 87 'escape', 88 'count' 89 ); 90 /** 91 * This is an array of allowed tags. 92 * 93 * If empty no restriction by allowed_tags. 94 * @var array 95 */ 96 public $allowed_tags = array(); 97 /** 98 * This is an array of disabled tags. 99 * 100 * If empty no restriction by disabled_tags. 101 * @var array 102 */ 103 public $disabled_tags = array(); 104 /** 105 * This is an array of allowed modifier plugins. 106 * 107 * If empty no restriction by allowed_modifiers. 108 * @var array 109 */ 110 public $allowed_modifiers = array(); 111 /** 112 * This is an array of disabled modifier plugins. 113 * 114 * If empty no restriction by disabled_modifiers. 115 * @var array 116 */ 117 public $disabled_modifiers = array(); 118 /** 119 * This is an array of trusted streams. 120 * 121 * If empty all streams are allowed. 122 * To disable all streams set $streams = null. 123 * @var array 124 */ 125 public $streams = array('file'); 126 /** 127 * + flag if constants can be accessed from template 128 * @var boolean 129 */ 130 public $allow_constants = true; 131 /** 132 * + flag if super globals can be accessed from template 133 * @var boolean 134 */ 135 public $allow_super_globals = true; 136 137 /** 138 * Cache for $resource_dir lookups 139 * @var array 140 */ 141 protected $_resource_dir = null; 142 /** 143 * Cache for $template_dir lookups 144 * @var array 145 */ 146 protected $_template_dir = null; 147 /** 148 * Cache for $config_dir lookups 149 * @var array 150 */ 151 protected $_config_dir = null; 152 /** 153 * Cache for $secure_dir lookups 154 * @var array 155 */ 156 protected $_secure_dir = null; 157 /** 158 * Cache for $php_resource_dir lookups 159 * @var array 160 */ 161 protected $_php_resource_dir = null; 162 /** 163 * Cache for $trusted_dir lookups 164 * @var array 165 */ 166 protected $_trusted_dir = null; 167 168 169 /** 170 * @param Smarty $smarty 171 */ 172 public function __construct($smarty) 173 { 174 $this->smarty = $smarty; 175 } 176 177 /** 178 * Check if PHP function is trusted. 179 * 180 * @param string $function_name 181 * @param object $compiler compiler object 182 * @return boolean true if function is trusted 183 * @throws SmartyCompilerException if php function is not trusted 184 */ 185 public function isTrustedPhpFunction($function_name, $compiler) 186 { 187 if (isset($this->php_functions) && (empty($this->php_functions) || in_array($function_name, $this->php_functions))) { 188 return true; 189 } 190 191 $compiler->trigger_template_error("PHP function '{$function_name}' not allowed by security setting"); 192 return false; // should not, but who knows what happens to the compiler in the future? 193 } 194 195 /** 196 * Check if static class is trusted. 197 * 198 * @param string $class_name 199 * @param object $compiler compiler object 200 * @return boolean true if class is trusted 201 * @throws SmartyCompilerException if static class is not trusted 202 */ 203 public function isTrustedStaticClass($class_name, $compiler) 204 { 205 if (isset($this->static_classes) && (empty($this->static_classes) || in_array($class_name, $this->static_classes))) { 206 return true; 207 } 208 209 $compiler->trigger_template_error("access to static class '{$class_name}' not allowed by security setting"); 210 return false; // should not, but who knows what happens to the compiler in the future? 211 } 212 213 /** 214 * Check if PHP modifier is trusted. 215 * 216 * @param string $modifier_name 217 * @param object $compiler compiler object 218 * @return boolean true if modifier is trusted 219 * @throws SmartyCompilerException if modifier is not trusted 220 */ 221 public function isTrustedPhpModifier($modifier_name, $compiler) 222 { 223 if (isset($this->php_modifiers) && (empty($this->php_modifiers) || in_array($modifier_name, $this->php_modifiers))) { 224 return true; 225 } 226 227 $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting"); 228 return false; // should not, but who knows what happens to the compiler in the future? 229 } 230 231 /** 232 * Check if tag is trusted. 233 * 234 * @param string $tag_name 235 * @param object $compiler compiler object 236 * @return boolean true if tag is trusted 237 * @throws SmartyCompilerException if modifier is not trusted 238 */ 239 public function isTrustedTag($tag_name, $compiler) 240 { 241 // check for internal always required tags 242 if (in_array($tag_name, array('assign', 'call', 'private_filter', 'private_block_plugin', 'private_function_plugin', 'private_object_block_function', 243 'private_object_function', 'private_registered_function', 'private_registered_block', 'private_special_variable', 'private_print_expression', 'private_modifier'))) { 244 return true; 245 } 246 // check security settings 247 if (empty($this->allowed_tags)) { 248 if (empty($this->disabled_tags) || !in_array($tag_name, $this->disabled_tags)) { 249 return true; 250 } else { 251 $compiler->trigger_template_error("tag '{$tag_name}' disabled by security setting", $compiler->lex->taglineno); 252 } 253 } else if (in_array($tag_name, $this->allowed_tags) && !in_array($tag_name, $this->disabled_tags)) { 254 return true; 255 } else { 256 $compiler->trigger_template_error("tag '{$tag_name}' not allowed by security setting", $compiler->lex->taglineno); 257 } 258 return false; // should not, but who knows what happens to the compiler in the future? 259 } 260 261 /** 262 * Check if modifier plugin is trusted. 263 * 264 * @param string $modifier_name 265 * @param object $compiler compiler object 266 * @return boolean true if tag is trusted 267 * @throws SmartyCompilerException if modifier is not trusted 268 */ 269 public function isTrustedModifier($modifier_name, $compiler) 270 { 271 // check for internal always allowed modifier 272 if (in_array($modifier_name, array('default'))) { 273 return true; 274 } 275 // check security settings 276 if (empty($this->allowed_modifiers)) { 277 if (empty($this->disabled_modifiers) || !in_array($modifier_name, $this->disabled_modifiers)) { 278 return true; 279 } else { 280 $compiler->trigger_template_error("modifier '{$modifier_name}' disabled by security setting", $compiler->lex->taglineno); 281 } 282 } else if (in_array($modifier_name, $this->allowed_modifiers) && !in_array($modifier_name, $this->disabled_modifiers)) { 283 return true; 284 } else { 285 $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting", $compiler->lex->taglineno); 286 } 287 return false; // should not, but who knows what happens to the compiler in the future? 288 } 289 290 /** 291 * Check if stream is trusted. 292 * 293 * @param string $stream_name 294 * @return boolean true if stream is trusted 295 * @throws SmartyException if stream is not trusted 296 */ 297 public function isTrustedStream($stream_name) 298 { 299 if (isset($this->streams) && (empty($this->streams) || in_array($stream_name, $this->streams))) { 300 return true; 301 } 302 303 throw new SmartyException("stream '{$stream_name}' not allowed by security setting"); 304 } 305 306 /** 307 * Check if directory of file resource is trusted. 308 * 309 * @param string $filepath 310 * @return boolean true if directory is trusted 311 * @throws SmartyException if directory is not trusted 312 */ 313 public function isTrustedResourceDir($filepath) 314 { 315 $_template = false; 316 $_config = false; 317 $_secure = false; 318 319 $_template_dir = $this->smarty->getTemplateDir(); 320 $_config_dir = $this->smarty->getConfigDir(); 321 322 // check if index is outdated 323 if ((!$this->_template_dir || $this->_template_dir !== $_template_dir) 324 || (!$this->_config_dir || $this->_config_dir !== $_config_dir) 325 || (!empty($this->secure_dir) && (!$this->_secure_dir || $this->_secure_dir !== $this->secure_dir)) 326 ) { 327 $this->_resource_dir = array(); 328 $_template = true; 329 $_config = true; 330 $_secure = !empty($this->secure_dir); 331 } 332 333 // rebuild template dir index 334 if ($_template) { 335 $this->_template_dir = $_template_dir; 336 foreach ($_template_dir as $directory) { 337 $directory = realpath($directory); 338 $this->_resource_dir[$directory] = true; 339 } 340 } 341 342 // rebuild config dir index 343 if ($_config) { 344 $this->_config_dir = $_config_dir; 345 foreach ($_config_dir as $directory) { 346 $directory = realpath($directory); 347 $this->_resource_dir[$directory] = true; 348 } 349 } 350 351 // rebuild secure dir index 352 if ($_secure) { 353 $this->_secure_dir = $this->secure_dir; 354 foreach ((array) $this->secure_dir as $directory) { 355 $directory = realpath($directory); 356 $this->_resource_dir[$directory] = true; 357 } 358 } 359 360 $_filepath = realpath($filepath); 361 $directory = dirname($_filepath); 362 $_directory = array(); 363 while (true) { 364 // remember the directory to add it to _resource_dir in case we're successful 365 $_directory[] = $directory; 366 // test if the directory is trusted 367 if (isset($this->_resource_dir[$directory])) { 368 // merge sub directories of current $directory into _resource_dir to speed up subsequent lookups 369 $this->_resource_dir = array_merge($this->_resource_dir, $_directory); 370 return true; 371 } 372 // abort if we've reached root 373 if (($pos = strrpos($directory, DS)) === false || !isset($directory[1])) { 374 break; 375 } 376 // bubble up one level 377 $directory = substr($directory, 0, $pos); 378 } 379 380 // give up 381 throw new SmartyException("directory '{$_filepath}' not allowed by security setting"); 382 } 383 384 /** 385 * Check if URI (e.g. {fetch} or {html_image}) is trusted 386 * 387 * To simplify things, isTrustedUri() resolves all input to "{$PROTOCOL}://{$HOSTNAME}". 388 * So "http://username:[email protected]:8080/some-path?some=query-string" 389 * is reduced to "http://hello.world.example.org" prior to applying the patters from {@link $trusted_uri}. 390 * @param string $uri 391 * @return boolean true if URI is trusted 392 * @throws SmartyException if URI is not trusted 393 * @uses $trusted_uri for list of patterns to match against $uri 394 */ 395 public function isTrustedUri($uri) 396 { 397 $_uri = parse_url($uri); 398 if (!empty($_uri['scheme']) && !empty($_uri['host'])) { 399 $_uri = $_uri['scheme'] . '://' . $_uri['host']; 400 foreach ($this->trusted_uri as $pattern) { 401 if (preg_match($pattern, $_uri)) { 402 return true; 403 } 404 } 405 } 406 407 throw new SmartyException("URI '{$uri}' not allowed by security setting"); 408 } 409 410 /** 411 * Check if directory of file resource is trusted. 412 * 413 * @param string $filepath 414 * @return boolean true if directory is trusted 415 * @throws SmartyException if PHP directory is not trusted 416 */ 417 public function isTrustedPHPDir($filepath) 418 { 419 if (empty($this->trusted_dir)) { 420 throw new SmartyException("directory '{$filepath}' not allowed by security setting (no trusted_dir specified)"); 421 } 422 423 // check if index is outdated 424 if (!$this->_trusted_dir || $this->_trusted_dir !== $this->trusted_dir) { 425 $this->_php_resource_dir = array(); 426 427 $this->_trusted_dir = $this->trusted_dir; 428 foreach ((array) $this->trusted_dir as $directory) { 429 $directory = realpath($directory); 430 $this->_php_resource_dir[$directory] = true; 431 } 432 } 433 434 $_filepath = realpath($filepath); 435 $directory = dirname($_filepath); 436 $_directory = array(); 437 while (true) { 438 // remember the directory to add it to _resource_dir in case we're successful 439 $_directory[] = $directory; 440 // test if the directory is trusted 441 if (isset($this->_php_resource_dir[$directory])) { 442 // merge sub directories of current $directory into _resource_dir to speed up subsequent lookups 443 $this->_php_resource_dir = array_merge($this->_php_resource_dir, $_directory); 444 return true; 445 } 446 // abort if we've reached root 447 if (($pos = strrpos($directory, DS)) === false || !isset($directory[2])) { 448 break; 449 } 450 // bubble up one level 451 $directory = substr($directory, 0, $pos); 452 } 453 454 throw new SmartyException("directory '{$_filepath}' not allowed by security setting"); 455 } 456 457 } 458 459 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |