From 915acbde458fe3c31091bda6068b9dcee1439227 Mon Sep 17 00:00:00 2001
From: Helmut Hummel <helmut.hummel@typo3.org>
Date: Thu, 27 Feb 2014 15:09:23 +0100
Subject: [PATCH] [!!!][SECURITY] Allow first install only with FIRST_INSTALL
 file

It was previously possible to access the install tool
by using a specially crafted URL, which caused
the install tool enable file check to fail.

As there was no easy solution to solve this issue,
we now introduce the need to create a file on first
install.

So in the installation directory the following must
be present:

d typo3
f index.php
f FIRST_INSTALL

After the installation the file will be removed.

Resolves: #55387
Releases: 6.2
Change-Id: I583581f18b939ba032950451bab17ac20131683b
Reviewed-on: https://review.typo3.org/28612
Reviewed-by: Markus Klein
Tested-by: Markus Klein
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
---
 .../Classes/Controller/AbstractController.php | 27 +++++++++---
 .../Action/Common/AccessNotAllowedAction.php  | 42 +++++++++++++++++++
 .../Action/Step/EnvironmentAndFolders.php     |  2 +
 .../Classes/Controller/AjaxController.php     | 12 ++----
 .../Classes/Service/EnableFileService.php     | 33 +++++++++++++++
 .../Action/Common/AccessNotAllowed.html       | 25 +++++++++++
 typo3/sysext/install/Start/Install.php        | 24 +++++------
 7 files changed, 138 insertions(+), 27 deletions(-)
 create mode 100644 typo3/sysext/install/Classes/Controller/Action/Common/AccessNotAllowedAction.php
 create mode 100644 typo3/sysext/install/Resources/Private/Templates/Action/Common/AccessNotAllowed.html

diff --git a/typo3/sysext/install/Classes/Controller/AbstractController.php b/typo3/sysext/install/Classes/Controller/AbstractController.php
index 61e4cb3879fe..01537284c41d 100644
--- a/typo3/sysext/install/Classes/Controller/AbstractController.php
+++ b/typo3/sysext/install/Classes/Controller/AbstractController.php
@@ -27,6 +27,7 @@ namespace TYPO3\CMS\Install\Controller;
  ***************************************************************/
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Service\EnableFileService;
 
 /**
  * Controller abstract for shared parts of Tool, Step and Ajax controller
@@ -48,6 +49,18 @@ class AbstractController {
 	 */
 	protected $authenticationActions = array();
 
