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.
This commit is contained in:
Mounir IDRASSI 2023-08-13 00:56:49 +02:00
parent eb2f5f33c9
commit 8c7962bda7
No known key found for this signature in database
GPG Key ID: 02C30AE90FAE4A6F
10 changed files with 183 additions and 8 deletions

View File

@ -497,3 +497,8 @@ DWORD BaseCom::NotifyService(DWORD dwNotifyCode)
{
return SendServiceNotification(dwNotifyCode);
}
DWORD BaseCom::FastFileResize (BSTR filePath, __int64 fileSize)
{
return ::FastResizeFile (filePath, fileSize);
}

View File

@ -120,6 +120,7 @@ public:
static DWORD UpdateSetupConfigFile (BOOL bForInstall);
static DWORD GetSecureBootConfig (BOOL* pSecureBootEnabled, BOOL *pVeraCryptKeysLoaded);
static DWORD NotifyService (DWORD dwNotifyCode);
static DWORD FastFileResize (BSTR filePath, __int64 fileSize);
};

View File

@ -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

View File

@ -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

View File

@ -345,6 +345,7 @@ begin_format:
{
/* 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 @@ begin_format:
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 @@ begin_format:
}
}
// 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 @@ begin_format:
// 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;

View File

@ -187,6 +187,11 @@ public:
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<ITrueCryptFormatCom> 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;
}

View File

@ -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
}

View File

@ -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);
};
[

View File

@ -208,6 +208,11 @@ public:
return BaseCom::NotifyService (dwNotifyCode);
}
virtual DWORD STDMETHODCALLTYPE FastFileResize (BSTR filePath, __int64 fileSize)
{
return BaseCom::FastFileResize (filePath, fileSize);
}
protected:
DWORD MessageThreadId;
LONG RefCount;

View File

@ -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);
};
[