Browse Source

Don't write to config file if `config_is_read_only` is set

Also don't write to cache in this case to prevent cache and config file
being out of sync.

Fixes: #29901
Signed-off-by: Jonas Meurer <jonas@freesources.org>
Jonas Meurer 2 years ago
parent
commit
241dfef7fb
3 changed files with 33 additions and 5 deletions
  1. 5 5
      config/config.sample.php
  2. 26 0
      lib/private/Config.php
  3. 2 0
      lib/public/IConfig.php

+ 5 - 5
config/config.sample.php

@@ -809,11 +809,11 @@ $CONFIG = [
 
 /**
  * In certain environments it is desired to have a read-only configuration file.
- * When this switch is set to ``true`` Nextcloud will not verify whether the
- * configuration is writable. However, it will not be possible to configure
- * all options via the Web interface. Furthermore, when updating Nextcloud
- * it is required to make the configuration file writable again for the update
- * process.
+ * When this switch is set to ``true``, writing to the config file will be
+ * forbidden. Therefore, it will not be possible to configure all options via
+ * the Web interface. Furthermore, when updating Nextcloud it is required to
+ * make the configuration file writable again and to set this switch to ``false``
+ * for the update process.
  *
  * Defaults to ``false``
  */

+ 26 - 0
lib/private/Config.php

@@ -57,6 +57,8 @@ class Config {
 	protected $configFilePath;
 	/** @var string */
 	protected $configFileName;
+	/** @var bool */
+	protected $isReadOnly;
 
 	/**
 	 * @param string $configDir Path to the config dir, needs to end with '/'
@@ -67,6 +69,7 @@ class Config {
 		$this->configFilePath = $this->configDir.$fileName;
 		$this->configFileName = $fileName;
 		$this->readData();
+		$this->isReadOnly = $this->getValue('config_is_read_only', false);
 	}
 
 	/**
@@ -109,6 +112,7 @@ class Config {
 	 *
 	 * @param array $configs Associative array with `key => value` pairs
 	 *                       If value is null, the config key will be deleted
+	 * @throws HintException
 	 */
 	public function setValues(array $configs) {
 		$needsUpdate = false;
@@ -131,6 +135,7 @@ class Config {
 	 *
 	 * @param string $key key
 	 * @param mixed $value value
+	 * @throws HintException
 	 */
 	public function setValue($key, $value) {
 		if ($this->set($key, $value)) {
@@ -145,8 +150,11 @@ class Config {
 	 * @param string $key key
 	 * @param mixed $value value
 	 * @return bool True if the file needs to be updated, false otherwise
+	 * @throws HintException
 	 */
 	protected function set($key, $value) {
+		$this->checkReadOnly();
+
 		if (!isset($this->cache[$key]) || $this->cache[$key] !== $value) {
 			// Add change
 			$this->cache[$key] = $value;
@@ -158,7 +166,9 @@ class Config {
 
 	/**
 	 * Removes a key from the config and removes it from config.php if required
+	 *
 	 * @param string $key
+	 * @throws HintException
 	 */
 	public function deleteKey($key) {
 		if ($this->delete($key)) {
@@ -172,8 +182,11 @@ class Config {
 	 *
 	 * @param string $key
 	 * @return bool True if the file needs to be updated, false otherwise
+	 * @throws HintException
 	 */
 	protected function delete($key) {
+		$this->checkReadOnly();
+
 		if (isset($this->cache[$key])) {
 			// Delete key from cache
 			unset($this->cache[$key]);
@@ -239,6 +252,8 @@ class Config {
 	 * @throws \Exception If no file lock can be acquired
 	 */
 	private function writeData() {
+		$this->checkReadOnly();
+
 		// Create a php file ...
 		$content = "<?php\n";
 		$content .= '$CONFIG = ';
@@ -274,4 +289,15 @@ class Config {
 			@opcache_invalidate($this->configFilePath, true);
 		}
 	}
+
+	/**
+	 * @throws HintException
+	 */
+	private function checkReadOnly(): void {
+		if ($this->isReadOnly) {
+			throw new HintException(
+				'Config is set to be read-only via option "config_is_read_only".',
+				'Unset "config_is_read_only" to allow changes to the config file.');
+		}
+	}
 }

+ 2 - 0
lib/public/IConfig.php

@@ -47,6 +47,7 @@ interface IConfig {
 	 *
 	 * @param array $configs Associative array with `key => value` pairs
 	 *                       If value is null, the config key will be deleted
+	 * @throws HintException if config file is read-only
 	 * @since 8.0.0
 	 */
 	public function setSystemValues(array $configs);
@@ -56,6 +57,7 @@ interface IConfig {
 	 *
 	 * @param string $key the key of the value, under which will be saved
 	 * @param mixed $value the value that should be stored
+	 * @throws HintException if config file is read-only
 	 * @since 8.0.0
 	 */
 	public function setSystemValue($key, $value);