From b401d39aec8d340a86de5a6fd14e51b7566e10d8 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 18 Mar 2013 15:30:09 +1300 Subject: [PATCH] NEW: Move temp data into a user-specific subfolder, to stop temp-permission bugs from occurring. Anyone who has run "sudo -u www-data ./framework/sake dev/build" knows that SilverStripe's temp folder permissions can be very brittle. This patch resolves this by making the temp folder user-specific. To minimise directory pollution it first creates a chmod 777 parent folder with the same name as the current folder. It then creates a subfolder of this with the same name as the current user. The positive impact of this change is that sake can be used without fear of messing up file permissions. This means, among other things, that we can put a Composer post-update-cmd into the installer to run dev/build. Progress! The negative impact is that you will get two caches if you run sake as a different user. However, that is much better than the current situation - which is a bunch of bugs - and if you're concerned about that, you still have the option of running sake as www-data. --- core/TempPath.php | 54 ++++++++++++++++++++++++++++++++++++++--- tests/core/CoreTest.php | 18 +++++++++----- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/core/TempPath.php b/core/TempPath.php index 13b48d324..57d146b97 100644 --- a/core/TempPath.php +++ b/core/TempPath.php @@ -6,6 +6,40 @@ * @return string Path to temp */ function getTempFolder($base = null) { + $parent = getTempParentFolder($base); + + // The actual temp folder is a subfolder of getTempParentFolder(), named by username + $subfolder = $parent . DIRECTORY_SEPARATOR . getTempFolderUsername(); + + if(!@file_exists($subfolder)) { + mkdir($subfolder); + } + + return $subfolder; +} + +/** + * Returns as best a representation of the current username as we can glean. + */ +function getTempFolderUsername() { + $user = getenv('APACHE_RUN_USER'); + if(!$user) $user = getenv('USER'); + if(!$user) $user = getenv('USERNAME'); + if(!$user && function_exists('posix_getuid')) { + $userDetails = posix_getpwuid(posix_getuid()); + $user = $userDetails['name']; + } + if(!$user) $user = 'unknown'; + $user = preg_replace('/[^A-Za-z0-9_\-]/', '', $user); + return $user; +} + +/** + * Return the parent folder of the temp folder. + * The temp folder will be a subfolder of this, named by username. + * This structure prevents permission problems. + */ +function getTempParentFolder($base = null) { if(!$base && defined('BASE_PATH')) $base = BASE_PATH; $tempPath = ''; @@ -14,6 +48,9 @@ function getTempFolder($base = null) { // first, try finding a silverstripe-cache dir built off the base path $tempPath = $base . '/silverstripe-cache'; if(@file_exists($tempPath)) { + if((fileperms($tempPath) & 0777) != 0777) { + @chmod($tempPath, 0777); + } return $tempPath; } @@ -21,7 +58,15 @@ function getTempFolder($base = null) { $cacheFolder = '/silverstripe-cache' . str_replace(array(' ', '/', ':', '\\'), '-', $base); $tempPath = sys_get_temp_dir() . $cacheFolder; if(!@file_exists($tempPath)) { - $worked = @mkdir($tempPath); + $oldUMask = umask(0); + $worked = @mkdir($tempPath, 0777); + umask($oldUMask); + + // if the folder already exists, correct perms + } else { + if((fileperms($tempPath) & 0777) != 0777) { + @chmod($tempPath, 0777); + } } // failing to use the system path, attempt to create a local silverstripe-cache dir @@ -29,7 +74,9 @@ function getTempFolder($base = null) { $worked = true; $tempPath = $base . '/silverstripe-cache'; if(!@file_exists($tempPath)) { - $worked = @mkdir($tempPath); + $oldUMask = umask(0); + $worked = @mkdir($tempPath, 0777); + umask($oldUMask); } } @@ -42,5 +89,4 @@ function getTempFolder($base = null) { } return $tempPath; -} - +} \ No newline at end of file diff --git a/tests/core/CoreTest.php b/tests/core/CoreTest.php index 8948693fd..73e10ffa5 100644 --- a/tests/core/CoreTest.php +++ b/tests/core/CoreTest.php @@ -19,29 +19,35 @@ class CoreTest extends SapphireTest { if(file_exists($this->tempPath)) { $this->assertEquals(getTempFolder(BASE_PATH), $this->tempPath); } else { + $user = getTempFolderUsername(); + // A typical Windows location for where sites are stored on IIS - $this->assertEquals(getTempFolder('C:\\inetpub\\wwwroot\\silverstripe-test-project'), - sys_get_temp_dir() . '/silverstripe-cacheC--inetpub-wwwroot-silverstripe-test-project'); + $this->assertEquals(sys_get_temp_dir() . '/silverstripe-cacheC--inetpub-wwwroot-silverstripe-test-project/' . $user, + getTempFolder('C:\\inetpub\\wwwroot\\silverstripe-test-project')); // A typical Mac OS X location for where sites are stored - $this->assertEquals(getTempFolder('/Users/joebloggs/Sites/silverstripe-test-project'), - sys_get_temp_dir() . '/silverstripe-cache-Users-joebloggs-Sites-silverstripe-test-project'); + $this->assertEquals(sys_get_temp_dir() . '/silverstripe-cache-Users-joebloggs-Sites-silverstripe-test-project/' . $user, + getTempFolder('/Users/joebloggs/Sites/silverstripe-test-project')); // A typical Linux location for where sites are stored - $this->assertEquals(getTempFolder('/var/www/silverstripe-test-project'), - sys_get_temp_dir() . '/silverstripe-cache-var-www-silverstripe-test-project'); + $this->assertEquals(sys_get_temp_dir() . '/silverstripe-cache-var-www-silverstripe-test-project/' . $user, + getTempFolder('/var/www/silverstripe-test-project')); } } public function tearDown() { parent::tearDown(); + $user = getTempFolderUsername(); if(file_exists(sys_get_temp_dir() . '/silverstripe-cacheC--inetpub-wwwroot-silverstripe-test-project')) { + rmdir(sys_get_temp_dir() . '/silverstripe-cacheC--inetpub-wwwroot-silverstripe-test-project/' . $user); rmdir(sys_get_temp_dir() . '/silverstripe-cacheC--inetpub-wwwroot-silverstripe-test-project'); } if(file_exists(sys_get_temp_dir() . '/silverstripe-cache-Users-joebloggs-Sites-silverstripe-test-project')) { + rmdir(sys_get_temp_dir() . '/silverstripe-cache-Users-joebloggs-Sites-silverstripe-test-project/' . $user); rmdir(sys_get_temp_dir() . '/silverstripe-cache-Users-joebloggs-Sites-silverstripe-test-project'); } if(file_exists(sys_get_temp_dir() . '/silverstripe-cache-var-www-silverstripe-test-project')) { + rmdir(sys_get_temp_dir() . '/silverstripe-cache-var-www-silverstripe-test-project/' . $user); rmdir(sys_get_temp_dir() . '/silverstripe-cache-var-www-silverstripe-test-project'); } }