From a1c0c5e1a2fdc20ee4f35d6c9195bb9425695a2f Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 14 Mar 2014 13:03:18 +0100 Subject: [PATCH 1/3] Added .ocdata file to check for data folder validity In environments where the data folder is mount from another partition, it is important to check that the data folder we see is actually the real one. If the mount failed for some reasons, this fix will make ownCloud temporarily unavailable instead of causing unpredictable behavior. Backport of 3c46dcd from master --- lib/private/setup.php | 4 ++ lib/private/updater.php | 5 ++ lib/private/util.php | 34 +++++++++-- tests/lib/utilcheckserver.php | 108 ++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 tests/lib/utilcheckserver.php diff --git a/lib/private/setup.php b/lib/private/setup.php index f3ef4df200d..8ef563b0be0 100644 --- a/lib/private/setup.php +++ b/lib/private/setup.php @@ -107,6 +107,10 @@ class OC_Setup { //guess what this does OC_Installer::installShippedApps(); + // create empty file in data dir, so we can later find + // out that this is indeed an ownCloud data directory + file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.ocdata', ''); + //create htaccess files for apache hosts if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) { self::createHtaccess(); diff --git a/lib/private/updater.php b/lib/private/updater.php index c58c12fec2c..95ebd4db235 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -105,6 +105,11 @@ class Updater extends BasicEmitter { } $this->emit('\OC\Updater', 'maintenanceStart'); + // create empty file in data dir, so we can later find + // out that this is indeed an ownCloud data directory + // (in case it didn't exist before) + file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', ''); + /* * START CONFIG CHANGES FOR OLDER VERSIONS */ diff --git a/lib/private/util.php b/lib/private/util.php index 7b9d2238093..3ab4f742197 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -288,12 +288,18 @@ class OC_Util { * @return array arrays with error messages and hints */ public static function checkServer() { - // Assume that if checkServer() succeeded before in this session, then all is fine. - if(\OC::$session->exists('checkServer_suceeded') && \OC::$session->get('checkServer_suceeded')) { - return array(); + $errors = array(); + $CONFIG_DATADIRECTORY = OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data'); + + if (!\OC::needUpgrade() && OC_Config::getValue('installed', false)) { + // this check needs to be done every time + $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY); } - $errors = array(); + // Assume that if checkServer() succeeded before in this session, then all is fine. + if(\OC::$session->exists('checkServer_suceeded') && \OC::$session->get('checkServer_suceeded')) { + return $errors; + } $defaults = new \OC_Defaults(); @@ -339,7 +345,6 @@ class OC_Util { ); } } - $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); // Create root dir. if(!is_dir($CONFIG_DATADIRECTORY)) { $success=@mkdir($CONFIG_DATADIRECTORY); @@ -538,6 +543,25 @@ class OC_Util { return $errors; } + /** + * Check that the data directory exists and is valid by + * checking the existence of the ".ocdata" file. + * + * @param string $dataDirectory data directory path + * @return bool true if the data directory is valid, false otherwise + */ + public static function checkDataDirectoryValidity($dataDirectory) { + $errors = array(); + if (!file_exists($dataDirectory.'/.ocdata')) { + $errors[] = array( + 'error' => 'Data directory (' . $dataDirectory . ') is invalid', + 'hint' => 'Please check that the data directory contains a file' . + ' ".ocdata" in its root.' + ); + } + return $errors; + } + /** * @return void */ diff --git a/tests/lib/utilcheckserver.php b/tests/lib/utilcheckserver.php new file mode 100644 index 00000000000..155d617c4ad --- /dev/null +++ b/tests/lib/utilcheckserver.php @@ -0,0 +1,108 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Tests for server check functions + */ +class Test_Util_CheckServer extends PHPUnit_Framework_TestCase { + + private $datadir; + + public function setUp() { + $this->datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data'); + + file_put_contents($this->datadir . '/.ocdata', ''); + } + + public function tearDown() { + // clean up + @unlink($this->datadir . '/.ocdata'); + } + + /** + * Test that checkServer() returns no errors in the regular case. + */ + public function testCheckServer() { + $result = \OC_Util::checkServer(); + $this->assertEmpty($result); + } + + /** + * Test that checkServer() does not check the data dir validity + * when the server is not installed yet (else the setup cannot + * be run...) + */ + public function testCheckServerSkipDataDirValidityOnSetup() { + // simulate old version that didn't have it + unlink($this->datadir . '/.ocdata'); + + $session = \OC::$server->getSession(); + $oldInstalled = \OC_Config::getValue('installed', false); + + // simulate that the server isn't setup yet + \OC_Config::setValue('installed', false); + + // even though ".ocdata" is missing, the error isn't + // triggered to allow setup to run + $result = \OC_Util::checkServer(); + $this->assertEmpty($result); + + // restore config + \OC_Config::setValue('installed', $oldInstalled); + } + + /** + * Test that checkServer() does not check the data dir validity + * when an upgrade is required (else the upgrade cannot be + * performed...) + */ + public function testCheckServerSkipDataDirValidityOnUpgrade() { + // simulate old version that didn't have it + unlink($this->datadir . '/.ocdata'); + + $session = \OC::$server->getSession(); + $oldCurrentVersion = $session->get('OC_Version'); + $oldInstallVersion = \OC_Config::getValue('version', '0.0.0'); + + // upgrade condition to simulate needUpgrade() === true + $session->set('OC_Version', array(6, 0, 0, 2)); + \OC_Config::setValue('version', '6.0.0.1'); + + // even though ".ocdata" is missing, the error isn't + // triggered to allow for upgrade + $result = \OC_Util::checkServer(); + $this->assertEmpty($result); + + // restore versions + $session->set('OC_Version', $oldCurrentVersion); + \OC_Config::setValue('version', $oldInstallVersion); + } + + /** + * Test that checkDataDirectoryValidity returns no error + * when ".ocdata" is present. + */ + public function testCheckDataDirValidity() { + $result = \OC_Util::checkDataDirectoryValidity($this->datadir); + $this->assertEmpty($result); + } + + /** + * Test that checkDataDirectoryValidity and checkServer + * both return an error when ".ocdata" is missing. + */ + public function testCheckDataDirValidityWhenFileMissing() { + unlink($this->datadir . '/.ocdata'); + $result = \OC_Util::checkDataDirectoryValidity($this->datadir); + $this->assertEquals(1, count($result)); + + $result = \OC_Util::checkServer(); + $this->assertEquals(1, count($result)); + } + +} From d85d3a4493dc0e789ef3b120e6885ede7f1990a1 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 14 Mar 2014 13:58:34 +0100 Subject: [PATCH 2/3] Return 503 when a config/data dir error exists Backport of b619ff6 from master --- lib/base.php | 1 + lib/private/response.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/base.php b/lib/base.php index e2e9de3298a..dba905f8cd9 100644 --- a/lib/base.php +++ b/lib/base.php @@ -525,6 +525,7 @@ class OC { echo $error['hint'] . "\n\n"; } } else { + OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE); OC_Template::printGuestPage('', 'error', array('errors' => $errors)); } exit; diff --git a/lib/private/response.php b/lib/private/response.php index 04746437347..ecac06e9e50 100644 --- a/lib/private/response.php +++ b/lib/private/response.php @@ -12,6 +12,7 @@ class OC_Response { const STATUS_TEMPORARY_REDIRECT = 307; const STATUS_NOT_FOUND = 404; const STATUS_INTERNAL_SERVER_ERROR = 500; + const STATUS_SERVICE_UNAVAILABLE = 503; /** * @brief Enable response caching by sending correct HTTP headers @@ -74,6 +75,9 @@ class OC_Response { case self::STATUS_INTERNAL_SERVER_ERROR; $status = $status . ' Internal Server Error'; break; + case self::STATUS_SERVICE_UNAVAILABLE; + $status = $status . ' Service Unavailable'; + break; } header($protocol.' '.$status); } From 288c40e2a617f149c8a30b9aec8361144176244c Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 17 Mar 2014 17:58:19 +0100 Subject: [PATCH 3/3] Increase version to trigger upgrade related to .ocdata --- version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.php b/version.php index 5c95607eaa9..b26d336bd3a 100644 --- a/version.php +++ b/version.php @@ -1,7 +1,7 @@