[BUGFIX] Fix security level "normal" for backend login
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_beuserauth.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
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 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains class for TYPO3 backend user authentication
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
32 *
33 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
34 * @internal
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 76: class t3lib_beUserAuth extends t3lib_userAuthGroup
42 * 150: function trackBeUser($flag)
43 * 168: function checkLockToIP()
44 * 188: function backendCheckLogin()
45 * 216: function checkCLIuser()
46 * 240: function backendSetUC()
47 * 278: function overrideUC()
48 * 288: function resetUC()
49 * 301: function emailAtLogin()
50 * 353: function veriCode()
51 *
52 * TOTAL FUNCTIONS: 9
53 * (This index is automatically created/updated by the extension "extdeveval")
54 *
55 */
56
57
58 /**
59 * TYPO3 user authentication, backend
60 * Could technically have been the same class as t3lib_userauthgroup since these two are always used together and only together.
61 * t3lib_userauthgroup contains most of the functions used for checking permissions, authenticating users, setting up the user etc. This class is most interesting in terms of an API for user from outside.
62 * This class contains the configuration of the database fields used plus some functions for the authentication process of backend users.
63 *
64 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
65 * @package TYPO3
66 * @subpackage t3lib
67 */
68 class t3lib_beUserAuth extends t3lib_userAuthGroup {
69 var $session_table = 'be_sessions'; // Table to use for session data.
70 var $name = 'be_typo_user'; // Session/Cookie name
71
72 var $user_table = 'be_users'; // Table in database with userdata
73 var $username_column = 'username'; // Column for login-name
74 var $userident_column = 'password'; // Column for password
75 var $userid_column = 'uid'; // Column for user-id
76 var $lastLogin_column = 'lastlogin';
77
78 var $enablecolumns = Array(
79 'rootLevel' => 1,
80 'deleted' => 'deleted',
81 'disabled' => 'disable',
82 'starttime' => 'starttime',
83 'endtime' => 'endtime'
84 );
85
86 var $formfield_uname = 'username'; // formfield with login-name
87 var $formfield_uident = 'userident'; // formfield with password
88 var $formfield_chalvalue = 'challenge'; // formfield with a unique value which is used to encrypt the password and username
89 var $formfield_status = 'login_status'; // formfield with status: *'login', 'logout'
90
91 var $writeStdLog = 1; // Decides if the writelog() function is called at login and logout
92 var $writeAttemptLog = 1; // If the writelog() functions is called if a login-attempt has be tried without success
93
94 var $auth_include = ''; // this is the name of the include-file containing the login form. If not set, login CAN be anonymous. If set login IS needed.
95
96 var $auth_timeout_field = 6000; // if > 0 : session-timeout in seconds. if false/<0 : no timeout. if string: The string is fieldname from the usertable where the timeout can be found.
97 var $lifetime = 0; // 0 = Session-cookies. If session-cookies, the browser will stop session when the browser is closed. Else it keeps the session for $lifetime seconds.
98 var $challengeStoredInCookie = TRUE;
99
100
101 // User Config:
102 var $uc;
103
104 // User Config Default values:
105 // The array may contain other fields for configuration. For this, see "setup" extension and "TSConfig" document (User TSconfig, "setup.[xxx]....")
106 /*
107 Reserved keys for other storage of session data:
108 moduleData
109 moduleSessionID
110 */
111 var $uc_default = Array(
112 'interfaceSetup' => '', // serialized content that is used to store interface pane and menu positions. Set by the logout.php-script
113 'moduleData' => Array(), // user-data for the modules
114 'thumbnailsByDefault' => 0,
115 'emailMeAtLogin' => 0,
116 'condensedMode' => 0,
117 'noMenuMode' => 0,
118 'startModule' => 'help_aboutmodules',
119 'hideSubmoduleIcons' => 0,
120 'helpText' => 1,
121 'titleLen' => 30,
122 'edit_wideDocument' => '0',
123 'edit_showFieldHelp' => 'icon',
124 'edit_RTE' => '1',
125 'edit_docModuleUpload' => '1',
126 'enableFlashUploader' => '1',
127 'disableCMlayers' => 0,
128 'navFrameWidth' => '', // Default is 245 pixels
129 'navFrameResizable' => 0,
130 'resizeTextareas' => 1,
131 'resizeTextareas_MaxHeight' => 300,
132 'resizeTextareas_Flexible' => 1,
133 );
134
135
136 /**
137 * Sets the security level for the Backend login
138 *
139 * @return void
140 */
141 function start() {
142 $securityLevel = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']);
143 $standardSecurityLevels = array('normal', 'challenged', 'superchallenged');
144
145 // No challenge is stored in the session if security level is normal
146 if ($securityLevel === 'normal') {
147 $this->challengeStoredInCookie = FALSE;
148 }
149
150 // The TYPO3 standard login service relies on $this->security_level being set
151 // to 'superchallenged' because of the password in the database is stored as md5 hash
152 // @see t3lib_userauth::processLoginData()
153 if (!empty($securityLevel) && !in_array($securityLevel, $standardSecurityLevels)) {
154 $this->security_level = $securityLevel;
155 } else {
156 $this->security_level = 'superchallenged';
157 }
158
159 parent::start();
160 }
161
162 /**
163 * If flag is set and the extensions 'beuser_tracking' is loaded, this will insert a table row with the REQUEST_URI of current script - thus tracking the scripts the backend users uses...
164 * This function works ONLY with the "beuser_tracking" extension and is deprecated since it does nothing useful.
165 *
166 * @param boolean Activate insertion of the URL.
167 * @return void
168 * @deprecated since TYPO3 3.6, this function will be removed in TYPO3 4.6.
169 */
170 function trackBeUser($flag) {
171 t3lib_div::logDeprecatedFunction();
172
173 if ($flag && t3lib_extMgm::isLoaded('beuser_tracking')) {
174 $insertFields = array(
175 'userid' => intval($this->user['uid']),
176 'tstamp' => $GLOBALS['EXEC_TIME'],
177 'script' => t3lib_div::getIndpEnv('REQUEST_URI')
178 );
179
180 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_trackbeuser', $insertFields);
181 }
182 }
183
184 /**
185 * If TYPO3_CONF_VARS['BE']['enabledBeUserIPLock'] is enabled and an IP-list is found in the User TSconfig objString "options.lockToIP", then make an IP comparison with REMOTE_ADDR and return the outcome (true/false)
186 *
187 * @return boolean True, if IP address validates OK (or no check is done at all)
188 * @access private
189 */
190 function checkLockToIP() {
191 global $TYPO3_CONF_VARS;
192 $out = 1;
193 if ($TYPO3_CONF_VARS['BE']['enabledBeUserIPLock']) {
194 $IPList = $this->getTSConfigVal('options.lockToIP');
195 if (trim($IPList)) {
196 $baseIP = t3lib_div::getIndpEnv('REMOTE_ADDR');
197 $out = t3lib_div::cmpIP($baseIP, $IPList);
198 }
199 }
200 return $out;
201 }
202
203 /**
204 * Check if user is logged in and if so, call ->fetchGroupData() to load group information and access lists of all kind, further check IP, set the ->uc array and send login-notification email if required.
205 * If no user is logged in the default behaviour is to exit with an error message, but this will happen ONLY if the constant TYPO3_PROCEED_IF_NO_USER is set true.
206 * This function is called right after ->start() in fx. init.php
207 *
208 * @return void
209 */
210 function backendCheckLogin() {
211 if (!$this->user['uid']) {
212 if (!defined('TYPO3_PROCEED_IF_NO_USER') || !TYPO3_PROCEED_IF_NO_USER) {
213 t3lib_utility_Http::redirect($GLOBALS['BACK_PATH']);
214 }
215 } else { // ...and if that's the case, call these functions
216 $this->fetchGroupData(); // The groups are fetched and ready for permission checking in this initialization. Tables.php must be read before this because stuff like the modules has impact in this
217 if ($this->checkLockToIP()) {
218 if ($this->isUserAllowedToLogin()) {
219 $this->backendSetUC(); // Setting the UC array. It's needed with fetchGroupData first, due to default/overriding of values.
220 $this->emailAtLogin(); // email at login - if option set.
221 } else {
222 throw new RuntimeException('Login Error: TYPO3 is in maintenance mode at the moment. Only administrators are allowed access.');
223 }
224 } else {
225 throw new RuntimeException('Login Error: IP locking prevented you from being authorized. Can\'t proceed, sorry.');
226 }
227 }
228 }
229
230 /**
231 * If the backend script is in CLI mode, it will try to load a backend user named by the CLI module name (in lowercase)
232 *
233 * @return boolean Returns true if a CLI user was loaded, otherwise false!
234 */
235 function checkCLIuser() {
236 // First, check if cliMode is enabled:
237 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
238 if (!$this->user['uid']) {
239 if (substr($GLOBALS['MCONF']['name'], 0, 5) == '_CLI_') {
240 $userName = strtolower($GLOBALS['MCONF']['name']);
241 $this->setBeUserByName($userName);
242 if ($this->user['uid']) {
243 if (!$this->isAdmin()) {
244 return TRUE;
245 } else {
246 die('ERROR: CLI backend user "' . $userName . '" was ADMIN which is not allowed!' . LF . LF);
247 }
248 } else {
249 die('ERROR: No backend user named "' . $userName . '" was found! [Database: ' . TYPO3_db . ']' . LF . LF);
250 }
251 } else {
252 die('ERROR: Module name, "' . $GLOBALS['MCONF']['name'] . '", was not prefixed with "_CLI_"' . LF . LF);
253 }
254 } else {
255 die('ERROR: Another user was already loaded which is impossible in CLI mode!' . LF . LF);
256 }
257 }
258 }
259
260 /**
261 * Initialize the internal ->uc array for the backend user
262 * Will make the overrides if necessary, and write the UC back to the be_users record if changes has happend
263 *
264 * @return void
265 * @internal
266 */
267 function backendSetUC() {
268 global $TYPO3_CONF_VARS;
269
270 // UC - user configuration is a serialized array inside the userobject
271 $temp_theSavedUC = unserialize($this->user['uc']); // if there is a saved uc we implement that instead of the default one.
272 if (is_array($temp_theSavedUC)) {
273 $this->unpack_uc($temp_theSavedUC);
274 }
275 // Setting defaults if uc is empty
276 if (!is_array($this->uc)) {
277 $this->uc = array_merge(
278 $this->uc_default,
279 (array) $TYPO3_CONF_VARS['BE']['defaultUC'],
280 t3lib_div::removeDotsFromTS((array) $this->getTSConfigProp('setup.default'))
281 );
282 $this->overrideUC();
283 $U = 1;
284 }
285 // If TSconfig is updated, update the defaultUC.
286 if ($this->userTSUpdated) {
287 $this->overrideUC();
288 $U = 1;
289 }
290 // Setting default lang from be_user record.
291 if (!isset($this->uc['lang'])) {
292 $this->uc['lang'] = $this->user['lang'];
293 $U = 1;
294 }
295 // Setting the time of the first login:
296 if (!isset($this->uc['firstLoginTimeStamp'])) {
297 $this->uc['firstLoginTimeStamp'] = $GLOBALS['EXEC_TIME'];
298 $U = TRUE;
299 }
300
301 // Saving if updated.
302 if ($U) {
303 $this->writeUC(); // Method from the t3lib_userauth class.
304 }
305 }
306
307 /**
308 * Override: Call this function every time the uc is updated.
309 * That is 1) by reverting to default values, 2) in the setup-module, 3) userTS changes (userauthgroup)
310 *
311 * @return void
312 * @internal
313 */
314 function overrideUC() {
315 $this->uc = array_merge((array) $this->uc, (array) $this->getTSConfigProp('setup.override')); // Candidate for t3lib_div::array_merge() if integer-keys will some day make trouble...
316 }
317
318 /**
319 * Clears the user[uc] and ->uc to blank strings. Then calls ->backendSetUC() to fill it again with reset contents
320 *
321 * @return void
322 * @internal
323 */
324 function resetUC() {
325 $this->user['uc'] = '';
326 $this->uc = '';
327 $this->backendSetUC();
328 }
329
330 /**
331 * Will send an email notification to warning_email_address/the login users email address when a login session is just started.
332 * Depends on various parameters whether mails are send and to whom.
333 *
334 * @return void
335 * @access private
336 */
337 function emailAtLogin() {
338 if ($this->loginSessionStarted) {
339 // Send notify-mail
340 $subject = 'At "' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . '"' .
341 ' from ' . t3lib_div::getIndpEnv('REMOTE_ADDR') .
342 (t3lib_div::getIndpEnv('REMOTE_HOST') ? ' (' . t3lib_div::getIndpEnv('REMOTE_HOST') . ')' : '');
343 $msg = sprintf('User "%s" logged in from %s (%s) at "%s" (%s)',
344 $this->user['username'],
345 t3lib_div::getIndpEnv('REMOTE_ADDR'),
346 t3lib_div::getIndpEnv('REMOTE_HOST'),
347 $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
348 t3lib_div::getIndpEnv('HTTP_HOST')
349 );
350
351 // Warning email address
352 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr']) {
353 $warn = 0;
354 $prefix = '';
355 if (intval($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_mode']) & 1) { // first bit: All logins
356 $warn = 1;
357 $prefix = $this->isAdmin() ? '[AdminLoginWarning]' : '[LoginWarning]';
358 }
359 if ($this->isAdmin() && (intval($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_mode']) & 2)) { // second bit: Only admin-logins
360 $warn = 1;
361 $prefix = '[AdminLoginWarning]';
362 }
363 if ($warn) {
364 $from = t3lib_utility_Mail::getSystemFrom();
365 /** @var $mail t3lib_mail_Message */
366 $mail = t3lib_div::makeInstance('t3lib_mail_Message');
367 $mail->setTo($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'])
368 ->setFrom($from)
369 ->setSubject($prefix . ' ' . $subject)
370 ->setBody($msg);
371 $mail->send();
372 }
373 }
374
375 // If An email should be sent to the current user, do that:
376 if ($this->uc['emailMeAtLogin'] && strstr($this->user['email'], '@')) {
377 $from = t3lib_utility_Mail::getSystemFrom();
378 /** @var $mail t3lib_mail_Message */
379 $mail = t3lib_div::makeInstance('t3lib_mail_Message');
380 $mail->setTo($this->user['email'])
381 ->setFrom($from)
382 ->setSubject($subject)
383 ->setBody($msg);
384 $mail->send();
385 }
386 }
387 }
388
389 /**
390 * Determines whether a backend user is allowed to access the backend.
391 *
392 * The conditions are:
393 * + backend user is a regular user and adminOnly is not defined
394 * + backend user is an admin user
395 * + backend user is used in CLI context and adminOnly is explicitely set to "2"
396 *
397 * @return boolean Whether a backend user is allowed to access the backend
398 */
399 protected function isUserAllowedToLogin() {
400 $isUserAllowedToLogin = FALSE;
401 $adminOnlyMode = $GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'];
402
403 // Backend user is allowed if adminOnly is not set or user is an admin:
404 if (!$adminOnlyMode || $this->isAdmin()) {
405 $isUserAllowedToLogin = TRUE;
406 // Backend user is allowed if adminOnly is set to 2 (CLI) and a CLI process is running:
407 } elseif ($adminOnlyMode == 2 && (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI)) {
408 $isUserAllowedToLogin = TRUE;
409 }
410
411 return $isUserAllowedToLogin;
412 }
413
414 /**
415 * Logs out the current user and clears the form protection tokens.
416 */
417 public function logoff() {
418 if (isset($GLOBALS['BE_USER'])) {
419 t3lib_formProtection_Factory::get()->clean();
420 }
421 parent::logoff();
422 }
423 }
424
425
426 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_beuserauth.php'])) {
427 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_beuserauth.php']);
428 }
429
430 ?>