sal/osl/w32/file_dirvol.cxx | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)
New commits: commit 1b5d039d8b5861b5ea21ef00ff521c6e2565105f Author: Balazs Varga <balazs.va...@collabora.com> AuthorDate: Fri Oct 10 09:38:42 2025 +0200 Commit: Thorsten Behrens <thorsten.behr...@collabora.com> CommitDate: Fri Oct 10 16:24:26 2025 +0200 tdf#150118 check file permissions on windows if have no readonly attribute already set on a file. Check if the file has write access, if not, set the read only flag. Change-Id: Id3b16ffffd1d5aeb09feed7b5ff2da51fba9174c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192150 Reviewed-by: Thorsten Behrens <thorsten.behr...@collabora.com> Tested-by: Jenkins diff --git a/sal/osl/w32/file_dirvol.cxx b/sal/osl/w32/file_dirvol.cxx index ad92c6f05087..d2a87fbaac21 100644 --- a/sal/osl/w32/file_dirvol.cxx +++ b/sal/osl/w32/file_dirvol.cxx @@ -21,6 +21,7 @@ #include <systools/win32/extended_max_path.hxx> #include <systools/win32/uwinapi.h> +#include <aclapi.h> #include "file_url.hxx" #include "filetime.hxx" @@ -1525,6 +1526,56 @@ oslFileError SAL_CALL osl_getFileStatus( // https://learn.microsoft.com/en-us/windows/desktop/FileIO/file-attribute-constants if (pStatus->uAttributes & FILE_ATTRIBUTE_DIRECTORY) pStatus->uAttributes &= ~sal_uInt64(FILE_ATTRIBUTE_READONLY); + + // tdf#150118: if there is no Read Only attribute set, lets check if the user has write access on the file + if ( (pStatus->uAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) == 0 ) + { + HANDLE hProcessToken = nullptr; + OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &hProcessToken); + + HANDLE hImpersonationToken = nullptr; + DuplicateToken(hProcessToken, SecurityImpersonation, &hImpersonationToken); + + PSECURITY_DESCRIPTOR pSD = nullptr; + // https://learn.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-getnamedsecurityinfow + DWORD aResult = GetNamedSecurityInfoW( + o3tl::toW(sFullPath.getStr()), SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + nullptr, nullptr, nullptr, nullptr, &pSD); + + if (aResult == ERROR_SUCCESS) + { + GENERIC_MAPPING mapping + = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS }; + DWORD grantedAccess = 0; + BOOL accessStatus = TRUE; + + // https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-accesscheck + BOOL bResult = AccessCheck(pSD, hImpersonationToken, FILE_GENERIC_WRITE, &mapping, + nullptr, nullptr, &grantedAccess, &accessStatus); + + if (bResult) + { + if (!accessStatus) + { + // User does NOT have write access: set Read Only attribute + pStatus->uAttributes |= sal_uInt64(FILE_ATTRIBUTE_READONLY); + } + } + else + { + SAL_WARN("AccessCheck API failed with: ", oslTranslateFileError(GetLastError())); + } + LocalFree(pSD); // free memory + } + else + { + SAL_WARN("GetNamedSecurityInfoW API failed with: ", aResult); + } + CloseHandle(hImpersonationToken); // free memory + CloseHandle(hProcessToken); // free memory + } + pStatus->uValidFields |= osl_FileStatus_Mask_Attributes; pStatus->uFileSize = static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeLow) + (static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeHigh) << 32);