[TASK] Reports module uses internal data of salted passwords
[Packages/TYPO3.CMS.git] / typo3 / sysext / reports / reports / status / class.tx_reports_reports_status_securitystatus.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009-2011 Ingo Renner <ingo@typo3.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25
26 /**
27 * Performs several checks about the system's health
28 *
29 * @author Ingo Renner <ingo@typo3.org>
30 * @package TYPO3
31 * @subpackage reports
32 */
33 class tx_reports_reports_status_SecurityStatus implements tx_reports_StatusProvider {
34
35 /**
36 * Determines the Install Tool's status, mainly concerning its protection.
37 *
38 * @return array List of statuses
39 * @see typo3/sysext/reports/interfaces/tx_reports_StatusProvider::getStatus()
40 */
41 public function getStatus() {
42 $this->executeAdminCommand();
43
44 $statuses = array(
45 'adminUserAccount' => $this->getAdminAccountStatus(),
46 'encryptionKeyEmpty' => $this->getEncryptionKeyStatus(),
47 'fileDenyPattern' => $this->getFileDenyPatternStatus(),
48 'htaccessUpload' => $this->getHtaccessUploadStatus(),
49 'installToolEnabled' => $this->getInstallToolProtectionStatus(),
50 'installToolPassword' => $this->getInstallToolPasswordStatus(),
51 'saltedpasswords' => $this->getSaltedPasswordsStatus()
52 );
53
54 return $statuses;
55 }
56
57 /**
58 * Checks whether a an BE user account named admin with default password exists.
59 *
60 * @return tx_reports_reports_status_Status An tx_reports_reports_status_Status object representing whether a default admin account exists
61 */
62 protected function getAdminAccountStatus() {
63 $value = $GLOBALS['LANG']->getLL('status_ok');
64 $message = '';
65 $severity = tx_reports_reports_status_Status::OK;
66
67 $whereClause = 'username = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr('admin', 'be_users')
68 . t3lib_BEfunc::deleteClause('be_users');
69 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
70 'uid, username, password',
71 'be_users',
72 $whereClause
73 );
74 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
75 $secure = TRUE;
76
77 // Check against salted password
78 if (t3lib_extMgm::isLoaded('saltedpasswords')) {
79
80 if (tx_saltedpasswords_div::isUsageEnabled('BE')) {
81 /** @var $saltingObject tx_saltedpasswords_salts */
82 $saltingObject = tx_saltedpasswords_salts_factory::getSaltingInstance($row['password']);
83 if (is_object($saltingObject)) {
84 if ($saltingObject->checkPassword('password', $row['password'])) {
85 $secure = FALSE;
86 }
87 }
88 }
89 }
90
91 // Check against plain MD5
92 if ($row['password'] === '5f4dcc3b5aa765d61d8327deb882cf99') {
93 $secure = FALSE;
94 }
95
96 if (!$secure) {
97 $value = $GLOBALS['LANG']->getLL('status_insecure');
98 $severity = tx_reports_reports_status_Status::ERROR;
99
100 $editUserAccountUrl = 'alt_doc.php?returnUrl=mod.php?M=tools_txreportsM1&edit[be_users][' . $row['uid'] . ']=edit';
101 $message = sprintf(
102 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.backend_admin'),
103 '<a href="' . $editUserAccountUrl . '">',
104 '</a>'
105 );
106 }
107 }
108 $GLOBALS['TYPO3_DB']->sql_free_result($res);
109
110 return t3lib_div::makeInstance('tx_reports_reports_status_Status',
111 $GLOBALS['LANG']->getLL('status_adminUserAccount'), $value, $message, $severity
112 );
113 }
114
115 /**
116 * Checks whether the encryption key is empty.
117 *
118 * @return tx_reports_reports_status_Status An tx_reports_reports_status_Status object representing whether the encryption key is empty or not
119 */
120 protected function getEncryptionKeyStatus() {
121 $value = $GLOBALS['LANG']->getLL('status_ok');
122 $message = '';
123 $severity = tx_reports_reports_status_Status::OK;
124
125 if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
126 $value = $GLOBALS['LANG']->getLL('status_insecure');
127 $severity = tx_reports_reports_status_Status::ERROR;
128
129 $url = 'install/index.php?redirect_url=index.php'
130 . urlencode('?TYPO3_INSTALL[type]=config#set_encryptionKey');
131
132 $message = sprintf(
133 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_encryption'),
134 '<a href="' . $url . '">',
135 '</a>'
136 );
137 }
138
139 return t3lib_div::makeInstance('tx_reports_reports_status_Status',
140 $GLOBALS['LANG']->getLL('status_encryptionKey'), $value, $message, $severity
141 );
142 }
143
144 /**
145 * Checks if fileDenyPattern was changed which is dangerous on Apache
146 *
147 * @return tx_reports_reports_status_Status An tx_reports_reports_status_Status object representing whether the file deny pattern has changed
148 */
149 protected function getFileDenyPatternStatus() {
150 $value = $GLOBALS['LANG']->getLL('status_ok');
151 $message = '';
152 $severity = tx_reports_reports_status_Status::OK;
153
154 $defaultParts = t3lib_div::trimExplode('|', FILE_DENY_PATTERN_DEFAULT, TRUE);
155 $givenParts = t3lib_div::trimExplode('|', $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'], TRUE);
156 $result = array_intersect($defaultParts, $givenParts);
157 if ($defaultParts !== $result) {
158 $value = $GLOBALS['LANG']->getLL('status_insecure');
159 $severity = tx_reports_reports_status_Status::ERROR;
160
161 $url = 'install/index.php?redirect_url=index.php'
162 . urlencode('?TYPO3_INSTALL[type]=config#set_encryptionKey');
163
164 $message = sprintf(
165 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_deny_pattern_partsNotPresent'),
166 '<br /><pre>'
167 . htmlspecialchars(FILE_DENY_PATTERN_DEFAULT)
168 . '</pre><br />'
169 );
170 }
171
172 return t3lib_div::makeInstance('tx_reports_reports_status_Status',
173 $GLOBALS['LANG']->getLL('status_fileDenyPattern'), $value, $message, $severity
174 );
175 }
176
177 /**
178 * Checks if fileDenyPattern allows to upload .htaccess files which is
179 * dangerous on Apache.
180 *
181 * @return tx_reports_reports_status_Status An tx_reports_reports_status_Status object representing whether it's possible to upload .htaccess files
182 */
183 protected function getHtaccessUploadStatus() {
184 $value = $GLOBALS['LANG']->getLL('status_ok');
185 $message = '';
186 $severity = tx_reports_reports_status_Status::OK;
187
188 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] != FILE_DENY_PATTERN_DEFAULT && t3lib_div::verifyFilenameAgainstDenyPattern('.htaccess')) {
189 $value = $GLOBALS['LANG']->getLL('status_insecure');
190 $severity = tx_reports_reports_status_Status::ERROR;
191 $message = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_deny_htaccess');
192 }
193
194 return t3lib_div::makeInstance('tx_reports_reports_status_Status',
195 $GLOBALS['LANG']->getLL('status_htaccessUploadProtection'), $value, $message, $severity
196 );
197 }
198
199 /**
200 * Checks whether memcached is configured, if that's the case we asume it's also used.
201 *
202 * @return boolean TRUE if memcached is used, FALSE otherwise.
203 */
204 protected function isMemcachedUsed() {
205 $memcachedUsed = FALSE;
206
207 $memcachedServers = $this->getConfiguredMemcachedServers();
208 if (count($memcachedServers)) {
209 $memcachedUsed = TRUE;
210 }
211
212 return $memcachedUsed;
213 }
214
215
216 /**
217 * Executes commands like removing the Install Tool enable file.
218 *
219 * @return void
220 */
221 protected function executeAdminCommand() {
222 $command = t3lib_div::_GET('adminCmd');
223
224 switch ($command) {
225 case 'remove_ENABLE_INSTALL_TOOL':
226 unlink(PATH_site . 'typo3conf/ENABLE_INSTALL_TOOL');
227 break;
228 }
229 }
230
231 /**
232 * Checks whether the Install Tool password is set to its default value.
233 *
234 * @return tx_reports_reports_status_Status An tx_reports_reports_status_Status object representing the security of the install tool password
235 */
236 protected function getInstallToolPasswordStatus() {
237 $value = $GLOBALS['LANG']->getLL('status_ok');
238 $message = '';
239 $severity = tx_reports_reports_status_Status::OK;
240
241 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'] == md5('joh316')) {
242 $value = $GLOBALS['LANG']->getLL('status_insecure');
243 $severity = tx_reports_reports_status_Status::ERROR;
244
245 $changeInstallToolPasswordUrl = 'install/index.php?redirect_url=index.php'
246 . urlencode('?TYPO3_INSTALL[type]=about');
247
248 $message = sprintf(
249 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_password'),
250 '<a href="' . $changeInstallToolPasswordUrl . '">',
251 '</a>'
252 );
253 }
254
255 return t3lib_div::makeInstance('tx_reports_reports_status_Status',
256 $GLOBALS['LANG']->getLL('status_installToolPassword'), $value, $message, $severity
257 );
258 }
259
260 /**
261 * Checks whether the Install Tool password is set to its default value.
262 *
263 * @return tx_reports_reports_status_Status An tx_reports_reports_status_Status object representing the security of the saltedpassswords extension
264 */
265 protected function getSaltedPasswordsStatus() {
266 $value = $GLOBALS['LANG']->getLL('status_ok');
267 $message = '';
268 $severity = tx_reports_reports_status_Status::OK;
269
270 if (!t3lib_extMgm::isLoaded('saltedpasswords')) {
271 $value = $GLOBALS['LANG']->getLL('status_insecure');
272 $severity = tx_reports_reports_status_Status::ERROR;
273 $message .= $GLOBALS['LANG']->getLL('status_saltedPasswords_notInstalled');
274 } else {
275 /** @var tx_saltedpasswords_emconfhelper $configCheck */
276 $configCheck = t3lib_div::makeInstance('tx_saltedpasswords_emconfhelper');
277 $message .= '<p>' . $GLOBALS['LANG']->getLL('status_saltedPasswords_infoText') . '</p>';
278 $flashMessage = $configCheck->checkConfigurationBackend(array(), new t3lib_tsStyleConfig());
279
280 if (strpos($flashMessage, 'message-error') !== FALSE ||
281 strpos($flashMessage, 'message-warning') !== FALSE ||
282 strpos($flashMessage, 'message-information') !== FALSE
283 ) {
284 $value = $GLOBALS['LANG']->getLL('status_insecure');
285 $severity = tx_reports_reports_status_Status::ERROR;
286 $message .= $flashMessage;
287 }
288
289 $unsecureUserCount = tx_saltedpasswords_div::getNumberOfBackendUsersWithInsecurePassword();
290 if ($unsecureUserCount > 0) {
291 $value = $GLOBALS['LANG']->getLL('status_insecure');
292 $severity = tx_reports_reports_status_Status::ERROR;
293 $message .= '<div class="typo3-message message-warning">' .
294 $GLOBALS['LANG']->getLL('status_saltedPasswords_notAllPasswordsHashed') .'</div>';
295 }
296 }
297
298 return t3lib_div::makeInstance('tx_reports_reports_status_Status',
299 $GLOBALS['LANG']->getLL('status_saltedPasswords'), $value, $message, $severity
300 );
301 }
302
303 /**
304 * Checks for the existance of the ENABLE_INSTALL_TOOL file.
305 *
306 * @return tx_reports_reports_status_Status An tx_reports_reports_status_Status object representing whether ENABLE_INSTALL_TOOL exists
307 */
308 protected function getInstallToolProtectionStatus() {
309 $enableInstallToolFile = PATH_site . 'typo3conf/ENABLE_INSTALL_TOOL';
310 $value = $GLOBALS['LANG']->getLL('status_disabled');
311 $message = '';
312 $severity = tx_reports_reports_status_Status::OK;
313
314 $enableInstallToolFileExists = is_file($enableInstallToolFile);
315
316 if ($enableInstallToolFileExists) {
317
318 if (trim(file_get_contents($enableInstallToolFile)) === 'KEEP_FILE') {
319
320 $severity = tx_reports_reports_status_Status::WARNING;
321
322 $disableInstallToolUrl = t3lib_div::getIndpEnv('TYPO3_REQUEST_URL')
323 . '&amp;adminCmd=remove_ENABLE_INSTALL_TOOL';
324
325 $value = $GLOBALS['LANG']->getLL('status_enabledPermanently');
326
327 $message = sprintf(
328 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_enabled'),
329 '<span style="white-space: nowrap;">' . $enableInstallToolFile . '</span>');
330 $message .= ' <a href="' . $disableInstallToolUrl . '">'
331 . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_enabled_cmd')
332 . '</a>';
333
334 } else {
335
336 $enableInstallToolFileTtl = filemtime($enableInstallToolFile) + 3600 - time();
337
338 if ($enableInstallToolFileTtl <= 0) {
339
340 unlink($enableInstallToolFile);
341
342 } else {
343
344 $severity = tx_reports_reports_status_Status::NOTICE;
345
346 $disableInstallToolUrl = t3lib_div::getIndpEnv('TYPO3_REQUEST_URL')
347 . '&amp;adminCmd=remove_ENABLE_INSTALL_TOOL';
348
349 $value = $GLOBALS['LANG']->getLL('status_enabledTemporarily');
350
351 $message = sprintf(
352 $GLOBALS['LANG']->getLL('status_installEnabledTemporarily'),
353 '<span style="white-space: nowrap;">' . $enableInstallToolFile . '</span>', floor($enableInstallToolFileTtl/60) );
354 $message .= ' <a href="' . $disableInstallToolUrl . '">'
355 . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_enabled_cmd')
356 . '</a>';
357 }
358 }
359 }
360
361 return t3lib_div::makeInstance('tx_reports_reports_status_Status',
362 $GLOBALS['LANG']->getLL('status_installTool'), $value, $message, $severity
363 );
364 }
365
366 }
367
368
369 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/reports/reports/status/class.tx_reports_reports_status_securitystatus.php'])) {
370 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/reports/reports/status/class.tx_reports_reports_status_securitystatus.php']);
371 }
372
373 ?>