From 33f4d279b82bca0a509227a17065244c6156e68f Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Tue, 13 Feb 2024 10:06:13 +0100 Subject: [PATCH] [SECURITY] Prevent arbitrary access to privileged resources via t3:// Resolves: #93571 Releases: main, 13.0, 12.4, 11.5 Change-Id: I9622bfa47ef9637cecaff4a790f742445f598682 Security-Bulletin: TYPO3-CORE-SA-2024-005 Security-References: CVE-2024-25120 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82949 Reviewed-by: Oliver Hader <oliver.hader@typo3.org> Tested-by: Oliver Hader <oliver.hader@typo3.org> --- .../Backend/Shortcut/ShortcutRepository.php | 2 +- .../Classes/Controller/LinkController.php | 2 +- .../Resource/ResourceController.php | 2 +- .../Classes/Form/Element/LinkElement.php | 13 ++++-- .../Classes/LinkHandler/PageLinkHandler.php | 13 +++++- .../Classes/LinkHandling/FileLinkHandler.php | 8 ++++ .../LegacyLinkNotationConverter.php | 2 +- .../core/Classes/Resource/ResourceStorage.php | 35 ++++++++++++--- .../Security/StoragePermissionsAspect.php | 7 +-- .../Utility/File/ExtendedFileUtility.php | 2 +- .../TypoLinkSoftReferenceParserTest.php | 3 ++ .../TypoLinkTagSoftReferenceParserTest.php | 2 + .../Unit/LinkHandling/FileLinkHandlerTest.php | 2 +- .../Controller/File/CreateFileController.php | 2 +- .../Controller/File/EditFileController.php | 2 +- .../Controller/File/FileUploadController.php | 2 +- .../Controller/File/ReplaceFileController.php | 2 +- .../Classes/Controller/FileListController.php | 2 +- .../AbstractResourceLinkHandler.php | 43 +++++++++++++++---- 19 files changed, 110 insertions(+), 36 deletions(-) diff --git a/typo3/sysext/backend/Classes/Backend/Shortcut/ShortcutRepository.php b/typo3/sysext/backend/Classes/Backend/Shortcut/ShortcutRepository.php index 90d2d6786280..d3ac50d07d03 100644 --- a/typo3/sysext/backend/Classes/Backend/Shortcut/ShortcutRepository.php +++ b/typo3/sysext/backend/Classes/Backend/Shortcut/ShortcutRepository.php @@ -405,7 +405,7 @@ class ShortcutRepository $combinedIdentifier = (string)($arguments['id'] ?? ''); if ($combinedIdentifier !== '') { $storage = GeneralUtility::makeInstance(StorageRepository::class)->findByCombinedIdentifier($combinedIdentifier); - if ($storage === null || $storage->getUid() === 0) { + if ($storage === null || $storage->isFallbackStorage()) { // Continue, if invalid storage or disallowed fallback storage continue; } diff --git a/typo3/sysext/backend/Classes/Controller/LinkController.php b/typo3/sysext/backend/Classes/Controller/LinkController.php index d67d10960992..9254b20f51a1 100644 --- a/typo3/sysext/backend/Classes/Controller/LinkController.php +++ b/typo3/sysext/backend/Classes/Controller/LinkController.php @@ -56,7 +56,7 @@ final class LinkController if (!$resource instanceof File && !$resource instanceof Folder) { throw new \InvalidArgumentException('Resource must be a file or a folder', 1679039649); } - if ($resource->getStorage()->getUid() === 0) { + if ($resource->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1679039650); } if ($resource instanceof File) { diff --git a/typo3/sysext/backend/Classes/Controller/Resource/ResourceController.php b/typo3/sysext/backend/Classes/Controller/Resource/ResourceController.php index 9d86b618b39b..8528e4eb0a61 100644 --- a/typo3/sysext/backend/Classes/Controller/Resource/ResourceController.php +++ b/typo3/sysext/backend/Classes/Controller/Resource/ResourceController.php @@ -54,7 +54,7 @@ final class ResourceController if (!$origin instanceof File && !$origin instanceof Folder) { throw new \InvalidArgumentException('Resource must be a file or a folder', 1676979120); } - if ($origin->getStorage()->getUid() === 0) { + if ($origin->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1676299579); } if (!$origin->checkActionPermission('rename')) { diff --git a/typo3/sysext/backend/Classes/Form/Element/LinkElement.php b/typo3/sysext/backend/Classes/Form/Element/LinkElement.php index 8986b75bc647..621bcef6d560 100644 --- a/typo3/sysext/backend/Classes/Form/Element/LinkElement.php +++ b/typo3/sysext/backend/Classes/Form/Element/LinkElement.php @@ -31,6 +31,7 @@ use TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException; use TYPO3\CMS\Core\Resource\Exception\InvalidPathException; use TYPO3\CMS\Core\Resource\File; use TYPO3\CMS\Core\Resource\Folder; +use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Core\Utility\StringUtility; @@ -335,10 +336,12 @@ class LinkElement extends AbstractFormElement } } + $backendUser = $this->getBackendUser(); // Resolve the actual link switch ($linkData['type']) { case LinkService::TYPE_PAGE: - $pageRecord = BackendUtility::readPageAccess($linkData['pageuid'] ?? null, '1=1'); + $pagePermissionClause = $backendUser->getPagePermsClause(Permission::PAGE_SHOW); + $pageRecord = BackendUtility::readPageAccess($linkData['pageuid'] ?? null, $pagePermissionClause); // Is this a real page if ($pageRecord['uid'] ?? 0) { $fragmentTitle = ''; @@ -372,7 +375,7 @@ class LinkElement extends AbstractFormElement break; case LinkService::TYPE_FILE: $file = $linkData['file'] ?? null; - if ($file instanceof File) { + if ($file instanceof File && $file->checkActionPermission('read') && !$file->getStorage()->isFallbackStorage()) { $data = [ 'text' => $file->getPublicUrl(), 'icon' => $this->iconFactory->getIconForFileExtension($file->getExtension(), Icon::SIZE_SMALL)->render(), @@ -381,7 +384,7 @@ class LinkElement extends AbstractFormElement break; case LinkService::TYPE_FOLDER: $folder = $linkData['folder'] ?? null; - if ($folder instanceof Folder) { + if ($folder instanceof Folder && $folder->checkActionPermission('read') && !$folder->getStorage()->isFallbackStorage()) { $data = [ 'text' => $folder->getPublicUrl(), 'icon' => $this->iconFactory->getIcon('apps-filetree-folder-default', Icon::SIZE_SMALL)->render(), @@ -391,7 +394,9 @@ class LinkElement extends AbstractFormElement case LinkService::TYPE_RECORD: $table = $this->data['pageTsConfig']['TCEMAIN.']['linkHandler.'][$linkData['identifier'] . '.']['configuration.']['table'] ?? ''; $record = BackendUtility::getRecord($table, $linkData['uid']); - if ($record) { + $pagePermissionClause = $backendUser->getPagePermsClause(Permission::PAGE_SHOW); + $hasPageAccess = BackendUtility::readPageAccess($record['pid'] ?? null, $pagePermissionClause) !== false; + if ($record && $hasPageAccess && $backendUser->check('tables_select', $table)) { $recordTitle = BackendUtility::getRecordTitle($table, $record); $tableTitle = $this->getLanguageService()->sL($GLOBALS['TCA'][$table]['ctrl']['title']); $data = [ diff --git a/typo3/sysext/backend/Classes/LinkHandler/PageLinkHandler.php b/typo3/sysext/backend/Classes/LinkHandler/PageLinkHandler.php index c805e6658c2b..f7f48a73f4e5 100644 --- a/typo3/sysext/backend/Classes/LinkHandler/PageLinkHandler.php +++ b/typo3/sysext/backend/Classes/LinkHandler/PageLinkHandler.php @@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction; use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\LinkHandling\LinkService; +use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; @@ -87,11 +88,19 @@ class PageLinkHandler extends AbstractLinkHandler implements LinkHandlerInterfac $titleLen = (int)$this->getBackendUser()->uc['titleLen']; $id = (int)$this->linkParts['url']['pageuid']; - $pageTitle = BackendUtility::getRecordWSOL('pages', $id, 'title')['title'] ?? ''; + $idInfo = 'ID: ' . $id . (!empty($this->linkParts['url']['fragment']) ? ', #' . $this->linkParts['url']['fragment'] : ''); + + $permsClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW); + $pageRecord = BackendUtility::readPageAccess($id, $permsClause); + if ($pageRecord === false) { + return $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_browse_links.xlf:page') . ' ' . $idInfo; + } + + $pageTitle = $pageRecord['title'] ?? ''; return $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_browse_links.xlf:page') . ($pageTitle ? ' \'' . GeneralUtility::fixed_lgd_cs($pageTitle, $titleLen) . '\'' : '') - . ' (ID: ' . $id . (!empty($this->linkParts['url']['fragment']) ? ', #' . $this->linkParts['url']['fragment'] : '') . ')'; + . ' (' . $idInfo . ')'; } /** diff --git a/typo3/sysext/core/Classes/LinkHandling/FileLinkHandler.php b/typo3/sysext/core/Classes/LinkHandling/FileLinkHandler.php index f6d7ce8dfbc1..845cceb9cfad 100644 --- a/typo3/sysext/core/Classes/LinkHandling/FileLinkHandler.php +++ b/typo3/sysext/core/Classes/LinkHandling/FileLinkHandler.php @@ -20,6 +20,7 @@ namespace TYPO3\CMS\Core\LinkHandling; use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException; use TYPO3\CMS\Core\Resource\FileInterface; use TYPO3\CMS\Core\Resource\ResourceFactory; +use TYPO3\CMS\Core\Resource\Security\FileNameValidator; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -71,6 +72,13 @@ class FileLinkHandler implements LinkHandlingInterface { try { $file = $this->resolveFile($data); + $fileNameValidator = GeneralUtility::makeInstance(FileNameValidator::class); + if ( + !$fileNameValidator->isValid(basename($file->getIdentifier())) || + !$fileNameValidator->isValid($file->getName()) + ) { + $file = null; + } } catch (FileDoesNotExistException $e) { $file = null; } diff --git a/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php b/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php index 889b484a297c..80555d3fa965 100644 --- a/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php +++ b/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php @@ -220,7 +220,7 @@ class LegacyLinkNotationConverter } $fileOrFolderObject = $this->getResourceFactory()->retrieveFileOrFolderObject($fileIdentifier); // Links to a file/folder in the main TYPO3 directory should not be considered as file links, but an external link - if ($fileOrFolderObject instanceof ResourceInterface && $fileOrFolderObject->getStorage()->getUid() === 0) { + if ($fileOrFolderObject instanceof ResourceInterface && $fileOrFolderObject->getStorage()->isFallbackStorage()) { return [ 'type' => LinkService::TYPE_URL, 'url' => $mixedIdentifier, diff --git a/typo3/sysext/core/Classes/Resource/ResourceStorage.php b/typo3/sysext/core/Classes/Resource/ResourceStorage.php index e0db2210ecc3..38f61e199731 100644 --- a/typo3/sysext/core/Classes/Resource/ResourceStorage.php +++ b/typo3/sysext/core/Classes/Resource/ResourceStorage.php @@ -354,6 +354,17 @@ class ResourceStorage implements ResourceStorageInterface return true; } + /** + * Returns true if this storage is a virtual storage that provides + * access to all files in the project root. + * + * @internal + */ + public function isFallbackStorage(): bool + { + return $this->getUid() === 0; + } + /********************************* * Capabilities ********************************/ @@ -718,7 +729,7 @@ class ResourceStorage implements ResourceStorageInterface return false; } // Check 3: No action allowed on files for denied file extensions - if (!$this->checkFileExtensionPermission($file->getName())) { + if (!$this->checkValidFileExtension($file)) { return false; } $isReadCheck = false; @@ -830,6 +841,17 @@ class ResourceStorage implements ResourceStorageInterface return GeneralUtility::makeInstance(FileNameValidator::class)->isValid($fileName); } + /** + * Check file extension of an existing file against the + * current file deny pattern. + */ + protected function checkValidFileExtension(FileInterface $file): bool + { + $fileNameValidator = GeneralUtility::makeInstance(FileNameValidator::class); + return $fileNameValidator->isValid($file->getName()) && + $fileNameValidator->isValid(basename($file->getIdentifier())); + } + /** * Assures read permission for given folder. * @@ -896,7 +918,7 @@ class ResourceStorage implements ResourceStorageInterface 1375955429 ); } - if (!$this->checkFileExtensionPermission($file->getName())) { + if (!$this->checkValidFileExtension($file)) { throw new IllegalFileExtensionException( 'You are not allowed to use that file extension. File: "' . $file->getName() . '"', 1375955430 @@ -917,7 +939,7 @@ class ResourceStorage implements ResourceStorageInterface if (!$this->checkFileActionPermission('write', $file)) { throw new InsufficientFileWritePermissionsException('Writing to file "' . $file->getIdentifier() . '" is not allowed.', 1330121088); } - if (!$this->checkFileExtensionPermission($file->getName())) { + if (!$this->checkValidFileExtension($file)) { throw new IllegalFileExtensionException('You are not allowed to edit a file with extension "' . $file->getExtension() . '"', 1366711933); } } @@ -950,7 +972,7 @@ class ResourceStorage implements ResourceStorageInterface protected function assureFileDeletePermissions(FileInterface $file) { // Check for disallowed file extensions - if (!$this->checkFileExtensionPermission($file->getName())) { + if (!$this->checkValidFileExtension($file)) { throw new IllegalFileExtensionException('You are not allowed to delete a file with extension "' . $file->getExtension() . '"', 1377778916); } // Check further permissions if file is not a processed file @@ -1071,7 +1093,7 @@ class ResourceStorage implements ResourceStorageInterface protected function assureFileRenamePermissions(FileInterface $file, $targetFileName) { // Check if file extension is allowed - if (!$this->checkFileExtensionPermission($targetFileName) || !$this->checkFileExtensionPermission($file->getName())) { + if (!$this->checkFileExtensionPermission($targetFileName) || !$this->checkValidFileExtension($file)) { throw new IllegalFileExtensionException('You are not allowed to rename a file with this extension. File given: "' . $file->getName() . '"', 1371466663); } // Check if user is allowed to rename @@ -1114,7 +1136,7 @@ class ResourceStorage implements ResourceStorageInterface throw new InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1319550435); } // Check for a valid file extension - if (!$this->checkFileExtensionPermission($targetFileName) || !$this->checkFileExtensionPermission($file->getName())) { + if (!$this->checkFileExtensionPermission($targetFileName) || !$this->checkValidFileExtension($file)) { throw new IllegalFileExtensionException('You are not allowed to copy a file of that type.', 1319553317); } } @@ -1733,6 +1755,7 @@ class ResourceStorage implements ResourceStorageInterface string $alternativeFilename = null, string $overrideMimeType = null ): ResponseInterface { + $this->assureFileReadPermission($file); if (!$this->driver instanceof StreamableDriverInterface) { return $this->getPseudoStream($file, $asDownload, $alternativeFilename, $overrideMimeType); } diff --git a/typo3/sysext/core/Classes/Resource/Security/StoragePermissionsAspect.php b/typo3/sysext/core/Classes/Resource/Security/StoragePermissionsAspect.php index a01c7ea2f213..f5459b3b93cc 100644 --- a/typo3/sysext/core/Classes/Resource/Security/StoragePermissionsAspect.php +++ b/typo3/sysext/core/Classes/Resource/Security/StoragePermissionsAspect.php @@ -42,13 +42,10 @@ final class StoragePermissionsAspect if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend() && !$GLOBALS['BE_USER']->isAdmin() + && !$storage->isFallbackStorage() ) { $storage->setEvaluatePermissions(true); - if ($storage->getUid() > 0) { - $storage->setUserPermissions($GLOBALS['BE_USER']->getFilePermissionsForStorage($storage)); - } else { - $storage->setEvaluatePermissions(false); - } + $storage->setUserPermissions($GLOBALS['BE_USER']->getFilePermissionsForStorage($storage)); $this->addFileMountsToStorage($storage); } } diff --git a/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php b/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php index 79167723aa62..31bd5612667c 100644 --- a/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php +++ b/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php @@ -590,7 +590,7 @@ class ExtendedFileUtility extends BasicFileUtility if ($object === null) { throw new InvalidFileException('The item ' . $identifier . ' was not a file or directory', 1320122453); } - if ($object->getStorage()->getUid() === 0) { + if ($object->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1375889830); } return $object; diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php index 2e28e6c92f44..e1ca423840d9 100644 --- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php +++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php @@ -247,6 +247,9 @@ final class TypoLinkSoftReferenceParserTest extends AbstractSoftReferenceParserT $storageObject->method('getUid')->willReturn(1); $fileObject = $this->createMock(File::class); $fileObject->expects(self::once())->method('getUid')->willReturn(42); + $fileObject->expects(self::any())->method('getName')->willReturn('download.jpg'); + $fileObject->expects(self::any())->method('getIdentifier')->willReturn('fileadmin/download.jpg'); + $fileObject->expects(self::any())->method('getStorage')->willReturn($storageObject); $resourceFactory = $this->createMock(ResourceFactory::class); diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php index 2c96f03814fc..eb8d7738b3dd 100644 --- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php +++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php @@ -189,6 +189,8 @@ final class TypoLinkTagSoftReferenceParserTest extends AbstractSoftReferencePars { $fileObject = $this->createMock(File::class); $fileObject->expects(self::once())->method('getUid')->willReturn(42); + $fileObject->expects(self::any())->method('getName')->willReturn('download.jpg'); + $fileObject->expects(self::any())->method('getIdentifier')->willReturn('fileadmin/download.jpg'); $resourceFactory = $this->createMock(ResourceFactory::class); $resourceFactory->method('getFileObject')->with('42')->willReturn($fileObject); diff --git a/typo3/sysext/core/Tests/Unit/LinkHandling/FileLinkHandlerTest.php b/typo3/sysext/core/Tests/Unit/LinkHandling/FileLinkHandlerTest.php index 66a3e9f9e8e1..284efec7cc8f 100644 --- a/typo3/sysext/core/Tests/Unit/LinkHandling/FileLinkHandlerTest.php +++ b/typo3/sysext/core/Tests/Unit/LinkHandling/FileLinkHandlerTest.php @@ -98,7 +98,7 @@ final class FileLinkHandlerTest extends UnitTestCase ->getMock(); // fake methods to return proper objects - $fileObject = new File(['identifier' => $expected['file'], 'name' => 'foobar.txt'], $storage); + $fileObject = new File(['identifier' => 'fileadmin/deep/down.jpg', 'name' => 'down.jpg'], $storage); $factory->method('getFileObject')->with($expected['file'])->willReturn($fileObject); $factory->method('getFileObjectFromCombinedIdentifier')->with($expected['file'])->willReturn($fileObject); $expected['file'] = $fileObject; diff --git a/typo3/sysext/filelist/Classes/Controller/File/CreateFileController.php b/typo3/sysext/filelist/Classes/Controller/File/CreateFileController.php index fcb8ff4bf886..d7c970ef3384 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/CreateFileController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/CreateFileController.php @@ -119,7 +119,7 @@ class CreateFileController $message = $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir'); throw new \RuntimeException($title . ': ' . $message, 1667565756); } - if ($this->folderObject->getStorage()->getUid() === 0) { + if ($this->folderObject->getStorage()->isFallbackStorage()) { throw new InsufficientFolderAccessPermissionsException( 'You are not allowed to access folders outside your storages', 1667565757 diff --git a/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php b/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php index 7ed140836342..0ad65be4a762 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/EditFileController.php @@ -119,7 +119,7 @@ class EditFileController if (!$file instanceof FileInterface) { throw new InvalidFileException('Referenced target "' . $combinedIdentifier . '" could not be resolved to a valid file', 1294586841); } - if ($file->getStorage()->getUid() === 0) { + if ($file->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1375889832); } diff --git a/typo3/sysext/filelist/Classes/Controller/File/FileUploadController.php b/typo3/sysext/filelist/Classes/Controller/File/FileUploadController.php index f27b6d80d174..a9d9f623863e 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/FileUploadController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/FileUploadController.php @@ -58,7 +58,7 @@ class FileUploadController $folder = $this->resourceFactory->retrieveFileOrFolderObject($targetFolderCombinedIdentifier); if (!$folder instanceof FolderInterface - || $folder->getStorage()->getUid() === 0 + || $folder->getStorage()->isFallbackStorage() ) { throw new InsufficientFolderAccessPermissionsException('You are not allowed to access folders outside your storages, or the folder couldn\'t be resolved', 1375889834); } diff --git a/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php b/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php index 10634c27e3b7..39f50c38af76 100644 --- a/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php +++ b/typo3/sysext/filelist/Classes/Controller/File/ReplaceFileController.php @@ -103,7 +103,7 @@ class ReplaceFileController $message = $lang->sL('LLL:EXT:filelist/Resources/Private/Language/locallang_mod_file_list.xlf:targetNoDir'); throw new \RuntimeException($title . ': ' . $message, 1436895930); } - if ($this->fileOrFolderObject->getStorage()->getUid() === 0) { + if ($this->fileOrFolderObject->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException( 'You are not allowed to access files outside your storages', 1436895931 diff --git a/typo3/sysext/filelist/Classes/Controller/FileListController.php b/typo3/sysext/filelist/Classes/Controller/FileListController.php index fd0bd0840082..dd09637fa2b7 100644 --- a/typo3/sysext/filelist/Classes/Controller/FileListController.php +++ b/typo3/sysext/filelist/Classes/Controller/FileListController.php @@ -124,7 +124,7 @@ class FileListController implements LoggerAwareInterface } $this->folderObject = $storage->getFolder($identifier); // Disallow access to fallback storage 0 - if ($storage->getUid() === 0) { + if ($storage->isFallbackStorage()) { throw new InsufficientFolderAccessPermissionsException( 'You are not allowed to access files outside your storages', 1434539815 diff --git a/typo3/sysext/filelist/Classes/LinkHandler/AbstractResourceLinkHandler.php b/typo3/sysext/filelist/Classes/LinkHandler/AbstractResourceLinkHandler.php index 06665c551658..07d282e01583 100644 --- a/typo3/sysext/filelist/Classes/LinkHandler/AbstractResourceLinkHandler.php +++ b/typo3/sysext/filelist/Classes/LinkHandler/AbstractResourceLinkHandler.php @@ -98,6 +98,13 @@ abstract class AbstractResourceLinkHandler implements LinkHandlerInterface, Link public function formatCurrentUrl(): string { + $resource = $this->linkParts['url'][$this->type->value]; + if (!$resource->checkActionPermission('read')) { + return ''; + } + if ($resource->getStorage()->isFallbackStorage()) { + return ''; + } return $this->linkParts['url'][$this->type->value]->getName(); } @@ -181,6 +188,12 @@ abstract class AbstractResourceLinkHandler implements LinkHandlerInterface, Link } catch (FolderDoesNotExistException $e) { } } + if ($this->selectedFolder?->checkActionPermission('read') === false) { + $this->selectedFolder = null; + } + if ($this->selectedFolder?->getStorage()?->isFallbackStorage()) { + $this->selectedFolder = null; + } if (!$this->selectedFolder) { $this->selectedFolder = $this->resourceFactory->getDefaultStorage()?->getRootLevelFolder() ?? null; } @@ -202,6 +215,13 @@ abstract class AbstractResourceLinkHandler implements LinkHandlerInterface, Link public function isUpdateSupported(): bool { + $resource = $this->linkParts['url'][$this->type->value]; + if (!$resource->checkActionPermission('read')) { + return false; + } + if ($resource->getStorage()->isFallbackStorage()) { + return false; + } return true; } @@ -215,15 +235,22 @@ abstract class AbstractResourceLinkHandler implements LinkHandlerInterface, Link */ public function getBodyTagAttributes(): array { - if (isset($this->linkParts['url'][$this->type->value]) && $this->linkParts['url'][$this->type->value] instanceof ($this->type->getResourceType())) { - return [ - 'data-linkbrowser-current-link' => GeneralUtility::makeInstance(LinkService::class)->asString([ - 'type' => $this->type->getLinkServiceType(), - $this->type->value => $this->linkParts['url'][$this->type->value], - ]), - ]; + $resource = $this->linkParts['url'][$this->type->value] ?? null; + if (!$resource instanceof ($this->type->getResourceType())) { + return []; + } + if (!$resource->checkActionPermission('read')) { + return []; + } + if ($resource->getStorage()->isFallbackStorage()) { + return []; } - return []; + return [ + 'data-linkbrowser-current-link' => GeneralUtility::makeInstance(LinkService::class)->asString([ + 'type' => $this->type->getLinkServiceType(), + $this->type->value => $resource, + ]), + ]; } protected function createUri(ServerRequestInterface $request, array $parameters = []): string -- GitLab