From cdbe54e60542231f832d59389381bf9b56b710be Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Fri, 30 Dec 2016 12:17:09 +0100 Subject: Windows: Implement Secure Desktop for password entry. Add option and command line switch to activate it. --- src/Common/Dlgcode.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Common/Dlgcode.h | 4 ++ src/Common/Language.xml | 1 + 3 files changed, 181 insertions(+) (limited to 'src/Common') diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index 001d7102..3fc5c06a 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -26,6 +26,11 @@ #include #include #include +#ifdef TCMOUNT +#include +#include +#include +#endif #include "Resource.h" @@ -108,6 +113,9 @@ BOOL bShowDisconnectedNetworkDrives = FALSE; BOOL bHideWaitingDialog = FALSE; BOOL bCmdHideWaitingDialog = FALSE; BOOL bCmdHideWaitingDialogValid = FALSE; +BOOL bUseSecureDesktop = FALSE; +BOOL bCmdUseSecureDesktop = FALSE; +BOOL bCmdUseSecureDesktopValid = FALSE; BOOL bStartOnLogon = FALSE; BOOL bMountDevicesOnLogon = FALSE; BOOL bMountFavoritesOnLogon = FALSE; @@ -12225,3 +12233,171 @@ BOOL DeleteDirectory (const wchar_t* szDirName) } return bStatus; } + +#ifdef TCMOUNT +/*********************************************************************/ + +static BOOL GenerateRandomString (HWND hwndDlg, LPTSTR szName, DWORD maxCharsCount) +{ + BOOL bRet = FALSE; + if (Randinit () != ERR_SUCCESS) + { + handleError (hwndDlg, (CryptoAPILastError == ERROR_SUCCESS)? ERR_RAND_INIT_FAILED : ERR_CAPI_INIT_FAILED, SRC_POS); + } + else + { + BYTE* indexes = (BYTE*) malloc (maxCharsCount + 1); + bRet = RandgetBytesFull (hwndDlg, indexes, maxCharsCount + 1, TRUE, TRUE); + if (bRet) + { + static LPCTSTR chars = _T("0123456789@#$%^&_-*abcdefghijklmnopqrstuvwxyz"); + DWORD i, charsLen = (DWORD) _tcslen (chars); + DWORD effectiveLen = (indexes[0] % (64 - 16)) + 16; // random length between 16 to 64 + effectiveLen = (effectiveLen > maxCharsCount)? maxCharsCount : effectiveLen; + + for (i = 0; i < effectiveLen; i++) + { + szName[i] = chars[indexes[i + 1] % charsLen]; + } + + szName[effectiveLen] = 0; + } + burn (indexes, maxCharsCount + 1); + free (indexes); + } + + return bRet; +} + +typedef struct +{ + HDESK hDesk; + HINSTANCE hInstance; + LPCWSTR lpTemplateName; + DLGPROC lpDialogFunc; + LPARAM dwInitParam; + INT_PTR retValue; +} SecureDesktopThreadParam; + +static DWORD WINAPI SecureDesktopThread(LPVOID lpThreadParameter) +{ + SecureDesktopThreadParam* pParam = (SecureDesktopThreadParam*) lpThreadParameter; + + SetThreadDesktop (pParam->hDesk); + SwitchDesktop (pParam->hDesk); + + pParam->retValue = DialogBoxParamW (pParam->hInstance, pParam->lpTemplateName, + NULL, pParam->lpDialogFunc, pParam->dwInitParam); + + return 0; +} + +static void GetCtfMonProcessIdList (map& processIdList) +{ + HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + PROCESSENTRY32 pEntry; + BOOL hRes; + + pEntry.dwSize = sizeof (pEntry); + processIdList.clear(); + hRes = Process32First(hSnapShot, &pEntry); + while (hRes) + { + LPTSTR szFileName = PathFindFileName (pEntry.szExeFile); + if (_wcsicmp(szFileName, L"ctfmon.exe") == 0) + { + processIdList[pEntry.th32ProcessID] = TRUE; + } + hRes = Process32Next(hSnapShot, &pEntry); + } + CloseHandle(hSnapShot); +} + +static void KillProcess (DWORD dwProcessId) +{ + HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, dwProcessId); + if (hProcess != NULL) + { + TerminateProcess(hProcess, (UINT) -1); + CloseHandle(hProcess); + } +} + +INT_PTR SecureDesktopDialogBoxParam( + HINSTANCE hInstance, + LPCWSTR lpTemplateName, + HWND hWndParent, + DLGPROC lpDialogFunc, + LPARAM dwInitParam) +{ + TCHAR szDesktopName[65] = {0}; + BOOL bSuccess = FALSE; + INT_PTR retValue = 0; + BOOL bEffectiveUseSecureDesktop = bCmdUseSecureDesktopValid? bCmdUseSecureDesktop : bUseSecureDesktop; + + if (bEffectiveUseSecureDesktop && GenerateRandomString (hWndParent, szDesktopName, 64)) + { + map ctfmonBeforeList, ctfmonAfterList; + DWORD desktopAccess = DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS; + HDESK hSecureDesk; + + // get the initial list of ctfmon.exe processes before creating new desktop + GetCtfMonProcessIdList (ctfmonBeforeList); + + hSecureDesk = CreateDesktop (szDesktopName, NULL, NULL, 0, desktopAccess, NULL); + if (hSecureDesk) + { + HDESK hOriginalDesk = GetThreadDesktop (GetCurrentThreadId ()); + SecureDesktopThreadParam param; + + param.hDesk = hSecureDesk; + param.hInstance = hInstance; + param.lpTemplateName = lpTemplateName; + param.lpDialogFunc = lpDialogFunc; + param.dwInitParam = dwInitParam; + param.retValue = 0; + + HANDLE hThread = ::CreateThread (NULL, 0, SecureDesktopThread, (LPVOID) ¶m, 0, NULL); + if (hThread) + { + WaitForSingleObject (hThread, INFINITE); + CloseHandle (hThread); + + SwitchDesktop (hOriginalDesk); + SetThreadDesktop (hOriginalDesk); + + retValue = param.retValue; + bSuccess = TRUE; + } + + CloseDesktop (hSecureDesk); + + // get the new list of ctfmon.exe processes in order to find the ID of the + // ctfmon.exe instance that corresponds to the desktop we create so that + // we can kill it, otherwise it would remain running + GetCtfMonProcessIdList (ctfmonAfterList); + + for (map::iterator It = ctfmonAfterList.begin(); + It != ctfmonAfterList.end(); It++) + { + if (ctfmonBeforeList[It->first] != TRUE) + { + // Kill process + KillProcess (It->first); + } + } + } + + burn (szDesktopName, sizeof (szDesktopName)); + } + + if (!bSuccess) + { + // fallback to displaying in normal desktop + retValue = DialogBoxParamW (hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); + } + + return retValue; +} + +#endif diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 86afbe0f..a1930f67 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -121,6 +121,9 @@ extern BOOL bShowDisconnectedNetworkDrives; extern BOOL bHideWaitingDialog; extern BOOL bCmdHideWaitingDialog; extern BOOL bCmdHideWaitingDialogValid; +extern BOOL bUseSecureDesktop; +extern BOOL bCmdUseSecureDesktop; +extern BOOL bCmdUseSecureDesktopValid; extern BOOL bStartOnLogon; extern BOOL bMountDevicesOnLogon; extern BOOL bMountFavoritesOnLogon; @@ -514,6 +517,7 @@ BOOL LaunchElevatedProcess (HWND hwndDlg, const wchar_t* szModPath, const wchar_ BOOL GetFreeDriveLetter(WCHAR* pCh); BOOL RaisePrivileges(void); BOOL DeleteDirectory (const wchar_t* szDirName); +INT_PTR SecureDesktopDialogBoxParam (HINSTANCE, LPCWSTR, HWND, DLGPROC, LPARAM); #ifdef __cplusplus } diff --git a/src/Common/Language.xml b/src/Common/Language.xml index 1addd375..6c5697b4 100644 --- a/src/Common/Language.xml +++ b/src/Common/Language.xml @@ -1413,6 +1413,7 @@ Cannot verify that the Rescue Disk has been correctly extracted.\n\nIf you have extracted the Rescue Disk, please eject and reinsert the USB stick; then click Next to try again. If this does not help, please try another USB stick and/or another ZIP software.\n\nIf you have not extracted the Rescue Disk yet, please do so, and then click Next.\n\nIf you attempted to verify a VeraCrypt Rescue Disk created before you started this wizard, please note that such Rescue Disk cannot be used, because it was created for a different master key. You need to extract the newly generated Rescue Disk ZIP image. Cannot verify that the Rescue Disk has been correctly extracted.\n\nIf you have extracted the Rescue Disk image to a USB stick, please eject it and reinsert it; then try again. If this does not help, please try other ZIP software and/or medium.\n\nIf you attempted to verify a VeraCrypt Rescue Disk created for a different master key, password, salt, etc., please note that such Rescue Disk will always fail this verification. To create a new Rescue Disk fully compatible with your current configuration, select 'System' > 'Create Rescue Disk'. The Rescue Disk image has been created and stored in this file:\n%s\n\nNow you need to extract the Rescue Disk image to a USB stick that is formatted as FAT/FAT32.\n\nIMPORTANT: Note that the zip file must be extracted directly to the root of the USB stick. For example, if the drive letter of the USB stick is E: then extracting the zip file should create a folder E:\\EFI on the USB stick.\n\nAfter you create the Rescue Disk, select 'System' > 'Verify Rescue Disk' to verify that it has been correctly created. + Use Secure Desktop for password entry -- cgit v1.2.3