From 5e86f5687b30397c0e520fd32a9fc92b7e155a16 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Mon, 2 Sep 2013 11:25:36 -0500 Subject: [ticket/11727] Template loader support for safe directories to load files from PHPBB3-11727 --- phpBB/phpbb/template/twig/loader.php | 150 +++++++++++++++++++++++++++++++++++ phpBB/phpbb/template/twig/twig.php | 22 +++-- 2 files changed, 165 insertions(+), 7 deletions(-) create mode 100644 phpBB/phpbb/template/twig/loader.php (limited to 'phpBB/phpbb/template/twig') diff --git a/phpBB/phpbb/template/twig/loader.php b/phpBB/phpbb/template/twig/loader.php new file mode 100644 index 0000000000..997c05f57c --- /dev/null +++ b/phpBB/phpbb/template/twig/loader.php @@ -0,0 +1,150 @@ +safe_directories = array(); + + if (!empty($directories)) + { + foreach ($directories as $directory) + { + $this->addSafeDirectory($directory); + } + } + + return $this; + } + + /** + * Add safe directory + * + * @param string $directory Directory that should be added + * @return Twig_Loader_Filesystem + */ + public function addSafeDirectory($directory) + { + $directory = phpbb_realpath($directory); + + if ($directory !== false) + { + $this->safe_directories[] = $directory; + } + + return $this; + } + + /** + * Get current safe directories + * + * @return array + */ + public function getSafeDirectories() + { + return $this->safe_directories; + } + + /** + * Override for parent::validateName() + * + * This is done because we added support for safe directories, and when Twig + * findTemplate() is called, validateName() is called first, which would + * always throw an exception if the file is outside of the configured + * template directories. + */ + protected function validateName($name) + { + return; + } + + /** + * Find the template + * + * Override for Twig_Loader_Filesystem::findTemplate to add support + * for loading from safe directories. + */ + protected function findTemplate($name) + { + $name = (string) $name; + + // normalize name + $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); + + // If this is in the cache we can skip the entire process below + // as it should have already been validated + if (isset($this->cache[$name])) { + return $this->cache[$name]; + } + + // First, find the template name. The override above of validateName + // causes the validateName process to be skipped for this call + $file = parent::findTemplate($name); + + try + { + // Try validating the name (which may throw an exception) + parent::validateName($name); + } + catch (Twig_Error_Loader $e) + { + if (strpos($e->getRawMessage(), 'Looks like you try to load a template outside configured directories') === 0) + { + // Ok, so outside of the configured template directories, we + // can now check if we're within a "safe" directory + + // Find the real path of the directory the file is in + $directory = phpbb_realpath(dirname($file)); + + if ($directory === false) + { + // Some sort of error finding the actual path, must throw the exception + throw $e; + } + + foreach ($this->safe_directories as $safe_directory) + { + if (strpos($directory, $safe_directory) === 0) + { + // The directory being loaded is below a directory + // that is "safe". We're good to load it! + return $file; + } + } + } + + // Not within any safe directories + throw $e; + } + + // No exception from validateName, safe to load. + return $file; + } +} diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php index 1ed89d3ccc..5746cc64a3 100644 --- a/phpBB/phpbb/template/twig/twig.php +++ b/phpBB/phpbb/template/twig/twig.php @@ -91,7 +91,7 @@ class phpbb_template_twig extends phpbb_template_base $this->cachepath = $phpbb_root_path . 'cache/twig/'; // Initiate the loader, __main__ namespace paths will be setup later in set_style_names() - $loader = new Twig_Loader_Filesystem(''); + $loader = new phpbb_template_twig_loader(''); $this->twig = new phpbb_template_twig_environment( $this->config, @@ -181,11 +181,15 @@ class phpbb_template_twig extends phpbb_template_base { foreach ($names as $name) { - $path = $this->phpbb_root_path . trim($directory, '/') . "/{$name}/template/"; + $path = $this->phpbb_root_path . trim($directory, '/') . "/{$name}/"; + $template_path = $path . 'template/'; - if (is_dir($path)) + if (is_dir($template_path)) { - $paths[] = $path; + // Add the base style directory as a safe directory + $this->twig->getLoader()->addSafeDirectory($path); + + $paths[] = $template_path; } } } @@ -233,11 +237,15 @@ class phpbb_template_twig extends phpbb_template_base foreach ($names as $style_name) { - $ext_style_path = $ext_path . 'styles/' . $style_name . '/template'; + $ext_style_path = $ext_path . 'styles/' . $style_name . '/'; + $ext_style_template_path = $ext_style_path . 'template/'; - if (is_dir($ext_style_path)) + if (is_dir($ext_style_template_path)) { - $paths[] = $ext_style_path; + // Add the base style directory as a safe directory + $this->twig->getLoader()->addSafeDirectory($ext_style_path); + + $paths[] = $ext_style_template_path; } } -- cgit v1.2.1 From 088dfc120003c2a44f6f8a2de36b39819a5332ab Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 12 Sep 2013 23:32:08 -0500 Subject: [ticket/11727] Fix indentation PHPBB3-11727 --- phpBB/phpbb/template/twig/loader.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'phpBB/phpbb/template/twig') diff --git a/phpBB/phpbb/template/twig/loader.php b/phpBB/phpbb/template/twig/loader.php index 997c05f57c..8bf9adfbbe 100644 --- a/phpBB/phpbb/template/twig/loader.php +++ b/phpBB/phpbb/template/twig/loader.php @@ -91,18 +91,18 @@ class phpbb_template_twig_loader extends Twig_Loader_Filesystem * Override for Twig_Loader_Filesystem::findTemplate to add support * for loading from safe directories. */ - protected function findTemplate($name) - { - $name = (string) $name; + protected function findTemplate($name) + { + $name = (string) $name; - // normalize name - $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); + // normalize name + $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); // If this is in the cache we can skip the entire process below // as it should have already been validated - if (isset($this->cache[$name])) { - return $this->cache[$name]; - } + if (isset($this->cache[$name])) { + return $this->cache[$name]; + } // First, find the template name. The override above of validateName // causes the validateName process to be skipped for this call @@ -110,7 +110,7 @@ class phpbb_template_twig_loader extends Twig_Loader_Filesystem try { - // Try validating the name (which may throw an exception) + // Try validating the name (which may throw an exception) parent::validateName($name); } catch (Twig_Error_Loader $e) -- cgit v1.2.1 From 288649dd5ee71596637ede27b5c0487f5f737e84 Mon Sep 17 00:00:00 2001 From: Nathan Guse Date: Thu, 12 Sep 2013 23:32:45 -0500 Subject: [ticket/11727] Fix indentation PHPBB3-11727 --- phpBB/phpbb/template/twig/loader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/phpbb/template/twig') diff --git a/phpBB/phpbb/template/twig/loader.php b/phpBB/phpbb/template/twig/loader.php index 8bf9adfbbe..0829e519f7 100644 --- a/phpBB/phpbb/template/twig/loader.php +++ b/phpBB/phpbb/template/twig/loader.php @@ -110,7 +110,7 @@ class phpbb_template_twig_loader extends Twig_Loader_Filesystem try { - // Try validating the name (which may throw an exception) + // Try validating the name (which may throw an exception) parent::validateName($name); } catch (Twig_Error_Loader $e) -- cgit v1.2.1