+	/**
+	 * @return bool
+	 */
+	protected function isInstallToolAvailable() {
+		/** @var \TYPO3\CMS\Install\Service\EnableFileService $installToolEnableService */
+		$installToolEnableService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\EnableFileService');
+		if ($installToolEnableService->isFirstInstallAllowed()) {
+			return TRUE;
+		}
+		return $installToolEnableService->checkInstallToolEnableFile();
+	}
+
 	/**
 	 * Guard method checking typo3conf/ENABLE_INSTALL_TOOL
 	 *
@@ -58,16 +71,18 @@ class AbstractController {
 	 * @return void
 	 */
 	protected function outputInstallToolNotEnabledMessageIfNeeded() {
-		if (is_dir(PATH_typo3conf)) {
-			/** @var \TYPO3\CMS\Install\Service\EnableFileService $installToolEnableService */
-			$installToolEnableService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\EnableFileService');
-			if (!$installToolEnableService->checkInstallToolEnableFile()) {
+		if (!$this->isInstallToolAvailable()) {
+			if (!EnableFileService::isFirstInstallAllowed() && !is_dir(PATH_typo3conf)) {
+				/** @var \TYPO3\CMS\Install\Controller\Action\ActionInterface $action */
+				$action = $this->objectManager->get('TYPO3\\CMS\\Install\\Controller\\Action\\Common\\AccessNotAllowedAction');
+				$action->setAction('accessNotAllowed');
+			} else {
 				/** @var \TYPO3\CMS\Install\Controller\Action\ActionInterface $action */
 				$action = $this->objectManager->get('TYPO3\\CMS\\Install\\Controller\\Action\\Common\\InstallToolDisabledAction');
-				$action->setController('common');
 				$action->setAction('installToolDisabled');
-				$this->output($action->handle());
 			}
+			$action->setController('common');
+			$this->output($action->handle());
 		}
 	}
 
diff --git a/typo3/sysext/install/Classes/Controller/Action/Common/AccessNotAllowedAction.php b/typo3/sysext/install/Classes/Controller/Action/Common/AccessNotAllowedAction.php
new file mode 100644
index 000000000000..62873535fc68
--- /dev/null
+++ b/typo3/sysext/install/Classes/Controller/Action/Common/AccessNotAllowedAction.php
@@ -0,0 +1,42 @@
+<?php
+namespace TYPO3\CMS\Install\Controller\Action\Common;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Christian Kuhn <lolli@schwarzbu.ch>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Install\Controller\Action;
+
+/**
+ * Welcome page
+ */
+class AccessNotAllowedAction extends Action\AbstractAction {
+
+	/**
+	 * Handle this action
+	 *
+	 * @return string content
+	 */
+	public function executeAction() {
+		return $this->view->render();
+	}
+}
diff --git a/typo3/sysext/install/Classes/Controller/Action/Step/EnvironmentAndFolders.php b/typo3/sysext/install/Classes/Controller/Action/Step/EnvironmentAndFolders.php
index ae86aa8b92e0..808a10f3e204 100644
--- a/typo3/sysext/install/Classes/Controller/Action/Step/EnvironmentAndFolders.php
+++ b/typo3/sysext/install/Classes/Controller/Action/Step/EnvironmentAndFolders.php
@@ -72,7 +72,9 @@ class EnvironmentAndFolders extends AbstractStepAction {
 			}
 
 			// Create enable install tool file after typo3conf & LocalConfiguration were created
+			/** @var \TYPO3\CMS\Install\Service\EnableFileService $installToolService */
 			$installToolService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\EnableFileService');
+			$installToolService->removeFirstInstallFile();
 			$installToolService->createInstallToolEnableFile();
 		}
 
diff --git a/typo3/sysext/install/Classes/Controller/AjaxController.php b/typo3/sysext/install/Classes/Controller/AjaxController.php
index 1fd137403d40..74087fd23184 100644
--- a/typo3/sysext/install/Classes/Controller/AjaxController.php
+++ b/typo3/sysext/install/Classes/Controller/AjaxController.php
@@ -65,7 +65,7 @@ class AjaxController extends AbstractController {
 		$this->initializeObjectManager();
 		// Warning: Order of these methods is security relevant and interferes with different access
 		// conditions (new/existing installation). See the single method comments for details.
-		$this->checkInstallToolEnabled();
+		$this->outputInstallToolNotEnabledMessageIfNeeded();
 		$this->checkInstallToolPasswordNotSet();
 		$this->initializeSession();
 		$this->checkSessionToken();
@@ -79,13 +79,9 @@ class AjaxController extends AbstractController {
 	 *
 	 * @return void
 	 */
-	protected function checkInstallToolEnabled() {
-		if (is_dir(PATH_typo3conf)) {
-			/** @var \TYPO3\CMS\Install\Service\EnableFileService $installToolEnableService */
-			$installToolEnableService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\EnableFileService');
-			if (!$installToolEnableService->checkInstallToolEnableFile()) {
-				$this->output($this->unauthorized);
-			}
+	protected function outputInstallToolNotEnabledMessageIfNeeded() {
+		if (!$this->isInstallToolAvailable()) {
+			$this->output($this->unauthorized);
 		}
 	}
 
diff --git a/typo3/sysext/install/Classes/Service/EnableFileService.php b/typo3/sysext/install/Classes/Service/EnableFileService.php
index 24b234395f2d..74bd6867b56b 100644
--- a/typo3/sysext/install/Classes/Service/EnableFileService.php
+++ b/typo3/sysext/install/Classes/Service/EnableFileService.php
@@ -37,6 +37,21 @@ class EnableFileService {
 	 */
 	const INSTALL_TOOL_ENABLE_FILE_PATH = 'typo3conf/ENABLE_INSTALL_TOOL';
 
+	/**
+	 * @constant Relative path to  FIRST_INSTALL file
+	 */
+	const FIRST_INSTALL_FILE_PATH = 'FIRST_INSTALL';
+
+	/**
+	 * @return bool
+	 */
+	static public function isFirstInstallAllowed() {
+		if (!is_dir(PATH_typo3conf) && is_file(self::getFirstInstallFilePath())) {
+			return TRUE;
+		}
+		return FALSE;
+	}
+
 	/**
 	 * Creates the INSTALL_TOOL_ENABLE file
 	 *
@@ -63,6 +78,15 @@ class EnableFileService {
 		return unlink(self::getInstallToolEnableFilePath());
 	}
 
+	/**
+	 * Removes the FIRST_INSTALL file
+	 *
+	 * @return boolean
+	 */
+	static public function removeFirstInstallFile() {
+		return unlink(self::getFirstInstallFilePath());
+	}
+
 	/**
 	 * Checks if the install tool file exists
 	 *
@@ -114,4 +138,13 @@ class EnableFileService {
 	static protected function getInstallToolEnableFilePath() {
 		return PATH_site . self::INSTALL_TOOL_ENABLE_FILE_PATH;
 	}
+
+	/**
+	 * Returns the path to the INSTALL_TOOL_ENABLE file
+	 *
+	 * @return string
+	 */
+	static protected function getFirstInstallFilePath() {
+		return PATH_site . self::FIRST_INSTALL_FILE_PATH;
+	}
 }
diff --git a/typo3/sysext/install/Resources/Private/Templates/Action/Common/AccessNotAllowed.html b/typo3/sysext/install/Resources/Private/Templates/Action/Common/AccessNotAllowed.html
new file mode 100644
index 000000000000..c5c160857dac
--- /dev/null
+++ b/typo3/sysext/install/Resources/Private/Templates/Action/Common/AccessNotAllowed.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<title>The Access to the Install Tool blocked</title>
+	<link rel="stylesheet" type="text/css" href="../Resources/Public/Stylesheets/Action/Common/EarlyExit.css?{time}" />
+</head>
+<body>
+<div id="container">
+	<h1>TYPO3</h1>
+	<div class="typo3-message message-warning">
+		<h2>Thank you for installing TYPO3</h2>
+		<p>
+			To proceed with the installation, create the file <strong>FIRST_INSTALL</strong>
+			in your root directory.
+			The filename is case-sensitive but the file itself can be empty.
+		</p>
+
+		<p>
+			<strong>Note:</strong>
+			The file will be deleted once you proceed with the installation.
+		</p>
+	</div>
+</div>
+</body>
+</html>
diff --git a/typo3/sysext/install/Start/Install.php b/typo3/sysext/install/Start/Install.php
index 1c525745e06d..91f7f98b4c7a 100644
--- a/typo3/sysext/install/Start/Install.php
+++ b/typo3/sysext/install/Start/Install.php
@@ -118,17 +118,15 @@ require __DIR__ . '/../../core/Classes/Core/Bootstrap.php';
 
 // Execute 'tool' or 'step' controller depending on install[controller] GET/POST parameter
 $getPost = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('install');
-if (isset($getPost['controller']) && $getPost['controller'] === 'tool') {
-	$controller = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
-		'TYPO3\\CMS\\Install\\Controller\\ToolController'
-	);
-} elseif ($getPost['controller'] === 'ajax') {
-	$controller = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
-		'TYPO3\\CMS\\Install\\Controller\\AjaxController'
-	);
-} else {
-	$controller = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
-		'TYPO3\\CMS\\Install\\Controller\\StepController'
-	);
+$controllerClassName = 'TYPO3\\CMS\\Install\\Controller\\StepController';
+if (isset($getPost['controller'])) {
+	switch ($getPost['controller']) {
+		case 'tool':
+			$controllerClassName = 'TYPO3\\CMS\\Install\\Controller\\ToolController';
+			break;
+		case 'ajax':
+			$controllerClassName = 'TYPO3\\CMS\\Install\\Controller\\AjaxController';
+			break;
+	}
 }
-$controller->execute();
+\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($controllerClassName)->execute();
-- 
GitLab