From 8c7962bda7ea260049226fe99a351675fd0780a2 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sun, 13 Aug 2023 00:56:49 +0200 Subject: [PATCH] Windows: Better way to enable required privileges for FastCreate Options If we can set required privilege, we ask the user using UAC to enable them. --- src/Common/BaseCom.cpp | 5 +++ src/Common/BaseCom.h | 1 + src/Common/Dlgcode.c | 85 ++++++++++++++++++++++++++++++++++++++++ src/Common/Dlgcode.h | 2 + src/Common/Format.c | 59 ++++++++++++++++++++++++---- src/Format/FormatCom.cpp | 31 +++++++++++++++ src/Format/FormatCom.h | 1 + src/Format/FormatCom.idl | 1 + src/Mount/MainCom.cpp | 5 +++ src/Mount/MainCom.idl | 1 + 10 files changed, 183 insertions(+), 8 deletions(-) diff --git a/src/Common/BaseCom.cpp b/src/Common/BaseCom.cpp index dde4b55d..3eaaf809 100644 --- a/src/Common/BaseCom.cpp +++ b/src/Common/BaseCom.cpp @@ -497,3 +497,8 @@ DWORD BaseCom::NotifyService(DWORD dwNotifyCode) { return SendServiceNotification(dwNotifyCode); } + +DWORD BaseCom::FastFileResize (BSTR filePath, __int64 fileSize) +{ + return ::FastResizeFile (filePath, fileSize); +} diff --git a/src/Common/BaseCom.h b/src/Common/BaseCom.h index 937e37ec..431b0257 100644 --- a/src/Common/BaseCom.h +++ b/src/Common/BaseCom.h @@ -120,6 +120,7 @@ class BaseCom static DWORD UpdateSetupConfigFile (BOOL bForInstall); static DWORD GetSecureBootConfig (BOOL* pSecureBootEnabled, BOOL *pVeraCryptKeysLoaded); static DWORD NotifyService (DWORD dwNotifyCode); + static DWORD FastFileResize (BSTR filePath, __int64 fileSize); }; diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index b137c57b..6739a7a3 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -13977,6 +13977,41 @@ BOOL SetPrivilege(LPTSTR szPrivilegeName, BOOL bEnable) return bRet; } +BOOL IsPrivilegeEnabled (LPTSTR szPrivilegeName) +{ + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + BOOL bRet = FALSE; + DWORD dwLastError = 0; + + if (OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &hToken)) + { + if (LookupPrivilegeValue(NULL, szPrivilegeName, + &tkp.Privileges[0].Luid)) + { + DWORD dwSize = sizeof (tkp); + if (GetTokenInformation (hToken, TokenPrivileges, &tkp, dwSize, &dwSize)) + { + bRet = (tkp.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) != 0; + } + else + dwLastError = GetLastError (); + } + else + dwLastError = GetLastError (); + + CloseHandle(hToken); + } + else + dwLastError = GetLastError (); + + SetLastError (dwLastError); + + return bRet; +} + BOOL DeleteDirectory (const wchar_t* szDirName) { BOOL bStatus = RemoveDirectory (szDirName); @@ -15743,4 +15778,54 @@ DWORD SendServiceNotification (DWORD dwNotificationCmd) return dwRet; } + +DWORD FastResizeFile (const wchar_t* filePath, __int64 fileSize) +{ + DWORD dwRet = ERROR_INVALID_PARAMETER; + if (filePath && fileSize > 0) + { + // we set required privileges to speedup file creation before we create the file so that the file handle inherits the privileges + BOOL bPrivilegesSet = IsPrivilegeEnabled (SE_MANAGE_VOLUME_NAME); + if (!bPrivilegesSet && !SetPrivilege(SE_MANAGE_VOLUME_NAME, TRUE)) + { + dwRet = GetLastError (); + } + else + { + HANDLE dev = CreateFile (filePath, GENERIC_WRITE | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (dev != INVALID_HANDLE_VALUE) + { + LARGE_INTEGER liSize; + liSize.QuadPart = fileSize; + // Preallocate the file with desired size + if (!SetFilePointerEx (dev, liSize, NULL, FILE_BEGIN) + || !SetEndOfFile (dev)) + { + dwRet = GetLastError (); + } + else + { + if (!SetFileValidData (dev, fileSize)) + { + dwRet = GetLastError (); + } + else + { + dwRet = ERROR_SUCCESS; + } + } + + FlushFileBuffers (dev); + CloseHandle (dev); + } + else + dwRet = GetLastError (); + + if (!bPrivilegesSet) + SetPrivilege(SE_MANAGE_VOLUME_NAME, FALSE); + } + } + + return dwRet; +} #endif // VC_COMREG \ No newline at end of file diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 4a7e40c7..92901b28 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -577,6 +577,7 @@ BOOL CopyTextToClipboard (const wchar_t* txtValue); BOOL LaunchElevatedProcess (HWND hwndDlg, const wchar_t* szModPath, const wchar_t* args); BOOL GetFreeDriveLetter(WCHAR* pCh); BOOL SetPrivilege(LPTSTR szPrivilegeName, BOOL bEnable); +BOOL IsPrivilegeEnabled (LPTSTR szPrivilegeName); BOOL DeleteDirectory (const wchar_t* szDirName); BOOL IsThreadInSecureDesktop(DWORD dwThreadID); INT_PTR SecureDesktopDialogBoxParam (HINSTANCE, LPCWSTR, HWND, DLGPROC, LPARAM); @@ -589,6 +590,7 @@ void SafeOpenURL (LPCWSTR szUrl); BitLockerEncryptionStatus GetBitLockerEncryptionStatus(WCHAR driveLetter); BOOL IsTestSigningModeEnabled (); DWORD SendServiceNotification (DWORD dwNotificationCmd); +DWORD FastResizeFile (const wchar_t* filePath, __int64 fileSize); #ifdef _WIN64 void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed); #endif diff --git a/src/Common/Format.c b/src/Common/Format.c index 6c3e2fff..334bff3d 100644 --- a/src/Common/Format.c +++ b/src/Common/Format.c @@ -345,6 +345,7 @@ int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams) { /* File-hosted volume */ BOOL speedupFileCreation = FALSE; + BOOL delayedSpeedupFileCreation = FALSE; // speedup for file creation only makes sens when using quick format for non hidden volumes if (!volParams->hiddenVol && !bInstantRetryOtherFilesys && volParams->quickFormat && volParams->fastCreateFile) { @@ -352,7 +353,12 @@ int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams) if (!SetPrivilege(SE_MANAGE_VOLUME_NAME, TRUE)) { DWORD dwLastError = GetLastError(); - if (Silent || (MessageBoxW(hwndDlg, GetString ("ADMIN_PRIVILEGES_WARN_MANAGE_VOLUME"), lpszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDNO)) + if (!IsAdmin () && IsUacSupported ()) + { + speedupFileCreation = TRUE; + delayedSpeedupFileCreation = TRUE; + } + else if (Silent || (MessageBoxW(hwndDlg, GetString ("ADMIN_PRIVILEGES_WARN_MANAGE_VOLUME"), lpszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDNO)) { SetLastError(dwLastError); nStatus = ERR_OS_ERROR; @@ -406,12 +412,15 @@ int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams) } } - // Preallocate the file - if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN) - || !SetEndOfFile (dev)) + if (!delayedSpeedupFileCreation) { - nStatus = ERR_OS_ERROR; - goto error; + // Preallocate the file + if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN) + || !SetEndOfFile (dev)) + { + nStatus = ERR_OS_ERROR; + goto error; + } } if (speedupFileCreation) @@ -420,8 +429,42 @@ int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams) // this has security issues since it will put existing disk content into file container // We use this mechanism only when switch /fastCreateFile specific and when quick format // also specified and which is documented to have security issues. - // we don't check returned status because failure is not issue for us - if (!SetFileValidData (dev, volumeSize.QuadPart)) + if (delayedSpeedupFileCreation) + { + // in case of delayed speedup we need to set the file size to a minimal value before performing the real preallocation through UAC + LARGE_INTEGER minimalSize; + DWORD dwOpStatus; + // 16K + minimalSize.QuadPart = 16 * 1024; + if (!SetFilePointerEx (dev, minimalSize, NULL, FILE_BEGIN) + || !SetEndOfFile (dev)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + FlushFileBuffers (dev); + CloseHandle (dev); + dev = INVALID_HANDLE_VALUE; + + dwOpStatus = UacFastFileCreation (volParams->hwndDlg, volParams->volumePath, volumeSize.QuadPart); + if (dwOpStatus != 0) + { + SetLastError(dwOpStatus); + nStatus = ERR_OS_ERROR; + goto error; + } + + // open again the file now that it was created + dev = CreateFile (volParams->volumePath, GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (dev == INVALID_HANDLE_VALUE) + { + nStatus = ERR_OS_ERROR; + goto error; + } + } + else if (!SetFileValidData (dev, volumeSize.QuadPart)) { nStatus = ERR_OS_ERROR; goto error; diff --git a/src/Format/FormatCom.cpp b/src/Format/FormatCom.cpp index 18653761..d696f00f 100644 --- a/src/Format/FormatCom.cpp +++ b/src/Format/FormatCom.cpp @@ -187,6 +187,11 @@ class TrueCryptFormatCom : public ITrueCryptFormatCom return BaseCom::NotifyService (dwNotifyCode); } + virtual DWORD STDMETHODCALLTYPE FastFileResize (BSTR filePath, __int64 fileSize) + { + return BaseCom::FastFileResize (filePath, fileSize); + } + protected: DWORD MessageThreadId; LONG RefCount; @@ -335,3 +340,29 @@ extern "C" BOOL UacWriteLocalMachineRegistryDword (HWND hwndDlg, wchar_t *keyPat } } +extern "C" DWORD UacFastFileCreation (HWND hWnd, wchar_t* filePath, __int64 fileSize) +{ + CComPtr tc; + DWORD r; + + CoInitialize (NULL); + + if (ComGetInstance (hWnd, &tc)) + { + CComBSTR filePathBstr; + BSTR bstr = W2BSTR(filePath); + if (bstr) + { + filePathBstr.Attach (bstr); + r = tc->FastFileResize (filePathBstr, fileSize); + } + else + r = ERROR_OUTOFMEMORY; + } + else + r = GetLastError(); + + CoUninitialize (); + + return r; +} diff --git a/src/Format/FormatCom.h b/src/Format/FormatCom.h index 5ab6bd52..e474608d 100644 --- a/src/Format/FormatCom.h +++ b/src/Format/FormatCom.h @@ -30,6 +30,7 @@ int UacAnalyzeHiddenVolumeHost (HWND hwndDlg, int *driveNo, __int64 hiddenVolHos int UacFormatVolume (char *cvolumePath , BOOL bDevice , unsigned __int64 size , unsigned __int64 hiddenVolHostSize , Password *password , int cipher , int pkcs5 , BOOL quickFormat, BOOL sparseFileSwitch, int fileSystem , int clusterSize, HWND hwndDlg , BOOL hiddenVol , int *realClusterSize); BOOL UacUpdateProgressBar (__int64 nSecNo, BOOL *bVolTransformThreadCancel); BOOL UacWriteLocalMachineRegistryDword (HWND hwndDlg, wchar_t *keyPath, wchar_t *valueName, DWORD value); +DWORD UacFastFileCreation (HWND hWnd, wchar_t* filePath, __int64 fileSize); #ifdef __cplusplus } diff --git a/src/Format/FormatCom.idl b/src/Format/FormatCom.idl index cae4e155..7276de81 100644 --- a/src/Format/FormatCom.idl +++ b/src/Format/FormatCom.idl @@ -50,6 +50,7 @@ library TrueCryptFormatCom DWORD UpdateSetupConfigFile (BOOL bForInstall); DWORD GetSecureBootConfig (BOOL* pSecureBootEnabled, BOOL *pVeraCryptKeysLoaded); DWORD NotifyService (DWORD dwNotifyCode); + DWORD FastFileResize (BSTR filePath, __int64 fileSize); }; [ diff --git a/src/Mount/MainCom.cpp b/src/Mount/MainCom.cpp index 9226e15b..aa628f57 100644 --- a/src/Mount/MainCom.cpp +++ b/src/Mount/MainCom.cpp @@ -208,6 +208,11 @@ class TrueCryptMainCom : public ITrueCryptMainCom return BaseCom::NotifyService (dwNotifyCode); } + virtual DWORD STDMETHODCALLTYPE FastFileResize (BSTR filePath, __int64 fileSize) + { + return BaseCom::FastFileResize (filePath, fileSize); + } + protected: DWORD MessageThreadId; LONG RefCount; diff --git a/src/Mount/MainCom.idl b/src/Mount/MainCom.idl index 6ad9dd1b..06c2e48f 100644 --- a/src/Mount/MainCom.idl +++ b/src/Mount/MainCom.idl @@ -54,6 +54,7 @@ library TrueCryptMainCom DWORD UpdateSetupConfigFile (BOOL bForInstall); DWORD GetSecureBootConfig (BOOL* pSecureBootEnabled, BOOL *pVeraCryptKeysLoaded); DWORD NotifyService (DWORD dwNotifyCode); + DWORD FastFileResize (BSTR filePath, __int64 fileSize); }; [