From 3f0e59f6e060e406a742e9b8232e2e5dea95873f Mon Sep 17 00:00:00 2001 From: Andrew Hunt Date: Tue, 18 Oct 2016 14:43:00 -0400 Subject: [PATCH] CRM-19533 System check: check for writable directories --- CRM/Utils/Check/Component/Env.php | 50 ++++++++++++++++++++++++++ CRM/Utils/Check/Component/Security.php | 18 ++++++---- CRM/Utils/File.php | 19 ++++++++++ 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/CRM/Utils/Check/Component/Env.php b/CRM/Utils/Check/Component/Env.php index ee89958f5a..75d6e5b208 100644 --- a/CRM/Utils/Check/Component/Env.php +++ b/CRM/Utils/Check/Component/Env.php @@ -375,6 +375,56 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component { return $messages; } + /** + * Check that important directories are writable. + * + * @return array + * Any CRM_Utils_Check_Message instances that need to be generated. + */ + public function checkDirsWritable() { + $notWritable = array(); + + $config = CRM_Core_Config::singleton(); + $directories = array( + 'uploadDir' => ts('Temporary Files Directory'), + 'imageUploadDir' => ts('Images Directory'), + 'customFileUploadDir' => ts('Custom Files Directory'), + 'extensionsDir' => ts('CiviCRM Extensions Directory'), + ); + + foreach ($directories as $directory => $label) { + $file = CRM_Utils_File::createFakeFile($config->$directory); + + if ($file === FALSE) { + $notWritable[] = "$label ({$config->$directory})"; + } + else { + $dirWithSlash = CRM_Utils_File::addTrailingSlash($config->$directory); + unlink($dirWithSlash . $file); + } + } + + $messages = array(); + + if (!empty($notWritable)) { + $messages[] = new CRM_Utils_Check_Message( + __FUNCTION__, + ts('The %1 is not writable. Please check your file permissions.', array( + 1 => implode(', ', $notWritable), + 'count' => count($notWritable), + 'plural' => 'The following directories are not writable: %1. Please check your file permissions.', + )), + ts('Directory not writable', array( + 'count' => count($notWritable), + 'plural' => 'Directories not writable', + )), + \Psr\Log\LogLevel::ERROR, + 'fa-ban' + ); + } + + return $messages; + } /** * Checks if new versions are available diff --git a/CRM/Utils/Check/Component/Security.php b/CRM/Utils/Check/Component/Security.php index 458dd5131c..db176db86a 100644 --- a/CRM/Utils/Check/Component/Security.php +++ b/CRM/Utils/Check/Component/Security.php @@ -323,10 +323,15 @@ class CRM_Utils_Check_Component_Security extends CRM_Utils_Check_Component { } $result = FALSE; - $file = 'delete-this-' . CRM_Utils_String::createRandom(10, CRM_Utils_String::ALPHANUMERIC); // this could be a new system with no uploads (yet) -- so we'll make a file - file_put_contents("$dir/$file", "delete me"); + $file = CRM_Utils_File::createFakeFile($dir); + + if ($file === FALSE) { + // Couldn't write the file + return FALSE; + } + $content = @file_get_contents("$url"); if (stristr($content, $file)) { $result = TRUE; @@ -347,17 +352,18 @@ class CRM_Utils_Check_Component_Security extends CRM_Utils_Check_Component { * @return bool */ public function isDirAccessible($dir, $url) { - $dir = rtrim($dir, '/'); $url = rtrim($url, '/'); if (empty($dir) || empty($url) || !is_dir($dir)) { return FALSE; } $result = FALSE; - $file = 'delete-this-' . CRM_Utils_String::createRandom(10, CRM_Utils_String::ALPHANUMERIC); + $file = CRM_Utils_File::createFakeFile($dir, 'delete me'); - // this could be a new system with no uploads (yet) -- so we'll make a file - file_put_contents("$dir/$file", "delete me"); + if ($file === FALSE) { + // Couldn't write the file + return FALSE; + } $headers = @get_headers("$url/$file"); if (stripos($headers[0], '200')) { diff --git a/CRM/Utils/File.php b/CRM/Utils/File.php index 5d9d3a9a1c..c2459104c1 100644 --- a/CRM/Utils/File.php +++ b/CRM/Utils/File.php @@ -286,6 +286,25 @@ class CRM_Utils_File { return $path; } + /** + * Save a fake file somewhere + * + * @param string $dir + * The directory where the file should be saved. + * @param string $contents + * Optional: the contents of the file. + * + * @return string + * The filename saved, or FALSE on failure. + */ + public static function createFakeFile($dir, $contents = 'delete me') { + $dir = self::addTrailingSlash($dir); + $file = 'delete-this-' . CRM_Utils_String::createRandom(10, CRM_Utils_String::ALPHANUMERIC); + $success = file_put_contents($dir . $file, $contents); + + return ($success === FALSE) ? FALSE : $file; + } + /** * @param string|NULL $dsn * Use NULL to load the default/active connection from CRM_Core_DAO. -- 2.25.1