diff options
-rw-r--r-- | SECURITY.md | 25 | ||||
-rw-r--r-- | apps/admin_audit/lib/AppInfo/Application.php | 1 | ||||
-rw-r--r-- | apps/files/lib/Listener/LegacyLoadAdditionalScriptsAdapter.php | 2 | ||||
-rw-r--r-- | apps/files_external/lib/Lib/Auth/Password/UserGlobalAuth.php | 5 | ||||
-rw-r--r-- | apps/updatenotification/Makefile | 1 | ||||
-rw-r--r-- | build/files-checker.php | 1 | ||||
-rw-r--r-- | core/Command/Maintenance/Install.php | 5 | ||||
-rw-r--r-- | lib/private/Session/CryptoWrapper.php | 18 | ||||
-rw-r--r-- | lib/private/Session/Internal.php | 12 | ||||
-rw-r--r-- | lib/private/Setup.php | 14 | ||||
-rw-r--r-- | lib/private/Setup/MySQL.php | 27 |
11 files changed, 99 insertions, 12 deletions
diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..ee4bdb12eca --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policy + +## Supported Versions + +The latest three major release versions of Nextcloud are currently being supported with security updates. +Please visit https://github.com/nextcloud/server/wiki/Maintenance-and-Release-Schedule for further details. + +## Reporting a Vulnerability + +Security is very important to us. If you have discovered a security issue with Nextcloud, +please read our responsible disclosure guidelines and contact us at [hackerone.com/nextcloud](https://hackerone.com/nextcloud). +Your report should include: + +- Product version +- A vulnerability description +- Reproduction steps + +A member of the security team will confirm the vulnerability, determine its impact, and develop a fix. +The fix will be applied to the master branch, tested, and packaged in the next security release. +The vulnerability will be publicly announced after the release. Finally, your name will be added +to the [hall of fame](https://hackerone.com/nextcloud/thanks) as a thank you from the entire Nextcloud community. Note our +[threat model](https://nextcloud.com/security/threat-model) to know what is expected behavior. + + +Please visit https://nextcloud.com/security/ for further information about security. diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php index 44d713f7df0..6d7eff012f0 100644 --- a/apps/admin_audit/lib/AppInfo/Application.php +++ b/apps/admin_audit/lib/AppInfo/Application.php @@ -134,6 +134,7 @@ class Application extends App { Util::connectHook(Share::class, 'post_shared', $shareActions, 'shared'); Util::connectHook(Share::class, 'post_unshare', $shareActions, 'unshare'); + Util::connectHook(Share::class, 'post_unshareFromSelf', $shareActions, 'unshare'); Util::connectHook(Share::class, 'post_update_permissions', $shareActions, 'updatePermissions'); Util::connectHook(Share::class, 'post_update_password', $shareActions, 'updatePassword'); Util::connectHook(Share::class, 'post_set_expiration_date', $shareActions, 'updateExpirationDate'); diff --git a/apps/files/lib/Listener/LegacyLoadAdditionalScriptsAdapter.php b/apps/files/lib/Listener/LegacyLoadAdditionalScriptsAdapter.php index fc8926c08bb..938eb5a4819 100644 --- a/apps/files/lib/Listener/LegacyLoadAdditionalScriptsAdapter.php +++ b/apps/files/lib/Listener/LegacyLoadAdditionalScriptsAdapter.php @@ -31,7 +31,7 @@ use OC\EventDispatcher\SymfonyAdapter; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; -use OCP\EventDispatcher\GenericEvent; +use Symfony\Component\EventDispatcher\GenericEvent; class LegacyLoadAdditionalScriptsAdapter implements IEventListener { diff --git a/apps/files_external/lib/Lib/Auth/Password/UserGlobalAuth.php b/apps/files_external/lib/Lib/Auth/Password/UserGlobalAuth.php index a0c7f91e6f7..9231e5b6a41 100644 --- a/apps/files_external/lib/Lib/Auth/Password/UserGlobalAuth.php +++ b/apps/files_external/lib/Lib/Auth/Password/UserGlobalAuth.php @@ -56,6 +56,11 @@ class UserGlobalAuth extends AuthMechanism { } public function saveBackendOptions(IUser $user, $id, $backendOptions) { + // backendOptions are set when invoked via Files app + // but they are not set when invoked via ext storage settings + if(!isset($backendOptions['user']) && !isset($backendOptions['password'])) { + return; + } // make sure we're not setting any unexpected keys $credentials = [ 'user' => $backendOptions['user'], diff --git a/apps/updatenotification/Makefile b/apps/updatenotification/Makefile index 11c4eec98dd..ca810f6aa5a 100644 --- a/apps/updatenotification/Makefile +++ b/apps/updatenotification/Makefile @@ -44,6 +44,7 @@ package: clean build-js-production --exclude=/CONTRIBUTING.md \ --exclude=/issue_template.md \ --exclude=/README.md \ + --exclude=/SECURITY.md \ --exclude=/.gitignore \ --exclude=/.scrutinizer.yml \ --exclude=/.travis.yml \ diff --git a/build/files-checker.php b/build/files-checker.php index 27604a07e30..34533698163 100644 --- a/build/files-checker.php +++ b/build/files-checker.php @@ -73,6 +73,7 @@ $expectedFiles = [ 'remote.php', 'resources', 'robots.txt', + 'SECURITY.md', 'status.php', 'tests', 'themes', diff --git a/core/Command/Maintenance/Install.php b/core/Command/Maintenance/Install.php index f92d86d0243..fa18ef721b2 100644 --- a/core/Command/Maintenance/Install.php +++ b/core/Command/Maintenance/Install.php @@ -134,6 +134,10 @@ class Install extends Command { } else { $dbHost = $input->getOption('database-host'); } + if ($dbPort) { + // Append the port to the host so it is the same as in the config (there is no dbport config) + $dbHost .= ':' . $dbPort; + } $dbTablePrefix = 'oc_'; if ($input->hasParameterOption('--database-table-prefix')) { $dbTablePrefix = (string) $input->getOption('database-table-prefix'); @@ -183,7 +187,6 @@ class Install extends Command { 'dbpass' => $dbPass, 'dbname' => $dbName, 'dbhost' => $dbHost, - 'dbport' => $dbPort, 'dbtableprefix' => $dbTablePrefix, 'adminlogin' => $adminLogin, 'adminpass' => $adminPassword, diff --git a/lib/private/Session/CryptoWrapper.php b/lib/private/Session/CryptoWrapper.php index bbaa907b268..b9dbc90edd6 100644 --- a/lib/private/Session/CryptoWrapper.php +++ b/lib/private/Session/CryptoWrapper.php @@ -86,7 +86,23 @@ class CryptoWrapper { if($webRoot === '') { $webRoot = '/'; } - setcookie(self::COOKIE_NAME, $this->passphrase, 0, $webRoot, '', $secureCookie, true); + + if (PHP_VERSION_ID < 70300) { + setcookie(self::COOKIE_NAME, $this->passphrase, 0, $webRoot, '', $secureCookie, true); + } else { + setcookie( + self::COOKIE_NAME, + $this->passphrase, + [ + 'expires' => 0, + 'path' => $webRoot, + 'domain' => '', + 'secure' => $secureCookie, + 'httponly' => true, + 'samesite' => 'Lax', + ] + ); + } } } } diff --git a/lib/private/Session/Internal.php b/lib/private/Session/Internal.php index d235e9eb50b..b9aae76c3b0 100644 --- a/lib/private/Session/Internal.php +++ b/lib/private/Session/Internal.php @@ -56,7 +56,7 @@ class Internal extends Session { set_error_handler([$this, 'trapError']); $this->invoke('session_name', [$name]); try { - $this->invoke('session_start'); + $this->startSession(); } catch (\Exception $e) { setcookie($this->invoke('session_name'), '', -1, \OC::$WEBROOT ?: '/'); } @@ -106,7 +106,7 @@ class Internal extends Session { public function clear() { $this->invoke('session_unset'); $this->regenerateId(); - $this->invoke('session_start', [], true); + $this->startSession(); $_SESSION = []; } @@ -214,4 +214,12 @@ class Internal extends Session { $this->trapError($e->getCode(), $e->getMessage()); } } + + private function startSession() { + if (PHP_VERSION_ID < 70300) { + $this->invoke('session_start'); + } else { + $this->invoke('session_start', [['cookie_samesite' => 'Lax']]); + } + } } diff --git a/lib/private/Setup.php b/lib/private/Setup.php index 9b604895468..795c8cabcea 100644 --- a/lib/private/Setup.php +++ b/lib/private/Setup.php @@ -353,11 +353,9 @@ class Setup { $this->config->setValues($newConfigValues); + $dbSetup->initialize($options); try { - $dbSetup->initialize($options); $dbSetup->setupDatabase($username); - // apply necessary migrations - $dbSetup->runMigrations(); } catch (\OC\DatabaseSetupException $e) { $error[] = [ 'error' => $e->getMessage(), @@ -371,6 +369,16 @@ class Setup { ]; return $error; } + try { + // apply necessary migrations + $dbSetup->runMigrations(); + } catch (Exception $e) { + $error[] = [ + 'error' => 'Error while trying to initialise the database: ' . $e->getMessage(), + 'hint' => '', + ]; + return $error; + } //create the user and group $user = null; diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php index 3f4dd616a2f..7371c7aeab2 100644 --- a/lib/private/Setup/MySQL.php +++ b/lib/private/Setup/MySQL.php @@ -34,6 +34,7 @@ namespace OC\Setup; use OC\DB\MySqlTools; use OCP\IDBConnection; use OCP\ILogger; +use Doctrine\DBAL\Platforms\MySQL80Platform; class MySQL extends AbstractDatabase { public $dbprettyname = 'MySQL/MariaDB'; @@ -57,6 +58,16 @@ class MySQL extends AbstractDatabase { //fill the database if needed $query='select count(*) from information_schema.tables where table_schema=? AND table_name = ?'; $connection->executeQuery($query, [$this->dbName, $this->tablePrefix.'users']); + + $connection->close(); + $connection = $this->connect(); + try { + $connection->connect(); + } catch (\Exception $e) { + $this->logger->logException($e); + throw new \OC\DatabaseSetupException($this->trans->t('MySQL username and/or password not valid'), + $this->trans->t('You need to enter details of an existing account.')); + } } /** @@ -102,10 +113,18 @@ class MySQL extends AbstractDatabase { $password = $this->dbPassword; // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one, // the anonymous user would take precedence when there is one. - $query = "CREATE USER '$name'@'localhost' IDENTIFIED WITH mysql_native_password BY '$password'"; - $connection->executeUpdate($query); - $query = "CREATE USER '$name'@'%' IDENTIFIED WITH mysql_native_password BY '$password'"; - $connection->executeUpdate($query); + + if ($connection->getDatabasePlatform() instanceof Mysql80Platform) { + $query = "CREATE USER '$name'@'localhost' IDENTIFIED WITH mysql_native_password BY '$password'"; + $connection->executeUpdate($query); + $query = "CREATE USER '$name'@'%' IDENTIFIED WITH mysql_native_password BY '$password'"; + $connection->executeUpdate($query); + } else { + $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; + $connection->executeUpdate($query); + $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; + $connection->executeUpdate($query); + } } catch (\Exception $ex){ $this->logger->logException($ex, [ |