TYPO3 CMS  TYPO3_7-6
BackendUserAuthentication.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
23 
32 {
37  public $usergroup_column = 'usergroup';
38 
43  public $usergroup_table = 'be_groups';
44 
50  public $groupData = [
51  'filemounts' => []
52  ];
53 
58  public $userGroups = [];
59 
64  public $userGroupsUID = [];
65 
70  public $groupList = '';
71 
80  public $workspace = -99;
81 
86  public $workspaceRec = [];
87 
95  public $dataLists = [
96  'webmount_list' => '',
97  'filemount_list' => '',
98  'file_permissions' => '',
99  'modList' => '',
100  'tables_select' => '',
101  'tables_modify' => '',
102  'pagetypes_select' => '',
103  'non_exclude_fields' => '',
104  'explicit_allowdeny' => '',
105  'allowed_languages' => '',
106  'workspace_perms' => '',
107  'custom_options' => ''
108  ];
109 
114  public $includeHierarchy = [];
115 
120  public $includeGroupArray = [];
121 
127  public $OS = '';
128 
133  public $TSdataArray = [];
134 
139  public $userTS_text = '';
140 
145  public $userTS = [];
146 
151  public $userTSUpdated = false;
152 
157  public $userTS_dontGetCached = false;
158 
163  public $errorMsg = '';
164 
170 
174  protected $fileStorages;
175 
179  protected $filePermissions;
180 
185  public $session_table = 'be_sessions';
186 
191  public $user_table = 'be_users';
192 
197  public $username_column = 'username';
198 
203  public $userident_column = 'password';
204 
209  public $userid_column = 'uid';
210 
214  public $lastLogin_column = 'lastlogin';
215 
219  public $enablecolumns = [
220  'rootLevel' => 1,
221  'deleted' => 'deleted',
222  'disabled' => 'disable',
223  'starttime' => 'starttime',
224  'endtime' => 'endtime'
225  ];
226 
231  public $formfield_uname = 'username';
232 
237  public $formfield_uident = 'userident';
238 
243  public $formfield_status = 'login_status';
244 
249  public $writeStdLog = true;
250 
255  public $writeAttemptLog = true;
256 
263  public $auth_timeout_field = 6000;
264 
268  public $firstMainGroup = 0;
269 
274  public $uc;
275 
285  public $uc_default = [
286  'interfaceSetup' => '',
287  // serialized content that is used to store interface pane and menu positions. Set by the logout.php-script
288  'moduleData' => [],
289  // user-data for the modules
290  'thumbnailsByDefault' => 1,
291  'emailMeAtLogin' => 0,
292  'startModule' => 'help_AboutmodulesAboutmodules',
293  'hideSubmoduleIcons' => 0,
294  'titleLen' => 50,
295  'edit_RTE' => '1',
296  'edit_docModuleUpload' => '1',
297  // Default is 245 pixels
298  'navFrameResizable' => 0,
299  'resizeTextareas' => 1,
300  'resizeTextareas_MaxHeight' => 500,
301  'resizeTextareas_Flexible' => 0
302  ];
303 
307  public function __construct()
308  {
309  parent::__construct();
310  $this->name = self::getCookieName();
311  $this->loginType = 'BE';
312  $this->OS = TYPO3_OS;
313  }
314 
321  public function isAdmin()
322  {
323  return is_array($this->user) && ($this->user['admin'] & 1) == 1;
324  }
325 
334  public function isMemberOfGroup($groupId)
335  {
336  $groupId = (int)$groupId;
337  if ($this->groupList && $groupId) {
338  return GeneralUtility::inList($this->groupList, $groupId);
339  }
340  return false;
341  }
342 
358  public function doesUserHaveAccess($row, $perms)
359  {
360  $userPerms = $this->calcPerms($row);
361  return ($userPerms & $perms) == $perms;
362  }
363 
380  public function isInWebMount($id, $readPerms = '', $exitOnError = 0)
381  {
382  if (!$GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts'] || $this->isAdmin()) {
383  return 1;
384  }
385  $id = (int)$id;
386  // Check if input id is an offline version page in which case we will map id to the online version:
387  $checkRec = BackendUtility::getRecord('pages', $id, 'pid,t3ver_oid');
388  if ($checkRec['pid'] == -1) {
389  $id = (int)$checkRec['t3ver_oid'];
390  }
391  if (!$readPerms) {
392  $readPerms = $this->getPagePermsClause(1);
393  }
394  if ($id > 0) {
395  $wM = $this->returnWebmounts();
396  $rL = BackendUtility::BEgetRootLine($id, ' AND ' . $readPerms);
397  foreach ($rL as $v) {
398  if ($v['uid'] && in_array($v['uid'], $wM)) {
399  return $v['uid'];
400  }
401  }
402  }
403  if ($exitOnError) {
404  throw new \RuntimeException('Access Error: This page is not within your DB-mounts', 1294586445);
405  }
406  return null;
407  }
408 
417  public function modAccess($conf, $exitOnError)
418  {
419  if (!BackendUtility::isModuleSetInTBE_MODULES($conf['name'])) {
420  if ($exitOnError) {
421  throw new \RuntimeException('Fatal Error: This module "' . $conf['name'] . '" is not enabled in TBE_MODULES', 1294586446);
422  }
423  return false;
424  }
425  // Workspaces check:
426  if (
427  !empty($conf['workspaces'])
428  && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')
429  && ($this->workspace !== 0 || !GeneralUtility::inList($conf['workspaces'], 'online'))
430  && ($this->workspace !== -1 || !GeneralUtility::inList($conf['workspaces'], 'offline'))
431  && ($this->workspace <= 0 || !GeneralUtility::inList($conf['workspaces'], 'custom'))
432  ) {
433  if ($exitOnError) {
434  throw new \RuntimeException('Workspace Error: This module "' . $conf['name'] . '" is not available under the current workspace', 1294586447);
435  }
436  return false;
437  }
438  // Returns TRUE if conf[access] is not set at all or if the user is admin
439  if (!$conf['access'] || $this->isAdmin()) {
440  return true;
441  }
442  // If $conf['access'] is set but not with 'admin' then we return TRUE, if the module is found in the modList
443  $acs = false;
444  if (!strstr($conf['access'], 'admin') && $conf['name']) {
445  $acs = $this->check('modules', $conf['name']);
446  }
447  if (!$acs && $exitOnError) {
448  throw new \RuntimeException('Access Error: You don\'t have access to this module.', 1294586448);
449  } else {
450  return $acs;
451  }
452  }
453 
469  public function getPagePermsClause($perms)
470  {
471  if (is_array($this->user)) {
472  if ($this->isAdmin()) {
473  return ' 1=1';
474  }
475  $perms = (int)$perms;
476  // Make sure it's integer.
477  $str = ' (' . '(pages.perms_everybody & ' . $perms . ' = ' . $perms . ')' . ' OR (pages.perms_userid = '
478  . $this->user['uid'] . ' AND pages.perms_user & ' . $perms . ' = ' . $perms . ')';
479  // User
480  if ($this->groupList) {
481  // Group (if any is set)
482  $str .= ' OR (pages.perms_groupid in (' . $this->groupList . ') AND pages.perms_group & '
483  . $perms . ' = ' . $perms . ')';
484  }
485  $str .= ')';
486  // ****************
487  // getPagePermsClause-HOOK
488  // ****************
489  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getPagePermsClause'])) {
490  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getPagePermsClause'] as $_funcRef) {
491  $_params = ['currentClause' => $str, 'perms' => $perms];
492  $str = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
493  }
494  }
495  return $str;
496  } else {
497  return ' 1=0';
498  }
499  }
500 
510  public function calcPerms($row)
511  {
512  // Return 31 for admin users.
513  if ($this->isAdmin()) {
514  return Permission::ALL;
515  }
516  // Return 0 if page is not within the allowed web mount
517  if (!$this->isInWebMount($row['uid'])) {
518  return Permission::NOTHING;
519  }
520  $out = Permission::NOTHING;
521  if (
522  isset($row['perms_userid']) && isset($row['perms_user']) && isset($row['perms_groupid'])
523  && isset($row['perms_group']) && isset($row['perms_everybody']) && isset($this->groupList)
524  ) {
525  if ($this->user['uid'] == $row['perms_userid']) {
526  $out |= $row['perms_user'];
527  }
528  if ($this->isMemberOfGroup($row['perms_groupid'])) {
529  $out |= $row['perms_group'];
530  }
531  $out |= $row['perms_everybody'];
532  }
533  // ****************
534  // CALCPERMS hook
535  // ****************
536  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['calcPerms'])) {
537  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['calcPerms'] as $_funcRef) {
538  $_params = [
539  'row' => $row,
540  'outputPermissions' => $out
541  ];
542  $out = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
543  }
544  }
545  return $out;
546  }
547 
553  public function isRTE()
554  {
555  return (bool)$this->uc['edit_RTE'];
556  }
557 
568  public function check($type, $value)
569  {
570  if (isset($this->groupData[$type])) {
571  if ($this->isAdmin() || GeneralUtility::inList($this->groupData[$type], $value)) {
572  return true;
573  }
574  }
575  return false;
576  }
577 
587  public function checkAuthMode($table, $field, $value, $authMode)
588  {
589  // Admin users can do anything:
590  if ($this->isAdmin()) {
591  return true;
592  }
593  // Allow all blank values:
594  if ((string)$value === '') {
595  return true;
596  }
597  // Certain characters are not allowed in the value
598  if (preg_match('/[:|,]/', $value)) {
599  return false;
600  }
601  // Initialize:
602  $testValue = $table . ':' . $field . ':' . $value;
603  $out = true;
604  // Checking value:
605  switch ((string)$authMode) {
606  case 'explicitAllow':
607  if (!GeneralUtility::inList($this->groupData['explicit_allowdeny'], ($testValue . ':ALLOW'))) {
608  $out = false;
609  }
610  break;
611  case 'explicitDeny':
612  if (GeneralUtility::inList($this->groupData['explicit_allowdeny'], $testValue . ':DENY')) {
613  $out = false;
614  }
615  break;
616  case 'individual':
617  if (is_array($GLOBALS['TCA'][$table]) && is_array($GLOBALS['TCA'][$table]['columns'][$field])) {
618  $items = $GLOBALS['TCA'][$table]['columns'][$field]['config']['items'];
619  if (is_array($items)) {
620  foreach ($items as $iCfg) {
621  if ((string)$iCfg[1] === (string)$value && $iCfg[4]) {
622  switch ((string)$iCfg[4]) {
623  case 'EXPL_ALLOW':
624  if (!GeneralUtility::inList($this->groupData['explicit_allowdeny'], ($testValue . ':ALLOW'))) {
625  $out = false;
626  }
627  break;
628  case 'EXPL_DENY':
629  if (GeneralUtility::inList($this->groupData['explicit_allowdeny'], $testValue . ':DENY')) {
630  $out = false;
631  }
632  break;
633  }
634  break;
635  }
636  }
637  }
638  }
639  break;
640  }
641  return $out;
642  }
643 
650  public function checkLanguageAccess($langValue)
651  {
652  // The users language list must be non-blank - otherwise all languages are allowed.
653  if (trim($this->groupData['allowed_languages']) !== '') {
654  $langValue = (int)$langValue;
655  // Language must either be explicitly allowed OR the lang Value be "-1" (all languages)
656  if ($langValue != -1 && !$this->check('allowed_languages', $langValue)) {
657  return false;
658  }
659  }
660  return true;
661  }
662 
670  public function checkFullLanguagesAccess($table, $record)
671  {
672  $recordLocalizationAccess = $this->checkLanguageAccess(0);
673  if ($recordLocalizationAccess && (BackendUtility::isTableLocalizable($table) || isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable']))) {
674  if (isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable'])) {
675  $l10nTable = $GLOBALS['TCA'][$table]['ctrl']['transForeignTable'];
676  $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField'];
677  $pointerValue = $record['uid'];
678  } else {
679  $l10nTable = $table;
680  $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField'];
681  $pointerValue = $record[$pointerField] > 0 ? $record[$pointerField] : $record['uid'];
682  }
683  $recordLocalizations = BackendUtility::getRecordsByField($l10nTable, $pointerField, $pointerValue, '', '', '', '1');
684  if (is_array($recordLocalizations)) {
685  foreach ($recordLocalizations as $localization) {
686  $recordLocalizationAccess = $recordLocalizationAccess
687  && $this->checkLanguageAccess($localization[$GLOBALS['TCA'][$l10nTable]['ctrl']['languageField']]);
688  if (!$recordLocalizationAccess) {
689  break;
690  }
691  }
692  }
693  }
694  return $recordLocalizationAccess;
695  }
696 
712  public function recordEditAccessInternals($table, $idOrRow, $newRecord = false, $deletedRecord = false, $checkFullLanguageAccess = false)
713  {
714  if (!isset($GLOBALS['TCA'][$table])) {
715  return false;
716  }
717  // Always return TRUE for Admin users.
718  if ($this->isAdmin()) {
719  return true;
720  }
721  // Fetching the record if the $idOrRow variable was not an array on input:
722  if (!is_array($idOrRow)) {
723  if ($deletedRecord) {
724  $idOrRow = BackendUtility::getRecord($table, $idOrRow, '*', '', false);
725  } else {
726  $idOrRow = BackendUtility::getRecord($table, $idOrRow);
727  }
728  if (!is_array($idOrRow)) {
729  $this->errorMsg = 'ERROR: Record could not be fetched.';
730  return false;
731  }
732  }
733  // Checking languages:
734  if ($GLOBALS['TCA'][$table]['ctrl']['languageField']) {
735  // Language field must be found in input row - otherwise it does not make sense.
736  if (isset($idOrRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
737  if (!$this->checkLanguageAccess($idOrRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
738  $this->errorMsg = 'ERROR: Language was not allowed.';
739  return false;
740  } elseif (
741  $checkFullLanguageAccess && $idOrRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']] == 0
742  && !$this->checkFullLanguagesAccess($table, $idOrRow)
743  ) {
744  $this->errorMsg = 'ERROR: Related/affected language was not allowed.';
745  return false;
746  }
747  } else {
748  $this->errorMsg = 'ERROR: The "languageField" field named "'
749  . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '" was not found in testing record!';
750  return false;
751  }
752  } elseif (
753  isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable']) && $checkFullLanguageAccess &&
754  !$this->checkFullLanguagesAccess($table, $idOrRow)
755  ) {
756  return false;
757  }
758  // Checking authMode fields:
759  if (is_array($GLOBALS['TCA'][$table]['columns'])) {
760  foreach ($GLOBALS['TCA'][$table]['columns'] as $fieldName => $fieldValue) {
761  if (isset($idOrRow[$fieldName])) {
762  if (
763  $fieldValue['config']['type'] === 'select' && $fieldValue['config']['authMode']
764  && $fieldValue['config']['authMode_enforce'] === 'strict'
765  ) {
766  if (!$this->checkAuthMode($table, $fieldName, $idOrRow[$fieldName], $fieldValue['config']['authMode'])) {
767  $this->errorMsg = 'ERROR: authMode "' . $fieldValue['config']['authMode']
768  . '" failed for field "' . $fieldName . '" with value "'
769  . $idOrRow[$fieldName] . '" evaluated';
770  return false;
771  }
772  }
773  }
774  }
775  }
776  // Checking "editlock" feature (doesn't apply to new records)
777  if (!$newRecord && $GLOBALS['TCA'][$table]['ctrl']['editlock']) {
778  if (isset($idOrRow[$GLOBALS['TCA'][$table]['ctrl']['editlock']])) {
779  if ($idOrRow[$GLOBALS['TCA'][$table]['ctrl']['editlock']]) {
780  $this->errorMsg = 'ERROR: Record was locked for editing. Only admin users can change this state.';
781  return false;
782  }
783  } else {
784  $this->errorMsg = 'ERROR: The "editLock" field named "' . $GLOBALS['TCA'][$table]['ctrl']['editlock']
785  . '" was not found in testing record!';
786  return false;
787  }
788  }
789  // Checking record permissions
790  // THIS is where we can include a check for "perms_" fields for other records than pages...
791  // Process any hooks
792  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['recordEditAccessInternals'])) {
793  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['recordEditAccessInternals'] as $funcRef) {
794  $params = [
795  'table' => $table,
796  'idOrRow' => $idOrRow,
797  'newRecord' => $newRecord
798  ];
799  if (!GeneralUtility::callUserFunction($funcRef, $params, $this)) {
800  return false;
801  }
802  }
803  }
804  // Finally, return TRUE if all is well.
805  return true;
806  }
807 
818  public function isPSet($compiledPermissions, $tableName, $actionType = '')
819  {
820  if ($this->isAdmin()) {
821  $result = true;
822  } elseif ($tableName == 'pages') {
823  switch ($actionType) {
824  case 'edit':
825  $result = ($compiledPermissions & Permission::PAGE_EDIT) !== 0;
826  break;
827  case 'new':
828  // Create new page OR page content
829  $result = ($compiledPermissions & Permission::PAGE_NEW + Permission::CONTENT_EDIT) !== 0;
830  break;
831  case 'delete':
832  $result = ($compiledPermissions & Permission::PAGE_DELETE) !== 0;
833  break;
834  case 'editcontent':
835  $result = ($compiledPermissions & Permission::CONTENT_EDIT) !== 0;
836  break;
837  default:
838  $result = false;
839  }
840  } else {
841  $result = ($compiledPermissions & Permission::CONTENT_EDIT) !== 0;
842  }
843  return $result;
844  }
845 
851  public function mayMakeShortcut()
852  {
853  return $this->getTSConfigVal('options.enableBookmarks')
854  && !$this->getTSConfigVal('options.mayNotCreateEditBookmarks');
855  }
856 
868  public function workspaceCannotEditRecord($table, $recData)
869  {
870  // Only test offline spaces:
871  if ($this->workspace !== 0) {
872  if (!is_array($recData)) {
873  $recData = BackendUtility::getRecord(
874  $table,
875  $recData,
876  'pid' . ($GLOBALS['TCA'][$table]['ctrl']['versioningWS'] ? ',t3ver_wsid,t3ver_stage' : '')
877  );
878  }
879  if (is_array($recData)) {
880  // We are testing a "version" (identified by a pid of -1): it can be edited provided
881  // that workspace matches and versioning is enabled for the table.
882  if ((int)$recData['pid'] === -1) {
883  // No versioning, basic error, inconsistency even! Such records should not have a pid of -1!
884  if (!$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
885  return 'Versioning disabled for table';
886  } elseif ((int)$recData['t3ver_wsid'] !== $this->workspace) {
887  // So does workspace match?
888  return 'Workspace ID of record didn\'t match current workspace';
889  } else {
890  // So is the user allowed to "use" the edit stage within the workspace?
891  return $this->workspaceCheckStageForCurrent(0)
892  ? false
893  : 'User\'s access level did not allow for editing';
894  }
895  } else {
896  // We are testing a "live" record:
897  // For "Live" records, check that PID for table allows editing
898  if ($res = $this->workspaceAllowLiveRecordsInPID($recData['pid'], $table)) {
899  // Live records are OK in this branch, but what about the stage of branch point, if any:
900  // OK
901  return $res > 0
902  ? false
903  : 'Stage for versioning root point and users access level did not allow for editing';
904  } else {
905  // If not offline and not in versionized branch, output error:
906  return 'Online record was not in versionized branch!';
907  }
908  }
909  } else {
910  return 'No record';
911  }
912  } else {
913  // OK because workspace is 0
914  return false;
915  }
916  }
917 
926  public function workspaceCannotEditOfflineVersion($table, $recData)
927  {
928  if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
929  if (!is_array($recData)) {
930  $recData = BackendUtility::getRecord($table, $recData, 'uid,pid,t3ver_wsid,t3ver_stage');
931  }
932  if (is_array($recData)) {
933  if ((int)$recData['pid'] === -1) {
934  return $this->workspaceCannotEditRecord($table, $recData);
935  } else {
936  return 'Not an offline version';
937  }
938  } else {
939  return 'No record';
940  }
941  } else {
942  return 'Table does not support versioning.';
943  }
944  }
945 
957  public function workspaceAllowLiveRecordsInPID($pid, $table)
958  {
959  // Always for Live workspace AND if live-edit is enabled
960  // and tables are completely without versioning it is ok as well.
961  if (
962  $this->workspace === 0
963  || $this->workspaceRec['live_edit'] && !$GLOBALS['TCA'][$table]['ctrl']['versioningWS']
964  || $GLOBALS['TCA'][$table]['ctrl']['versioningWS_alwaysAllowLiveEdit']
965  ) {
966  // OK to create for this table.
967  return 2;
968  } else {
969  // If the answer is FALSE it means the only valid way to create or edit records in the PID is by versioning
970  return false;
971  }
972  }
973 
981  public function workspaceCreateNewRecord($pid, $table)
982  {
983  if ($res = $this->workspaceAllowLiveRecordsInPID($pid, $table)) {
984  // If LIVE records cannot be created in the current PID due to workspace restrictions, prepare creation of placeholder-record
985  if ($res < 0) {
986  // Stage for versioning root point and users access level did not allow for editing
987  return false;
988  }
989  } elseif (!$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
990  // So, if no live records were allowed, we have to create a new version of this record:
991  return false;
992  }
993  return true;
994  }
995 
1004  public function workspaceAllowAutoCreation($table, $id, $recpid)
1005  {
1006  // Auto-creation of version: In offline workspace, test if versioning is
1007  // enabled and look for workspace version of input record.
1008  // If there is no versionized record found we will create one and save to that.
1009  if (
1010  $this->workspace !== 0
1011  && $GLOBALS['TCA'][$table]['ctrl']['versioningWS'] && $recpid >= 0
1012  && !BackendUtility::getWorkspaceVersionOfRecord($this->workspace, $table, $id, 'uid')
1013  ) {
1014  // There must be no existing version of this record in workspace.
1015  return true;
1016  }
1017  return false;
1018  }
1019 
1029  public function workspaceCheckStageForCurrent($stage)
1030  {
1031  // Always allow for admins
1032  if ($this->isAdmin()) {
1033  return true;
1034  }
1035  if ($this->workspace !== 0 && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')) {
1036  $stage = (int)$stage;
1037  $stat = $this->checkWorkspaceCurrent();
1038  // Check if custom staging is activated
1039  $workspaceRec = BackendUtility::getRecord('sys_workspace', $stat['uid']);
1040  if ($workspaceRec['custom_stages'] > 0 && $stage !== 0 && $stage !== -10) {
1041  // Get custom stage record
1042  $workspaceStageRec = BackendUtility::getRecord('sys_workspace_stage', $stage);
1043  // Check if the user is responsible for the current stage
1044  if (
1045  $stat['_ACCESS'] === 'owner'
1046  || $stat['_ACCESS'] === 'member'
1047  && GeneralUtility::inList($workspaceStageRec['responsible_persons'], 'be_users_' . $this->user['uid'])
1048  ) {
1049  return true;
1050  }
1051  // Check if the user is in a group which is responsible for the current stage
1052  foreach ($this->userGroupsUID as $groupUid) {
1053  if (
1054  $stat['_ACCESS'] === 'owner'
1055  || $stat['_ACCESS'] === 'member'
1056  && GeneralUtility::inList($workspaceStageRec['responsible_persons'], 'be_groups_' . $groupUid)
1057  ) {
1058  return true;
1059  }
1060  }
1061  } elseif ($stage == -10 || $stage == -20) {
1062  if ($stat['_ACCESS'] === 'owner') {
1063  return true;
1064  } else {
1065  return false;
1066  }
1067  } else {
1068  $memberStageLimit = $this->workspaceRec['review_stage_edit'] ? 1 : 0;
1069  if (
1070  $stat['_ACCESS'] === 'owner'
1071  || $stat['_ACCESS'] === 'reviewer' && $stage <= 1
1072  || $stat['_ACCESS'] === 'member' && $stage <= $memberStageLimit
1073  ) {
1074  return true;
1075  }
1076  }
1077  } else {
1078  // Always OK for live workspace.
1079  return true;
1080  }
1081  return false;
1082  }
1083 
1094  public function workspacePublishAccess($wsid)
1095  {
1096  if ($this->isAdmin()) {
1097  return true;
1098  }
1099  // If no access to workspace, of course you cannot publish!
1100  $retVal = false;
1101  $wsAccess = $this->checkWorkspace($wsid);
1102  if ($wsAccess) {
1103  switch ($wsAccess['uid']) {
1104  case 0:
1105  // Live workspace
1106  // If access to Live workspace, no problem.
1107  $retVal = true;
1108  break;
1109  default:
1110  // Custom workspace
1111  $retVal = $wsAccess['_ACCESS'] === 'owner' || $this->checkWorkspace(0) && !($wsAccess['publish_access'] & Permission::PAGE_EDIT);
1112  // Either be an adminuser OR have access to online
1113  // workspace which is OK as well as long as publishing
1114  // access is not limited by workspace option.
1115  }
1116  }
1117  return $retVal;
1118  }
1119 
1125  public function workspaceSwapAccess()
1126  {
1127  if ($this->workspace > 0 && (int)$this->workspaceRec['swap_modes'] === 2) {
1128  return false;
1129  } else {
1130  return true;
1131  }
1132  }
1133 
1142  public function getTSConfig($objectString, $config = '')
1143  {
1144  if (!is_array($config)) {
1145  // Getting Root-ts if not sent
1146  $config = $this->userTS;
1147  }
1148  $TSConf = ['value' => null, 'properties' => null];
1149  $parts = GeneralUtility::trimExplode('.', $objectString, true, 2);
1150  $key = $parts[0];
1151  if ($key !== '') {
1152  if (count($parts) > 1 && $parts[1] !== '') {
1153  // Go on, get the next level
1154  if (is_array($config[$key . '.'])) {
1155  $TSConf = $this->getTSConfig($parts[1], $config[$key . '.']);
1156  }
1157  } else {
1158  $TSConf['value'] = $config[$key];
1159  $TSConf['properties'] = $config[$key . '.'];
1160  }
1161  }
1162  return $TSConf;
1163  }
1164 
1172  public function getTSConfigVal($objectString)
1173  {
1174  $TSConf = $this->getTSConfig($objectString);
1175  return $TSConf['value'];
1176  }
1177 
1185  public function getTSConfigProp($objectString)
1186  {
1187  $TSConf = $this->getTSConfig($objectString);
1188  return $TSConf['properties'];
1189  }
1190 
1199  public function returnWebmounts()
1200  {
1201  return (string)$this->groupData['webmounts'] != '' ? explode(',', $this->groupData['webmounts']) : [];
1202  }
1203 
1211  public function setWebmounts(array $mountPointUids, $append = false)
1212  {
1213  if (empty($mountPointUids)) {
1214  return;
1215  }
1216  if ($append) {
1217  $currentWebMounts = GeneralUtility::intExplode(',', $this->groupData['webmounts']);
1218  $mountPointUids = array_merge($currentWebMounts, $mountPointUids);
1219  }
1220  $this->groupData['webmounts'] = implode(',', array_unique($mountPointUids));
1221  }
1222 
1231  public function jsConfirmation($bitmask)
1232  {
1233  try {
1234  $alertPopupsSetting = trim((string)$this->getTSConfig('options.alertPopups')['value']);
1235  $alertPopup = JsConfirmation::cast($alertPopupsSetting === '' ? null : (int)$alertPopupsSetting);
1236  } catch (InvalidEnumerationValueException $e) {
1237  $alertPopup = new JsConfirmation();
1238  }
1239 
1240  return JsConfirmation::cast($bitmask)->matches($alertPopup);
1241  }
1242 
1253  public function fetchGroupData()
1254  {
1255  if ($this->user['uid']) {
1256  // Get lists for the be_user record and set them as default/primary values.
1257  // Enabled Backend Modules
1258  $this->dataLists['modList'] = $this->user['userMods'];
1259  // Add Allowed Languages
1260  $this->dataLists['allowed_languages'] = $this->user['allowed_languages'];
1261  // Set user value for workspace permissions.
1262  $this->dataLists['workspace_perms'] = $this->user['workspace_perms'];
1263  // Database mountpoints
1264  $this->dataLists['webmount_list'] = $this->user['db_mountpoints'];
1265  // File mountpoints
1266  $this->dataLists['filemount_list'] = $this->user['file_mountpoints'];
1267  // Fileoperation permissions
1268  $this->dataLists['file_permissions'] = $this->user['file_permissions'];
1269  // Setting default User TSconfig:
1270  $this->TSdataArray[] = $this->addTScomment('From $GLOBALS["TYPO3_CONF_VARS"]["BE"]["defaultUserTSconfig"]:')
1271  . $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultUserTSconfig'];
1272  // Default TSconfig for admin-users
1273  if ($this->isAdmin()) {
1274  $this->TSdataArray[] = $this->addTScomment('"admin" user presets:') . '
1275  admPanel.enable.all = 1
1276  ';
1277  if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sys_note')) {
1278  $this->TSdataArray[] = '
1279  // Setting defaults for sys_note author / email...
1280  TCAdefaults.sys_note.author = ' . $this->user['realName'] . '
1281  TCAdefaults.sys_note.email = ' . $this->user['email'] . '
1282  ';
1283  }
1284  }
1285  // BE_GROUPS:
1286  // Get the groups...
1287  if (!empty($this->user[$this->usergroup_column])) {
1288  // Fetch groups will add a lot of information to the internal arrays: modules, accesslists, TSconfig etc.
1289  // Refer to fetchGroups() function.
1290  $this->fetchGroups($this->user[$this->usergroup_column]);
1291  }
1292 
1293  // Populating the $this->userGroupsUID -array with the groups in the order in which they were LAST included.!!
1294  $this->userGroupsUID = array_reverse(array_unique(array_reverse($this->includeGroupArray)));
1295  // Finally this is the list of group_uid's in the order they are parsed (including subgroups!)
1296  // and without duplicates (duplicates are presented with their last entrance in the list,
1297  // which thus reflects the order of the TypoScript in TSconfig)
1298  $this->groupList = implode(',', $this->userGroupsUID);
1299  $this->setCachedList($this->groupList);
1300 
1301  // Add the TSconfig for this specific user:
1302  $this->TSdataArray[] = $this->addTScomment('USER TSconfig field') . $this->user['TSconfig'];
1303  // Check include lines.
1304  $this->TSdataArray = \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::checkIncludeLines_array($this->TSdataArray);
1305  // Imploding with "[global]" will make sure that non-ended confinements with braces are ignored.
1306  $this->userTS_text = implode(LF . '[GLOBAL]' . LF, $this->TSdataArray);
1307  if (!$this->userTS_dontGetCached) {
1308  // Perform TS-Config parsing with condition matching
1309  $parseObj = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TsConfigParser::class);
1310  $res = $parseObj->parseTSconfig($this->userTS_text, 'userTS');
1311  if ($res) {
1312  $this->userTS = $res['TSconfig'];
1313  $this->userTSUpdated = (bool)$res['cached'];
1314  }
1315  } else {
1316  // Parsing the user TSconfig (or getting from cache)
1317  $hash = md5('userTS:' . $this->userTS_text);
1318  $cachedContent = BackendUtility::getHash($hash);
1319  if (is_array($cachedContent) && !$this->userTS_dontGetCached) {
1320  $this->userTS = $cachedContent;
1321  } else {
1322  $parseObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::class);
1323  $parseObj->parse($this->userTS_text);
1324  $this->userTS = $parseObj->setup;
1325  BackendUtility::storeHash($hash, $this->userTS, 'BE_USER_TSconfig');
1326  // Update UC:
1327  $this->userTSUpdated = true;
1328  }
1329  }
1330  // Processing webmounts
1331  // Admin's always have the root mounted
1332  if ($this->isAdmin() && !$this->getTSConfigVal('options.dontMountAdminMounts')) {
1333  $this->dataLists['webmount_list'] = '0,' . $this->dataLists['webmount_list'];
1334  }
1335  // The lists are cleaned for duplicates
1336  $this->groupData['webmounts'] = GeneralUtility::uniqueList($this->dataLists['webmount_list']);
1337  $this->groupData['pagetypes_select'] = GeneralUtility::uniqueList($this->dataLists['pagetypes_select']);
1338  $this->groupData['tables_select'] = GeneralUtility::uniqueList($this->dataLists['tables_modify'] . ',' . $this->dataLists['tables_select']);
1339  $this->groupData['tables_modify'] = GeneralUtility::uniqueList($this->dataLists['tables_modify']);
1340  $this->groupData['non_exclude_fields'] = GeneralUtility::uniqueList($this->dataLists['non_exclude_fields']);
1341  $this->groupData['explicit_allowdeny'] = GeneralUtility::uniqueList($this->dataLists['explicit_allowdeny']);
1342  $this->groupData['allowed_languages'] = GeneralUtility::uniqueList($this->dataLists['allowed_languages']);
1343  $this->groupData['custom_options'] = GeneralUtility::uniqueList($this->dataLists['custom_options']);
1344  $this->groupData['modules'] = GeneralUtility::uniqueList($this->dataLists['modList']);
1345  $this->groupData['file_permissions'] = GeneralUtility::uniqueList($this->dataLists['file_permissions']);
1346  $this->groupData['workspace_perms'] = $this->dataLists['workspace_perms'];
1347 
1348  // Checking read access to webmounts:
1349  if (trim($this->groupData['webmounts']) !== '') {
1350  $webmounts = explode(',', $this->groupData['webmounts']);
1351  // Explode mounts
1352  // Selecting all webmounts with permission clause for reading
1353  $where = 'deleted=0 AND uid IN (' . $this->groupData['webmounts'] . ') AND ' . $this->getPagePermsClause(1);
1354  $MProws = $this->db->exec_SELECTgetRows('uid', 'pages', $where, '', '', '', 'uid');
1355  foreach ($webmounts as $idx => $mountPointUid) {
1356  // If the mount ID is NOT found among selected pages, unset it:
1357  if ($mountPointUid > 0 && !isset($MProws[$mountPointUid])) {
1358  unset($webmounts[$idx]);
1359  }
1360  }
1361  // Implode mounts in the end.
1362  $this->groupData['webmounts'] = implode(',', $webmounts);
1363  }
1364  // Setting up workspace situation (after webmounts are processed!):
1365  $this->workspaceInit();
1366  }
1367  }
1368 
1378  public function fetchGroups($grList, $idList = '')
1379  {
1380  // Fetching records of the groups in $grList (which are not blocked by lockedToDomain either):
1381  $lockToDomain_SQL = ' AND (lockToDomain=\'\' OR lockToDomain IS NULL OR lockToDomain=' . $this->db->fullQuoteStr(GeneralUtility::getIndpEnv('HTTP_HOST'), $this->usergroup_table) . ')';
1382  $grList = $this->db->cleanIntList($grList);
1383  $whereSQL = 'deleted=0 AND hidden=0 AND pid=0 AND uid IN (' . $grList . ')' . $lockToDomain_SQL;
1384  // Hook for manipulation of the WHERE sql sentence which controls which BE-groups are included
1385  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroupQuery'])) {
1386  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroupQuery'] as $classRef) {
1387  $hookObj = GeneralUtility::getUserObj($classRef);
1388  if (method_exists($hookObj, 'fetchGroupQuery_processQuery')) {
1389  $whereSQL = $hookObj->fetchGroupQuery_processQuery($this, $grList, $idList, $whereSQL);
1390  }
1391  }
1392  }
1393  $res = $this->db->exec_SELECTquery('*', $this->usergroup_table, $whereSQL);
1394  // The userGroups array is filled
1395  while ($row = $this->db->sql_fetch_assoc($res)) {
1396  $this->userGroups[$row['uid']] = $row;
1397  }
1398  $this->db->sql_free_result($res);
1399  // Traversing records in the correct order
1400  foreach (explode(',', $grList) as $uid) {
1401  // Get row:
1402  $row = $this->userGroups[$uid];
1403  // Must be an array and $uid should not be in the idList, because then it is somewhere previously in the grouplist
1404  if (is_array($row) && !GeneralUtility::inList($idList, $uid)) {
1405  // Include sub groups
1406  if (trim($row['subgroup'])) {
1407  // Make integer list
1408  $theList = implode(',', GeneralUtility::intExplode(',', $row['subgroup']));
1409  // Call recursively, pass along list of already processed groups so they are not recursed again.
1410  $this->fetchGroups($theList, $idList . ',' . $uid);
1411  }
1412  // Add the group uid, current list, TSconfig to the internal arrays.
1413  $this->includeGroupArray[] = $uid;
1414  $this->includeHierarchy[] = $idList;
1415  $this->TSdataArray[] = $this->addTScomment('Group "' . $row['title'] . '" [' . $row['uid'] . '] TSconfig field:') . $row['TSconfig'];
1416  // Mount group database-mounts
1417  if (($this->user['options'] & Permission::PAGE_SHOW) == 1) {
1418  $this->dataLists['webmount_list'] .= ',' . $row['db_mountpoints'];
1419  }
1420  // Mount group file-mounts
1421  if (($this->user['options'] & Permission::PAGE_EDIT) == 2) {
1422  $this->dataLists['filemount_list'] .= ',' . $row['file_mountpoints'];
1423  }
1424  // The lists are made: groupMods, tables_select, tables_modify, pagetypes_select, non_exclude_fields, explicit_allowdeny, allowed_languages, custom_options
1425  $this->dataLists['modList'] .= ',' . $row['groupMods'];
1426  $this->dataLists['tables_select'] .= ',' . $row['tables_select'];
1427  $this->dataLists['tables_modify'] .= ',' . $row['tables_modify'];
1428  $this->dataLists['pagetypes_select'] .= ',' . $row['pagetypes_select'];
1429  $this->dataLists['non_exclude_fields'] .= ',' . $row['non_exclude_fields'];
1430  $this->dataLists['explicit_allowdeny'] .= ',' . $row['explicit_allowdeny'];
1431  $this->dataLists['allowed_languages'] .= ',' . $row['allowed_languages'];
1432  $this->dataLists['custom_options'] .= ',' . $row['custom_options'];
1433  $this->dataLists['file_permissions'] .= ',' . $row['file_permissions'];
1434  // Setting workspace permissions:
1435  $this->dataLists['workspace_perms'] |= $row['workspace_perms'];
1436  // If this function is processing the users OWN group-list (not subgroups) AND
1437  // if the ->firstMainGroup is not set, then the ->firstMainGroup will be set.
1438  if ($idList === '' && !$this->firstMainGroup) {
1439  $this->firstMainGroup = $uid;
1440  }
1441  }
1442  }
1443  // HOOK: fetchGroups_postProcessing
1444  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroups_postProcessing'])) {
1445  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroups_postProcessing'] as $_funcRef) {
1446  $_params = [];
1447  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1448  }
1449  }
1450  }
1451 
1463  public function setCachedList($cList)
1464  {
1465  if ((string)$cList != (string)$this->user['usergroup_cached_list']) {
1466  $this->db->exec_UPDATEquery('be_users', 'uid=' . (int)$this->user['uid'], ['usergroup_cached_list' => $cList]);
1467  }
1468  }
1469 
1476  protected function initializeFileStorages()
1477  {
1478  $this->fileStorages = [];
1480  $storageRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\StorageRepository::class);
1481  // Admin users have all file storages visible, without any filters
1482  if ($this->isAdmin()) {
1483  $storageObjects = $storageRepository->findAll();
1484  foreach ($storageObjects as $storageObject) {
1485  $this->fileStorages[$storageObject->getUid()] = $storageObject;
1486  }
1487  } else {
1488  // Regular users only have storages that are defined in their filemounts
1489  // Permissions and file mounts for the storage are added in StoragePermissionAspect
1490  foreach ($this->getFileMountRecords() as $row) {
1491  if (!array_key_exists((int)$row['base'], $this->fileStorages)) {
1492  $storageObject = $storageRepository->findByUid($row['base']);
1493  if ($storageObject) {
1494  $this->fileStorages[$storageObject->getUid()] = $storageObject;
1495  }
1496  }
1497  }
1498  }
1499 
1500  // This has to be called always in order to set certain filters
1502  }
1503 
1510  public function getCategoryMountPoints()
1511  {
1512  $categoryMountPoints = '';
1513 
1514  // Category mounts of the groups
1515  if (is_array($this->userGroups)) {
1516  foreach ($this->userGroups as $group) {
1517  if ($group['category_perms']) {
1518  $categoryMountPoints .= ',' . $group['category_perms'];
1519  }
1520  }
1521  }
1522 
1523  // Category mounts of the user record
1524  if ($this->user['category_perms']) {
1525  $categoryMountPoints .= ',' . $this->user['category_perms'];
1526  }
1527 
1528  // Make the ids unique
1529  $categoryMountPoints = GeneralUtility::trimExplode(',', $categoryMountPoints);
1530  $categoryMountPoints = array_filter($categoryMountPoints); // remove empty value
1531  $categoryMountPoints = array_unique($categoryMountPoints); // remove unique value
1532 
1533  return $categoryMountPoints;
1534  }
1535 
1543  public function getFileMountRecords()
1544  {
1545  static $fileMountRecordCache = [];
1546 
1547  if (!empty($fileMountRecordCache)) {
1548  return $fileMountRecordCache;
1549  }
1550 
1551  // Processing file mounts (both from the user and the groups)
1552  $fileMounts = array_unique(GeneralUtility::intExplode(',', $this->dataLists['filemount_list'], true));
1553 
1554  // Limit file mounts if set in workspace record
1555  if ($this->workspace > 0 && !empty($this->workspaceRec['file_mountpoints'])) {
1556  $workspaceFileMounts = GeneralUtility::intExplode(',', $this->workspaceRec['file_mountpoints'], true);
1557  $fileMounts = array_intersect($fileMounts, $workspaceFileMounts);
1558  }
1559 
1560  if (!empty($fileMounts)) {
1561  $orderBy = isset($GLOBALS['TCA']['sys_filemounts']['ctrl']['default_sortby'])
1562  ? $this->db->stripOrderBy($GLOBALS['TCA']['sys_filemounts']['ctrl']['default_sortby'])
1563  : 'sorting';
1564  $fileMountRecords = $this->db->exec_SELECTgetRows(
1565  '*',
1566  'sys_filemounts',
1567  'deleted=0 AND hidden=0 AND pid=0 AND uid IN (' . implode(',', $fileMounts) . ')',
1568  '',
1569  $orderBy
1570  );
1571  foreach ($fileMountRecords as $fileMount) {
1572  $fileMountRecordCache[$fileMount['base'] . $fileMount['path']] = $fileMount;
1573  }
1574  }
1575 
1576  // Read-only file mounts
1577  $readOnlyMountPoints = trim($GLOBALS['BE_USER']->getTSConfigVal('options.folderTree.altElementBrowserMountPoints'));
1578  if ($readOnlyMountPoints) {
1579  // We cannot use the API here but need to fetch the default storage record directly
1580  // to not instantiate it (which directly applies mount points) before all mount points are resolved!
1581  $whereClause = 'is_default=1 ' . BackendUtility::BEenableFields('sys_file_storage') . BackendUtility::deleteClause('sys_file_storage');
1582  $defaultStorageRow = $this->db->exec_SELECTgetSingleRow('uid', 'sys_file_storage', $whereClause);
1583  $readOnlyMountPointArray = GeneralUtility::trimExplode(',', $readOnlyMountPoints);
1584  foreach ($readOnlyMountPointArray as $readOnlyMountPoint) {
1585  $readOnlyMountPointConfiguration = GeneralUtility::trimExplode(':', $readOnlyMountPoint);
1586  if (count($readOnlyMountPointConfiguration) === 2) {
1587  // A storage is passed in the configuration
1588  $storageUid = (int)$readOnlyMountPointConfiguration[0];
1589  $path = $readOnlyMountPointConfiguration[1];
1590  } else {
1591  if (empty($defaultStorageRow)) {
1592  throw new \RuntimeException('Read only mount points have been defined in User TsConfig without specific storage, but a default storage could not be resolved.', 1404472382);
1593  }
1594  // Backwards compatibility: If no storage is passed, we use the default storage
1595  $storageUid = $defaultStorageRow['uid'];
1596  $path = $readOnlyMountPointConfiguration[0];
1597  }
1598  $fileMountRecordCache[$storageUid . $path] = [
1599  'base' => $storageUid,
1600  'title' => $path,
1601  'path' => $path,
1602  'read_only' => true
1603  ];
1604  }
1605  }
1606 
1607  // Personal or Group filemounts are not accessible if file mount list is set in workspace record
1608  if ($this->workspace <= 0 || empty($this->workspaceRec['file_mountpoints'])) {
1609  // If userHomePath is set, we attempt to mount it
1610  if ($GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath']) {
1611  list($userHomeStorageUid, $userHomeFilter) = explode(':', $GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath'], 2);
1612  $userHomeStorageUid = (int)$userHomeStorageUid;
1613  $userHomeFilter = '/' . ltrim($userHomeFilter, '/');
1614  if ($userHomeStorageUid > 0) {
1615  // Try and mount with [uid]_[username]
1616  $path = $userHomeFilter . $this->user['uid'] . '_' . $this->user['username'] . $GLOBALS['TYPO3_CONF_VARS']['BE']['userUploadDir'];
1617  $fileMountRecordCache[$userHomeStorageUid . $path] = [
1618  'base' => $userHomeStorageUid,
1619  'title' => $this->user['username'],
1620  'path' => $path,
1621  'read_only' => false,
1622  'user_mount' => true
1623  ];
1624  // Try and mount with only [uid]
1625  $path = $userHomeFilter . $this->user['uid'] . $GLOBALS['TYPO3_CONF_VARS']['BE']['userUploadDir'];
1626  $fileMountRecordCache[$userHomeStorageUid . $path] = [
1627  'base' => $userHomeStorageUid,
1628  'title' => $this->user['username'],
1629  'path' => $path,
1630  'read_only' => false,
1631  'user_mount' => true
1632  ];
1633  }
1634  }
1635 
1636  // Mount group home-dirs
1637  if ((is_array($this->user) && $this->user['options'] & Permission::PAGE_EDIT) == 2 && $GLOBALS['TYPO3_CONF_VARS']['BE']['groupHomePath'] != '') {
1638  // If groupHomePath is set, we attempt to mount it
1639  list($groupHomeStorageUid, $groupHomeFilter) = explode(':', $GLOBALS['TYPO3_CONF_VARS']['BE']['groupHomePath'], 2);
1640  $groupHomeStorageUid = (int)$groupHomeStorageUid;
1641  $groupHomeFilter = '/' . ltrim($groupHomeFilter, '/');
1642  if ($groupHomeStorageUid > 0) {
1643  foreach ($this->userGroups as $groupData) {
1644  $path = $groupHomeFilter . $groupData['uid'];
1645  $fileMountRecordCache[$groupHomeStorageUid . $path] = [
1646  'base' => $groupHomeStorageUid,
1647  'title' => $groupData['title'],
1648  'path' => $path,
1649  'read_only' => false,
1650  'user_mount' => true
1651  ];
1652  }
1653  }
1654  }
1655  }
1656 
1657  return $fileMountRecordCache;
1658  }
1659 
1668  public function getFileStorages()
1669  {
1670  // Initializing file mounts after the groups are fetched
1671  if ($this->fileStorages === null) {
1672  $this->initializeFileStorages();
1673  }
1674  return $this->fileStorages;
1675  }
1676 
1685  {
1686  // Add the option for also displaying the non-hidden files
1687  if ($this->uc['showHiddenFilesAndFolders']) {
1689  }
1690  }
1691 
1729  public function getFilePermissions()
1730  {
1731  if (!isset($this->filePermissions)) {
1732  $filePermissions = [
1733  // File permissions
1734  'addFile' => false,
1735  'readFile' => false,
1736  'writeFile' => false,
1737  'copyFile' => false,
1738  'moveFile' => false,
1739  'renameFile' => false,
1740  'unzipFile' => false,
1741  'deleteFile' => false,
1742  // Folder permissions
1743  'addFolder' => false,
1744  'readFolder' => false,
1745  'writeFolder' => false,
1746  'copyFolder' => false,
1747  'moveFolder' => false,
1748  'renameFolder' => false,
1749  'deleteFolder' => false,
1750  'recursivedeleteFolder' => false
1751  ];
1752  if ($this->isAdmin()) {
1753  $filePermissions = array_map('is_bool', $filePermissions);
1754  } else {
1755  $userGroupRecordPermissions = GeneralUtility::trimExplode(',', $this->groupData['file_permissions'], true);
1756  array_walk(
1757  $userGroupRecordPermissions,
1758  function ($permission) use (&$filePermissions) {
1759  $filePermissions[$permission] = true;
1760  }
1761  );
1762 
1763  // Finally overlay any userTSconfig
1764  $permissionsTsConfig = $this->getTSConfigProp('permissions.file.default');
1765  if (!empty($permissionsTsConfig)) {
1766  array_walk(
1767  $permissionsTsConfig,
1768  function ($value, $permission) use (&$filePermissions) {
1769  $filePermissions[$permission] = (bool)$value;
1770  }
1771  );
1772  }
1773  }
1774  $this->filePermissions = $filePermissions;
1775  }
1776  return $this->filePermissions;
1777  }
1778 
1789  public function getFilePermissionsForStorage(\TYPO3\CMS\Core\Resource\ResourceStorage $storageObject)
1790  {
1791  $finalUserPermissions = $this->getFilePermissions();
1792  if (!$this->isAdmin()) {
1793  $storageFilePermissions = $this->getTSConfigProp('permissions.file.storage.' . $storageObject->getUid());
1794  if (!empty($storageFilePermissions)) {
1795  array_walk(
1796  $storageFilePermissions,
1797  function ($value, $permission) use (&$finalUserPermissions) {
1798  $finalUserPermissions[$permission] = (bool)$value;
1799  }
1800  );
1801  }
1802  }
1803  return $finalUserPermissions;
1804  }
1805 
1823  public function getDefaultUploadFolder($pid = null, $table = null, $field = null)
1824  {
1825  $uploadFolder = $this->getTSConfigVal('options.defaultUploadFolder');
1826  if ($uploadFolder) {
1827  $uploadFolder = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($uploadFolder);
1828  } else {
1829  foreach ($this->getFileStorages() as $storage) {
1830  if ($storage->isDefault() && $storage->isWritable()) {
1831  try {
1832  $uploadFolder = $storage->getDefaultFolder();
1833  if ($uploadFolder->checkActionPermission('write')) {
1834  break;
1835  }
1836  $uploadFolder = null;
1837  } catch (\TYPO3\CMS\Core\Resource\Exception $folderAccessException) {
1838  // If the folder is not accessible (no permissions / does not exist) we skip this one.
1839  }
1840  break;
1841  }
1842  }
1843  if (!$uploadFolder instanceof \TYPO3\CMS\Core\Resource\Folder) {
1845  foreach ($this->getFileStorages() as $storage) {
1846  if ($storage->isWritable()) {
1847  try {
1848  $uploadFolder = $storage->getDefaultFolder();
1849  if ($uploadFolder->checkActionPermission('write')) {
1850  break;
1851  }
1852  $uploadFolder = null;
1853  } catch (\TYPO3\CMS\Core\Resource\Exception $folderAccessException) {
1854  // If the folder is not accessible (no permissions / does not exist) try the next one.
1855  }
1856  }
1857  }
1858  }
1859  }
1860 
1861  // HOOK: getDefaultUploadFolder
1862  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getDefaultUploadFolder'])) {
1863  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getDefaultUploadFolder'] as $_funcRef) {
1864  $_params = [
1865  'uploadFolder' => $uploadFolder,
1866  'pid' => $pid,
1867  'table' => $table,
1868  'field' => $field,
1869  ];
1870  $uploadFolder = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1871  }
1872  }
1873 
1874  if ($uploadFolder instanceof \TYPO3\CMS\Core\Resource\Folder) {
1875  return $uploadFolder;
1876  } else {
1877  return false;
1878  }
1879  }
1880 
1890  {
1891  $defaultTemporaryFolder = null;
1892  $defaultFolder = $this->getDefaultUploadFolder();
1893 
1894  if ($defaultFolder !== false) {
1895  $tempFolderName = '_temp_';
1896  $createFolder = !$defaultFolder->hasFolder($tempFolderName);
1897  if ($createFolder === true) {
1898  try {
1899  $defaultTemporaryFolder = $defaultFolder->createFolder($tempFolderName);
1900  } catch (\TYPO3\CMS\Core\Resource\Exception $folderAccessException) {
1901  }
1902  } else {
1903  $defaultTemporaryFolder = $defaultFolder->getSubfolder($tempFolderName);
1904  }
1905  }
1906 
1907  return $defaultTemporaryFolder;
1908  }
1909 
1916  public function addTScomment($str)
1917  {
1918  $delimiter = '# ***********************************************';
1919  $out = $delimiter . LF;
1920  $lines = GeneralUtility::trimExplode(LF, $str);
1921  foreach ($lines as $v) {
1922  $out .= '# ' . $v . LF;
1923  }
1924  $out .= $delimiter . LF;
1925  return $out;
1926  }
1927 
1935  public function workspaceInit()
1936  {
1937  // Initializing workspace by evaluating and setting the workspace, possibly updating it in the user record!
1938  $this->setWorkspace($this->user['workspace_id']);
1939  // Limiting the DB mountpoints if there any selected in the workspace record
1941  if ($allowed_languages = $this->getTSConfigVal('options.workspaces.allowed_languages.' . $this->workspace)) {
1942  $this->groupData['allowed_languages'] = $allowed_languages;
1943  $this->groupData['allowed_languages'] = GeneralUtility::uniqueList($this->groupData['allowed_languages']);
1944  }
1945  }
1946 
1953  {
1954  $dbMountpoints = trim($this->workspaceRec['db_mountpoints']);
1955  if ($this->workspace > 0 && $dbMountpoints != '') {
1956  $filteredDbMountpoints = [];
1957  // Notice: We cannot call $this->getPagePermsClause(1);
1958  // as usual because the group-list is not available at this point.
1959  // But bypassing is fine because all we want here is check if the
1960  // workspace mounts are inside the current webmounts rootline.
1961  // The actual permission checking on page level is done elsewhere
1962  // as usual anyway before the page tree is rendered.
1963  $readPerms = '1=1';
1964  // Traverse mount points of the
1965  $dbMountpoints = GeneralUtility::intExplode(',', $dbMountpoints);
1966  foreach ($dbMountpoints as $mpId) {
1967  if ($this->isInWebMount($mpId, $readPerms)) {
1968  $filteredDbMountpoints[] = $mpId;
1969  }
1970  }
1971  // Re-insert webmounts:
1972  $filteredDbMountpoints = array_unique($filteredDbMountpoints);
1973  $this->groupData['webmounts'] = implode(',', $filteredDbMountpoints);
1974  }
1975  }
1976 
1984  public function checkWorkspace($wsRec, $fields = 'uid,title,adminusers,members,reviewers,publish_access,stagechg_notification')
1985  {
1986  $retVal = false;
1987  // If not array, look up workspace record:
1988  if (!is_array($wsRec)) {
1989  switch ((string)$wsRec) {
1990  case '0':
1991  $wsRec = ['uid' => $wsRec];
1992  break;
1993  default:
1994  if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')) {
1995  $wsRec = $this->db->exec_SELECTgetSingleRow($fields,
1996  'sys_workspace',
1997  'pid=0 AND uid=' . (int)$wsRec . BackendUtility::deleteClause('sys_workspace'),
1998  '',
1999  'title'
2000  );
2001  }
2002  }
2003  }
2004  // If wsRec is set to an array, evaluate it:
2005  if (is_array($wsRec)) {
2006  if ($this->isAdmin()) {
2007  return array_merge($wsRec, ['_ACCESS' => 'admin']);
2008  } else {
2009  switch ((string)$wsRec['uid']) {
2010  case '0':
2011  $retVal = $this->groupData['workspace_perms'] & Permission::PAGE_SHOW
2012  ? array_merge($wsRec, ['_ACCESS' => 'online'])
2013  : false;
2014  break;
2015  default:
2016  // Checking if the guy is admin:
2017  if (GeneralUtility::inList($wsRec['adminusers'], 'be_users_' . $this->user['uid'])) {
2018  return array_merge($wsRec, ['_ACCESS' => 'owner']);
2019  }
2020  // Checking if he is owner through a user group of his:
2021  foreach ($this->userGroupsUID as $groupUid) {
2022  if (GeneralUtility::inList($wsRec['adminusers'], 'be_groups_' . $groupUid)) {
2023  return array_merge($wsRec, ['_ACCESS' => 'owner']);
2024  }
2025  }
2026  // Checking if he is reviewer user:
2027  if (GeneralUtility::inList($wsRec['reviewers'], 'be_users_' . $this->user['uid'])) {
2028  return array_merge($wsRec, ['_ACCESS' => 'reviewer']);
2029  }
2030  // Checking if he is reviewer through a user group of his:
2031  foreach ($this->userGroupsUID as $groupUid) {
2032  if (GeneralUtility::inList($wsRec['reviewers'], 'be_groups_' . $groupUid)) {
2033  return array_merge($wsRec, ['_ACCESS' => 'reviewer']);
2034  }
2035  }
2036  // Checking if he is member as user:
2037  if (GeneralUtility::inList($wsRec['members'], 'be_users_' . $this->user['uid'])) {
2038  return array_merge($wsRec, ['_ACCESS' => 'member']);
2039  }
2040  // Checking if he is member through a user group of his:
2041  foreach ($this->userGroupsUID as $groupUid) {
2042  if (GeneralUtility::inList($wsRec['members'], 'be_groups_' . $groupUid)) {
2043  return array_merge($wsRec, ['_ACCESS' => 'member']);
2044  }
2045  }
2046  }
2047  }
2048  }
2049  return $retVal;
2050  }
2051 
2059  public function checkWorkspaceCurrent()
2060  {
2061  if (!isset($this->checkWorkspaceCurrent_cache)) {
2062  $this->checkWorkspaceCurrent_cache = $this->checkWorkspace($this->workspace);
2063  }
2065  }
2066 
2073  public function setWorkspace($workspaceId)
2074  {
2075  // Check workspace validity and if not found, revert to default workspace.
2076  if (!$this->setTemporaryWorkspace($workspaceId)) {
2077  $this->setDefaultWorkspace();
2078  }
2079  // Unset access cache:
2080  $this->checkWorkspaceCurrent_cache = null;
2081  // If ID is different from the stored one, change it:
2082  if ((int)$this->workspace !== (int)$this->user['workspace_id']) {
2083  $this->user['workspace_id'] = $this->workspace;
2084  $this->db->exec_UPDATEquery('be_users', 'uid=' . (int)$this->user['uid'], ['workspace_id' => $this->user['workspace_id']]);
2085  $this->simplelog('User changed workspace to "' . $this->workspace . '"');
2086  }
2087  }
2088 
2095  public function setTemporaryWorkspace($workspaceId)
2096  {
2097  $result = false;
2098  $workspaceRecord = $this->checkWorkspace($workspaceId, '*');
2099 
2100  if ($workspaceRecord) {
2101  $this->workspaceRec = $workspaceRecord;
2102  $this->workspace = (int)$workspaceId;
2103  $result = true;
2104  }
2105 
2106  return $result;
2107  }
2108 
2114  public function setDefaultWorkspace()
2115  {
2116  $this->workspace = (int)$this->getDefaultWorkspace();
2117  $this->workspaceRec = $this->checkWorkspace($this->workspace, '*');
2118  }
2119 
2126  public function setWorkspacePreview($previewState)
2127  {
2128  $this->user['workspace_preview'] = $previewState;
2129  $this->db->exec_UPDATEquery('be_users', 'uid=' . (int)$this->user['uid'], ['workspace_preview' => $this->user['workspace_preview']]);
2130  }
2131 
2139  public function getDefaultWorkspace()
2140  {
2141  $defaultWorkspace = -99;
2142  if (!\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces') || $this->checkWorkspace(0)) {
2143  // Check online
2144  $defaultWorkspace = 0;
2145  } elseif ($this->checkWorkspace(-1)) {
2146  // Check offline
2147  $defaultWorkspace = -1;
2148  } elseif (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')) {
2149  // Traverse custom workspaces:
2150  $workspaces = $this->db->exec_SELECTgetRows('uid,title,adminusers,members,reviewers', 'sys_workspace', 'pid=0' . BackendUtility::deleteClause('sys_workspace'), '', 'title');
2151  foreach ($workspaces as $rec) {
2152  if ($this->checkWorkspace($rec)) {
2153  $defaultWorkspace = $rec['uid'];
2154  break;
2155  }
2156  }
2157  }
2158  return $defaultWorkspace;
2159  }
2160 
2179  public function writelog($type, $action, $error, $details_nr, $details, $data, $tablename = '', $recuid = '', $recpid = '', $event_pid = -1, $NEWid = '', $userId = 0)
2180  {
2181  if (!$userId && !empty($this->user['uid'])) {
2182  $userId = $this->user['uid'];
2183  }
2184 
2185  if (!empty($this->user['ses_backuserid'])) {
2186  if (empty($data)) {
2187  $data = [];
2188  }
2189  $data['originalUser'] = $this->user['ses_backuserid'];
2190  }
2191 
2192  $fields_values = [
2193  'userid' => (int)$userId,
2194  'type' => (int)$type,
2195  'action' => (int)$action,
2196  'error' => (int)$error,
2197  'details_nr' => (int)$details_nr,
2198  'details' => $details,
2199  'log_data' => serialize($data),
2200  'tablename' => $tablename,
2201  'recuid' => (int)$recuid,
2202  'IP' => (string)GeneralUtility::getIndpEnv('REMOTE_ADDR'),
2203  'tstamp' => isset($GLOBALS['EXEC_TIME']) ? $GLOBALS['EXEC_TIME'] : time(),
2204  'event_pid' => (int)$event_pid,
2205  'NEWid' => $NEWid,
2206  'workspace' => $this->workspace
2207  ];
2208  $this->db->exec_INSERTquery('sys_log', $fields_values);
2209  return $this->db->sql_insert_id();
2210  }
2211 
2220  public function simplelog($message, $extKey = '', $error = 0)
2221  {
2222  return $this->writelog(4, 0, $error, 0, ($extKey ? '[' . $extKey . '] ' : '') . $message, []);
2223  }
2224 
2237  public function checkLogFailures($email, $secondsBack = 3600, $max = 3)
2238  {
2239  if ($email) {
2240  // Get last flag set in the log for sending
2241  $theTimeBack = $GLOBALS['EXEC_TIME'] - $secondsBack;
2242  $res = $this->db->exec_SELECTquery('tstamp', 'sys_log', 'type=255 AND action=4 AND tstamp>' . (int)$theTimeBack, '', 'tstamp DESC', '1');
2243  if ($testRow = $this->db->sql_fetch_assoc($res)) {
2244  $theTimeBack = $testRow['tstamp'];
2245  }
2246  $this->db->sql_free_result($res);
2247  // Check for more than $max number of error failures with the last period.
2248  $res = $this->db->exec_SELECTquery('*', 'sys_log', 'type=255 AND action=3 AND error<>0 AND tstamp>' . (int)$theTimeBack, '', 'tstamp');
2249  if ($this->db->sql_num_rows($res) > $max) {
2250  // OK, so there were more than the max allowed number of login failures - so we will send an email then.
2251  $subject = 'TYPO3 Login Failure Warning (at ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . ')';
2252  $email_body = 'There have been some attempts (' . $this->db->sql_num_rows($res) . ') to login at the TYPO3
2253 site "' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . '" (' . GeneralUtility::getIndpEnv('HTTP_HOST') . ').
2254 
2255 This is a dump of the failures:
2256 
2257 ';
2258  while ($testRows = $this->db->sql_fetch_assoc($res)) {
2259  $theData = unserialize($testRows['log_data']);
2260  $email_body .= date(
2261  $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'],
2262  $testRows['tstamp']
2263  ) . ': ' . @sprintf($testRows['details'], (string)$theData[0], (string)$theData[1], (string)$theData[2]);
2264  $email_body .= LF;
2265  }
2268  $mail = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
2269  $mail->setTo($email)->setFrom($from)->setSubject($subject)->setBody($email_body);
2270  $mail->send();
2271  // Logout written to log
2272  $this->writelog(255, 4, 0, 3, 'Failure warning (%s failures within %s seconds) sent by email to %s', [$this->db->sql_num_rows($res), $secondsBack, $email]);
2273  $this->db->sql_free_result($res);
2274  }
2275  }
2276  }
2277 
2284  public static function getCookieName()
2285  {
2286  $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['cookieName']);
2287  if (empty($configuredCookieName)) {
2288  $configuredCookieName = 'be_typo_user';
2289  }
2290  return $configuredCookieName;
2291  }
2292 
2300  public function checkLockToIP()
2301  {
2302  $out = 1;
2303  if ($GLOBALS['TYPO3_CONF_VARS']['BE']['enabledBeUserIPLock']) {
2304  $IPList = $this->getTSConfigVal('options.lockToIP');
2305  if (trim($IPList)) {
2306  $baseIP = GeneralUtility::getIndpEnv('REMOTE_ADDR');
2307  $out = GeneralUtility::cmpIP($baseIP, $IPList);
2308  }
2309  }
2310  return $out;
2311  }
2312 
2324  public function backendCheckLogin($proceedIfNoUserIsLoggedIn = false)
2325  {
2326  if (empty($this->user['uid'])) {
2327  if ($proceedIfNoUserIsLoggedIn === false) {
2328  $url = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir;
2330  }
2331  } else {
2332  // ...and if that's the case, call these functions
2333  $this->fetchGroupData();
2334  // The groups are fetched and ready for permission checking in this initialization.
2335  // Tables.php must be read before this because stuff like the modules has impact in this
2336  if ($this->checkLockToIP()) {
2337  if ($this->isUserAllowedToLogin()) {
2338  // Setting the UC array. It's needed with fetchGroupData first, due to default/overriding of values.
2339  $this->backendSetUC();
2340  // Email at login - if option set.
2341  $this->emailAtLogin();
2342  } else {
2343  throw new \RuntimeException('Login Error: TYPO3 is in maintenance mode at the moment. Only administrators are allowed access.', 1294585860);
2344  }
2345  } else {
2346  throw new \RuntimeException('Login Error: IP locking prevented you from being authorized. Can\'t proceed, sorry.', 1294585861);
2347  }
2348  }
2349  }
2350 
2357  public function checkCLIuser()
2358  {
2360  // First, check if cliMode is enabled:
2361  if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
2362  if (!$this->user['uid']) {
2363  if (substr($GLOBALS['MCONF']['name'], 0, 5) == '_CLI_') {
2364  $userName = strtolower($GLOBALS['MCONF']['name']);
2365  $this->setBeUserByName($userName);
2366  if ($this->user['uid']) {
2367  if (!$this->isAdmin()) {
2368  return true;
2369  } else {
2370  fwrite(STDERR, 'ERROR: CLI backend user "' . $userName . '" was ADMIN which is not allowed!' . LF . LF);
2371  die(3);
2372  }
2373  } else {
2374  fwrite(STDERR, 'ERROR: No backend user named "' . $userName . '" was found!' . LF . LF);
2375  die(3);
2376  }
2377  } else {
2378  fwrite(STDERR, 'ERROR: Module name, "' . $GLOBALS['MCONF']['name'] . '", was not prefixed with "_CLI_"' . LF . LF);
2379  die(3);
2380  }
2381  } else {
2382  fwrite(STDERR, 'ERROR: Another user was already loaded which is impossible in CLI mode!' . LF . LF);
2383  die(3);
2384  }
2385  }
2386  return false;
2387  }
2388 
2396  public function backendSetUC()
2397  {
2398  // UC - user configuration is a serialized array inside the user object
2399  // If there is a saved uc we implement that instead of the default one.
2400  $temp_theSavedUC = unserialize($this->user['uc']);
2401  if (is_array($temp_theSavedUC)) {
2402  $this->unpack_uc($temp_theSavedUC);
2403  }
2404  // Setting defaults if uc is empty
2405  $updated = false;
2406  $originalUc = [];
2407  if (is_array($this->uc) && isset($this->uc['ucSetByInstallTool'])) {
2408  $originalUc = $this->uc;
2409  unset($originalUc['ucSetByInstallTool'], $this->uc);
2410  }
2411  if (!is_array($this->uc)) {
2412  $this->uc = array_merge(
2413  $this->uc_default,
2414  (array)$GLOBALS['TYPO3_CONF_VARS']['BE']['defaultUC'],
2415  GeneralUtility::removeDotsFromTS((array)$this->getTSConfigProp('setup.default')),
2416  $originalUc
2417  );
2418  $this->overrideUC();
2419  $updated = true;
2420  }
2421  // If TSconfig is updated, update the defaultUC.
2422  if ($this->userTSUpdated) {
2423  $this->overrideUC();
2424  $updated = true;
2425  }
2426  // Setting default lang from be_user record.
2427  if (!isset($this->uc['lang'])) {
2428  $this->uc['lang'] = $this->user['lang'];
2429  $updated = true;
2430  }
2431  // Setting the time of the first login:
2432  if (!isset($this->uc['firstLoginTimeStamp'])) {
2433  $this->uc['firstLoginTimeStamp'] = $GLOBALS['EXEC_TIME'];
2434  $updated = true;
2435  }
2436  // Saving if updated.
2437  if ($updated) {
2438  $this->writeUC();
2439  }
2440  }
2441 
2449  public function overrideUC()
2450  {
2451  $this->uc = array_merge((array)$this->uc, (array)$this->getTSConfigProp('setup.override'));
2452  }
2453 
2460  public function resetUC()
2461  {
2462  $this->user['uc'] = '';
2463  $this->uc = '';
2464  $this->backendSetUC();
2465  }
2466 
2474  private function emailAtLogin()
2475  {
2476  if ($this->loginSessionStarted) {
2477  // Send notify-mail
2478  $subject = 'At "' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] . '"' . ' from '
2479  . GeneralUtility::getIndpEnv('REMOTE_ADDR')
2480  . (GeneralUtility::getIndpEnv('REMOTE_HOST') ? ' (' . GeneralUtility::getIndpEnv('REMOTE_HOST') . ')' : '');
2481  $msg = sprintf(
2482  'User "%s" logged in from %s (%s) at "%s" (%s)',
2483  $this->user['username'],
2484  GeneralUtility::getIndpEnv('REMOTE_ADDR'),
2485  GeneralUtility::getIndpEnv('REMOTE_HOST'),
2486  $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
2487  GeneralUtility::getIndpEnv('HTTP_HOST')
2488  );
2489  // Warning email address
2490  if ($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr']) {
2491  $warn = 0;
2492  $prefix = '';
2493  if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['warning_mode'] & 1) {
2494  // first bit: All logins
2495  $warn = 1;
2496  $prefix = $this->isAdmin() ? '[AdminLoginWarning]' : '[LoginWarning]';
2497  }
2498  if ($this->isAdmin() && (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['warning_mode'] & 2) {
2499  // second bit: Only admin-logins
2500  $warn = 1;
2501  $prefix = '[AdminLoginWarning]';
2502  }
2503  if ($warn) {
2506  $mail = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
2507  $mail->setTo($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'])->setFrom($from)->setSubject($prefix . ' ' . $subject)->setBody($msg);
2508  $mail->send();
2509  }
2510  }
2511  // If An email should be sent to the current user, do that:
2512  if ($this->uc['emailMeAtLogin'] && strstr($this->user['email'], '@')) {
2515  $mail = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
2516  $mail->setTo($this->user['email'])->setFrom($from)->setSubject($subject)->setBody($msg);
2517  $mail->send();
2518  }
2519  }
2520  }
2521 
2533  protected function isUserAllowedToLogin()
2534  {
2535  $isUserAllowedToLogin = false;
2536  $adminOnlyMode = $GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'];
2537  // Backend user is allowed if adminOnly is not set or user is an admin:
2538  if (!$adminOnlyMode || $this->isAdmin()) {
2539  $isUserAllowedToLogin = true;
2540  } elseif ($adminOnlyMode == 2 && TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
2541  $isUserAllowedToLogin = true;
2542  } elseif ($this->user['ses_backuserid']) {
2543  $backendUserId = (int)$this->user['ses_backuserid'];
2544  $whereAdmin = 'uid=' . $backendUserId . ' AND admin=1' . BackendUtility::BEenableFields('be_users');
2545  if ($this->db->exec_SELECTcountRows('uid', 'be_users', $whereAdmin) > 0) {
2546  $isUserAllowedToLogin = true;
2547  }
2548  }
2549  return $isUserAllowedToLogin;
2550  }
2551 
2555  public function logoff()
2556  {
2557  if (isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER'] instanceof self && isset($GLOBALS['BE_USER']->user['uid'])) {
2559  }
2560  parent::logoff();
2561  }
2562 }
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *')
checkWorkspace($wsRec, $fields='uid, title, adminusers, members, reviewers, publish_access, stagechg_notification')
writelog($type, $action, $error, $details_nr, $details, $data, $tablename='', $recuid='', $recpid='', $event_pid=-1, $NEWid='', $userId=0)
static setShowHiddenFilesAndFolders($showHiddenFilesAndFolders)
isPSet($compiledPermissions, $tableName, $actionType='')
static getRecordsByField($theTable, $theField, $theValue, $whereClause='', $groupBy='', $orderBy='', $limit='', $useDeleteClause=true)
static BEenableFields($table, $inv=false)
static BEgetRootLine($uid, $clause='', $workspaceOL=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static redirect($url, $httpStatus=self::HTTP_STATUS_303)
Definition: HttpUtility.php:76
getFilePermissionsForStorage(\TYPO3\CMS\Core\Resource\ResourceStorage $storageObject)
$uid
Definition: server.php:38
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static deleteClause($table, $tableAlias='')
static uniqueList($in_list, $secondParameter=null)
recordEditAccessInternals($table, $idOrRow, $newRecord=false, $deletedRecord=false, $checkFullLanguageAccess=false)