[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/libraries/Smarty/libs/sysplugins/ -> smarty_security.php (source)

   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  ?>


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1