summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x[-rw-r--r--]src/corelib/io/qfilesystemengine_win.cpp64
-rwxr-xr-x[-rw-r--r--]tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp25
2 files changed, 74 insertions, 15 deletions
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index b01aa55756..c9a56a81cc 100644..100755
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -178,6 +178,7 @@ static TRUSTEE_W currentUserTrusteeW;
static TRUSTEE_W worldTrusteeW;
static PSID currentUserSID = 0;
static PSID worldSID = 0;
+static HANDLE currentUserImpersonatedToken = nullptr;
/*
Deletes the allocated SIDs during global static cleanup
@@ -198,6 +199,11 @@ SidCleanup::~SidCleanup()
::FreeSid(worldSID);
worldSID = 0;
}
+
+ if (currentUserImpersonatedToken) {
+ ::CloseHandle(currentUserImpersonatedToken);
+ currentUserImpersonatedToken = nullptr;
+ }
}
Q_GLOBAL_STATIC(SidCleanup, initSidCleanup)
@@ -254,6 +260,12 @@ static void resolveLibs()
::CloseHandle(token);
}
+ token = nullptr;
+ if (::OpenProcessToken(hnd, TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &token)) {
+ ::DuplicateToken(token, SecurityImpersonation, &currentUserImpersonatedToken);
+ ::CloseHandle(token);
+ }
+
typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*);
PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid");
if (ptrAllocateAndInitializeSid) {
@@ -721,15 +733,49 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
ACCESS_MASK access_mask;
TRUSTEE_W trustee;
if (what & QFileSystemMetaData::UserPermissions) { // user
- data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
- if(ptrGetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
- access_mask = (ACCESS_MASK)-1;
- if(access_mask & ReadMask)
- data.entryFlags |= QFileSystemMetaData::UserReadPermission;
- if(access_mask & WriteMask)
- data.entryFlags|= QFileSystemMetaData::UserWritePermission;
- if(access_mask & ExecMask)
- data.entryFlags|= QFileSystemMetaData::UserExecutePermission;
+ // Using AccessCheck because GetEffectiveRightsFromAcl doesn't account for elevation
+ if (currentUserImpersonatedToken) {
+ GENERIC_MAPPING mapping = {FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS};
+ PRIVILEGE_SET privileges;
+ DWORD grantedAccess;
+ BOOL result;
+
+ data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
+ DWORD genericAccessRights = GENERIC_READ;
+ ::MapGenericMask(&genericAccessRights, &mapping);
+
+ DWORD privilegesLength = sizeof(privileges);
+ if (::AccessCheck(pSD, currentUserImpersonatedToken, genericAccessRights,
+ &mapping, &privileges, &privilegesLength, &grantedAccess, &result) && result) {
+ data.entryFlags |= QFileSystemMetaData::UserReadPermission;
+ }
+
+ privilegesLength = sizeof(privileges);
+ genericAccessRights = GENERIC_WRITE;
+ ::MapGenericMask(&genericAccessRights, &mapping);
+ if (::AccessCheck(pSD, currentUserImpersonatedToken, genericAccessRights,
+ &mapping, &privileges, &privilegesLength, &grantedAccess, &result) && result) {
+ data.entryFlags |= QFileSystemMetaData::UserWritePermission;
+ }
+
+ privilegesLength = sizeof(privileges);
+ genericAccessRights = GENERIC_EXECUTE;
+ ::MapGenericMask(&genericAccessRights, &mapping);
+ if (::AccessCheck(pSD, currentUserImpersonatedToken, genericAccessRights,
+ &mapping, &privileges, &privilegesLength, &grantedAccess, &result) && result) {
+ data.entryFlags |= QFileSystemMetaData::UserExecutePermission;
+ }
+ } else { // fallback to GetEffectiveRightsFromAcl
+ data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
+ if (ptrGetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
+ access_mask = ACCESS_MASK(-1);
+ if (access_mask & ReadMask)
+ data.entryFlags |= QFileSystemMetaData::UserReadPermission;
+ if (access_mask & WriteMask)
+ data.entryFlags|= QFileSystemMetaData::UserWritePermission;
+ if (access_mask & ExecMask)
+ data.entryFlags|= QFileSystemMetaData::UserExecutePermission;
+ }
}
if (what & QFileSystemMetaData::OwnerPermissions) { // owner
data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions;
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index f35dab2cad..efb261ce7e 100644..100755
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -64,6 +64,14 @@
#define Q_NO_SYMLINKS
#endif
+#if defined(Q_OS_WIN)
+QT_BEGIN_NAMESPACE
+extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
+QT_END_NAMESPACE
+# ifndef Q_OS_WINRT
+bool IsUserAdmin();
+# endif
+#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
inline bool qt_isEvilFsTypeName(const char *name)
@@ -1634,6 +1642,15 @@ void tst_QFileInfo::isWritable()
QVERIFY2(fi.exists(), msgDoesNotExist(fi.absoluteFilePath()).constData());
QVERIFY(!fi.isWritable());
#endif
+
+#if defined (Q_OS_WIN) && !defined(Q_OS_WINRT)
+ QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup);
+ qt_ntfs_permission_lookup = 1;
+ QFileInfo fi2(QFile::decodeName(qgetenv("SystemRoot") + "/system.ini"));
+ QVERIFY(fi2.exists());
+ QCOMPARE(fi2.isWritable(), IsUserAdmin());
+#endif
+
#if defined (Q_OS_QNX) // On QNX /etc is usually on a read-only filesystem
QVERIFY(!QFileInfo("/etc/passwd").isWritable());
#elif defined (Q_OS_UNIX) && !defined(Q_OS_VXWORKS) // VxWorks does not have users/groups
@@ -1807,7 +1824,7 @@ void tst_QFileInfo::detachingOperations()
}
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
-BOOL IsUserAdmin()
+bool IsUserAdmin()
{
BOOL b;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
@@ -1825,13 +1842,9 @@ BOOL IsUserAdmin()
FreeSid(AdministratorsGroup);
}
- return(b);
+ return b != FALSE;
}
-QT_BEGIN_NAMESPACE
-extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
-QT_END_NAMESPACE
-
#endif // Q_OS_WIN && !Q_OS_WINRT
#ifndef Q_OS_WINRT