15725 lines
426 KiB
C
15725 lines
426 KiB
C
/*
|
|
Legal Notice: Some portions of the source code contained in this file were
|
|
derived from the source code of TrueCrypt 7.1a, which is
|
|
Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
|
|
governed by the TrueCrypt License 3.0, also from the source code of
|
|
Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
|
|
and which is governed by the 'License Agreement for Encryption for the Masses'
|
|
Modifications and additions to the original source code (contained in this file)
|
|
and all other portions of this file are Copyright (c) 2013-2017 IDRIX
|
|
and are governed by the Apache License 2.0 the full text of which is
|
|
contained in the file License.txt included in VeraCrypt binary and source
|
|
code distribution packages. */
|
|
|
|
#include "Tcdefs.h"
|
|
|
|
#include <windowsx.h>
|
|
#include <dbghelp.h>
|
|
#include <dbt.h>
|
|
#include <Setupapi.h>
|
|
#include <aclapi.h>
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
#include <math.h>
|
|
#include <shlobj.h>
|
|
#include <shlwapi.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <tchar.h>
|
|
#include <Richedit.h>
|
|
#if defined (TCMOUNT) || defined (VOLFORMAT)
|
|
#include <process.h>
|
|
#include <Tlhelp32.h>
|
|
#endif
|
|
|
|
#include "Resource.h"
|
|
|
|
#include "Platform/Finally.h"
|
|
#include "Platform/ForEach.h"
|
|
#include "Apidrvr.h"
|
|
#include "BootEncryption.h"
|
|
#include "Combo.h"
|
|
#include "Crc.h"
|
|
#include "Crypto.h"
|
|
#include "Dictionary.h"
|
|
#include "Dlgcode.h"
|
|
#include "EncryptionThreadPool.h"
|
|
#include "Endian.h"
|
|
#include "Format/Inplace.h"
|
|
#include "Language.h"
|
|
#include "Keyfiles.h"
|
|
#include "Pkcs5.h"
|
|
#include "Random.h"
|
|
#include "Registry.h"
|
|
#include "SecurityToken.h"
|
|
#include "Tests.h"
|
|
#include "Volumes.h"
|
|
#include "Wipe.h"
|
|
#include "Xml.h"
|
|
#include "Xts.h"
|
|
#include "Boot/Windows/BootCommon.h"
|
|
#include "Progress.h"
|
|
#include "zip.h"
|
|
#include "rdrand.h"
|
|
#include "jitterentropy.h"
|
|
|
|
#ifdef TCMOUNT
|
|
#include "Mount/Mount.h"
|
|
#include "Mount/resource.h"
|
|
#endif
|
|
|
|
#ifdef VOLFORMAT
|
|
#include "Format/Tcformat.h"
|
|
#endif
|
|
|
|
#ifdef SETUP
|
|
#include "Setup/Setup.h"
|
|
#endif
|
|
|
|
#include <Setupapi.h>
|
|
#include <Softpub.h>
|
|
#include <WinTrust.h>
|
|
#include <strsafe.h>
|
|
|
|
#define _WIN32_DCOM
|
|
#include <comdef.h>
|
|
#include <Wbemidl.h>
|
|
|
|
#pragma comment(lib, "wbemuuid.lib")
|
|
#pragma comment( lib, "setupapi.lib" )
|
|
|
|
#ifndef TTI_INFO_LARGE
|
|
#define TTI_INFO_LARGE 4
|
|
#endif
|
|
|
|
#ifndef TTI_WARNING_LARGE
|
|
#define TTI_WARNING_LARGE 5
|
|
#endif
|
|
|
|
#ifndef TTI_ERROR_LARGE
|
|
#define TTI_ERROR_LARGE 6
|
|
#endif
|
|
|
|
/* GPT Partition Type GUIDs */
|
|
#define LOCAL_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name = {l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8}
|
|
LOCAL_DEFINE_GUID(PARTITION_ENTRY_UNUSED_GUID, 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // Entry unused
|
|
LOCAL_DEFINE_GUID(PARTITION_SYSTEM_GUID, 0xC12A7328L, 0xF81F, 0x11D2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B); // EFI system partition
|
|
LOCAL_DEFINE_GUID(PARTITION_MSFT_RESERVED_GUID, 0xE3C9E316L, 0x0B5C, 0x4DB8, 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE); // Microsoft reserved space
|
|
LOCAL_DEFINE_GUID(PARTITION_BASIC_DATA_GUID, 0xEBD0A0A2L, 0xB9E5, 0x4433, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7); // Basic data partition
|
|
LOCAL_DEFINE_GUID(PARTITION_LDM_METADATA_GUID, 0x5808C8AAL, 0x7E8F, 0x42E0, 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3); // Logical Disk Manager metadata partition
|
|
LOCAL_DEFINE_GUID(PARTITION_LDM_DATA_GUID, 0xAF9B60A0L, 0x1431, 0x4F62, 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69, 0xAD); // Logical Disk Manager data partition
|
|
LOCAL_DEFINE_GUID(PARTITION_MSFT_RECOVERY_GUID, 0xDE94BBA4L, 0x06D1, 0x4D40, 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC); // Microsoft recovery partition
|
|
LOCAL_DEFINE_GUID(PARTITION_CLUSTER_GUID, 0xdb97dba9L, 0x0840, 0x4bae, 0x97, 0xf0, 0xff, 0xb9, 0xa3, 0x27, 0xc7, 0xe1); // Cluster metadata partition
|
|
|
|
#ifndef PROCESSOR_ARCHITECTURE_ARM64
|
|
#define PROCESSOR_ARCHITECTURE_ARM64 12
|
|
#endif
|
|
|
|
#ifndef IMAGE_FILE_MACHINE_ARM64
|
|
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
|
|
#endif
|
|
|
|
|
|
using namespace VeraCrypt;
|
|
|
|
LONG DriverVersion;
|
|
|
|
char *LastDialogId;
|
|
wchar_t szHelpFile[TC_MAX_PATH];
|
|
wchar_t szHelpFile2[TC_MAX_PATH];
|
|
wchar_t SecurityTokenLibraryPath[TC_MAX_PATH];
|
|
char CmdTokenPin [TC_MAX_PATH] = {0};
|
|
|
|
HFONT hFixedDigitFont = NULL;
|
|
HFONT hBoldFont = NULL;
|
|
HFONT hTitleFont = NULL;
|
|
HFONT hFixedFont = NULL;
|
|
|
|
HFONT hUserFont = NULL;
|
|
HFONT hUserUnderlineFont = NULL;
|
|
HFONT hUserBoldFont = NULL;
|
|
HFONT hUserUnderlineBoldFont = NULL;
|
|
|
|
HFONT WindowTitleBarFont;
|
|
|
|
WCHAR EditPasswordChar = 0;
|
|
|
|
int ScreenDPI = USER_DEFAULT_SCREEN_DPI;
|
|
double DPIScaleFactorX = 1;
|
|
double DPIScaleFactorY = 1;
|
|
double DlgAspectRatio = 1;
|
|
|
|
HWND MainDlg = NULL;
|
|
wchar_t *lpszTitle = NULL;
|
|
|
|
BOOL Silent = FALSE;
|
|
BOOL bPreserveTimestamp = TRUE;
|
|
BOOL bShowDisconnectedNetworkDrives = FALSE;
|
|
BOOL bHideWaitingDialog = FALSE;
|
|
BOOL bCmdHideWaitingDialog = FALSE;
|
|
BOOL bCmdHideWaitingDialogValid = FALSE;
|
|
BOOL bUseSecureDesktop = FALSE;
|
|
BOOL bUseLegacyMaxPasswordLength = FALSE;
|
|
BOOL bCmdUseSecureDesktop = FALSE;
|
|
BOOL bCmdUseSecureDesktopValid = FALSE;
|
|
BOOL bStartOnLogon = FALSE;
|
|
BOOL bMountDevicesOnLogon = FALSE;
|
|
BOOL bMountFavoritesOnLogon = FALSE;
|
|
|
|
BOOL bHistory = FALSE;
|
|
|
|
#ifndef SETUP
|
|
BOOL bLanguageSetInSetup = FALSE;
|
|
#else
|
|
extern BOOL bMakePackage;
|
|
#endif
|
|
|
|
#ifdef TCMOUNT
|
|
extern BOOL ServiceMode;
|
|
#endif
|
|
|
|
// Status of detection of hidden sectors (whole-system-drive encryption).
|
|
// 0 - Unknown/undetermined/completed, 1: Detection is or was in progress (but did not complete e.g. due to system crash).
|
|
int HiddenSectorDetectionStatus = 0;
|
|
|
|
OSVersionEnum nCurrentOS = WIN_UNKNOWN;
|
|
int CurrentOSMajor = 0;
|
|
int CurrentOSMinor = 0;
|
|
int CurrentOSServicePack = 0;
|
|
int CurrentOSBuildNumber = 0;
|
|
BOOL RemoteSession = FALSE;
|
|
BOOL UacElevated = FALSE;
|
|
|
|
BOOL bPortableModeConfirmed = FALSE; // TRUE if it is certain that the instance is running in portable mode
|
|
|
|
BOOL bInPlaceEncNonSysPending = FALSE; // TRUE if the non-system in-place encryption config file indicates that one or more partitions are scheduled to be encrypted. This flag is set only when config files are loaded during app startup.
|
|
|
|
/* Globals used by Mount and Format (separately per instance) */
|
|
BOOL PimEnable = FALSE;
|
|
BOOL KeyFilesEnable = FALSE;
|
|
KeyFile *FirstKeyFile = NULL;
|
|
KeyFilesDlgParam defaultKeyFilesParam = {0};
|
|
|
|
BOOL IgnoreWmDeviceChange = FALSE;
|
|
BOOL DeviceChangeBroadcastDisabled = FALSE;
|
|
BOOL LastMountedVolumeDirty;
|
|
BOOL MountVolumesAsSystemFavorite = FALSE;
|
|
BOOL FavoriteMountOnArrivalInProgress = FALSE;
|
|
BOOL MultipleMountOperationInProgress = FALSE;
|
|
BOOL EMVSupportEnabled = FALSE;
|
|
|
|
volatile BOOL NeedPeriodicDeviceListUpdate = FALSE;
|
|
BOOL DisablePeriodicDeviceListUpdate = FALSE;
|
|
BOOL EnableMemoryProtection = FALSE;
|
|
|
|
BOOL WaitDialogDisplaying = FALSE;
|
|
|
|
/* Handle to the device driver */
|
|
HANDLE hDriver = INVALID_HANDLE_VALUE;
|
|
|
|
/* This mutex is used to prevent multiple instances of the wizard or main app from dealing with system encryption */
|
|
volatile HANDLE hSysEncMutex = NULL;
|
|
|
|
/* This mutex is used for non-system in-place encryption but only for informative (non-blocking) purposes,
|
|
such as whether an app should prompt the user whether to resume scheduled process. */
|
|
volatile HANDLE hNonSysInplaceEncMutex = NULL;
|
|
|
|
/* This mutex is used to prevent multiple instances of the wizard or main app from trying to install or
|
|
register the driver or from trying to launch it in portable mode at the same time. */
|
|
volatile HANDLE hDriverSetupMutex = NULL;
|
|
|
|
/* This mutex is used to prevent users from running the main TrueCrypt app or the wizard while an instance
|
|
of the TrueCrypt installer is running (which is also useful for enforcing restart before the apps can be used). */
|
|
volatile HANDLE hAppSetupMutex = NULL;
|
|
|
|
/* Critical section used to protect access to global variables used in WNetGetConnection calls */
|
|
CRITICAL_SECTION csWNetCalls;
|
|
|
|
/* Critical section used to protect access to global list of physical drives */
|
|
CRITICAL_SECTION csMountableDevices;
|
|
CRITICAL_SECTION csVolumeIdCandidates;
|
|
|
|
static std::vector<HostDevice> mountableDevices;
|
|
static std::vector<HostDevice> rawHostDeviceList;
|
|
|
|
/* Critical section used to ensure that only one thread at a time can create a secure desktop */
|
|
CRITICAL_SECTION csSecureDesktop;
|
|
|
|
/* Boolean that indicates if our Secure Desktop is active and being used or not */
|
|
volatile BOOL bSecureDesktopOngoing = FALSE;
|
|
TCHAR SecureDesktopName[65];
|
|
|
|
HINSTANCE hInst = NULL;
|
|
HCURSOR hCursor = NULL;
|
|
|
|
ATOM hDlgClass, hSplashClass;
|
|
|
|
/* This value may changed only by calling ChangeSystemEncryptionStatus(). Only the wizard can change it
|
|
(others may still read it though). */
|
|
int SystemEncryptionStatus = SYSENC_STATUS_NONE;
|
|
|
|
/* Only the wizard can change this value (others may only read it). */
|
|
WipeAlgorithmId nWipeMode = TC_WIPE_NONE;
|
|
|
|
BOOL bSysPartitionSelected = FALSE; /* TRUE if the user selected the system partition via the Select Device dialog */
|
|
BOOL bSysDriveSelected = FALSE; /* TRUE if the user selected the system drive via the Select Device dialog */
|
|
|
|
/* To populate these arrays, call GetSysDevicePaths(). If they contain valid paths, bCachedSysDevicePathsValid is TRUE. */
|
|
wchar_t SysPartitionDevicePath [TC_MAX_PATH];
|
|
wchar_t SysDriveDevicePath [TC_MAX_PATH];
|
|
wstring ExtraBootPartitionDevicePath;
|
|
char bCachedSysDevicePathsValid = FALSE;
|
|
|
|
BOOL bHyperLinkBeingTracked = FALSE;
|
|
|
|
int WrongPwdRetryCounter = 0;
|
|
|
|
static FILE *ConfigFileHandle;
|
|
char *ConfigBuffer;
|
|
|
|
BOOL SystemFileSelectorCallPending = FALSE;
|
|
DWORD SystemFileSelectorCallerThreadId;
|
|
|
|
#define RANDPOOL_DISPLAY_REFRESH_INTERVAL 30
|
|
#define RANDPOOL_DISPLAY_ROWS 16
|
|
#define RANDPOOL_DISPLAY_COLUMNS 20
|
|
|
|
HMODULE hRichEditDll = NULL;
|
|
HMODULE hComctl32Dll = NULL;
|
|
HMODULE hSetupDll = NULL;
|
|
HMODULE hShlwapiDll = NULL;
|
|
HMODULE hProfApiDll = NULL;
|
|
HMODULE hUsp10Dll = NULL;
|
|
HMODULE hCryptSpDll = NULL;
|
|
HMODULE hUXThemeDll = NULL;
|
|
HMODULE hUserenvDll = NULL;
|
|
HMODULE hRsaenhDll = NULL;
|
|
HMODULE himm32dll = NULL;
|
|
HMODULE hMSCTFdll = NULL;
|
|
HMODULE hfltlibdll = NULL;
|
|
HMODULE hframedyndll = NULL;
|
|
HMODULE hpsapidll = NULL;
|
|
HMODULE hsecur32dll = NULL;
|
|
HMODULE hnetapi32dll = NULL;
|
|
HMODULE hauthzdll = NULL;
|
|
HMODULE hxmllitedll = NULL;
|
|
HMODULE hmprdll = NULL;
|
|
HMODULE hsppdll = NULL;
|
|
HMODULE vssapidll = NULL;
|
|
HMODULE hvsstracedll = NULL;
|
|
HMODULE hcfgmgr32dll = NULL;
|
|
HMODULE hdevobjdll = NULL;
|
|
HMODULE hpowrprofdll = NULL;
|
|
HMODULE hsspiclidll = NULL;
|
|
HMODULE hcryptbasedll = NULL;
|
|
HMODULE hdwmapidll = NULL;
|
|
HMODULE hmsasn1dll = NULL;
|
|
HMODULE hcrypt32dll = NULL;
|
|
HMODULE hbcryptdll = NULL;
|
|
HMODULE hbcryptprimitivesdll = NULL;
|
|
HMODULE hMsls31 = NULL;
|
|
HMODULE hntmartadll = NULL;
|
|
HMODULE hwinscarddll = NULL;
|
|
HMODULE hmsvcrtdll = NULL;
|
|
HMODULE hWinTrustLib = NULL;
|
|
HMODULE hAdvapi32Dll = NULL;
|
|
|
|
#define FREE_DLL(h) if (h) { FreeLibrary (h); h = NULL;}
|
|
|
|
#ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
|
|
#define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE 0x00000001
|
|
#endif
|
|
|
|
#ifndef BASE_SEARCH_PATH_PERMANENT
|
|
#define BASE_SEARCH_PATH_PERMANENT 0x00008000
|
|
#endif
|
|
|
|
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
|
|
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
|
|
#endif
|
|
|
|
typedef BOOL (WINAPI *SetDllDirectoryPtr)(LPCWSTR lpPathName);
|
|
typedef BOOL (WINAPI *SetSearchPathModePtr)(DWORD Flags);
|
|
typedef BOOL (WINAPI *SetDefaultDllDirectoriesPtr)(DWORD DirectoryFlags);
|
|
|
|
|
|
typedef void (WINAPI *InitCommonControlsPtr)(void);
|
|
typedef HIMAGELIST (WINAPI *ImageList_CreatePtr)(int cx, int cy, UINT flags, int cInitial, int cGrow);
|
|
typedef int (WINAPI *ImageList_AddPtr)(HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask);
|
|
|
|
typedef VOID (WINAPI *SetupCloseInfFilePtr)(HINF InfHandle);
|
|
typedef HKEY (WINAPI *SetupDiOpenClassRegKeyPtr)(CONST GUID *ClassGuid,REGSAM samDesired);
|
|
typedef BOOL (WINAPI *SetupInstallFromInfSectionWPtr)(HWND,HINF,PCWSTR,UINT,HKEY,PCWSTR,UINT,PSP_FILE_CALLBACK_W,PVOID,HDEVINFO,PSP_DEVINFO_DATA);
|
|
typedef HINF (WINAPI *SetupOpenInfFileWPtr)(PCWSTR FileName,PCWSTR InfClass,DWORD InfStyle,PUINT ErrorLine);
|
|
|
|
typedef LSTATUS (STDAPICALLTYPE *SHDeleteKeyWPtr)(HKEY hkey, LPCWSTR pszSubKey);
|
|
|
|
typedef HRESULT (STDAPICALLTYPE *SHStrDupWPtr)(LPCWSTR psz, LPWSTR *ppwsz);
|
|
|
|
typedef HRESULT (STDAPICALLTYPE *UrlUnescapeWPtr)(
|
|
PWSTR pszUrl,
|
|
PWSTR pszUnescaped,
|
|
DWORD *pcchUnescaped,
|
|
DWORD dwFlags
|
|
);
|
|
|
|
// ChangeWindowMessageFilter
|
|
typedef BOOL (WINAPI *ChangeWindowMessageFilterPtr) (UINT, DWORD);
|
|
|
|
typedef BOOL (WINAPI *CreateProcessWithTokenWFn)(
|
|
__in HANDLE hToken,
|
|
__in DWORD dwLogonFlags,
|
|
__in_opt LPCWSTR lpApplicationName,
|
|
__inout_opt LPWSTR lpCommandLine,
|
|
__in DWORD dwCreationFlags,
|
|
__in_opt LPVOID lpEnvironment,
|
|
__in_opt LPCWSTR lpCurrentDirectory,
|
|
__in LPSTARTUPINFOW lpStartupInfo,
|
|
__out LPPROCESS_INFORMATION lpProcessInformation
|
|
);
|
|
|
|
typedef HRESULT (WINAPI *IUnknown_QueryServiceFn)(
|
|
__in IUnknown* punk,
|
|
__in REFGUID guidService,
|
|
__in REFIID riid,
|
|
__deref_out void ** ppvOut);
|
|
|
|
SetDllDirectoryPtr SetDllDirectoryFn = NULL;
|
|
SetSearchPathModePtr SetSearchPathModeFn = NULL;
|
|
SetDefaultDllDirectoriesPtr SetDefaultDllDirectoriesFn = NULL;
|
|
|
|
ImageList_CreatePtr ImageList_CreateFn = NULL;
|
|
ImageList_AddPtr ImageList_AddFn = NULL;
|
|
|
|
SetupCloseInfFilePtr SetupCloseInfFileFn = NULL;
|
|
SetupDiOpenClassRegKeyPtr SetupDiOpenClassRegKeyFn = NULL;
|
|
SetupInstallFromInfSectionWPtr SetupInstallFromInfSectionWFn = NULL;
|
|
SetupOpenInfFileWPtr SetupOpenInfFileWFn = NULL;
|
|
SHDeleteKeyWPtr SHDeleteKeyWFn = NULL;
|
|
SHStrDupWPtr SHStrDupWFn = NULL;
|
|
UrlUnescapeWPtr UrlUnescapeWFn = NULL;
|
|
ChangeWindowMessageFilterPtr ChangeWindowMessageFilterFn = NULL;
|
|
CreateProcessWithTokenWFn CreateProcessWithTokenWPtr = NULL;
|
|
IUnknown_QueryServiceFn IUnknown_QueryServicePtr = NULL;
|
|
|
|
typedef LONG (WINAPI *WINVERIFYTRUST)(HWND hwnd, GUID *pgActionID, LPVOID pWVTData);
|
|
typedef CRYPT_PROVIDER_DATA* (WINAPI *WTHELPERPROVDATAFROMSTATEDATA)(HANDLE hStateData);
|
|
typedef CRYPT_PROVIDER_SGNR* (WINAPI *WTHELPERGETPROVSIGNERFROMCHAIN)(CRYPT_PROVIDER_DATA *pProvData,
|
|
DWORD idxSigner,
|
|
BOOL fCounterSigner,
|
|
DWORD idxCounterSigner);
|
|
typedef CRYPT_PROVIDER_CERT* (WINAPI *WTHELPERGETPROVCERTFROMCHAIN)(CRYPT_PROVIDER_SGNR *pSgnr,
|
|
DWORD idxCert);
|
|
|
|
static WINVERIFYTRUST WinVerifyTrustFn = NULL;
|
|
static WTHELPERPROVDATAFROMSTATEDATA WTHelperProvDataFromStateDataFn = NULL;
|
|
static WTHELPERGETPROVSIGNERFROMCHAIN WTHelperGetProvSignerFromChainFn = NULL;
|
|
static WTHELPERGETPROVCERTFROMCHAIN WTHelperGetProvCertFromChainFn = NULL;
|
|
|
|
static unsigned char gpbSha256CodeSignCertFingerprint[64] = {
|
|
0x9C, 0xA0, 0x21, 0xD3, 0x7C, 0x90, 0x61, 0x88, 0xEF, 0x5F, 0x99, 0x3D,
|
|
0x54, 0x9F, 0xB8, 0xCE, 0x72, 0x32, 0x4F, 0x57, 0x4F, 0x19, 0xD2, 0xA4,
|
|
0xDC, 0x84, 0xFF, 0xE2, 0x84, 0x2B, 0xD4, 0x30, 0xAB, 0xA7, 0xE4, 0x63,
|
|
0x18, 0xD1, 0xD8, 0x32, 0x0E, 0xA4, 0x81, 0x3C, 0x19, 0xBF, 0x13, 0x11,
|
|
0xA4, 0x37, 0xD6, 0xDB, 0x26, 0xBA, 0xDC, 0x8F, 0x86, 0x96, 0x55, 0x96,
|
|
0xDB, 0x6F, 0xC0, 0x62
|
|
};
|
|
|
|
static unsigned char gpbSha256MSCodeSignCertFingerprint[64] = {
|
|
0x9C, 0x96, 0x81, 0x3B, 0x88, 0x54, 0xCB, 0x81, 0xB5, 0x94, 0x40, 0x4E,
|
|
0x15, 0x81, 0x20, 0xA1, 0x19, 0x00, 0x4E, 0x49, 0x8A, 0xA8, 0x98, 0x13,
|
|
0x9D, 0xE2, 0x86, 0x6A, 0xC1, 0xFA, 0xD3, 0x00, 0x0D, 0xAC, 0xE9, 0xE3,
|
|
0x3B, 0xFC, 0x6B, 0x26, 0xCE, 0xC8, 0xE2, 0x36, 0x3B, 0x60, 0x9C, 0x8E,
|
|
0x0A, 0x2A, 0x74, 0x20, 0xD7, 0x4E, 0x0F, 0xEE, 0x2E, 0x79, 0xE2, 0xAF,
|
|
0x1C, 0x90, 0x0B, 0x9C
|
|
};
|
|
|
|
|
|
typedef HRESULT (WINAPI *SHGETKNOWNFOLDERPATH) (
|
|
_In_ REFKNOWNFOLDERID rfid,
|
|
_In_ DWORD dwFlags,
|
|
_In_opt_ HANDLE hToken,
|
|
_Out_ PWSTR *ppszPath
|
|
);
|
|
|
|
/* Windows dialog class */
|
|
#define WINDOWS_DIALOG_CLASS L"#32770"
|
|
|
|
/* Custom class names */
|
|
#define TC_DLG_CLASS L"VeraCryptCustomDlg"
|
|
#define TC_SPLASH_CLASS L"VeraCryptSplashDlg"
|
|
|
|
/* constant used by ChangeWindowMessageFilter calls */
|
|
#ifndef MSGFLT_ADD
|
|
#define MSGFLT_ADD 1
|
|
#endif
|
|
|
|
/* undocumented message sent during drag-n-drop */
|
|
#ifndef WM_COPYGLOBALDATA
|
|
#define WM_COPYGLOBALDATA 0x0049
|
|
#endif
|
|
|
|
/* Benchmarks */
|
|
|
|
#ifndef SETUP
|
|
|
|
#define BENCHMARK_MAX_ITEMS 100
|
|
#define BENCHMARK_DEFAULT_BUF_SIZE BYTES_PER_MB
|
|
#define HASH_FNC_BENCHMARKS FALSE // For development purposes only. Must be FALSE when building a public release.
|
|
#define PKCS5_BENCHMARKS FALSE // For development purposes only. Must be FALSE when building a public release.
|
|
#if PKCS5_BENCHMARKS && HASH_FNC_BENCHMARKS
|
|
#error PKCS5_BENCHMARKS and HASH_FNC_BENCHMARKS are both TRUE (at least one of them should be FALSE).
|
|
#endif
|
|
|
|
enum
|
|
{
|
|
BENCHMARK_TYPE_ENCRYPTION = 0,
|
|
BENCHMARK_TYPE_PRF,
|
|
BENCHMARK_TYPE_HASH
|
|
};
|
|
|
|
enum
|
|
{
|
|
BENCHMARK_SORT_BY_NAME = 0,
|
|
BENCHMARK_SORT_BY_SPEED
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
int id;
|
|
wchar_t name[100];
|
|
unsigned __int64 encSpeed;
|
|
unsigned __int64 decSpeed;
|
|
unsigned __int64 meanBytesPerSec;
|
|
} BENCHMARK_REC;
|
|
|
|
BENCHMARK_REC benchmarkTable [BENCHMARK_MAX_ITEMS];
|
|
int benchmarkTotalItems = 0;
|
|
int benchmarkBufferSize = BENCHMARK_DEFAULT_BUF_SIZE;
|
|
int benchmarkLastBufferSize = BENCHMARK_DEFAULT_BUF_SIZE;
|
|
int benchmarkSortMethod = BENCHMARK_SORT_BY_SPEED;
|
|
LARGE_INTEGER benchmarkPerformanceFrequency;
|
|
int benchmarkType = BENCHMARK_TYPE_ENCRYPTION;
|
|
int benchmarkPim = -1;
|
|
BOOL benchmarkPreBoot = FALSE;
|
|
BOOL benchmarkGPT = FALSE;
|
|
|
|
#endif // #ifndef SETUP
|
|
|
|
|
|
typedef struct
|
|
{
|
|
void *strings;
|
|
BOOL bold;
|
|
|
|
} MULTI_CHOICE_DLGPROC_PARAMS;
|
|
|
|
|
|
|
|
|
|
// Loads a 32-bit integer from the file at the specified file offset. The saved value is assumed to have been
|
|
// processed by mputLong(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
|
|
BOOL LoadInt32 (const wchar_t *filePath, unsigned __int32 *result, __int64 fileOffset)
|
|
{
|
|
DWORD bufSize = sizeof(__int32);
|
|
unsigned char *buffer = (unsigned char *) malloc (bufSize);
|
|
unsigned char *bufferPtr = buffer;
|
|
HANDLE src = NULL;
|
|
DWORD bytesRead;
|
|
LARGE_INTEGER seekOffset, seekOffsetNew;
|
|
BOOL retVal = FALSE;
|
|
|
|
if (buffer == NULL)
|
|
return -1;
|
|
|
|
src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (src == INVALID_HANDLE_VALUE)
|
|
{
|
|
free (buffer);
|
|
return FALSE;
|
|
}
|
|
|
|
seekOffset.QuadPart = fileOffset;
|
|
|
|
if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
|
|
goto fsif_end;
|
|
|
|
if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
|
|
|| bytesRead != bufSize)
|
|
goto fsif_end;
|
|
|
|
|
|
retVal = TRUE;
|
|
|
|
*result = mgetLong(bufferPtr);
|
|
|
|
fsif_end:
|
|
CloseHandle (src);
|
|
free (buffer);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// Loads a 16-bit integer from the file at the specified file offset. The saved value is assumed to have been
|
|
// processed by mputWord(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
|
|
BOOL LoadInt16 (const wchar_t *filePath, int *result, __int64 fileOffset)
|
|
{
|
|
DWORD bufSize = sizeof(__int16);
|
|
unsigned char *buffer = (unsigned char *) malloc (bufSize);
|
|
unsigned char *bufferPtr = buffer;
|
|
HANDLE src = NULL;
|
|
DWORD bytesRead;
|
|
LARGE_INTEGER seekOffset, seekOffsetNew;
|
|
BOOL retVal = FALSE;
|
|
|
|
if (buffer == NULL)
|
|
return -1;
|
|
|
|
src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (src == INVALID_HANDLE_VALUE)
|
|
{
|
|
free (buffer);
|
|
return FALSE;
|
|
}
|
|
|
|
seekOffset.QuadPart = fileOffset;
|
|
|
|
if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
|
|
goto fsif_end;
|
|
|
|
if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
|
|
|| bytesRead != bufSize)
|
|
goto fsif_end;
|
|
|
|
|
|
retVal = TRUE;
|
|
|
|
*result = mgetWord(bufferPtr);
|
|
|
|
fsif_end:
|
|
CloseHandle (src);
|
|
free (buffer);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// Returns NULL if there's any error. Although the buffer can contain binary data, it is always null-terminated.
|
|
char *LoadFile (const wchar_t *fileName, DWORD *size)
|
|
{
|
|
char *buf;
|
|
DWORD fileSize = INVALID_FILE_SIZE;
|
|
HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
*size = 0;
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
return NULL;
|
|
|
|
if ((fileSize = GetFileSize (h, NULL)) == INVALID_FILE_SIZE)
|
|
{
|
|
CloseHandle (h);
|
|
return NULL;
|
|
}
|
|
|
|
buf = (char *) calloc (fileSize + 1, 1);
|
|
|
|
if (buf == NULL)
|
|
{
|
|
CloseHandle (h);
|
|
return NULL;
|
|
}
|
|
|
|
if (!ReadFile (h, buf, fileSize, size, NULL))
|
|
{
|
|
free (buf);
|
|
buf = NULL;
|
|
}
|
|
else
|
|
{
|
|
buf[*size] = 0; //make coverity happy eventhough buf is guaranteed to be null terminated because of fileSize+1 in calloc call
|
|
}
|
|
|
|
CloseHandle (h);
|
|
return buf;
|
|
}
|
|
|
|
|
|
// Returns NULL if there's any error.
|
|
char *LoadFileBlock (const wchar_t *fileName, __int64 fileOffset, DWORD count)
|
|
{
|
|
char *buf;
|
|
DWORD bytesRead = 0;
|
|
LARGE_INTEGER seekOffset, seekOffsetNew;
|
|
BOOL bStatus;
|
|
|
|
HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
return NULL;
|
|
|
|
seekOffset.QuadPart = fileOffset;
|
|
|
|
if (SetFilePointerEx (h, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
|
|
{
|
|
CloseHandle (h);
|
|
return NULL;
|
|
}
|
|
|
|
buf = (char *) calloc (count, 1);
|
|
|
|
if (buf == NULL)
|
|
{
|
|
CloseHandle (h);
|
|
return NULL;
|
|
}
|
|
|
|
bStatus = ReadFile (h, buf, count, &bytesRead, NULL);
|
|
|
|
CloseHandle (h);
|
|
|
|
if (!bStatus || (bytesRead != count))
|
|
{
|
|
free (buf);
|
|
return NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
// Returns -1 if there is an error, or the size of the file.
|
|
__int64 GetFileSize64 (const wchar_t *path)
|
|
{
|
|
HANDLE h = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
LARGE_INTEGER size;
|
|
__int64 retSize = -1;
|
|
|
|
if (h)
|
|
{
|
|
if (GetFileSizeEx (h, &size))
|
|
{
|
|
retSize = size.QuadPart;
|
|
}
|
|
|
|
CloseHandle (h);
|
|
}
|
|
|
|
return retSize;
|
|
}
|
|
|
|
// If bAppend is TRUE, the buffer is appended to an existing file. If bAppend is FALSE, any existing file
|
|
// is replaced. If an error occurs, the incomplete file is deleted (provided that bAppend is FALSE).
|
|
BOOL SaveBufferToFile (const char *inputBuffer, const wchar_t *destinationFile, DWORD inputLength, BOOL bAppend, BOOL bRenameIfFailed)
|
|
{
|
|
HANDLE dst;
|
|
DWORD bytesWritten;
|
|
BOOL res = TRUE;
|
|
DWORD dwLastError = 0;
|
|
|
|
dst = CreateFile (destinationFile,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, bAppend ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
|
|
|
|
dwLastError = GetLastError();
|
|
if (!bAppend && bRenameIfFailed && (dst == INVALID_HANDLE_VALUE) && (GetLastError () == ERROR_SHARING_VIOLATION))
|
|
{
|
|
wchar_t renamedPath[TC_MAX_PATH + 1];
|
|
StringCbCopyW (renamedPath, sizeof(renamedPath), destinationFile);
|
|
StringCbCatW (renamedPath, sizeof(renamedPath), VC_FILENAME_RENAMED_SUFFIX);
|
|
|
|
/* rename the locked file in order to be able to create a new one */
|
|
if (MoveFileEx (destinationFile, renamedPath, MOVEFILE_REPLACE_EXISTING))
|
|
{
|
|
dst = CreateFile (destinationFile,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
|
|
dwLastError = GetLastError();
|
|
if (dst == INVALID_HANDLE_VALUE)
|
|
{
|
|
/* restore the original file name */
|
|
MoveFileEx (renamedPath, destinationFile, MOVEFILE_REPLACE_EXISTING);
|
|
}
|
|
else
|
|
{
|
|
/* delete the renamed file when the machine reboots */
|
|
MoveFileEx (renamedPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dst == INVALID_HANDLE_VALUE)
|
|
{
|
|
SetLastError (dwLastError);
|
|
handleWin32Error (MainDlg, SRC_POS);
|
|
return FALSE;
|
|
}
|
|
|
|
if (bAppend)
|
|
SetFilePointer (dst, 0, NULL, FILE_END);
|
|
|
|
if (!WriteFile (dst, inputBuffer, inputLength, &bytesWritten, NULL)
|
|
|| inputLength != bytesWritten)
|
|
{
|
|
res = FALSE;
|
|
}
|
|
|
|
if (!res)
|
|
{
|
|
// If CREATE_ALWAYS is used, ERROR_ALREADY_EXISTS is returned after successful overwrite
|
|
// of an existing file (it's not an error)
|
|
if (! (GetLastError() == ERROR_ALREADY_EXISTS && !bAppend) )
|
|
handleWin32Error (MainDlg, SRC_POS);
|
|
}
|
|
|
|
CloseHandle (dst);
|
|
|
|
if (!res && !bAppend)
|
|
_wremove (destinationFile);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
// Returns -1 if the specified string is not found in the buffer. Otherwise, returns the
|
|
// offset of the first occurrence of the string. The string and the buffer may contain zeroes,
|
|
// which do NOT terminate them.
|
|
int64 FindString (const char *buf, const char *str, int64 bufLen, int64 strLen, int64 startOffset)
|
|
{
|
|
if (buf == NULL
|
|
|| str == NULL
|
|
|| strLen > bufLen
|
|
|| bufLen < 1
|
|
|| strLen < 1
|
|
|| startOffset > bufLen - strLen)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (int64 i = startOffset; i <= bufLen - strLen; i++)
|
|
{
|
|
if (memcmp (buf + i, str, (size_t) strLen) == 0)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Returns TRUE if the file or directory exists (both may be enclosed in quotation marks).
|
|
BOOL FileExists (const wchar_t *filePathPtr)
|
|
{
|
|
wchar_t filePath [TC_MAX_PATH * 2 + 1];
|
|
|
|
// Strip quotation marks (if any)
|
|
if (filePathPtr [0] == L'"')
|
|
{
|
|
StringCbCopyW (filePath, sizeof(filePath), filePathPtr + 1);
|
|
}
|
|
else
|
|
{
|
|
StringCbCopyW (filePath, sizeof(filePath), filePathPtr);
|
|
}
|
|
|
|
// Strip quotation marks (if any)
|
|
if (filePath [wcslen (filePath) - 1] == L'"')
|
|
filePath [wcslen (filePath) - 1] = 0;
|
|
|
|
return (_waccess (filePath, 0) != -1);
|
|
}
|
|
|
|
|
|
// Searches the file from its end for the LAST occurrence of the string str.
|
|
// The string may contain zeroes, which do NOT terminate the string.
|
|
// If the string is found, its offset from the start of the file is returned.
|
|
// If the string isn't found or if any error occurs, -1 is returned.
|
|
__int64 FindStringInFile (const wchar_t *filePath, const char* str, int strLen)
|
|
{
|
|
int bufSize = 64 * BYTES_PER_KB;
|
|
char *buffer = (char *) err_malloc (bufSize);
|
|
HANDLE src = NULL;
|
|
DWORD bytesRead;
|
|
BOOL readRetVal;
|
|
__int64 filePos = GetFileSize64 (filePath);
|
|
int bufPos = 0;
|
|
LARGE_INTEGER seekOffset, seekOffsetNew;
|
|
BOOL bExit = FALSE;
|
|
int filePosStep;
|
|
__int64 retVal = -1;
|
|
|
|
if (filePos <= 0
|
|
|| buffer == NULL
|
|
|| strLen > bufSize
|
|
|| strLen < 1)
|
|
{
|
|
if (buffer)
|
|
free (buffer);
|
|
return -1;
|
|
}
|
|
|
|
src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (src == INVALID_HANDLE_VALUE)
|
|
{
|
|
free (buffer);
|
|
return -1;
|
|
}
|
|
|
|
filePosStep = bufSize - strLen + 1;
|
|
|
|
do
|
|
{
|
|
filePos -= filePosStep;
|
|
|
|
if (filePos < 0)
|
|
{
|
|
filePos = 0;
|
|
bExit = TRUE;
|
|
}
|
|
|
|
seekOffset.QuadPart = filePos;
|
|
|
|
if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
|
|
goto fsif_end;
|
|
|
|
if ((readRetVal = ReadFile (src, buffer, bufSize, &bytesRead, NULL)) == 0
|
|
|| bytesRead == 0)
|
|
goto fsif_end;
|
|
|
|
bufPos = bytesRead - strLen;
|
|
|
|
while (bufPos > 0)
|
|
{
|
|
if (memcmp (buffer + bufPos, str, strLen) == 0)
|
|
{
|
|
// String found
|
|
retVal = filePos + bufPos;
|
|
goto fsif_end;
|
|
}
|
|
bufPos--;
|
|
}
|
|
|
|
} while (!bExit);
|
|
|
|
fsif_end:
|
|
CloseHandle (src);
|
|
free (buffer);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// System CopyFile() copies source file attributes (like FILE_ATTRIBUTE_ENCRYPTED)
|
|
// so we need to use our own copy function
|
|
BOOL TCCopyFileBase (HANDLE src, HANDLE dst)
|
|
{
|
|
__int8 *buffer;
|
|
FILETIME fileTime;
|
|
DWORD bytesRead, bytesWritten;
|
|
BOOL res;
|
|
|
|
buffer = (char *) malloc (64 * 1024);
|
|
if (!buffer)
|
|
{
|
|
CloseHandle (src);
|
|
CloseHandle (dst);
|
|
return FALSE;
|
|
}
|
|
|
|
while (res = ReadFile (src, buffer, 64 * 1024, &bytesRead, NULL))
|
|
{
|
|
if (bytesRead == 0)
|
|
{
|
|
res = 1;
|
|
break;
|
|
}
|
|
|
|
if (!WriteFile (dst, buffer, bytesRead, &bytesWritten, NULL)
|
|
|| bytesRead != bytesWritten)
|
|
{
|
|
res = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (GetFileTime (src, NULL, NULL, &fileTime))
|
|
SetFileTime (dst, NULL, NULL, &fileTime);
|
|
|
|
CloseHandle (src);
|
|
CloseHandle (dst);
|
|
|
|
free (buffer);
|
|
return res != 0;
|
|
}
|
|
|
|
BOOL TCCopyFile (wchar_t *sourceFileName, wchar_t *destinationFile)
|
|
{
|
|
HANDLE src, dst;
|
|
|
|
src = CreateFileW (sourceFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (src == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
dst = CreateFileW (destinationFile,
|
|
GENERIC_WRITE,
|
|
0, NULL, CREATE_ALWAYS, 0, NULL);
|
|
|
|
if (dst == INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle (src);
|
|
return FALSE;
|
|
}
|
|
|
|
return TCCopyFileBase (src, dst);
|
|
}
|
|
|
|
#if defined(NDEBUG) && !defined(VC_SKIP_OS_DRIVER_REQ_CHECK)
|
|
static BOOL InitializeWintrust()
|
|
{
|
|
if (!hWinTrustLib)
|
|
{
|
|
wchar_t szPath[MAX_PATH] = {0};
|
|
|
|
if (GetSystemDirectory(szPath, MAX_PATH))
|
|
StringCchCatW (szPath, MAX_PATH, L"\\Wintrust.dll");
|
|
else
|
|
StringCchCopyW (szPath, MAX_PATH, L"C:\\Windows\\System32\\Wintrust.dll");
|
|
|
|
hWinTrustLib = LoadLibrary (szPath);
|
|
if (hWinTrustLib)
|
|
{
|
|
WinVerifyTrustFn = (WINVERIFYTRUST) GetProcAddress (hWinTrustLib, "WinVerifyTrust");
|
|
WTHelperProvDataFromStateDataFn = (WTHELPERPROVDATAFROMSTATEDATA) GetProcAddress (hWinTrustLib, "WTHelperProvDataFromStateData");
|
|
WTHelperGetProvSignerFromChainFn = (WTHELPERGETPROVSIGNERFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvSignerFromChain");
|
|
WTHelperGetProvCertFromChainFn = (WTHELPERGETPROVCERTFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvCertFromChain");
|
|
|
|
if ( !WinVerifyTrustFn
|
|
|| !WTHelperProvDataFromStateDataFn
|
|
|| !WTHelperGetProvSignerFromChainFn
|
|
|| !WTHelperGetProvCertFromChainFn)
|
|
{
|
|
FreeLibrary (hWinTrustLib);
|
|
hWinTrustLib = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (hWinTrustLib)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static void FinalizeWintrust()
|
|
{
|
|
if (hWinTrustLib)
|
|
{
|
|
FreeLibrary (hWinTrustLib);
|
|
hWinTrustLib = NULL;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOL VerifyModuleSignature (const wchar_t* path)
|
|
{
|
|
#if defined(NDEBUG) && !defined (VC_SKIP_OS_DRIVER_REQ_CHECK)
|
|
BOOL bResult = FALSE;
|
|
HRESULT hResult;
|
|
GUID gActionID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
|
WINTRUST_FILE_INFO fileInfo = {0};
|
|
WINTRUST_DATA WVTData = {0};
|
|
wchar_t filePath [TC_MAX_PATH + 1024];
|
|
|
|
// we check our own authenticode signature only starting from Windows 10 since this is
|
|
// the minimal supported OS apart from XP where we can't verify SHA256 signatures
|
|
if (!IsOSAtLeast (WIN_10))
|
|
return TRUE;
|
|
|
|
// Strip quotation marks (if any)
|
|
if (path [0] == L'"')
|
|
{
|
|
StringCbCopyW (filePath, sizeof(filePath), path + 1);
|
|
}
|
|
else
|
|
{
|
|
StringCbCopyW (filePath, sizeof(filePath), path);
|
|
}
|
|
|
|
// Strip quotation marks (if any)
|
|
if (filePath [wcslen (filePath) - 1] == L'"')
|
|
filePath [wcslen (filePath) - 1] = 0;
|
|
|
|
if (!InitializeWintrust ())
|
|
return FALSE;
|
|
|
|
fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
|
fileInfo.pcwszFilePath = filePath;
|
|
fileInfo.hFile = NULL;
|
|
|
|
WVTData.cbStruct = sizeof(WINTRUST_DATA);
|
|
WVTData.dwUIChoice = WTD_UI_NONE;
|
|
WVTData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
|
WVTData.dwUnionChoice = WTD_CHOICE_FILE;
|
|
WVTData.pFile = &fileInfo;
|
|
WVTData.dwStateAction = WTD_STATEACTION_VERIFY;
|
|
WVTData.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_CACHE_ONLY_URL_RETRIEVAL;
|
|
|
|
hResult = WinVerifyTrustFn(0, &gActionID, &WVTData);
|
|
if (0 == hResult)
|
|
{
|
|
PCRYPT_PROVIDER_DATA pProviderData = WTHelperProvDataFromStateDataFn (WVTData.hWVTStateData);
|
|
if (pProviderData)
|
|
{
|
|
PCRYPT_PROVIDER_SGNR pProviderSigner = WTHelperGetProvSignerFromChainFn (pProviderData, 0, FALSE, 0);
|
|
if (pProviderSigner)
|
|
{
|
|
PCRYPT_PROVIDER_CERT pProviderCert = WTHelperGetProvCertFromChainFn (pProviderSigner, 0);
|
|
if (pProviderCert && (pProviderCert->pCert))
|
|
{
|
|
BYTE hashVal[64];
|
|
sha512 (hashVal, pProviderCert->pCert->pbCertEncoded, pProviderCert->pCert->cbCertEncoded);
|
|
|
|
if ( (0 == memcmp (hashVal, gpbSha256CodeSignCertFingerprint, 64))
|
|
|| (0 == memcmp (hashVal, gpbSha256MSCodeSignCertFingerprint, 64))
|
|
)
|
|
{
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
WVTData.dwUIChoice = WTD_UI_NONE;
|
|
WVTData.dwStateAction = WTD_STATEACTION_CLOSE;
|
|
WinVerifyTrustFn(0, &gActionID, &WVTData);
|
|
|
|
FinalizeWintrust ();
|
|
|
|
return bResult;
|
|
#else
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
DWORD handleWin32Error (HWND hwndDlg, const char* srcPos)
|
|
{
|
|
#ifndef VC_COMREG
|
|
PWSTR lpMsgBuf;
|
|
DWORD dwError = GetLastError ();
|
|
wchar_t szErrorValue[32];
|
|
wchar_t* pszDesc;
|
|
|
|
if (Silent || dwError == 0 || dwError == ERROR_INVALID_WINDOW_HANDLE)
|
|
return dwError;
|
|
|
|
// Access denied
|
|
if (dwError == ERROR_ACCESS_DENIED && !IsAdmin ())
|
|
{
|
|
ErrorDirect ( AppendSrcPos (GetString ("ERR_ACCESS_DENIED"), srcPos).c_str (), hwndDlg);
|
|
SetLastError (dwError); // Preserve the original error code
|
|
return dwError;
|
|
}
|
|
|
|
FormatMessageW (
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
dwError,
|
|
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
|
(PWSTR) &lpMsgBuf,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (lpMsgBuf)
|
|
pszDesc = (wchar_t*) lpMsgBuf;
|
|
else
|
|
{
|
|
StringCchPrintfW (szErrorValue, ARRAYSIZE (szErrorValue), L"Error 0x%.8X", dwError);
|
|
pszDesc = szErrorValue;
|
|
}
|
|
|
|
MessageBoxW (hwndDlg, AppendSrcPos (pszDesc, srcPos).c_str (), lpszTitle, ICON_HAND);
|
|
if (lpMsgBuf) LocalFree (lpMsgBuf);
|
|
|
|
// User-friendly hardware error explanation
|
|
if (IsDiskError (dwError))
|
|
Error ("ERR_HARDWARE_ERROR", hwndDlg);
|
|
|
|
// Device not ready
|
|
if (dwError == ERROR_NOT_READY)
|
|
HandleDriveNotReadyError(hwndDlg);
|
|
|
|
SetLastError (dwError); // Preserve the original error code
|
|
|
|
return dwError;
|
|
#else
|
|
return GetLastError();
|
|
#endif
|
|
}
|
|
|
|
int Error (char *stringId, HWND hwnd)
|
|
{
|
|
#ifndef VC_COMREG
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
BOOL IsOSAtLeast (OSVersionEnum reqMinOS)
|
|
{
|
|
return IsOSVersionAtLeast (reqMinOS, 0);
|
|
}
|
|
|
|
|
|
// Returns TRUE if the operating system is at least reqMinOS and service pack at least reqMinServicePack.
|
|
// Example 1: IsOSVersionAtLeast (WIN_VISTA, 1) called under Windows 2008, returns TRUE.
|
|
// Example 2: IsOSVersionAtLeast (WIN_XP, 3) called under Windows XP SP1, returns FALSE.
|
|
// Example 3: IsOSVersionAtLeast (WIN_XP, 3) called under Windows Vista SP1, returns TRUE.
|
|
BOOL IsOSVersionAtLeast (OSVersionEnum reqMinOS, int reqMinServicePack)
|
|
{
|
|
/* When updating this function, update IsOSAtLeast() in Ntdriver.c too. */
|
|
|
|
if (CurrentOSMajor <= 0)
|
|
TC_THROW_FATAL_EXCEPTION;
|
|
|
|
int major = 0, minor = 0;
|
|
|
|
switch (reqMinOS)
|
|
{
|
|
case WIN_2000: major = 5; minor = 0; break;
|
|
case WIN_XP: major = 5; minor = 1; break;
|
|
case WIN_SERVER_2003: major = 5; minor = 2; break;
|
|
case WIN_VISTA: major = 6; minor = 0; break;
|
|
case WIN_7: major = 6; minor = 1; break;
|
|
case WIN_8: major = 6; minor = 2; break;
|
|
case WIN_8_1: major = 6; minor = 3; break;
|
|
case WIN_10: major = 10; minor = 0; break;
|
|
|
|
default:
|
|
TC_THROW_FATAL_EXCEPTION;
|
|
break;
|
|
}
|
|
|
|
return ((CurrentOSMajor << 16 | CurrentOSMinor << 8 | CurrentOSServicePack)
|
|
>= (major << 16 | minor << 8 | reqMinServicePack));
|
|
}
|
|
|
|
#ifdef SETUP_DLL
|
|
static BOOL GetWindowVersionFromFile(DWORD* pdwMajor, DWORD* pdwMinor, DWORD* pdwBuildNumber)
|
|
{
|
|
wchar_t dllPath[MAX_PATH];
|
|
BOOL bRet = FALSE;
|
|
LPBYTE versionInfo = NULL;
|
|
UINT size;
|
|
VS_FIXEDFILEINFO *vinfo;
|
|
|
|
/* Load dll explictely from System32 to avoid Dll hijacking attacks*/
|
|
if (!GetSystemDirectory(dllPath, MAX_PATH))
|
|
StringCbCopyW(dllPath, sizeof(dllPath), L"C:\\Windows\\System32");
|
|
|
|
StringCbCatW(dllPath, sizeof(dllPath), L"\\");
|
|
StringCbCatW(dllPath, sizeof(dllPath), L"Kernel32.dll");
|
|
|
|
size = GetFileVersionInfoSizeW(dllPath, NULL);
|
|
if (size)
|
|
{
|
|
versionInfo = (LPBYTE) TCalloc(size);
|
|
if (GetFileVersionInfo(dllPath, 0, size, versionInfo))
|
|
{
|
|
|
|
if (VerQueryValueW(versionInfo, L"\\", (LPVOID *)&vinfo, &size) && (size >=sizeof(VS_FIXEDFILEINFO)))
|
|
{
|
|
*pdwMajor = HIWORD(vinfo->dwProductVersionMS);
|
|
*pdwMinor = LOWORD(vinfo->dwProductVersionMS);
|
|
*pdwBuildNumber = HIWORD(vinfo->dwProductVersionLS);
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (versionInfo)
|
|
TCfree(versionInfo);
|
|
return bRet;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Use RtlGetVersion to get Windows version because GetVersionEx is affected by application manifestation.
|
|
*/
|
|
typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
|
|
|
static BOOL GetWindowsVersion(LPOSVERSIONINFOW lpVersionInformation)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
#ifdef SETUP_DLL
|
|
DWORD dwMajor, dwMinor, dwBuildNumber;
|
|
#endif
|
|
RtlGetVersionPtr RtlGetVersionFn = (RtlGetVersionPtr) GetProcAddress(GetModuleHandle (L"ntdll.dll"), "RtlGetVersion");
|
|
if (RtlGetVersionFn != NULL)
|
|
{
|
|
if (ERROR_SUCCESS == RtlGetVersionFn (lpVersionInformation))
|
|
bRet = TRUE;
|
|
}
|
|
|
|
if (!bRet)
|
|
bRet = GetVersionExW (lpVersionInformation);
|
|
|
|
#ifdef SETUP_DLL
|
|
// we get real version from Kernel32.dll version since MSI always sets current version to 6.0
|
|
// https://stackoverflow.com/questions/49335885/windows-10-not-detecting-on-installshield/49343826#49343826
|
|
if (GetWindowVersionFromFile(&dwMajor, &dwMinor, &dwBuildNumber))
|
|
{
|
|
lpVersionInformation->dwMajorVersion = dwMajor;
|
|
lpVersionInformation->dwMinorVersion = dwMinor;
|
|
lpVersionInformation->dwBuildNumber = dwBuildNumber;
|
|
}
|
|
#endif
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
void InitOSVersionInfo ()
|
|
{
|
|
OSVERSIONINFOEXW os;
|
|
os.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
|
|
|
|
if (GetWindowsVersion ((LPOSVERSIONINFOW) &os) == FALSE)
|
|
AbortProcess ("NO_OS_VER");
|
|
|
|
CurrentOSMajor = os.dwMajorVersion;
|
|
CurrentOSMinor = os.dwMinorVersion;
|
|
CurrentOSServicePack = os.wServicePackMajor;
|
|
CurrentOSBuildNumber = os.dwBuildNumber;
|
|
|
|
if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 0)
|
|
nCurrentOS = WIN_2000;
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 1)
|
|
nCurrentOS = WIN_XP;
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 2)
|
|
{
|
|
if (os.wProductType == VER_NT_SERVER || os.wProductType == VER_NT_DOMAIN_CONTROLLER)
|
|
nCurrentOS = WIN_SERVER_2003;
|
|
else
|
|
nCurrentOS = WIN_XP64;
|
|
}
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 0)
|
|
{
|
|
if (os.wProductType != VER_NT_WORKSTATION)
|
|
nCurrentOS = WIN_SERVER_2008;
|
|
else
|
|
nCurrentOS = WIN_VISTA;
|
|
}
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 1)
|
|
nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2008_R2 : WIN_7);
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 2)
|
|
nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2012 : WIN_8);
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 3)
|
|
nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2012_R2 : WIN_8_1);
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 10 && CurrentOSMinor == 0)
|
|
nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2016 : WIN_10);
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 4)
|
|
nCurrentOS = WIN_NT4;
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 0)
|
|
nCurrentOS = WIN_95;
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 10)
|
|
nCurrentOS = WIN_98;
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 90)
|
|
nCurrentOS = WIN_ME;
|
|
else if (os.dwPlatformId == VER_PLATFORM_WIN32s)
|
|
nCurrentOS = WIN_31;
|
|
else
|
|
nCurrentOS = WIN_UNKNOWN;
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4702)
|
|
|
|
void *err_malloc (size_t size)
|
|
{
|
|
void *z = (void *) TCalloc (size);
|
|
if (z)
|
|
return z;
|
|
AbortProcess ("OUTOFMEMORY");
|
|
return 0;
|
|
}
|
|
|
|
#pragma warning(pop)
|
|
|
|
|
|
char *err_strdup (char *lpszText)
|
|
{
|
|
size_t j = (strlen (lpszText) + 1) * sizeof (char);
|
|
char *z = (char *) err_malloc (j);
|
|
memmove (z, lpszText, j);
|
|
return z;
|
|
}
|
|
|
|
void AbortProcessDirect (wchar_t *abortMsg)
|
|
{
|
|
// Note that this function also causes localcleanup() to be called (see atexit())
|
|
MessageBeep (MB_ICONEXCLAMATION);
|
|
MessageBoxW (NULL, abortMsg, lpszTitle, ICON_HAND);
|
|
#ifndef VC_COMREG
|
|
FREE_DLL (hRichEditDll);
|
|
FREE_DLL (hComctl32Dll);
|
|
FREE_DLL (hSetupDll);
|
|
FREE_DLL (hShlwapiDll);
|
|
FREE_DLL (hProfApiDll);
|
|
FREE_DLL (hUsp10Dll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hUXThemeDll);
|
|
FREE_DLL (hUserenvDll);
|
|
FREE_DLL (hRsaenhDll);
|
|
FREE_DLL (himm32dll);
|
|
FREE_DLL (hMSCTFdll);
|
|
FREE_DLL (hfltlibdll);
|
|
FREE_DLL (hframedyndll);
|
|
FREE_DLL (hpsapidll);
|
|
FREE_DLL (hsecur32dll);
|
|
FREE_DLL (hnetapi32dll);
|
|
FREE_DLL (hauthzdll);
|
|
FREE_DLL (hxmllitedll);
|
|
FREE_DLL (hmprdll);
|
|
FREE_DLL (hsppdll);
|
|
FREE_DLL (vssapidll);
|
|
FREE_DLL (hvsstracedll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hcfgmgr32dll);
|
|
FREE_DLL (hdevobjdll);
|
|
FREE_DLL (hpowrprofdll);
|
|
FREE_DLL (hsspiclidll);
|
|
FREE_DLL (hcryptbasedll);
|
|
FREE_DLL (hdwmapidll);
|
|
FREE_DLL (hmsasn1dll);
|
|
FREE_DLL (hcrypt32dll);
|
|
FREE_DLL (hbcryptdll);
|
|
FREE_DLL (hbcryptprimitivesdll);
|
|
FREE_DLL (hMsls31);
|
|
FREE_DLL (hntmartadll);
|
|
FREE_DLL (hwinscarddll);
|
|
FREE_DLL (hmsvcrtdll);
|
|
FREE_DLL (hAdvapi32Dll);
|
|
#endif
|
|
exit (1);
|
|
}
|
|
|
|
void AbortProcess (char *stringId)
|
|
{
|
|
// Note that this function also causes localcleanup() to be called (see atexit())
|
|
#ifndef VC_COMREG
|
|
AbortProcessDirect (GetString (stringId));
|
|
#else
|
|
static wchar_t g_wszUnknown[1024];
|
|
StringCbPrintfW (g_wszUnknown, sizeof(g_wszUnknown), UNKNOWN_STRING_ID L"%hs" UNKNOWN_STRING_ID, stringId);
|
|
AbortProcessDirect (g_wszUnknown);
|
|
#endif
|
|
}
|
|
|
|
#ifndef VC_COMREG
|
|
void AbortProcessSilent (void)
|
|
{
|
|
FREE_DLL (hRichEditDll);
|
|
FREE_DLL (hComctl32Dll);
|
|
FREE_DLL (hSetupDll);
|
|
FREE_DLL (hShlwapiDll);
|
|
FREE_DLL (hProfApiDll);
|
|
FREE_DLL (hUsp10Dll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hUXThemeDll);
|
|
FREE_DLL (hUserenvDll);
|
|
FREE_DLL (hRsaenhDll);
|
|
FREE_DLL (himm32dll);
|
|
FREE_DLL (hMSCTFdll);
|
|
FREE_DLL (hfltlibdll);
|
|
FREE_DLL (hframedyndll);
|
|
FREE_DLL (hpsapidll);
|
|
FREE_DLL (hsecur32dll);
|
|
FREE_DLL (hnetapi32dll);
|
|
FREE_DLL (hauthzdll);
|
|
FREE_DLL (hxmllitedll);
|
|
FREE_DLL (hmprdll);
|
|
FREE_DLL (hsppdll);
|
|
FREE_DLL (vssapidll);
|
|
FREE_DLL (hvsstracedll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hcfgmgr32dll);
|
|
FREE_DLL (hdevobjdll);
|
|
FREE_DLL (hpowrprofdll);
|
|
FREE_DLL (hsspiclidll);
|
|
FREE_DLL (hcryptbasedll);
|
|
FREE_DLL (hdwmapidll);
|
|
FREE_DLL (hmsasn1dll);
|
|
FREE_DLL (hcrypt32dll);
|
|
FREE_DLL (hbcryptdll);
|
|
FREE_DLL (hbcryptprimitivesdll);
|
|
FREE_DLL (hMsls31);
|
|
FREE_DLL (hntmartadll);
|
|
FREE_DLL (hwinscarddll);
|
|
FREE_DLL (hmsvcrtdll);
|
|
FREE_DLL (hAdvapi32Dll);
|
|
|
|
// Note that this function also causes localcleanup() to be called (see atexit())
|
|
exit (1);
|
|
}
|
|
|
|
void InitGlobalLocks ()
|
|
{
|
|
InitializeCriticalSection (&csWNetCalls);
|
|
InitializeCriticalSection (&csMountableDevices);
|
|
InitializeCriticalSection (&csVolumeIdCandidates);
|
|
InitializeCriticalSection (&csSecureDesktop);
|
|
}
|
|
|
|
void FinalizeGlobalLocks ()
|
|
{
|
|
DeleteCriticalSection (&csWNetCalls);
|
|
DeleteCriticalSection (&csMountableDevices);
|
|
DeleteCriticalSection (&csVolumeIdCandidates);
|
|
DeleteCriticalSection (&csSecureDesktop);
|
|
}
|
|
|
|
void cleanup ()
|
|
{
|
|
burn (&CmdTokenPin, sizeof (CmdTokenPin));
|
|
#ifndef SETUP
|
|
KeyFileRemoveAll (&FirstKeyFile);
|
|
KeyFileRemoveAll (&defaultKeyFilesParam.FirstKeyFile);
|
|
#endif
|
|
|
|
/* Cleanup the GDI fonts */
|
|
if (hFixedFont != NULL)
|
|
DeleteObject (hFixedFont);
|
|
if (hFixedDigitFont != NULL)
|
|
DeleteObject (hFixedDigitFont);
|
|
if (hBoldFont != NULL)
|
|
DeleteObject (hBoldFont);
|
|
if (hTitleFont != NULL)
|
|
DeleteObject (hTitleFont);
|
|
if (hUserFont != NULL)
|
|
DeleteObject (hUserFont);
|
|
if (hUserUnderlineFont != NULL)
|
|
DeleteObject (hUserUnderlineFont);
|
|
if (hUserBoldFont != NULL)
|
|
DeleteObject (hUserBoldFont);
|
|
if (hUserUnderlineBoldFont != NULL)
|
|
DeleteObject (hUserUnderlineBoldFont);
|
|
|
|
/* Cleanup our dialog class */
|
|
if (hDlgClass)
|
|
UnregisterClassW (TC_DLG_CLASS, hInst);
|
|
if (hSplashClass)
|
|
UnregisterClassW (TC_SPLASH_CLASS, hInst);
|
|
|
|
/* Close the device driver handle */
|
|
if (hDriver != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Unload driver mode if possible (non-install mode)
|
|
if (IsNonInstallMode ())
|
|
{
|
|
// If a dismount was forced in the lifetime of the driver, Windows may later prevent it to be loaded again from
|
|
// the same path. Therefore, the driver will not be unloaded even though it was loaded in non-install mode.
|
|
int driverUnloadDisabled;
|
|
DWORD dwResult;
|
|
|
|
if (!DeviceIoControl (hDriver, TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED, NULL, 0, &driverUnloadDisabled, sizeof (driverUnloadDisabled), &dwResult, NULL))
|
|
driverUnloadDisabled = 0;
|
|
|
|
if (!driverUnloadDisabled)
|
|
DriverUnload ();
|
|
else
|
|
{
|
|
CloseHandle (hDriver);
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseHandle (hDriver);
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
if (ConfigBuffer != NULL)
|
|
{
|
|
free (ConfigBuffer);
|
|
ConfigBuffer = NULL;
|
|
}
|
|
|
|
CoUninitialize ();
|
|
|
|
CloseSysEncMutex ();
|
|
|
|
#ifndef SETUP
|
|
try
|
|
{
|
|
if (SecurityToken::IsInitialized())
|
|
SecurityToken::CloseLibrary();
|
|
}
|
|
catch (...) { }
|
|
|
|
EncryptionThreadPoolStop();
|
|
#endif
|
|
|
|
FinalizeGlobalLocks ();
|
|
}
|
|
|
|
|
|
void LowerCaseCopy (wchar_t *lpszDest, const wchar_t *lpszSource)
|
|
{
|
|
size_t i = wcslen (lpszSource) + 1;
|
|
|
|
lpszDest[i - 1] = 0;
|
|
while (--i > 0)
|
|
{
|
|
lpszDest[i - 1] = (wchar_t) towlower (lpszSource[i - 1]);
|
|
}
|
|
|
|
}
|
|
|
|
void UpperCaseCopy (wchar_t *lpszDest, size_t cbDest, const wchar_t *lpszSource)
|
|
{
|
|
if (lpszDest && cbDest)
|
|
{
|
|
size_t i = wcslen (lpszSource);
|
|
if (i >= cbDest)
|
|
i = cbDest - 1;
|
|
|
|
lpszDest[i] = 0;
|
|
i++;
|
|
while (--i > 0)
|
|
{
|
|
lpszDest[i - 1] = (wchar_t) towupper (lpszSource[i - 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
std::wstring ToUpperCase (const std::wstring &str)
|
|
{
|
|
wstring u;
|
|
foreach (wchar_t c, str)
|
|
{
|
|
u += (wchar_t) towupper (c);
|
|
}
|
|
|
|
return u;
|
|
}
|
|
|
|
size_t TrimWhiteSpace(wchar_t *str)
|
|
{
|
|
wchar_t *end, *ptr = str;
|
|
size_t out_size;
|
|
|
|
if(!str || *str == 0)
|
|
return 0;
|
|
|
|
// Trim leading space
|
|
while(iswspace(*ptr)) ptr++;
|
|
|
|
if(*ptr == 0) // All spaces?
|
|
{
|
|
*str = 0;
|
|
return 0;
|
|
}
|
|
|
|
// Trim trailing space
|
|
end = str + wcslen(str) - 1;
|
|
while(end > ptr && iswspace(*end)) end--;
|
|
end++;
|
|
|
|
// Set output size to trimmed string length
|
|
out_size = (end - ptr);
|
|
|
|
// Copy trimmed string and add null terminator
|
|
wmemmove(str, ptr, out_size);
|
|
str[out_size] = 0;
|
|
|
|
return out_size;
|
|
}
|
|
|
|
BOOL IsNullTerminateString (const wchar_t* str, size_t cbSize)
|
|
{
|
|
if (str && cbSize)
|
|
{
|
|
for (size_t i = 0; i < cbSize; i++)
|
|
{
|
|
if (str[i] == 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// check the validity of a file name
|
|
BOOL IsValidFileName(const wchar_t* str)
|
|
{
|
|
static wchar_t invalidChars[9] = {L'<', L'>', L':', L'"', L'/', L'\\', L'|', L'?', L'*'};
|
|
wchar_t c;
|
|
int i;
|
|
BOOL bNotDotOnly = FALSE;
|
|
while ((c = *str))
|
|
{
|
|
if (c != L'.')
|
|
bNotDotOnly = TRUE;
|
|
for (i= 0; i < ARRAYSIZE(invalidChars); i++)
|
|
if (c == invalidChars[i])
|
|
return FALSE;
|
|
str++;
|
|
}
|
|
|
|
return bNotDotOnly;
|
|
}
|
|
|
|
BOOL IsVolumeDeviceHosted (const wchar_t *lpszDiskFile)
|
|
{
|
|
return wcsstr (lpszDiskFile, L"\\Device\\") == lpszDiskFile
|
|
|| wcsstr (lpszDiskFile, L"\\DEVICE\\") == lpszDiskFile;
|
|
}
|
|
|
|
|
|
void CreateFullVolumePath (wchar_t *lpszDiskFile, size_t cbDiskFile, const wchar_t *lpszFileName, BOOL * bDevice)
|
|
{
|
|
UpperCaseCopy (lpszDiskFile, cbDiskFile, lpszFileName);
|
|
|
|
*bDevice = FALSE;
|
|
|
|
if (wmemcmp (lpszDiskFile, L"\\DEVICE", 7) == 0)
|
|
{
|
|
*bDevice = TRUE;
|
|
}
|
|
|
|
StringCbCopyW (lpszDiskFile, cbDiskFile, lpszFileName);
|
|
|
|
#if _DEBUG
|
|
OutputDebugString (L"CreateFullVolumePath: ");
|
|
OutputDebugString (lpszDiskFile);
|
|
OutputDebugString (L"\n");
|
|
#endif
|
|
|
|
}
|
|
|
|
int FakeDosNameForDevice (const wchar_t *lpszDiskFile , wchar_t *lpszDosDevice , size_t cbDosDevice, wchar_t *lpszCFDevice , size_t cbCFDevice, BOOL bNameOnly)
|
|
{
|
|
BOOL bDosLinkCreated = TRUE;
|
|
StringCbPrintfW (lpszDosDevice, cbDosDevice,L"veracrypt%lu", GetCurrentProcessId ());
|
|
|
|
if (bNameOnly == FALSE)
|
|
bDosLinkCreated = DefineDosDevice (DDD_RAW_TARGET_PATH, lpszDosDevice, lpszDiskFile);
|
|
|
|
if (bDosLinkCreated == FALSE)
|
|
return ERR_OS_ERROR;
|
|
else
|
|
StringCbPrintfW (lpszCFDevice, cbCFDevice,L"\\\\.\\%s", lpszDosDevice);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int RemoveFakeDosName (wchar_t *lpszDiskFile, wchar_t *lpszDosDevice)
|
|
{
|
|
BOOL bDosLinkRemoved = DefineDosDevice (DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE |
|
|
DDD_REMOVE_DEFINITION, lpszDosDevice, lpszDiskFile);
|
|
if (bDosLinkRemoved == FALSE)
|
|
{
|
|
return ERR_OS_ERROR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL IsDiskReadError (DWORD error)
|
|
{
|
|
return (error == ERROR_CRC
|
|
|| error == ERROR_IO_DEVICE
|
|
|| error == ERROR_BAD_CLUSTERS
|
|
|| error == ERROR_SECTOR_NOT_FOUND
|
|
|| error == ERROR_READ_FAULT
|
|
|| error == ERROR_INVALID_FUNCTION // I/O error may be reported as ERROR_INVALID_FUNCTION by buggy chipset drivers
|
|
|| error == ERROR_SEM_TIMEOUT); // I/O operation timeout may be reported as ERROR_SEM_TIMEOUT
|
|
}
|
|
|
|
|
|
BOOL IsDiskWriteError (DWORD error)
|
|
{
|
|
return (error == ERROR_IO_DEVICE
|
|
|| error == ERROR_BAD_CLUSTERS
|
|
|| error == ERROR_SECTOR_NOT_FOUND
|
|
|| error == ERROR_WRITE_FAULT
|
|
|| error == ERROR_INVALID_FUNCTION // I/O error may be reported as ERROR_INVALID_FUNCTION by buggy chipset drivers
|
|
|| error == ERROR_SEM_TIMEOUT); // I/O operation timeout may be reported as ERROR_SEM_TIMEOUT
|
|
}
|
|
|
|
|
|
BOOL IsDiskError (DWORD error)
|
|
{
|
|
return IsDiskReadError (error) || IsDiskWriteError (error);
|
|
}
|
|
|
|
BOOL translateWin32Error (wchar_t *lpszMsgBuf, int nWSizeOfBuf)
|
|
{
|
|
DWORD dwError = GetLastError ();
|
|
|
|
if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError,
|
|
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
|
lpszMsgBuf, nWSizeOfBuf, NULL))
|
|
{
|
|
SetLastError (dwError); // Preserve the original error code
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError (dwError); // Preserve the original error code
|
|
return FALSE;
|
|
}
|
|
|
|
// If the user has a non-default screen DPI, all absolute font sizes must be
|
|
// converted using this function.
|
|
int CompensateDPIFont (int val)
|
|
{
|
|
if (ScreenDPI == USER_DEFAULT_SCREEN_DPI)
|
|
return val;
|
|
else
|
|
{
|
|
double tmpVal = (double) val * DPIScaleFactorY * DlgAspectRatio * 0.999;
|
|
|
|
if (tmpVal > 0)
|
|
return (int) floor(tmpVal);
|
|
else
|
|
return (int) ceil(tmpVal);
|
|
}
|
|
}
|
|
|
|
|
|
// If the user has a non-default screen DPI, some screen coordinates and sizes must
|
|
// be converted using this function
|
|
int CompensateXDPI (int val)
|
|
{
|
|
if (ScreenDPI == USER_DEFAULT_SCREEN_DPI)
|
|
return val;
|
|
else
|
|
{
|
|
double tmpVal = (double) val * DPIScaleFactorX;
|
|
|
|
if (tmpVal > 0)
|
|
return (int) floor(tmpVal);
|
|
else
|
|
return (int) ceil(tmpVal);
|
|
}
|
|
}
|
|
|
|
|
|
// If the user has a non-default screen DPI, some screen coordinates and sizes must
|
|
// be converted using this function
|
|
int CompensateYDPI (int val)
|
|
{
|
|
if (ScreenDPI == USER_DEFAULT_SCREEN_DPI)
|
|
return val;
|
|
else
|
|
{
|
|
double tmpVal = (double) val * DPIScaleFactorY;
|
|
|
|
if (tmpVal > 0)
|
|
return (int) floor(tmpVal);
|
|
else
|
|
return (int) ceil(tmpVal);
|
|
}
|
|
}
|
|
|
|
|
|
int GetTextGfxWidth (HWND hwndDlgItem, const wchar_t *text, HFONT hFont)
|
|
{
|
|
SIZE sizes;
|
|
TEXTMETRIC textMetrics;
|
|
HDC hdc = GetDC (hwndDlgItem);
|
|
|
|
SelectObject(hdc, (HGDIOBJ) hFont);
|
|
|
|
GetTextExtentPoint32W (hdc, text, (int) wcslen (text), &sizes);
|
|
|
|
GetTextMetrics(hdc, &textMetrics); // Necessary for non-TrueType raster fonts (tmOverhang)
|
|
|
|
ReleaseDC (hwndDlgItem, hdc);
|
|
|
|
return ((int) sizes.cx - (int) textMetrics.tmOverhang);
|
|
}
|
|
|
|
|
|
int GetTextGfxHeight (HWND hwndDlgItem, const wchar_t *text, HFONT hFont)
|
|
{
|
|
SIZE sizes;
|
|
HDC hdc = GetDC (hwndDlgItem);
|
|
|
|
SelectObject(hdc, (HGDIOBJ) hFont);
|
|
|
|
GetTextExtentPoint32W (hdc, text, (int) wcslen (text), &sizes);
|
|
|
|
ReleaseDC (hwndDlgItem, hdc);
|
|
|
|
return ((int) sizes.cy);
|
|
}
|
|
|
|
|
|
std::wstring FitPathInGfxWidth (HWND hwnd, HFONT hFont, LONG width, const std::wstring &path)
|
|
{
|
|
wstring newPath;
|
|
|
|
RECT rect;
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = width;
|
|
rect.bottom = LONG_MAX;
|
|
|
|
HDC hdc = GetDC (hwnd);
|
|
SelectObject (hdc, (HGDIOBJ) hFont);
|
|
|
|
wchar_t pathBuf[TC_MAX_PATH];
|
|
StringCchCopyW (pathBuf, ARRAYSIZE (pathBuf), path.c_str());
|
|
|
|
if (DrawText (hdc, pathBuf, (int) path.size(), &rect, DT_CALCRECT | DT_MODIFYSTRING | DT_PATH_ELLIPSIS | DT_SINGLELINE) != 0)
|
|
newPath = pathBuf;
|
|
|
|
ReleaseDC (hwnd, hdc);
|
|
return newPath;
|
|
}
|
|
|
|
|
|
static LRESULT CALLBACK HyperlinkProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WNDPROC wp = (WNDPROC) GetWindowLongPtrW (hwnd, GWLP_USERDATA);
|
|
|
|
switch (message)
|
|
{
|
|
case WM_SETCURSOR:
|
|
if (!bHyperLinkBeingTracked)
|
|
{
|
|
TRACKMOUSEEVENT trackMouseEvent;
|
|
|
|
trackMouseEvent.cbSize = sizeof(trackMouseEvent);
|
|
trackMouseEvent.dwFlags = TME_LEAVE;
|
|
trackMouseEvent.hwndTrack = hwnd;
|
|
|
|
bHyperLinkBeingTracked = TrackMouseEvent(&trackMouseEvent);
|
|
|
|
HandCursor();
|
|
}
|
|
return 0;
|
|
|
|
case WM_MOUSELEAVE:
|
|
bHyperLinkBeingTracked = FALSE;
|
|
NormalCursor();
|
|
return 0;
|
|
}
|
|
|
|
return CallWindowProcW (wp, hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
|
|
BOOL ToHyperlink (HWND hwndDlg, UINT ctrlId)
|
|
{
|
|
return ToCustHyperlink (hwndDlg, ctrlId, hUserUnderlineFont);
|
|
}
|
|
|
|
|
|
BOOL ToCustHyperlink (HWND hwndDlg, UINT ctrlId, HFONT hFont)
|
|
{
|
|
HWND hwndCtrl = GetDlgItem (hwndDlg, ctrlId);
|
|
|
|
SendMessageW (hwndCtrl, WM_SETFONT, (WPARAM) hFont, 0);
|
|
|
|
SetWindowLongPtrW (hwndCtrl, GWLP_USERDATA, (LONG_PTR) GetWindowLongPtrW (hwndCtrl, GWLP_WNDPROC));
|
|
SetWindowLongPtrW (hwndCtrl, GWLP_WNDPROC, (LONG_PTR) HyperlinkProc);
|
|
|
|
// Resize the field according to its actual size in pixels and move it if centered or right-aligned.
|
|
// This should be done again if the link text changes.
|
|
AccommodateTextField (hwndDlg, ctrlId, TRUE, hFont);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Resizes a text field according to its actual width and height in pixels (font size is taken into account) and moves
|
|
// it accordingly if the field is centered or right-aligned. Should be used on all hyperlinks upon dialog init
|
|
// after localization (bFirstUpdate should be TRUE) and later whenever a hyperlink text changes (bFirstUpdate
|
|
// must be FALSE).
|
|
void AccommodateTextField (HWND hwndDlg, UINT ctrlId, BOOL bFirstUpdate, HFONT hFont)
|
|
{
|
|
RECT rec, wrec, trec;
|
|
HWND hwndCtrl = GetDlgItem (hwndDlg, ctrlId);
|
|
int width, origWidth, height, origHeight;
|
|
int horizSubOffset, vertSubOffset, vertOffset, alignPosDiff = 0;
|
|
wchar_t text [MAX_URL_LENGTH];
|
|
WINDOWINFO windowInfo;
|
|
BOOL bBorderlessWindow = !(GetWindowLongPtrW (hwndDlg, GWL_STYLE) & (WS_BORDER | WS_DLGFRAME));
|
|
|
|
// Resize the field according to its length and font size and move if centered or right-aligned
|
|
|
|
GetWindowTextW (hwndCtrl, text, sizeof (text) / sizeof (wchar_t));
|
|
|
|
width = GetTextGfxWidth (hwndCtrl, text, hFont);
|
|
height = GetTextGfxHeight (hwndCtrl, text, hFont);
|
|
|
|
GetClientRect (hwndCtrl, &rec);
|
|
origWidth = rec.right;
|
|
origHeight = rec.bottom;
|
|
|
|
if (width >= 0
|
|
&& (!bFirstUpdate || origWidth > width)) // The original width of the field is the maximum allowed size
|
|
{
|
|
horizSubOffset = origWidth - width;
|
|
vertSubOffset = origHeight - height;
|
|
|
|
// Window coords
|
|
GetWindowRect(hwndDlg, &wrec);
|
|
GetClientRect(hwndDlg, &trec);
|
|
|
|
// Vertical "title bar" offset
|
|
vertOffset = wrec.bottom - wrec.top - trec.bottom - (bBorderlessWindow ? 0 : GetSystemMetrics(SM_CYFIXEDFRAME));
|
|
|
|
// Text field coords
|
|
GetWindowRect(hwndCtrl, &rec);
|
|
|
|
// Alignment offset
|
|
windowInfo.cbSize = sizeof(windowInfo);
|
|
GetWindowInfo (hwndCtrl, &windowInfo);
|
|
|
|
if (windowInfo.dwStyle & SS_CENTER)
|
|
alignPosDiff = horizSubOffset / 2;
|
|
else if (windowInfo.dwStyle & SS_RIGHT)
|
|
alignPosDiff = horizSubOffset;
|
|
|
|
// Resize/move
|
|
if (alignPosDiff > 0)
|
|
{
|
|
// Resize and move the text field
|
|
MoveWindow (hwndCtrl,
|
|
rec.left - wrec.left - (bBorderlessWindow ? 0 : GetSystemMetrics(SM_CXFIXEDFRAME)) + alignPosDiff,
|
|
rec.top - wrec.top - vertOffset,
|
|
origWidth - horizSubOffset,
|
|
origHeight - vertSubOffset,
|
|
TRUE);
|
|
}
|
|
else
|
|
{
|
|
// Resize the text field
|
|
SetWindowPos (hwndCtrl, 0, 0, 0,
|
|
origWidth - horizSubOffset,
|
|
origHeight - vertSubOffset,
|
|
SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
|
|
SetWindowPos (hwndCtrl, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
InvalidateRect (hwndCtrl, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
// Note that the user can still close the window by right-clicking its taskbar icon and selecting 'Close window', or by pressing Alt-F4, or using the Task Manager.
|
|
void DisableCloseButton (HWND hwndDlg)
|
|
{
|
|
EnableMenuItem (GetSystemMenu (hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
|
|
void EnableCloseButton (HWND hwndDlg)
|
|
{
|
|
EnableMenuItem (GetSystemMenu (hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
|
|
}
|
|
|
|
void HandlePasswordEditWmChar (HWND hwnd, WPARAM wParam)
|
|
{
|
|
DWORD dwStartPos = 0, dwEndPos = 0;
|
|
short vk = VkKeyScanW ((WCHAR) wParam);
|
|
BYTE vkCode = LOBYTE (vk);
|
|
BYTE vkState = HIBYTE (vk);
|
|
bool ctrlPressed = (vkState & 2) && !(vkState & 4);
|
|
int dwMaxPassLen = (int) SendMessage (hwnd, EM_GETLIMITTEXT, 0, 0);
|
|
|
|
// check if there is a selected text
|
|
SendMessage (hwnd, EM_GETSEL, (WPARAM) &dwStartPos, (LPARAM) &dwEndPos);
|
|
|
|
if ((dwStartPos == dwEndPos)
|
|
&& (vkCode != VK_DELETE) && (vkCode != VK_BACK)
|
|
&& !ctrlPressed
|
|
&& (GetWindowTextLength (hwnd) == dwMaxPassLen))
|
|
{
|
|
EDITBALLOONTIP ebt;
|
|
DWORD dwTextSize = (DWORD) wcslen (GetString ("PASSWORD_MAXLENGTH_REACHED")) + 16;
|
|
WCHAR* szErrorText = (WCHAR*) malloc (dwTextSize * sizeof (WCHAR));
|
|
|
|
StringCchPrintf (szErrorText, dwTextSize, GetString ("PASSWORD_MAXLENGTH_REACHED"), dwMaxPassLen);
|
|
|
|
ebt.cbStruct = sizeof( EDITBALLOONTIP );
|
|
ebt.pszText = szErrorText;
|
|
ebt.pszTitle = lpszTitle;
|
|
ebt.ttiIcon = TTI_ERROR_LARGE; // tooltip warning icon
|
|
|
|
SendMessage(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt);
|
|
|
|
MessageBeep (0xFFFFFFFF);
|
|
|
|
free (szErrorText);
|
|
}
|
|
else
|
|
SendMessage(hwnd, EM_HIDEBALLOONTIP, 0, 0);
|
|
}
|
|
|
|
// Protects an input field from having its content updated by a Paste action (call ToBootPwdField() to use this).
|
|
static LRESULT CALLBACK BootPwdFieldProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WNDPROC wp = (WNDPROC) GetWindowLongPtrW (hwnd, GWLP_USERDATA);
|
|
|
|
switch (message)
|
|
{
|
|
case WM_PASTE:
|
|
return 1;
|
|
case WM_CHAR:
|
|
HandlePasswordEditWmChar (hwnd, wParam);
|
|
break;
|
|
}
|
|
|
|
return CallWindowProcW (wp, hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
|
|
// Protects an input field from having its content updated by a Paste action. Used for pre-boot password
|
|
// input fields (only the US keyboard layout is supported in pre-boot environment so we must prevent the
|
|
// user from pasting a password typed using a non-US keyboard layout).
|
|
void ToBootPwdField (HWND hwndDlg, UINT ctrlId)
|
|
{
|
|
HWND hwndCtrl = GetDlgItem (hwndDlg, ctrlId);
|
|
WNDPROC originalwp = (WNDPROC) GetWindowLongPtrW (hwndCtrl, GWLP_USERDATA);
|
|
|
|
SendMessage (hwndCtrl, EM_LIMITTEXT, MAX_LEGACY_PASSWORD, 0);
|
|
|
|
// if ToNormalPwdField has been called before, GWLP_USERDATA already contains original WNDPROC
|
|
if (!originalwp)
|
|
{
|
|
SetWindowLongPtrW (hwndCtrl, GWLP_USERDATA, (LONG_PTR) GetWindowLongPtrW (hwndCtrl, GWLP_WNDPROC));
|
|
}
|
|
SetWindowLongPtrW (hwndCtrl, GWLP_WNDPROC, (LONG_PTR) BootPwdFieldProc);
|
|
}
|
|
|
|
// Ensures that a warning is displayed when user is pasting a password longer than the maximum
|
|
// length which is set to 64 characters
|
|
static LRESULT CALLBACK NormalPwdFieldProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WNDPROC wp = (WNDPROC) GetWindowLongPtrW (hwnd, GWLP_USERDATA);
|
|
|
|
switch (message)
|
|
{
|
|
case WM_PASTE:
|
|
{
|
|
bool bBlock = false;
|
|
if (OpenClipboard (NULL))
|
|
{
|
|
HANDLE h = GetClipboardData (CF_UNICODETEXT);
|
|
if (h)
|
|
{
|
|
wchar_t *pchData = (wchar_t*)GlobalLock(h);
|
|
int txtlen = 0;
|
|
int dwMaxPassLen = bUseLegacyMaxPasswordLength? MAX_LEGACY_PASSWORD : MAX_PASSWORD;
|
|
while (*pchData)
|
|
{
|
|
if (*pchData == '\r' || *pchData == '\n')
|
|
break;
|
|
else
|
|
{
|
|
txtlen++;
|
|
pchData++;
|
|
}
|
|
}
|
|
|
|
if (txtlen)
|
|
{
|
|
int curLen = GetWindowTextLength (hwnd);
|
|
if (curLen == dwMaxPassLen)
|
|
{
|
|
EDITBALLOONTIP ebt;
|
|
DWORD dwTextSize = (DWORD) wcslen (GetString ("PASSWORD_MAXLENGTH_REACHED")) + 16;
|
|
WCHAR* szErrorText = (WCHAR*) malloc (dwTextSize * sizeof (WCHAR));
|
|
|
|
StringCchPrintf (szErrorText, dwTextSize, GetString ("PASSWORD_MAXLENGTH_REACHED"), dwMaxPassLen);
|
|
|
|
ebt.cbStruct = sizeof( EDITBALLOONTIP );
|
|
ebt.pszText = szErrorText;
|
|
ebt.pszTitle = lpszTitle;
|
|
ebt.ttiIcon = TTI_ERROR_LARGE; // tooltip warning icon
|
|
|
|
SendMessage(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt);
|
|
|
|
MessageBeep (0xFFFFFFFF);
|
|
|
|
free (szErrorText);
|
|
|
|
bBlock = true;
|
|
}
|
|
else if ((txtlen + curLen) > dwMaxPassLen)
|
|
{
|
|
EDITBALLOONTIP ebt;
|
|
DWORD dwTextSize = (DWORD) wcslen (GetString ("PASSWORD_PASTED_TRUNCATED")) + 16;
|
|
WCHAR* szErrorText = (WCHAR*) malloc (dwTextSize * sizeof (WCHAR));
|
|
|
|
StringCchPrintf (szErrorText, dwTextSize, GetString ("PASSWORD_PASTED_TRUNCATED"), dwMaxPassLen);
|
|
|
|
ebt.cbStruct = sizeof( EDITBALLOONTIP );
|
|
ebt.pszText = szErrorText;
|
|
ebt.pszTitle = lpszTitle;
|
|
ebt.ttiIcon = TTI_WARNING_LARGE; // tooltip warning icon
|
|
|
|
SendMessage(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt);
|
|
|
|
MessageBeep (0xFFFFFFFF);
|
|
|
|
free (szErrorText);
|
|
}
|
|
else
|
|
SendMessage(hwnd, EM_HIDEBALLOONTIP, 0, 0);
|
|
}
|
|
GlobalUnlock(h);
|
|
}
|
|
CloseClipboard ();
|
|
}
|
|
|
|
if (bBlock)
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case WM_CHAR:
|
|
HandlePasswordEditWmChar (hwnd, wParam);
|
|
break;
|
|
}
|
|
|
|
return CallWindowProcW (wp, hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
void ToNormalPwdField (HWND hwndDlg, UINT ctrlId)
|
|
{
|
|
HWND hwndCtrl = GetDlgItem (hwndDlg, ctrlId);
|
|
WNDPROC originalwp = (WNDPROC) GetWindowLongPtrW (hwndCtrl, GWLP_USERDATA);
|
|
DWORD dwMaxPassLen = bUseLegacyMaxPasswordLength? MAX_LEGACY_PASSWORD : MAX_PASSWORD;
|
|
|
|
SendMessage (hwndCtrl, EM_LIMITTEXT, dwMaxPassLen, 0);
|
|
// only change WNDPROC if not changed already
|
|
if (!originalwp)
|
|
{
|
|
SetWindowLongPtrW (hwndCtrl, GWLP_USERDATA, (LONG_PTR) GetWindowLongPtrW (hwndCtrl, GWLP_WNDPROC));
|
|
SetWindowLongPtrW (hwndCtrl, GWLP_WNDPROC, (LONG_PTR) NormalPwdFieldProc);
|
|
}
|
|
}
|
|
|
|
|
|
// This function currently serves the following purposes:
|
|
// - Determines scaling factors for current screen DPI and GUI aspect ratio.
|
|
// - Determines how Windows skews the GUI aspect ratio (which happens when the user has a non-default DPI).
|
|
// The determined values must be used when performing some GUI operations and calculations.
|
|
BOOL CALLBACK AuxiliaryDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HDC hDC = GetDC (hwndDlg);
|
|
|
|
if (hDC)
|
|
{
|
|
ScreenDPI = GetDeviceCaps (hDC, LOGPIXELSY);
|
|
ReleaseDC (hwndDlg, hDC);
|
|
}
|
|
|
|
DPIScaleFactorX = 1;
|
|
DPIScaleFactorY = 1;
|
|
DlgAspectRatio = 1;
|
|
|
|
if (ScreenDPI != USER_DEFAULT_SCREEN_DPI)
|
|
{
|
|
// Windows skews the GUI aspect ratio if the user has a non-default DPI. Hence, working with
|
|
// actual screen DPI is redundant and leads to incorrect results. What really matters here is
|
|
// how Windows actually renders our GUI. This is determined by comparing the expected and current
|
|
// sizes of a hidden calibration text field.
|
|
|
|
RECT trec;
|
|
|
|
trec.right = 0;
|
|
trec.bottom = 0;
|
|
|
|
GetClientRect (GetDlgItem (hwndDlg, IDC_ASPECT_RATIO_CALIBRATION_BOX), &trec);
|
|
|
|
if (trec.right != 0 && trec.bottom != 0)
|
|
{
|
|
// The size of the 282x282 IDC_ASPECT_RATIO_CALIBRATION_BOX rendered at the default DPI (96) is 423x458
|
|
DPIScaleFactorX = (double) trec.right / 423;
|
|
DPIScaleFactorY = (double) trec.bottom / 458;
|
|
DlgAspectRatio = DPIScaleFactorX / DPIScaleFactorY;
|
|
}
|
|
}
|
|
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Except in response to the WM_INITDIALOG message, the dialog box procedure
|
|
should return nonzero if it processes the message, and zero if it does
|
|
not. - see DialogProc */
|
|
BOOL CALLBACK AboutDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
static HBITMAP hbmTextualLogoBitmapRescaled = NULL;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
wchar_t szTmp[100];
|
|
RECT rec;
|
|
|
|
LocalizeDialog (hwndDlg, "IDD_ABOUT_DLG");
|
|
|
|
// Hyperlink
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_HOMEPAGE), L"www.idrix.fr");
|
|
ToHyperlink (hwndDlg, IDC_HOMEPAGE);
|
|
|
|
// Logo area background (must not keep aspect ratio; must retain Windows-imposed distortion)
|
|
GetClientRect (GetDlgItem (hwndDlg, IDC_ABOUT_LOGO_AREA), &rec);
|
|
SetWindowPos (GetDlgItem (hwndDlg, IDC_ABOUT_BKG), HWND_TOP, 0, 0, rec.right, rec.bottom, SWP_NOMOVE);
|
|
|
|
// Resize the logo bitmap if the user has a non-default DPI
|
|
if (ScreenDPI != USER_DEFAULT_SCREEN_DPI)
|
|
{
|
|
// Logo (must recreate and keep the original aspect ratio as Windows distorts it)
|
|
hbmTextualLogoBitmapRescaled = RenderBitmap (MAKEINTRESOURCE (IDB_TEXTUAL_LOGO_288DPI),
|
|
GetDlgItem (hwndDlg, IDC_TEXTUAL_LOGO_IMG),
|
|
0, 0, 0, 0, FALSE, TRUE);
|
|
|
|
SetWindowPos (GetDlgItem (hwndDlg, IDC_ABOUT_BKG), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
|
|
// Version
|
|
SendMessage (GetDlgItem (hwndDlg, IDT_ABOUT_VERSION), WM_SETFONT, (WPARAM) hUserBoldFont, 0);
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), L"VeraCrypt %s", _T(VERSION_STRING) _T(VERSION_STRING_SUFFIX));
|
|
#ifdef _WIN64
|
|
StringCbCatW (szTmp, sizeof(szTmp), L" (64-bit)");
|
|
#else
|
|
StringCbCatW (szTmp, sizeof(szTmp), L" (32-bit)");
|
|
#endif
|
|
#if (defined(_DEBUG) || defined(DEBUG))
|
|
StringCbCatW (szTmp, sizeof(szTmp), L" (debug)");
|
|
#endif
|
|
SetDlgItemText (hwndDlg, IDT_ABOUT_VERSION, szTmp);
|
|
SetDlgItemText (hwndDlg, IDT_ABOUT_RELEASE, TC_STR_RELEASED_BY);
|
|
|
|
// Credits
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_ABOUT_CREDITS), WM_SETFONT, (WPARAM) hUserFont, (LPARAM) 0);
|
|
SendMessage (hwndDlg, WM_APP, 0, 0);
|
|
return 1;
|
|
}
|
|
|
|
case WM_APP:
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_ABOUT_CREDITS),
|
|
L"Based on TrueCrypt 7.1a, freely available at http://www.truecrypt.org/ .\r\n\r\n"
|
|
|
|
L"Portions of this software:\r\n"
|
|
L"Copyright \xA9 2013-2023 IDRIX. All rights reserved.\r\n"
|
|
L"Copyright \xA9 2003-2012 TrueCrypt Developers Association. All Rights Reserved.\r\n"
|
|
L"Copyright \xA9 1998-2000 Paul Le Roux. All Rights Reserved.\r\n"
|
|
L"Copyright \xA9 1998-2008 Brian Gladman. All Rights Reserved.\r\n"
|
|
L"Copyright \xA9 1995-2017 Jean-loup Gailly and Mark Adler.\r\n"
|
|
L"Copyright \xA9 2016 Disk Cryptography Services for EFI (DCS), Alex Kolotnikov.\r\n"
|
|
L"Copyright \xA9 1999-2020 Dieter Baron and Thomas Klausner.\r\n"
|
|
L"Copyright \xA9 2013, Alexey Degtyarev. All rights reserved.\r\n"
|
|
L"Copyright \xA9 1999-2016 Jack Lloyd. All rights reserved.\r\n"
|
|
L"Copyright \xA9 2013-2019 Stephan Mueller <smueller@chronox.de>\r\n"
|
|
L"Copyright \xA9 1999-2021 Igor Pavlov\r\n\r\n"
|
|
|
|
L"This software as a whole:\r\n"
|
|
L"Copyright \xA9 2013-2023 IDRIX. All rights reserved.\r\n\r\n"
|
|
|
|
L"An IDRIX Release");
|
|
|
|
return 1;
|
|
|
|
case WM_COMMAND:
|
|
if (lw == IDOK || lw == IDCANCEL)
|
|
{
|
|
PostMessage (hwndDlg, WM_CLOSE, 0, 0);
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDC_HOMEPAGE)
|
|
{
|
|
Applink ("main");
|
|
return 1;
|
|
}
|
|
|
|
// Disallow modification of credits
|
|
if (HIWORD (wParam) == EN_UPDATE)
|
|
{
|
|
SendMessage (hwndDlg, WM_APP, 0, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case WM_CLOSE:
|
|
/* Delete buffered bitmaps (if any) */
|
|
if (hbmTextualLogoBitmapRescaled != NULL)
|
|
{
|
|
DeleteObject ((HGDIOBJ) hbmTextualLogoBitmapRescaled);
|
|
hbmTextualLogoBitmapRescaled = NULL;
|
|
}
|
|
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static HWND StaticModelessWaitDlgHandle = NULL;
|
|
|
|
// Call DisplayStaticModelessWaitDlg() to open this dialog and CloseStaticModelessWaitDlg() to close it.
|
|
static BOOL CALLBACK StaticModelessWaitDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
|
|
if (lw == IDOK || lw == IDCANCEL)
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
|
|
case WM_CLOSE:
|
|
StaticModelessWaitDlgHandle = NULL;
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Opens a dialog window saying "Please wait..." which is not modal and does not need any GUI refresh after initialization.
|
|
void DisplayStaticModelessWaitDlg (HWND parent)
|
|
{
|
|
if (StaticModelessWaitDlgHandle != NULL)
|
|
return; // Already shown
|
|
|
|
StaticModelessWaitDlgHandle = CreateDialogParamW (hInst, MAKEINTRESOURCEW (IDD_STATIC_MODELESS_WAIT_DLG), parent, (DLGPROC) StaticModelessWaitDlgProc, (LPARAM) 0);
|
|
|
|
ShowWindow (StaticModelessWaitDlgHandle, SW_SHOWNORMAL);
|
|
|
|
// Allow synchronous use with the GUI being instantly and fully rendered
|
|
ProcessPaintMessages (StaticModelessWaitDlgHandle, 500);
|
|
}
|
|
|
|
|
|
void CloseStaticModelessWaitDlg (void)
|
|
{
|
|
if (StaticModelessWaitDlgHandle == NULL)
|
|
return; // Not shown
|
|
|
|
DestroyWindow (StaticModelessWaitDlgHandle);
|
|
}
|
|
|
|
|
|
BOOL IsButtonChecked (HWND hButton)
|
|
{
|
|
if (SendMessage (hButton, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void CheckButton (HWND hButton)
|
|
{
|
|
SendMessage (hButton, BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
|
|
|
|
void LeftPadString (wchar_t *szTmp, int len, int targetLen, wchar_t filler)
|
|
{
|
|
int i;
|
|
|
|
if (targetLen <= len)
|
|
return;
|
|
|
|
for (i = targetLen-1; i >= (targetLen-len); i--)
|
|
szTmp [i] = szTmp [i-(targetLen-len)];
|
|
|
|
wmemset (szTmp, filler, targetLen-len);
|
|
szTmp [targetLen] = 0;
|
|
}
|
|
|
|
/* InitDialog - initialize the applications main dialog, this function should
|
|
be called only once in the dialogs WM_INITDIALOG message handler */
|
|
void InitDialog (HWND hwndDlg)
|
|
{
|
|
NONCLIENTMETRICSW metric;
|
|
static BOOL aboutMenuAppended = FALSE;
|
|
|
|
int nHeight;
|
|
LOGFONTW lf;
|
|
HMENU hMenu;
|
|
Font *font;
|
|
|
|
/* Fonts */
|
|
|
|
memset (&lf, 0, sizeof(lf));
|
|
|
|
// Normal
|
|
font = GetFont ("font_normal");
|
|
|
|
metric.cbSize = sizeof (metric);
|
|
SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(metric), &metric, 0);
|
|
|
|
WindowTitleBarFont = CreateFontIndirectW (&metric.lfCaptionFont);
|
|
|
|
metric.lfMessageFont.lfHeight = CompensateDPIFont (!font ? -11 : -font->Size);
|
|
metric.lfMessageFont.lfWidth = 0;
|
|
|
|
if (font && wcscmp (font->FaceName, L"default") != 0)
|
|
{
|
|
StringCbCopyW ((WCHAR *)metric.lfMessageFont.lfFaceName, sizeof (metric.lfMessageFont.lfFaceName), font->FaceName);
|
|
}
|
|
else if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
// Vista's new default font (size and spacing) breaks compatibility with Windows 2k/XP applications.
|
|
// Force use of Tahoma (as Microsoft does in many dialogs) until a native Vista look is implemented.
|
|
StringCbCopyW ((WCHAR *)metric.lfMessageFont.lfFaceName, sizeof (metric.lfMessageFont.lfFaceName), L"Tahoma");
|
|
}
|
|
|
|
hUserFont = CreateFontIndirectW (&metric.lfMessageFont);
|
|
|
|
metric.lfMessageFont.lfUnderline = TRUE;
|
|
hUserUnderlineFont = CreateFontIndirectW (&metric.lfMessageFont);
|
|
|
|
metric.lfMessageFont.lfUnderline = FALSE;
|
|
metric.lfMessageFont.lfWeight = FW_BOLD;
|
|
hUserBoldFont = CreateFontIndirectW (&metric.lfMessageFont);
|
|
|
|
metric.lfMessageFont.lfUnderline = TRUE;
|
|
metric.lfMessageFont.lfWeight = FW_BOLD;
|
|
hUserUnderlineBoldFont = CreateFontIndirectW (&metric.lfMessageFont);
|
|
|
|
// Fixed-size (hexadecimal digits)
|
|
nHeight = CompensateDPIFont (-12);
|
|
lf.lfHeight = nHeight;
|
|
lf.lfWidth = 0;
|
|
lf.lfEscapement = 0;
|
|
lf.lfOrientation = 0;
|
|
lf.lfWeight = FW_NORMAL;
|
|
lf.lfItalic = FALSE;
|
|
lf.lfUnderline = FALSE;
|
|
lf.lfStrikeOut = FALSE;
|
|
lf.lfCharSet = DEFAULT_CHARSET;
|
|
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
lf.lfQuality = PROOF_QUALITY;
|
|
lf.lfPitchAndFamily = FF_DONTCARE;
|
|
StringCbCopyW (lf.lfFaceName, sizeof(lf.lfFaceName), L"Courier New");
|
|
hFixedDigitFont = CreateFontIndirectW (&lf);
|
|
if (hFixedDigitFont == NULL)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
AbortProcess ("NOFONT");
|
|
}
|
|
|
|
// Bold
|
|
font = GetFont ("font_bold");
|
|
|
|
nHeight = CompensateDPIFont (!font ? -13 : -font->Size);
|
|
lf.lfHeight = nHeight;
|
|
lf.lfWeight = FW_BLACK;
|
|
StringCbCopyW (lf.lfFaceName, sizeof(lf.lfFaceName), !font ? L"Arial" : font->FaceName);
|
|
hBoldFont = CreateFontIndirectW (&lf);
|
|
if (hBoldFont == NULL)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
AbortProcess ("NOFONT");
|
|
}
|
|
|
|
// Title
|
|
font = GetFont ("font_title");
|
|
|
|
nHeight = CompensateDPIFont (!font ? -21 : -font->Size);
|
|
lf.lfHeight = nHeight;
|
|
lf.lfWeight = FW_REGULAR;
|
|
StringCbCopyW (lf.lfFaceName, sizeof(lf.lfFaceName),!font ? L"Times New Roman" : font->FaceName);
|
|
hTitleFont = CreateFontIndirectW (&lf);
|
|
if (hTitleFont == NULL)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
AbortProcess ("NOFONT");
|
|
}
|
|
|
|
// Fixed-size
|
|
font = GetFont ("font_fixed");
|
|
|
|
nHeight = CompensateDPIFont (!font ? -12 : -font->Size);
|
|
lf.lfHeight = nHeight;
|
|
lf.lfWidth = 0;
|
|
lf.lfEscapement = 0;
|
|
lf.lfOrientation = 0;
|
|
lf.lfWeight = FW_NORMAL;
|
|
lf.lfItalic = FALSE;
|
|
lf.lfUnderline = FALSE;
|
|
lf.lfStrikeOut = FALSE;
|
|
lf.lfCharSet = DEFAULT_CHARSET;
|
|
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
lf.lfQuality = PROOF_QUALITY;
|
|
lf.lfPitchAndFamily = FF_DONTCARE;
|
|
StringCbCopyW (lf.lfFaceName, sizeof(lf.lfFaceName),!font ? L"Lucida Console" : font->FaceName);
|
|
hFixedFont = CreateFontIndirectW (&lf);
|
|
if (hFixedFont == NULL)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
AbortProcess ("NOFONT");
|
|
}
|
|
|
|
if (!aboutMenuAppended)
|
|
{
|
|
hMenu = GetSystemMenu (hwndDlg, FALSE);
|
|
AppendMenu (hMenu, MF_SEPARATOR, 0, L"");
|
|
AppendMenuW (hMenu, MF_ENABLED | MF_STRING, IDC_ABOUT, GetString ("ABOUTBOX"));
|
|
|
|
aboutMenuAppended = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// The parameter maxMessagesToProcess prevents endless processing of paint messages
|
|
void ProcessPaintMessages (HWND hwnd, int maxMessagesToProcess)
|
|
{
|
|
MSG paintMsg;
|
|
int msgCounter = maxMessagesToProcess;
|
|
|
|
while (PeekMessageW (&paintMsg, hwnd, 0, 0, PM_REMOVE | PM_QS_PAINT) != 0 && msgCounter-- > 0)
|
|
{
|
|
DispatchMessageW (&paintMsg);
|
|
}
|
|
}
|
|
|
|
|
|
HDC CreateMemBitmap (HINSTANCE hInstance, HWND hwnd, wchar_t *resource)
|
|
{
|
|
HBITMAP picture = LoadBitmap (hInstance, resource);
|
|
HDC viewDC = GetDC (hwnd), dcMem;
|
|
|
|
dcMem = CreateCompatibleDC (viewDC);
|
|
|
|
SetMapMode (dcMem, MM_TEXT);
|
|
|
|
SelectObject (dcMem, picture);
|
|
|
|
DeleteObject (picture);
|
|
|
|
ReleaseDC (hwnd, viewDC);
|
|
|
|
return dcMem;
|
|
}
|
|
|
|
|
|
/* Renders the specified bitmap at the specified location and stretches it to fit (anti-aliasing is applied).
|
|
If bDirectRender is FALSE and both nWidth and nHeight are zero, the width and height of hwndDest are
|
|
retrieved and adjusted according to screen DPI (the width and height of the resultant image are adjusted the
|
|
same way); furthermore, if bKeepAspectRatio is TRUE, the smaller DPI factor of the two (i.e. horiz. or vert.)
|
|
is used both for horiz. and vert. scaling (note that the overall GUI aspect ratio changes irregularly in
|
|
both directions depending on the DPI). If bDirectRender is TRUE, bKeepAspectRatio is ignored.
|
|
This function returns a handle to the scaled bitmap. When the bitmap is no longer needed, it should be
|
|
deleted by calling DeleteObject() with the handle passed as the parameter.
|
|
Known Windows issues:
|
|
- For some reason, anti-aliasing is not applied if the source bitmap contains less than 16K pixels.
|
|
- Windows 2000 may produce slightly inaccurate colors even when source, buffer, and target are 24-bit true color. */
|
|
HBITMAP RenderBitmap (wchar_t *resource, HWND hwndDest, int x, int y, int nWidth, int nHeight, BOOL bDirectRender, BOOL bKeepAspectRatio)
|
|
{
|
|
LRESULT lResult = 0;
|
|
|
|
HDC hdcSrc = CreateMemBitmap (hInst, hwndDest, resource);
|
|
if (!hdcSrc)
|
|
return NULL;
|
|
|
|
HGDIOBJ picture = GetCurrentObject (hdcSrc, OBJ_BITMAP);
|
|
|
|
HBITMAP hbmpRescaled = NULL;
|
|
BITMAP bitmap;
|
|
|
|
HDC hdcRescaled;
|
|
|
|
if (!bDirectRender && nWidth == 0 && nHeight == 0)
|
|
{
|
|
RECT rec;
|
|
|
|
GetClientRect (hwndDest, &rec);
|
|
|
|
if (bKeepAspectRatio)
|
|
{
|
|
if (DlgAspectRatio > 1)
|
|
{
|
|
// Do not fix this, it's correct. We use the Y scale factor intentionally for both
|
|
// directions to maintain aspect ratio (see above for more info).
|
|
nWidth = CompensateYDPI (rec.right);
|
|
nHeight = CompensateYDPI (rec.bottom);
|
|
}
|
|
else
|
|
{
|
|
// Do not fix this, it's correct. We use the X scale factor intentionally for both
|
|
// directions to maintain aspect ratio (see above for more info).
|
|
nWidth = CompensateXDPI (rec.right);
|
|
nHeight = CompensateXDPI (rec.bottom);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nWidth = CompensateXDPI (rec.right);
|
|
nHeight = CompensateYDPI (rec.bottom);
|
|
}
|
|
}
|
|
|
|
GetObject (picture, sizeof (BITMAP), &bitmap);
|
|
|
|
hdcRescaled = CreateCompatibleDC (hdcSrc);
|
|
|
|
if (hdcRescaled)
|
|
{
|
|
hbmpRescaled = CreateCompatibleBitmap (hdcSrc, nWidth, nHeight);
|
|
|
|
SelectObject (hdcRescaled, hbmpRescaled);
|
|
|
|
/* Anti-aliasing mode (HALFTONE is the only anti-aliasing algorithm natively supported by Windows 2000.
|
|
TODO: GDI+ offers higher quality -- InterpolationModeHighQualityBicubic) */
|
|
SetStretchBltMode (hdcRescaled, HALFTONE);
|
|
|
|
StretchBlt (hdcRescaled,
|
|
0,
|
|
0,
|
|
nWidth,
|
|
nHeight,
|
|
hdcSrc,
|
|
0,
|
|
0,
|
|
bitmap.bmWidth,
|
|
bitmap.bmHeight,
|
|
SRCCOPY);
|
|
|
|
DeleteDC (hdcSrc);
|
|
|
|
if (bDirectRender)
|
|
{
|
|
HDC hdcDest = GetDC (hwndDest);
|
|
if (hdcDest)
|
|
{
|
|
BitBlt (hdcDest, x, y, nWidth, nHeight, hdcRescaled, 0, 0, SRCCOPY);
|
|
ReleaseDC (hwndDest, hdcDest);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = SendMessage (hwndDest, (UINT) STM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) (HANDLE) hbmpRescaled);
|
|
}
|
|
|
|
if ((HGDIOBJ) lResult != NULL && (HGDIOBJ) lResult != (HGDIOBJ) hbmpRescaled)
|
|
DeleteObject ((HGDIOBJ) lResult);
|
|
|
|
DeleteDC (hdcRescaled);
|
|
}
|
|
|
|
return hbmpRescaled;
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK
|
|
RedTick (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_CREATE)
|
|
{
|
|
}
|
|
else if (uMsg == WM_DESTROY)
|
|
{
|
|
}
|
|
else if (uMsg == WM_TIMER)
|
|
{
|
|
}
|
|
else if (uMsg == WM_PAINT)
|
|
{
|
|
PAINTSTRUCT tmp;
|
|
HPEN hPen;
|
|
HDC hDC;
|
|
BOOL bEndPaint;
|
|
RECT Rect;
|
|
|
|
if (GetUpdateRect (hwnd, NULL, FALSE))
|
|
{
|
|
hDC = BeginPaint (hwnd, &tmp);
|
|
bEndPaint = TRUE;
|
|
if (hDC == NULL)
|
|
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
hDC = GetDC (hwnd);
|
|
bEndPaint = FALSE;
|
|
}
|
|
|
|
GetClientRect (hwnd, &Rect);
|
|
|
|
hPen = CreatePen (PS_SOLID, 2, RGB (0, 255, 0));
|
|
if (hPen != NULL)
|
|
{
|
|
HGDIOBJ hObj = SelectObject (hDC, hPen);
|
|
WORD bx = LOWORD (GetDialogBaseUnits ());
|
|
WORD by = HIWORD (GetDialogBaseUnits ());
|
|
|
|
MoveToEx (hDC, (Rect.right - Rect.left) / 2, Rect.bottom, NULL);
|
|
LineTo (hDC, Rect.right, Rect.top);
|
|
MoveToEx (hDC, (Rect.right - Rect.left) / 2, Rect.bottom, NULL);
|
|
|
|
LineTo (hDC, (3 * bx) / 4, (2 * by) / 8);
|
|
|
|
SelectObject (hDC, hObj);
|
|
DeleteObject (hPen);
|
|
}
|
|
|
|
if (bEndPaint)
|
|
EndPaint (hwnd, &tmp);
|
|
else
|
|
ReleaseDC (hwnd, hDC);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
BOOL
|
|
RegisterRedTick (HINSTANCE hInstance)
|
|
{
|
|
WNDCLASSW wc;
|
|
ULONG rc;
|
|
|
|
memset(&wc, 0 , sizeof wc);
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 4;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH);
|
|
wc.lpszClassName = L"VCREDTICK";
|
|
wc.lpfnWndProc = &RedTick;
|
|
|
|
rc = (ULONG) RegisterClassW (&wc);
|
|
|
|
return rc == 0 ? FALSE : TRUE;
|
|
}
|
|
|
|
BOOL
|
|
UnregisterRedTick (HINSTANCE hInstance)
|
|
{
|
|
return UnregisterClassW (L"VCREDTICK", hInstance);
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
SplashDlgProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return DefDlgProcW (hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
static int g_waitCursorCounter = 0;
|
|
|
|
void
|
|
WaitCursor ()
|
|
{
|
|
static HCURSOR hcWait = NULL;
|
|
if (hcWait == NULL)
|
|
hcWait = LoadCursor (NULL, IDC_WAIT);
|
|
|
|
if ((g_waitCursorCounter == 0) || (hCursor != hcWait))
|
|
{
|
|
if (!Silent) SetCursor (hcWait);
|
|
hCursor = hcWait;
|
|
}
|
|
g_waitCursorCounter++;
|
|
}
|
|
|
|
void
|
|
NormalCursor ()
|
|
{
|
|
static HCURSOR hcArrow = NULL;
|
|
if (hcArrow == NULL)
|
|
hcArrow = LoadCursor (NULL, IDC_ARROW);
|
|
if (g_waitCursorCounter > 0)
|
|
g_waitCursorCounter--;
|
|
if (g_waitCursorCounter == 0)
|
|
{
|
|
if (!Silent) SetCursor (hcArrow);
|
|
hCursor = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
ArrowWaitCursor ()
|
|
{
|
|
static HCURSOR hcArrowWait = NULL;
|
|
if (hcArrowWait == NULL)
|
|
hcArrowWait = LoadCursor (NULL, IDC_APPSTARTING);
|
|
if ((g_waitCursorCounter == 0) || (hCursor != hcArrowWait))
|
|
{
|
|
if (!Silent) SetCursor (hcArrowWait);
|
|
hCursor = hcArrowWait;
|
|
}
|
|
g_waitCursorCounter++;
|
|
}
|
|
|
|
void HandCursor ()
|
|
{
|
|
static HCURSOR hcHand = NULL;
|
|
if (hcHand == NULL)
|
|
hcHand = LoadCursor (NULL, IDC_HAND);
|
|
SetCursor (hcHand);
|
|
hCursor = hcHand;
|
|
}
|
|
|
|
void
|
|
AddComboPair (HWND hComboBox, const wchar_t *lpszItem, int value)
|
|
{
|
|
LPARAM nIndex;
|
|
|
|
nIndex = SendMessage (hComboBox, CB_ADDSTRING, 0, (LPARAM) lpszItem);
|
|
nIndex = SendMessage (hComboBox, CB_SETITEMDATA, nIndex, (LPARAM) value);
|
|
}
|
|
|
|
void
|
|
SelectAlgo (HWND hComboBox, int *algo_id)
|
|
{
|
|
LPARAM nCount = SendMessage (hComboBox, CB_GETCOUNT, 0, 0);
|
|
LPARAM x, i;
|
|
|
|
for (i = 0; i < nCount; i++)
|
|
{
|
|
x = SendMessage (hComboBox, CB_GETITEMDATA, i, 0);
|
|
if (x == (LPARAM) *algo_id)
|
|
{
|
|
SendMessage (hComboBox, CB_SETCURSEL, i, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Something went wrong ; couldn't find the requested algo id so we drop
|
|
back to a default */
|
|
|
|
*algo_id = (int) SendMessage (hComboBox, CB_GETITEMDATA, 0, 0);
|
|
|
|
SendMessage (hComboBox, CB_SETCURSEL, 0, 0);
|
|
|
|
}
|
|
|
|
void PopulateWipeModeCombo (HWND hComboBox, BOOL bNA, BOOL bInPlaceEncryption, BOOL bHeaderWipe)
|
|
{
|
|
if (bNA)
|
|
{
|
|
AddComboPair (hComboBox, GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE"), TC_WIPE_NONE);
|
|
}
|
|
else
|
|
{
|
|
if (!bHeaderWipe)
|
|
{
|
|
AddComboPair (hComboBox, GetString ("WIPE_MODE_NONE"), TC_WIPE_NONE);
|
|
}
|
|
|
|
AddComboPair (hComboBox, GetString ("WIPE_MODE_1_RAND"), TC_WIPE_1_RAND);
|
|
AddComboPair (hComboBox, GetString ("WIPE_MODE_3_DOD_5220"), TC_WIPE_3_DOD_5220);
|
|
AddComboPair (hComboBox, GetString ("WIPE_MODE_7_DOD_5220"), TC_WIPE_7_DOD_5220);
|
|
AddComboPair (hComboBox, GetString ("WIPE_MODE_35_GUTMANN"), TC_WIPE_35_GUTMANN);
|
|
|
|
if (bHeaderWipe)
|
|
AddComboPair (hComboBox, GetString ("WIPE_MODE_256"), TC_WIPE_256); // paranoid wipe for volume header
|
|
}
|
|
}
|
|
|
|
wchar_t *GetWipeModeName (WipeAlgorithmId modeId)
|
|
{
|
|
switch (modeId)
|
|
{
|
|
case TC_WIPE_NONE:
|
|
return GetString ("WIPE_MODE_NONE");
|
|
|
|
case TC_WIPE_1_RAND:
|
|
return GetString ("WIPE_MODE_1_RAND");
|
|
|
|
case TC_WIPE_3_DOD_5220:
|
|
return GetString ("WIPE_MODE_3_DOD_5220");
|
|
|
|
case TC_WIPE_7_DOD_5220:
|
|
return GetString ("WIPE_MODE_7_DOD_5220");
|
|
|
|
case TC_WIPE_35_GUTMANN:
|
|
return GetString ("WIPE_MODE_35_GUTMANN");
|
|
|
|
case TC_WIPE_256:
|
|
return GetString ("WIPE_MODE_256");
|
|
|
|
default:
|
|
return GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE");
|
|
}
|
|
}
|
|
|
|
wchar_t *GetPathType (const wchar_t *path, BOOL bUpperCase, BOOL *bIsPartition)
|
|
{
|
|
if (wcsstr (path, L"Partition")
|
|
&& wcsstr (path, L"Partition0") == NULL)
|
|
{
|
|
*bIsPartition = TRUE;
|
|
return GetString (bUpperCase ? "PARTITION_UPPER_CASE" : "PARTITION_LOWER_CASE");
|
|
}
|
|
else if (wcsstr (path, L"HarddiskVolume"))
|
|
{
|
|
*bIsPartition = TRUE;
|
|
return GetString (bUpperCase ? "VOLUME_UPPER_CASE" : "VOLUME_LOWER_CASE");
|
|
}
|
|
|
|
*bIsPartition = FALSE;
|
|
return GetString (bUpperCase ? "DEVICE_UPPER_CASE" : "DEVICE_LOWER_CASE");
|
|
}
|
|
|
|
LRESULT CALLBACK CustomDlgProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_SETCURSOR && hCursor != NULL)
|
|
{
|
|
SetCursor (hCursor);
|
|
return TRUE;
|
|
}
|
|
|
|
return DefDlgProcW (hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
/*
|
|
static BOOL IsReturnAddress (DWORD64 address)
|
|
{
|
|
static size_t codeEnd = 0;
|
|
byte *sp = (byte *) address;
|
|
|
|
if (codeEnd == 0)
|
|
{
|
|
MEMORY_BASIC_INFORMATION mi;
|
|
if (VirtualQuery ((LPCVOID) 0x401000, &mi, sizeof (mi)) >= sizeof (mi))
|
|
codeEnd = (size_t) mi.BaseAddress + mi.RegionSize;
|
|
}
|
|
|
|
if (address < 0x401000 + 8 || address > codeEnd)
|
|
return FALSE;
|
|
|
|
return sp[-5] == 0xe8 // call ADDR
|
|
|| (sp[-6] == 0xff && sp[-5] == 0x15) // call [ADDR]
|
|
|| (sp[-2] == 0xff && (sp[-1] & 0xf0) == 0xd0); // call REG
|
|
}
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
EXCEPTION_POINTERS *ExceptionPointers;
|
|
HANDLE ExceptionThread;
|
|
|
|
} ExceptionHandlerThreadArgs;
|
|
|
|
|
|
void ExceptionHandlerThread (void *threadArg)
|
|
{
|
|
ExceptionHandlerThreadArgs *args = (ExceptionHandlerThreadArgs *) threadArg;
|
|
|
|
EXCEPTION_POINTERS *ep = args->ExceptionPointers;
|
|
//DWORD addr;
|
|
DWORD exCode = ep->ExceptionRecord->ExceptionCode;
|
|
// SYSTEM_INFO si;
|
|
// wchar_t msg[8192];
|
|
// char modPath[MAX_PATH];
|
|
// int crc = 0;
|
|
// char url[MAX_URL_LENGTH];
|
|
// char lpack[128];
|
|
// stringstream callStack;
|
|
// addr = (DWORD) ep->ExceptionRecord->ExceptionAddress;
|
|
// PDWORD sp = (PDWORD) ep->ContextRecord->Esp;
|
|
// int frameNumber = 0;
|
|
|
|
switch (exCode)
|
|
{
|
|
case STATUS_IN_PAGE_ERROR:
|
|
case 0xeedfade:
|
|
// Exception not caused by VeraCrypt
|
|
MessageBoxW (0, GetString ("EXCEPTION_REPORT_EXT"),
|
|
GetString ("EXCEPTION_REPORT_TITLE"),
|
|
MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
|
|
return;
|
|
}
|
|
|
|
// Call stack
|
|
/* HMODULE dbgDll = LoadLibrary ("dbghelp.dll");
|
|
if (dbgDll)
|
|
{
|
|
typedef DWORD (__stdcall *SymGetOptions_t) ();
|
|
typedef DWORD (__stdcall *SymSetOptions_t) (DWORD SymOptions);
|
|
typedef BOOL (__stdcall *SymInitialize_t) (HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess);
|
|
typedef BOOL (__stdcall *StackWalk64_t) (DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
|
|
typedef BOOL (__stdcall * SymFromAddr_t) (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol);
|
|
|
|
SymGetOptions_t DbgHelpSymGetOptions = (SymGetOptions_t) GetProcAddress (dbgDll, "SymGetOptions");
|
|
SymSetOptions_t DbgHelpSymSetOptions = (SymSetOptions_t) GetProcAddress (dbgDll, "SymSetOptions");
|
|
SymInitialize_t DbgHelpSymInitialize = (SymInitialize_t) GetProcAddress (dbgDll, "SymInitialize");
|
|
PFUNCTION_TABLE_ACCESS_ROUTINE64 DbgHelpSymFunctionTableAccess64 = (PFUNCTION_TABLE_ACCESS_ROUTINE64) GetProcAddress (dbgDll, "SymFunctionTableAccess64");
|
|
PGET_MODULE_BASE_ROUTINE64 DbgHelpSymGetModuleBase64 = (PGET_MODULE_BASE_ROUTINE64) GetProcAddress (dbgDll, "SymGetModuleBase64");
|
|
StackWalk64_t DbgHelpStackWalk64 = (StackWalk64_t) GetProcAddress (dbgDll, "StackWalk64");
|
|
SymFromAddr_t DbgHelpSymFromAddr = (SymFromAddr_t) GetProcAddress (dbgDll, "SymFromAddr");
|
|
|
|
if (DbgHelpSymGetOptions && DbgHelpSymSetOptions && DbgHelpSymInitialize && DbgHelpSymFunctionTableAccess64 && DbgHelpSymGetModuleBase64 && DbgHelpStackWalk64 && DbgHelpSymFromAddr)
|
|
{
|
|
DbgHelpSymSetOptions (DbgHelpSymGetOptions() | SYMOPT_DEFERRED_LOADS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_NO_CPP);
|
|
|
|
if (DbgHelpSymInitialize (GetCurrentProcess(), NULL, TRUE))
|
|
{
|
|
STACKFRAME64 frame;
|
|
memset (&frame, 0, sizeof (frame));
|
|
|
|
frame.AddrPC.Offset = ep->ContextRecord->Eip;
|
|
frame.AddrPC.Mode = AddrModeFlat;
|
|
frame.AddrStack.Offset = ep->ContextRecord->Esp;
|
|
frame.AddrStack.Mode = AddrModeFlat;
|
|
frame.AddrFrame.Offset = ep->ContextRecord->Ebp;
|
|
frame.AddrFrame.Mode = AddrModeFlat;
|
|
|
|
string lastSymbol;
|
|
|
|
while (frameNumber < 32 && DbgHelpStackWalk64 (IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), args->ExceptionThread, &frame, ep->ContextRecord, NULL, DbgHelpSymFunctionTableAccess64, DbgHelpSymGetModuleBase64, NULL))
|
|
{
|
|
if (!frame.AddrPC.Offset)
|
|
continue;
|
|
|
|
ULONG64 symbolBuffer[(sizeof (SYMBOL_INFO) + MAX_SYM_NAME * sizeof (TCHAR) + sizeof (ULONG64) - 1) / sizeof (ULONG64)];
|
|
memset (symbolBuffer, 0, sizeof (symbolBuffer));
|
|
|
|
PSYMBOL_INFO symbol = (PSYMBOL_INFO) symbolBuffer;
|
|
symbol->SizeOfStruct = sizeof (SYMBOL_INFO);
|
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
|
|
|
if (DbgHelpSymFromAddr (GetCurrentProcess(), frame.AddrPC.Offset, NULL, symbol) && symbol->NameLen > 0)
|
|
{
|
|
for (size_t i = 0; i < symbol->NameLen; ++i)
|
|
{
|
|
if (!isalnum (symbol->Name[i]))
|
|
symbol->Name[i] = '_';
|
|
}
|
|
|
|
if (symbol->Name != lastSymbol)
|
|
callStack << "&st" << frameNumber++ << "=" << symbol->Name;
|
|
|
|
lastSymbol = symbol->Name;
|
|
}
|
|
else if (frameNumber == 0 || IsReturnAddress (frame.AddrPC.Offset))
|
|
{
|
|
callStack << "&st" << frameNumber++ << "=0x" << hex << frame.AddrPC.Offset << dec;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// StackWalk64() may fail due to missing frame pointers
|
|
list <DWORD> retAddrs;
|
|
if (frameNumber == 0)
|
|
retAddrs.push_back (ep->ContextRecord->Eip);
|
|
|
|
retAddrs.push_back (0);
|
|
|
|
MEMORY_BASIC_INFORMATION mi;
|
|
VirtualQuery (sp, &mi, sizeof (mi));
|
|
PDWORD stackTop = (PDWORD)((byte *) mi.BaseAddress + mi.RegionSize);
|
|
int i = 0;
|
|
|
|
while (retAddrs.size() < 16 && &sp[i] < stackTop)
|
|
{
|
|
if (IsReturnAddress (sp[i]))
|
|
{
|
|
bool duplicate = false;
|
|
foreach (DWORD prevAddr, retAddrs)
|
|
{
|
|
if (sp[i] == prevAddr)
|
|
{
|
|
duplicate = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!duplicate)
|
|
retAddrs.push_back (sp[i]);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (retAddrs.size() > 1)
|
|
{
|
|
foreach (DWORD addr, retAddrs)
|
|
{
|
|
callStack << "&st" << frameNumber++ << "=0x" << hex << addr << dec;
|
|
}
|
|
}
|
|
|
|
// Checksum of the module
|
|
if (GetModuleFileName (NULL, modPath, sizeof (modPath)))
|
|
{
|
|
HANDLE h = CreateFile (modPath, FILE_READ_DATA | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
{
|
|
BY_HANDLE_FILE_INFORMATION fi;
|
|
if (GetFileInformationByHandle (h, &fi))
|
|
{
|
|
char *buf = (char *) malloc (fi.nFileSizeLow);
|
|
if (buf)
|
|
{
|
|
DWORD bytesRead;
|
|
if (ReadFile (h, buf, fi.nFileSizeLow, &bytesRead, NULL) && bytesRead == fi.nFileSizeLow)
|
|
crc = GetCrc32 ((unsigned char *) buf, fi.nFileSizeLow);
|
|
free (buf);
|
|
}
|
|
}
|
|
CloseHandle (h);
|
|
}
|
|
}
|
|
|
|
GetSystemInfo (&si);
|
|
|
|
if (LocalizationActive)
|
|
sprintf_s (lpack, sizeof (lpack), "&langpack=%s_%s", GetPreferredLangId (), GetActiveLangPackVersion ());
|
|
else
|
|
lpack[0] = 0;
|
|
|
|
|
|
sprintf (url, TC_APPLINK_SECURE "&dest=err-report%s&os=%s&osver=%d.%d.%d&arch=%s&cpus=%d&app=%s&cksum=%x&dlg=%s&err=%x&addr=%x"
|
|
, lpack
|
|
, GetWindowsEdition().c_str()
|
|
, CurrentOSMajor
|
|
, CurrentOSMinor
|
|
, CurrentOSServicePack
|
|
, Is64BitOs () ? "x64" : "x86"
|
|
, si.dwNumberOfProcessors
|
|
#ifdef TCMOUNT
|
|
,"main"
|
|
#endif
|
|
#ifdef VOLFORMAT
|
|
,"format"
|
|
#endif
|
|
#ifdef SETUP
|
|
,"setup"
|
|
#endif
|
|
, crc
|
|
, LastDialogId ? LastDialogId : "-"
|
|
, exCode
|
|
, addr);
|
|
|
|
string urlStr = url + callStack.str();
|
|
|
|
_snwprintf (msg, array_capacity (msg), GetString ("EXCEPTION_REPORT"), urlStr.c_str());
|
|
|
|
if (IDYES == MessageBoxW (0, msg, GetString ("EXCEPTION_REPORT_TITLE"), MB_ICONERROR | MB_YESNO | MB_DEFBUTTON1))
|
|
ShellExecute (NULL, "open", urlStr.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
|
else */
|
|
UnhandledExceptionFilter (ep);
|
|
}
|
|
|
|
|
|
LONG __stdcall ExceptionHandler (EXCEPTION_POINTERS *ep)
|
|
{
|
|
SetUnhandledExceptionFilter (NULL);
|
|
|
|
if (SystemFileSelectorCallPending && SystemFileSelectorCallerThreadId == GetCurrentThreadId())
|
|
{
|
|
MessageBoxW (NULL, GetString ("EXCEPTION_REPORT_EXT_FILESEL"), GetString ("EXCEPTION_REPORT_TITLE"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
|
|
|
|
UnhandledExceptionFilter (ep);
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
ExceptionHandlerThreadArgs args;
|
|
args.ExceptionPointers = ep;
|
|
args.ExceptionThread = GetCurrentThread();
|
|
|
|
WaitForSingleObject ((HANDLE) _beginthread (ExceptionHandlerThread, 0, &args), INFINITE);
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
|
|
void InvalidParameterHandler (const wchar_t *expression, const wchar_t *function, const wchar_t *file, unsigned int line, uintptr_t reserved)
|
|
{
|
|
TC_THROW_FATAL_EXCEPTION;
|
|
}
|
|
|
|
|
|
static LRESULT CALLBACK NonInstallUacWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return DefWindowProcW (hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
BOOL LaunchElevatedProcess (HWND hwndDlg, const wchar_t* szModPath, const wchar_t* args)
|
|
{
|
|
wchar_t newCmdLine[4096];
|
|
WNDCLASSEXW wcex;
|
|
HWND hWnd;
|
|
|
|
memset (&wcex, 0, sizeof (wcex));
|
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
|
wcex.lpfnWndProc = (WNDPROC) NonInstallUacWndProc;
|
|
wcex.hInstance = hInst;
|
|
wcex.lpszClassName = L"VeraCrypt";
|
|
RegisterClassExW (&wcex);
|
|
|
|
// A small transparent window is necessary to bring the new instance to foreground
|
|
hWnd = CreateWindowExW (WS_EX_TOOLWINDOW | WS_EX_LAYERED,
|
|
L"VeraCrypt", L"VeraCrypt", 0,
|
|
GetSystemMetrics (SM_CXSCREEN)/2,
|
|
GetSystemMetrics (SM_CYSCREEN)/2,
|
|
1, 1, NULL, NULL, hInst, NULL);
|
|
|
|
SetLayeredWindowAttributes (hWnd, 0, 0, LWA_ALPHA);
|
|
ShowWindow (hWnd, SW_SHOWNORMAL);
|
|
|
|
StringCbCopyW (newCmdLine, sizeof(newCmdLine), L"/q UAC ");
|
|
StringCbCatW (newCmdLine, sizeof (newCmdLine), args);
|
|
|
|
if ((int)ShellExecuteW (hWnd, L"runas", szModPath, newCmdLine, NULL, SW_SHOWNORMAL) <= 32)
|
|
{
|
|
if (hwndDlg)
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
Sleep (2000);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// Mutex handling to prevent multiple instances of the wizard or main app from dealing with system encryption.
|
|
// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
|
|
BOOL CreateSysEncMutex (void)
|
|
{
|
|
return TCCreateMutex (&hSysEncMutex, TC_MUTEX_NAME_SYSENC);
|
|
}
|
|
|
|
|
|
BOOL InstanceHasSysEncMutex (void)
|
|
{
|
|
return (hSysEncMutex != NULL);
|
|
}
|
|
|
|
|
|
// Mutex handling to prevent multiple instances of the wizard from dealing with system encryption
|
|
void CloseSysEncMutex (void)
|
|
{
|
|
TCCloseMutex (&hSysEncMutex);
|
|
}
|
|
|
|
|
|
// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
|
|
BOOL CreateNonSysInplaceEncMutex (void)
|
|
{
|
|
return TCCreateMutex (&hNonSysInplaceEncMutex, TC_MUTEX_NAME_NONSYS_INPLACE_ENC);
|
|
}
|
|
|
|
|
|
BOOL InstanceHasNonSysInplaceEncMutex (void)
|
|
{
|
|
return (hNonSysInplaceEncMutex != NULL);
|
|
}
|
|
|
|
|
|
void CloseNonSysInplaceEncMutex (void)
|
|
{
|
|
TCCloseMutex (&hNonSysInplaceEncMutex);
|
|
}
|
|
|
|
|
|
// Returns TRUE if another instance of the wizard is preparing, resuming or performing non-system in-place encryption
|
|
BOOL NonSysInplaceEncInProgressElsewhere (void)
|
|
{
|
|
return (!InstanceHasNonSysInplaceEncMutex ()
|
|
&& MutexExistsOnSystem (TC_MUTEX_NAME_NONSYS_INPLACE_ENC));
|
|
}
|
|
|
|
|
|
// Mutex handling to prevent multiple instances of the wizard or main app from trying to install
|
|
// or register the driver or from trying to launch it in portable mode at the same time.
|
|
// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
|
|
BOOL CreateDriverSetupMutex (void)
|
|
{
|
|
return TCCreateMutex (&hDriverSetupMutex, TC_MUTEX_NAME_DRIVER_SETUP);
|
|
}
|
|
|
|
|
|
void CloseDriverSetupMutex (void)
|
|
{
|
|
TCCloseMutex (&hDriverSetupMutex);
|
|
}
|
|
|
|
|
|
BOOL CreateAppSetupMutex (void)
|
|
{
|
|
return TCCreateMutex (&hAppSetupMutex, TC_MUTEX_NAME_APP_SETUP);
|
|
}
|
|
|
|
|
|
void CloseAppSetupMutex (void)
|
|
{
|
|
TCCloseMutex (&hAppSetupMutex);
|
|
}
|
|
|
|
|
|
BOOL IsTrueCryptInstallerRunning (void)
|
|
{
|
|
return (MutexExistsOnSystem (TC_MUTEX_NAME_APP_SETUP));
|
|
}
|
|
|
|
|
|
// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
|
|
BOOL TCCreateMutex (volatile HANDLE *hMutex, wchar_t *name)
|
|
{
|
|
if (*hMutex != NULL)
|
|
return TRUE; // This instance already has the mutex
|
|
|
|
*hMutex = CreateMutex (NULL, TRUE, name);
|
|
if (*hMutex == NULL)
|
|
{
|
|
// In multi-user configurations, the OS returns "Access is denied" here when a user attempts
|
|
// to acquire the mutex if another user already has. However, on Vista, "Access is denied" is
|
|
// returned also if the mutex is owned by a process with admin rights while we have none.
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetLastError () == ERROR_ALREADY_EXISTS)
|
|
{
|
|
ReleaseMutex (*hMutex);
|
|
CloseHandle (*hMutex);
|
|
|
|
*hMutex = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void TCCloseMutex (volatile HANDLE *hMutex)
|
|
{
|
|
if (*hMutex != NULL)
|
|
{
|
|
if (ReleaseMutex (*hMutex)
|
|
&& CloseHandle (*hMutex))
|
|
*hMutex = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// Returns TRUE if a process running on the system has the specified mutex (otherwise FALSE).
|
|
BOOL MutexExistsOnSystem (wchar_t *name)
|
|
{
|
|
if (name[0] == 0)
|
|
return FALSE;
|
|
|
|
HANDLE hMutex = OpenMutex (MUTEX_ALL_ACCESS, FALSE, name);
|
|
|
|
if (hMutex == NULL)
|
|
{
|
|
if (GetLastError () == ERROR_FILE_NOT_FOUND)
|
|
return FALSE;
|
|
|
|
if (GetLastError () == ERROR_ACCESS_DENIED) // On Vista, this is returned if the owner of the mutex is elevated while we are not
|
|
return TRUE;
|
|
|
|
// The call failed and it is not certain whether the mutex exists or not
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle (hMutex);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
uint32 ReadDriverConfigurationFlags ()
|
|
{
|
|
DWORD configMap;
|
|
|
|
if (!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, &configMap))
|
|
configMap = 0;
|
|
|
|
return configMap;
|
|
}
|
|
|
|
uint32 ReadServiceConfigurationFlags ()
|
|
{
|
|
DWORD configMap;
|
|
|
|
if (!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, TC_SYSTEM_FAVORITES_SERVICE_NAME L"Config", &configMap))
|
|
configMap = 0;
|
|
|
|
return configMap;
|
|
}
|
|
|
|
|
|
uint32 ReadEncryptionThreadPoolFreeCpuCountLimit ()
|
|
{
|
|
DWORD count;
|
|
|
|
if (!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME, &count))
|
|
count = 0;
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
BOOL LoadSysEncSettings ()
|
|
{
|
|
BOOL status = TRUE;
|
|
DWORD size = 0;
|
|
char *sysEncCfgFileBuf = LoadFile (GetConfigPath (TC_APPD_FILENAME_SYSTEM_ENCRYPTION), &size);
|
|
char *xml = sysEncCfgFileBuf;
|
|
char paramName[100], paramVal[MAX_PATH];
|
|
|
|
// Defaults
|
|
int newSystemEncryptionStatus = SYSENC_STATUS_NONE;
|
|
WipeAlgorithmId newnWipeMode = TC_WIPE_NONE;
|
|
|
|
if (!FileExists (GetConfigPath (TC_APPD_FILENAME_SYSTEM_ENCRYPTION)))
|
|
{
|
|
SystemEncryptionStatus = newSystemEncryptionStatus;
|
|
nWipeMode = newnWipeMode;
|
|
}
|
|
|
|
if (xml == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
while (xml = XmlFindElement (xml, "config"))
|
|
{
|
|
XmlGetAttributeText (xml, "key", paramName, sizeof (paramName));
|
|
XmlGetNodeText (xml, paramVal, sizeof (paramVal));
|
|
|
|
if (strcmp (paramName, "SystemEncryptionStatus") == 0)
|
|
{
|
|
newSystemEncryptionStatus = atoi (paramVal);
|
|
}
|
|
else if (strcmp (paramName, "WipeMode") == 0)
|
|
{
|
|
newnWipeMode = (WipeAlgorithmId) atoi (paramVal);
|
|
}
|
|
|
|
xml++;
|
|
}
|
|
|
|
SystemEncryptionStatus = newSystemEncryptionStatus;
|
|
nWipeMode = newnWipeMode;
|
|
|
|
free (sysEncCfgFileBuf);
|
|
return status;
|
|
}
|
|
|
|
|
|
// Returns the number of partitions where non-system in-place encryption is progress or had been in progress
|
|
// but was interrupted. In addition, via the passed pointer, returns the last selected wipe algorithm ID.
|
|
int LoadNonSysInPlaceEncSettings (WipeAlgorithmId *wipeAlgorithm)
|
|
{
|
|
char *fileBuf = NULL;
|
|
char *fileBuf2 = NULL;
|
|
DWORD size, size2;
|
|
int count;
|
|
|
|
*wipeAlgorithm = TC_WIPE_NONE;
|
|
|
|
if (!FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC)))
|
|
return 0;
|
|
|
|
if ((fileBuf = LoadFile (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), &size)) == NULL)
|
|
return 0;
|
|
|
|
if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
|
|
{
|
|
if ((fileBuf2 = LoadFile (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE), &size2)) != NULL)
|
|
*wipeAlgorithm = (WipeAlgorithmId) atoi (fileBuf2);
|
|
}
|
|
|
|
count = atoi (fileBuf);
|
|
|
|
if (fileBuf != NULL)
|
|
TCfree (fileBuf);
|
|
|
|
if (fileBuf2 != NULL)
|
|
TCfree (fileBuf2);
|
|
|
|
return (count);
|
|
}
|
|
|
|
|
|
void RemoveNonSysInPlaceEncNotifications (void)
|
|
{
|
|
if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC)))
|
|
_wremove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC));
|
|
|
|
if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
|
|
_wremove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE));
|
|
|
|
if (!IsNonInstallMode () && SystemEncryptionStatus == SYSENC_STATUS_NONE)
|
|
ManageStartupSeqWiz (TRUE, L"");
|
|
}
|
|
|
|
|
|
void SavePostInstallTasksSettings (int command)
|
|
{
|
|
FILE *f = NULL;
|
|
|
|
if (IsNonInstallMode() && command != TC_POST_INSTALL_CFG_REMOVE_ALL)
|
|
return;
|
|
|
|
switch (command)
|
|
{
|
|
case TC_POST_INSTALL_CFG_REMOVE_ALL:
|
|
_wremove (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL));
|
|
_wremove (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES));
|
|
_wremove (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RESCUE_DISK));
|
|
break;
|
|
|
|
case TC_POST_INSTALL_CFG_TUTORIAL:
|
|
f = _wfopen (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL), L"w");
|
|
break;
|
|
|
|
case TC_POST_INSTALL_CFG_RELEASE_NOTES:
|
|
f = _wfopen (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES), L"w");
|
|
break;
|
|
|
|
case TC_POST_INSTALL_CFG_RESCUE_DISK:
|
|
f = _wfopen (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RESCUE_DISK), L"w");
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (f == NULL)
|
|
return;
|
|
|
|
if (fputws (L"1", f) < 0)
|
|
{
|
|
// Error
|
|
fclose (f);
|
|
return;
|
|
}
|
|
|
|
TCFlushFile (f);
|
|
|
|
fclose (f);
|
|
}
|
|
|
|
|
|
void DoPostInstallTasks (HWND hwndDlg)
|
|
{
|
|
BOOL bDone = FALSE;
|
|
|
|
if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL)))
|
|
{
|
|
if (AskYesNo ("AFTER_INSTALL_TUTORIAL", hwndDlg) == IDYES)
|
|
Applink ("beginnerstutorial");
|
|
|
|
bDone = TRUE;
|
|
}
|
|
|
|
if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES)))
|
|
{
|
|
if (AskYesNo ("AFTER_UPGRADE_RELEASE_NOTES", hwndDlg) == IDYES)
|
|
Applink ("releasenotes");
|
|
|
|
bDone = TRUE;
|
|
}
|
|
|
|
if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RESCUE_DISK)))
|
|
{
|
|
if (AskYesNo ("AFTER_UPGRADE_RESCUE_DISK", hwndDlg) == IDYES)
|
|
PostMessage (hwndDlg, VC_APPMSG_CREATE_RESCUE_DISK, 0, 0);
|
|
|
|
bDone = TRUE;
|
|
}
|
|
|
|
if (bDone)
|
|
SavePostInstallTasksSettings (TC_POST_INSTALL_CFG_REMOVE_ALL);
|
|
}
|
|
|
|
static void LoadSystemDll (LPCTSTR szModuleName, HMODULE *pHandle, BOOL bIgnoreError, const char* srcPos)
|
|
{
|
|
wchar_t dllPath[MAX_PATH];
|
|
|
|
/* Load dll explictely from System32 to avoid Dll hijacking attacks*/
|
|
if (!GetSystemDirectory(dllPath, MAX_PATH))
|
|
StringCbCopyW(dllPath, sizeof(dllPath), L"C:\\Windows\\System32");
|
|
|
|
StringCbCatW(dllPath, sizeof(dllPath), L"\\");
|
|
StringCbCatW(dllPath, sizeof(dllPath), szModuleName);
|
|
|
|
if (((*pHandle = LoadLibrary(dllPath)) == NULL) && !bIgnoreError)
|
|
{
|
|
// This error is fatal
|
|
handleWin32Error (NULL, srcPos);
|
|
AbortProcess ("INIT_DLL");
|
|
}
|
|
}
|
|
|
|
/* InitApp - initialize the application, this function is called once in the
|
|
applications WinMain function, but before the main dialog has been created */
|
|
void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine)
|
|
{
|
|
WNDCLASSW wc;
|
|
char langId[6];
|
|
InitCommonControlsPtr InitCommonControlsFn = NULL;
|
|
wchar_t modPath[MAX_PATH];
|
|
|
|
GetModuleFileNameW (NULL, modPath, ARRAYSIZE (modPath));
|
|
|
|
/* remove current directory from dll search path */
|
|
SetDllDirectoryFn = (SetDllDirectoryPtr) GetProcAddress (GetModuleHandle(L"kernel32.dll"), "SetDllDirectoryW");
|
|
SetSearchPathModeFn = (SetSearchPathModePtr) GetProcAddress (GetModuleHandle(L"kernel32.dll"), "SetSearchPathMode");
|
|
SetDefaultDllDirectoriesFn = (SetDefaultDllDirectoriesPtr) GetProcAddress (GetModuleHandle(L"kernel32.dll"), "SetDefaultDllDirectories");
|
|
|
|
if (SetDllDirectoryFn)
|
|
SetDllDirectoryFn (L"");
|
|
if (SetSearchPathModeFn)
|
|
SetSearchPathModeFn (BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT);
|
|
if (SetDefaultDllDirectoriesFn)
|
|
SetDefaultDllDirectoriesFn (LOAD_LIBRARY_SEARCH_SYSTEM32);
|
|
|
|
InitOSVersionInfo();
|
|
|
|
VirtualLock (&CmdTokenPin, sizeof (CmdTokenPin));
|
|
|
|
InitGlobalLocks ();
|
|
|
|
LoadSystemDll (L"msvcrt.dll", &hmsvcrtdll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"ntmarta.dll", &hntmartadll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"MPR.DLL", &hmprdll, TRUE, SRC_POS);
|
|
#ifdef SETUP
|
|
if (IsOSAtLeast (WIN_7))
|
|
{
|
|
LoadSystemDll (L"ProfApi.DLL", &hProfApiDll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"cryptbase.dll", &hcryptbasedll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"sspicli.dll", &hsspiclidll, TRUE, SRC_POS);
|
|
}
|
|
#endif
|
|
LoadSystemDll (L"psapi.dll", &hpsapidll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"secur32.dll", &hsecur32dll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"msasn1.dll", &hmsasn1dll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"Usp10.DLL", &hUsp10Dll, TRUE, SRC_POS);
|
|
if (IsOSAtLeast (WIN_7))
|
|
LoadSystemDll (L"dwmapi.dll", &hdwmapidll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"UXTheme.dll", &hUXThemeDll, TRUE, SRC_POS);
|
|
|
|
LoadSystemDll (L"msls31.dll", &hMsls31, TRUE, SRC_POS);
|
|
LoadSystemDll (L"SETUPAPI.DLL", &hSetupDll, FALSE, SRC_POS);
|
|
LoadSystemDll (L"SHLWAPI.DLL", &hShlwapiDll, FALSE, SRC_POS);
|
|
|
|
LoadSystemDll (L"userenv.dll", &hUserenvDll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"rsaenh.dll", &hRsaenhDll, TRUE, SRC_POS);
|
|
|
|
#ifdef SETUP
|
|
if (nCurrentOS < WIN_7)
|
|
{
|
|
if (nCurrentOS == WIN_XP)
|
|
{
|
|
LoadSystemDll (L"imm32.dll", &himm32dll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"MSCTF.dll", &hMSCTFdll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"fltlib.dll", &hfltlibdll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"wbem\\framedyn.dll", &hframedyndll, TRUE, SRC_POS);
|
|
}
|
|
|
|
if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
LoadSystemDll (L"netapi32.dll", &hnetapi32dll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"authz.dll", &hauthzdll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"xmllite.dll", &hxmllitedll, TRUE, SRC_POS);
|
|
}
|
|
}
|
|
|
|
if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
LoadSystemDll (L"atl.dll", &hsppdll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"vsstrace.dll", &hvsstracedll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"vssapi.dll", &vssapidll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"spp.dll", &hsppdll, TRUE, SRC_POS);
|
|
}
|
|
#endif
|
|
|
|
LoadSystemDll (L"crypt32.dll", &hcrypt32dll, TRUE, SRC_POS);
|
|
|
|
if (IsOSAtLeast (WIN_7))
|
|
{
|
|
LoadSystemDll (L"CryptSP.dll", &hCryptSpDll, TRUE, SRC_POS);
|
|
|
|
LoadSystemDll (L"cfgmgr32.dll", &hcfgmgr32dll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"devobj.dll", &hdevobjdll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"powrprof.dll", &hpowrprofdll, TRUE, SRC_POS);
|
|
|
|
LoadSystemDll (L"bcrypt.dll", &hbcryptdll, TRUE, SRC_POS);
|
|
LoadSystemDll (L"bcryptprimitives.dll", &hbcryptprimitivesdll, TRUE, SRC_POS);
|
|
}
|
|
|
|
#ifndef SETUP
|
|
LoadSystemDll (L"WINSCARD.DLL", &hwinscarddll, TRUE, SRC_POS);
|
|
#endif
|
|
|
|
LoadSystemDll (L"COMCTL32.DLL", &hComctl32Dll, FALSE, SRC_POS);
|
|
|
|
// call InitCommonControls function
|
|
InitCommonControlsFn = (InitCommonControlsPtr) GetProcAddress (hComctl32Dll, "InitCommonControls");
|
|
ImageList_AddFn = (ImageList_AddPtr) GetProcAddress (hComctl32Dll, "ImageList_Add");
|
|
ImageList_CreateFn = (ImageList_CreatePtr) GetProcAddress (hComctl32Dll, "ImageList_Create");
|
|
|
|
if (InitCommonControlsFn && ImageList_AddFn && ImageList_CreateFn)
|
|
{
|
|
InitCommonControlsFn();
|
|
}
|
|
else
|
|
AbortProcess ("INIT_DLL");
|
|
|
|
LoadSystemDll (L"Riched20.dll", &hRichEditDll, FALSE, SRC_POS);
|
|
LoadSystemDll (L"Advapi32.dll", &hAdvapi32Dll, FALSE, SRC_POS);
|
|
|
|
#if !defined(SETUP)
|
|
if (!VerifyModuleSignature (modPath))
|
|
AbortProcess ("DIST_PACKAGE_CORRUPTED");
|
|
#endif
|
|
// Get SetupAPI functions pointers
|
|
SetupCloseInfFileFn = (SetupCloseInfFilePtr) GetProcAddress (hSetupDll, "SetupCloseInfFile");
|
|
SetupDiOpenClassRegKeyFn = (SetupDiOpenClassRegKeyPtr) GetProcAddress (hSetupDll, "SetupDiOpenClassRegKey");
|
|
SetupInstallFromInfSectionWFn = (SetupInstallFromInfSectionWPtr) GetProcAddress (hSetupDll, "SetupInstallFromInfSectionW");
|
|
SetupOpenInfFileWFn = (SetupOpenInfFileWPtr) GetProcAddress (hSetupDll, "SetupOpenInfFileW");
|
|
|
|
if (!SetupCloseInfFileFn || !SetupDiOpenClassRegKeyFn || !SetupInstallFromInfSectionWFn || !SetupOpenInfFileWFn)
|
|
AbortProcess ("INIT_DLL");
|
|
|
|
// Get SHDeleteKeyW,SHStrDupW, UrlUnescapeW functions pointers
|
|
SHDeleteKeyWFn = (SHDeleteKeyWPtr) GetProcAddress (hShlwapiDll, "SHDeleteKeyW");
|
|
SHStrDupWFn = (SHStrDupWPtr) GetProcAddress (hShlwapiDll, "SHStrDupW");
|
|
UrlUnescapeWFn = (UrlUnescapeWPtr) GetProcAddress(hShlwapiDll, "UrlUnescapeW");
|
|
IUnknown_QueryServicePtr = (IUnknown_QueryServiceFn) GetProcAddress(hShlwapiDll, "IUnknown_QueryService");
|
|
if (!IUnknown_QueryServicePtr)
|
|
IUnknown_QueryServicePtr = (IUnknown_QueryServiceFn) GetProcAddress(hShlwapiDll, MAKEINTRESOURCEA(176));
|
|
if (!SHDeleteKeyWFn || !SHStrDupWFn || !UrlUnescapeWFn || !IUnknown_QueryServicePtr)
|
|
AbortProcess ("INIT_DLL");
|
|
|
|
if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
/* Get ChangeWindowMessageFilter used to enable some messages bypasss UIPI (User Interface Privilege Isolation) */
|
|
ChangeWindowMessageFilterFn = (ChangeWindowMessageFilterPtr) GetProcAddress (GetModuleHandle (L"user32.dll"), "ChangeWindowMessageFilter");
|
|
|
|
#ifndef SETUP
|
|
/* enable drag-n-drop when we are running elevated */
|
|
AllowMessageInUIPI (WM_DROPFILES);
|
|
AllowMessageInUIPI (WM_COPYDATA);
|
|
AllowMessageInUIPI (WM_COPYGLOBALDATA);
|
|
#endif
|
|
}
|
|
|
|
// Get CreateProcessWithTokenW function pointer
|
|
CreateProcessWithTokenWPtr = (CreateProcessWithTokenWFn) GetProcAddress(hAdvapi32Dll, "CreateProcessWithTokenW");
|
|
|
|
/* Save the instance handle for later */
|
|
hInst = hInstance;
|
|
|
|
SetErrorMode (SetErrorMode (0) | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
|
CoInitialize (NULL);
|
|
|
|
#ifndef SETUP
|
|
// Application ID
|
|
typedef HRESULT (WINAPI *SetAppId_t) (PCWSTR appID);
|
|
SetAppId_t setAppId = (SetAppId_t) GetProcAddress (GetModuleHandle (L"shell32.dll"), "SetCurrentProcessExplicitAppUserModelID");
|
|
|
|
if (setAppId)
|
|
setAppId (TC_APPLICATION_ID);
|
|
#endif
|
|
|
|
// Language
|
|
langId[0] = 0;
|
|
SetPreferredLangId (ConfigReadString ("Language", "", langId, sizeof (langId)));
|
|
|
|
#ifndef SETUP
|
|
if (langId[0] == 0)
|
|
{
|
|
// check if user selected a language during installation
|
|
WCHAR uiLang[6];
|
|
ReadRegistryString (L"Software\\VeraCrypt", L"SetupUILanguage", L"", uiLang, sizeof (uiLang));
|
|
if (0 < WideCharToMultiByte (CP_ACP, 0, uiLang, -1, langId, sizeof (langId), NULL, NULL))
|
|
{
|
|
SetPreferredLangId (langId);
|
|
bLanguageSetInSetup = TRUE;
|
|
}
|
|
}
|
|
|
|
#ifndef VCEXPANDER
|
|
// delete the registry key created by the installer (if any)
|
|
DeleteRegistryKey (HKEY_CURRENT_USER, L"Software\\VeraCrypt");
|
|
#endif
|
|
|
|
#endif
|
|
|
|
if (langId[0] == 0)
|
|
{
|
|
if (IsNonInstallMode ())
|
|
{
|
|
// only support automatic use of a language file in portable mode
|
|
// this is achieved by placing a unique language XML file in the same
|
|
// place as portable VeraCrypt binaries.
|
|
DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_LANGUAGE), NULL,
|
|
(DLGPROC) LanguageDlgProc, (LPARAM) 1);
|
|
}
|
|
else
|
|
{
|
|
// when installed, force using English as default language
|
|
SetPreferredLangId ("en");
|
|
}
|
|
}
|
|
|
|
LoadLanguageFile ();
|
|
|
|
#ifndef SETUP
|
|
// UAC elevation moniker cannot be used in portable mode.
|
|
// A new instance of the application must be created with elevated privileges.
|
|
if (IsNonInstallMode () && !IsAdmin () && IsUacSupported ())
|
|
{
|
|
|
|
if (wcsstr (lpszCommandLine, L"/q UAC ") == lpszCommandLine)
|
|
{
|
|
Error ("UAC_INIT_ERROR", NULL);
|
|
exit (1);
|
|
}
|
|
|
|
|
|
if (LaunchElevatedProcess (NULL, modPath, lpszCommandLine))
|
|
exit (0);
|
|
else
|
|
exit (1);
|
|
}
|
|
#endif
|
|
|
|
SetUnhandledExceptionFilter (ExceptionHandler);
|
|
_set_invalid_parameter_handler (InvalidParameterHandler);
|
|
|
|
RemoteSession = GetSystemMetrics (SM_REMOTESESSION) != 0;
|
|
|
|
#ifndef VC_SKIP_OS_DRIVER_REQ_CHECK
|
|
if (!IsSupportedOS())
|
|
{
|
|
MessageBoxW (NULL, GetString ("UNSUPPORTED_OS"), lpszTitle, MB_ICONSTOP);
|
|
exit (1);
|
|
}
|
|
#else
|
|
// in TESTSIGNING mode, we support only Windows Vista, Windows 7, Windows 8/8.1
|
|
if ( !IsOSVersionAtLeast(WIN_VISTA, 0)
|
|
#ifndef SETUP
|
|
|| IsOSVersionAtLeast(WIN_10, 0)
|
|
#else
|
|
|| (IsOSVersionAtLeast(WIN_10, 0) && !bMakePackage)
|
|
#endif
|
|
)
|
|
{
|
|
MessageBoxW (NULL, L"TESTSIGNING version of VeraCrypt targets only Windows Vista, Windows 7 and Windows 8/8.1.\n\nPlease use the standard version of VeraCrypt instead.", lpszTitle, MB_ICONSTOP);
|
|
exit (1);
|
|
}
|
|
else if ( !IsTestSigningModeEnabled()
|
|
#ifdef SETUP
|
|
&& !bMakePackage
|
|
#endif
|
|
)
|
|
{
|
|
MessageBoxW (NULL, L"Test-Signing Mode, which is required to run VeraCrypt TESTSIGNING binaries, is not enabled in Windows.\n\nExecution aborted!", lpszTitle, MB_ICONSTOP);
|
|
exit (1);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
// Service pack check & warnings about critical MS issues
|
|
switch (nCurrentOS)
|
|
{
|
|
case WIN_XP:
|
|
if (CurrentOSServicePack < 1)
|
|
{
|
|
HKEY k;
|
|
// PE environment does not report version of SP
|
|
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\minint", 0, KEY_READ, &k) != ERROR_SUCCESS)
|
|
Warning ("LARGE_IDE_WARNING_XP", NULL);
|
|
else
|
|
RegCloseKey (k);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Get the attributes for the standard dialog class */
|
|
if ((GetClassInfoW (hInst, WINDOWS_DIALOG_CLASS, &wc)) == 0)
|
|
{
|
|
handleWin32Error (NULL, SRC_POS);
|
|
AbortProcess ("INIT_REGISTER");
|
|
}
|
|
|
|
#ifndef SETUP
|
|
wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_TRUECRYPT_ICON));
|
|
#else
|
|
#include "../setup/resource.h"
|
|
wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_SETUP));
|
|
#endif
|
|
wc.lpszClassName = TC_DLG_CLASS;
|
|
wc.lpfnWndProc = &CustomDlgProc;
|
|
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
|
|
wc.cbWndExtra = DLGWINDOWEXTRA;
|
|
|
|
hDlgClass = RegisterClassW (&wc);
|
|
if (hDlgClass == 0)
|
|
{
|
|
handleWin32Error (NULL, SRC_POS);
|
|
AbortProcess ("INIT_REGISTER");
|
|
}
|
|
|
|
wc.lpszClassName = TC_SPLASH_CLASS;
|
|
wc.lpfnWndProc = &SplashDlgProc;
|
|
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
|
|
wc.cbWndExtra = DLGWINDOWEXTRA;
|
|
|
|
hSplashClass = RegisterClassW (&wc);
|
|
if (hSplashClass == 0)
|
|
{
|
|
handleWin32Error (NULL, SRC_POS);
|
|
AbortProcess ("INIT_REGISTER");
|
|
}
|
|
|
|
// DPI and GUI aspect ratio
|
|
DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_AUXILIARY_DLG), NULL,
|
|
(DLGPROC) AuxiliaryDlgProc, (LPARAM) 1);
|
|
|
|
InitHelpFileName ();
|
|
|
|
#ifndef SETUP
|
|
#ifdef _WIN64
|
|
if (IsOSAtLeast (WIN_7))
|
|
{
|
|
EnableRamEncryption ((ReadDriverConfigurationFlags() & VC_DRIVER_CONFIG_ENABLE_RAM_ENCRYPTION) ? TRUE : FALSE);
|
|
if (IsRamEncryptionEnabled())
|
|
{
|
|
if (!InitializeSecurityParameters(GetAppRandomSeed))
|
|
AbortProcess("OUTOFMEMORY");
|
|
}
|
|
}
|
|
#endif
|
|
if (!EncryptionThreadPoolStart (ReadEncryptionThreadPoolFreeCpuCountLimit()))
|
|
{
|
|
handleWin32Error (NULL, SRC_POS);
|
|
FREE_DLL (hRichEditDll);
|
|
FREE_DLL (hComctl32Dll);
|
|
FREE_DLL (hSetupDll);
|
|
FREE_DLL (hShlwapiDll);
|
|
FREE_DLL (hProfApiDll);
|
|
FREE_DLL (hUsp10Dll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hUXThemeDll);
|
|
FREE_DLL (hUserenvDll);
|
|
FREE_DLL (hRsaenhDll);
|
|
FREE_DLL (himm32dll);
|
|
FREE_DLL (hMSCTFdll);
|
|
FREE_DLL (hfltlibdll);
|
|
FREE_DLL (hframedyndll);
|
|
FREE_DLL (hpsapidll);
|
|
FREE_DLL (hsecur32dll);
|
|
FREE_DLL (hnetapi32dll);
|
|
FREE_DLL (hauthzdll);
|
|
FREE_DLL (hxmllitedll);
|
|
FREE_DLL (hmprdll);
|
|
FREE_DLL (hsppdll);
|
|
FREE_DLL (vssapidll);
|
|
FREE_DLL (hvsstracedll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hcfgmgr32dll);
|
|
FREE_DLL (hdevobjdll);
|
|
FREE_DLL (hpowrprofdll);
|
|
FREE_DLL (hsspiclidll);
|
|
FREE_DLL (hcryptbasedll);
|
|
FREE_DLL (hdwmapidll);
|
|
FREE_DLL (hmsasn1dll);
|
|
FREE_DLL (hcrypt32dll);
|
|
FREE_DLL (hbcryptdll);
|
|
FREE_DLL (hbcryptprimitivesdll);
|
|
FREE_DLL (hMsls31);
|
|
FREE_DLL (hntmartadll);
|
|
FREE_DLL (hwinscarddll);
|
|
FREE_DLL (hmsvcrtdll);
|
|
FREE_DLL (hAdvapi32Dll);
|
|
exit (1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void FinalizeApp (void)
|
|
{
|
|
FREE_DLL (hRichEditDll);
|
|
FREE_DLL (hComctl32Dll);
|
|
FREE_DLL (hSetupDll);
|
|
FREE_DLL (hShlwapiDll);
|
|
FREE_DLL (hProfApiDll);
|
|
FREE_DLL (hUsp10Dll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hUXThemeDll);
|
|
FREE_DLL (hUserenvDll);
|
|
FREE_DLL (hRsaenhDll);
|
|
FREE_DLL (himm32dll);
|
|
FREE_DLL (hMSCTFdll);
|
|
FREE_DLL (hfltlibdll);
|
|
FREE_DLL (hframedyndll);
|
|
FREE_DLL (hpsapidll);
|
|
FREE_DLL (hsecur32dll);
|
|
FREE_DLL (hnetapi32dll);
|
|
FREE_DLL (hauthzdll);
|
|
FREE_DLL (hxmllitedll);
|
|
FREE_DLL (hmprdll);
|
|
FREE_DLL (hsppdll);
|
|
FREE_DLL (vssapidll);
|
|
FREE_DLL (hvsstracedll);
|
|
FREE_DLL (hCryptSpDll);
|
|
FREE_DLL (hcfgmgr32dll);
|
|
FREE_DLL (hdevobjdll);
|
|
FREE_DLL (hpowrprofdll);
|
|
FREE_DLL (hsspiclidll);
|
|
FREE_DLL (hcryptbasedll);
|
|
FREE_DLL (hdwmapidll);
|
|
FREE_DLL (hmsasn1dll);
|
|
FREE_DLL (hcrypt32dll);
|
|
FREE_DLL (hbcryptdll);
|
|
FREE_DLL (hbcryptprimitivesdll);
|
|
FREE_DLL (hMsls31);
|
|
FREE_DLL (hntmartadll);
|
|
FREE_DLL (hwinscarddll);
|
|
FREE_DLL (hmsvcrtdll);
|
|
FREE_DLL (hAdvapi32Dll);
|
|
}
|
|
|
|
void InitHelpFileName (void)
|
|
{
|
|
wchar_t *lpszTmp;
|
|
|
|
GetModuleFileNameW (NULL, szHelpFile, ARRAYSIZE (szHelpFile));
|
|
lpszTmp = wcsrchr (szHelpFile, L'\\');
|
|
if (lpszTmp)
|
|
{
|
|
wchar_t szTemp[TC_MAX_PATH];
|
|
|
|
++lpszTmp;
|
|
*lpszTmp = 0; // add null terminating character to prepare for append operations
|
|
|
|
// Primary file name
|
|
if (strcmp (GetPreferredLangId(), "en") == 0
|
|
|| strlen(GetPreferredLangId()) == 0)
|
|
{
|
|
StringCbCatW (szHelpFile, sizeof(szHelpFile), L"docs\\VeraCrypt User Guide.chm");
|
|
}
|
|
else
|
|
{
|
|
StringCbPrintfW (szTemp, sizeof(szTemp), L"docs\\VeraCrypt User Guide.%S.chm", GetPreferredLangId());
|
|
StringCbCatW (szHelpFile, sizeof(szHelpFile), szTemp);
|
|
}
|
|
|
|
// Secondary file name (used when localized documentation is not found).
|
|
GetModuleFileNameW (NULL, szHelpFile2, ARRAYSIZE (szHelpFile2));
|
|
lpszTmp = wcsrchr (szHelpFile2, L'\\');
|
|
if (lpszTmp)
|
|
{
|
|
++lpszTmp;
|
|
*lpszTmp = 0;
|
|
StringCbCatW (szHelpFile2, sizeof(szHelpFile2), L"docs\\VeraCrypt User Guide.chm");
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef SETUP
|
|
BOOL OpenDevice (const wchar_t *lpszPath, OPEN_TEST_STRUCT *driver, BOOL detectFilesystem, BOOL computeVolumeIDs)
|
|
{
|
|
DWORD dwResult;
|
|
BOOL bResult;
|
|
wchar_t wszFileName[TC_MAX_PATH];
|
|
|
|
StringCbCopyW (wszFileName, sizeof(wszFileName), lpszPath);
|
|
|
|
memset (driver, 0, sizeof (OPEN_TEST_STRUCT));
|
|
memcpy (driver->wszFileName, wszFileName, sizeof (wszFileName));
|
|
|
|
driver->bDetectTCBootLoader = FALSE;
|
|
driver->DetectFilesystem = detectFilesystem;
|
|
driver->bComputeVolumeIDs = computeVolumeIDs;
|
|
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_OPEN_TEST,
|
|
driver, sizeof (OPEN_TEST_STRUCT),
|
|
driver, sizeof (OPEN_TEST_STRUCT),
|
|
&dwResult, NULL);
|
|
|
|
// check variable driver
|
|
if ( bResult
|
|
&& ( (driver->bDetectTCBootLoader != TRUE && driver->bDetectTCBootLoader != FALSE) ||
|
|
(driver->TCBootLoaderDetected != TRUE && driver->TCBootLoaderDetected != FALSE) ||
|
|
(driver->DetectFilesystem != TRUE && driver->DetectFilesystem != FALSE) ||
|
|
(driver->FilesystemDetected != TRUE && driver->FilesystemDetected != FALSE) ||
|
|
(wcscmp (wszFileName, driver->wszFileName))
|
|
)
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (bResult == FALSE)
|
|
{
|
|
dwResult = GetLastError ();
|
|
|
|
if (dwResult == ERROR_SHARING_VIOLATION || dwResult == ERROR_NOT_READY)
|
|
{
|
|
driver->TCBootLoaderDetected = FALSE;
|
|
driver->FilesystemDetected = FALSE;
|
|
memset (driver->VolumeIDComputed, 0, sizeof (driver->VolumeIDComputed));
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
// Tells the driver that it's running in portable mode
|
|
void NotifyDriverOfPortableMode (void)
|
|
{
|
|
if (hDriver != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwResult;
|
|
|
|
DeviceIoControl (hDriver, TC_IOCTL_SET_PORTABLE_MODE_STATUS, NULL, 0, NULL, 0, &dwResult, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL GetDriveLabel (int driveNo, wchar_t *label, int labelSize)
|
|
{
|
|
DWORD fileSystemFlags;
|
|
wchar_t root[] = { L'A' + (wchar_t) driveNo, L':', L'\\', 0 };
|
|
|
|
return GetVolumeInformationW (root, label, labelSize / 2, NULL, NULL, &fileSystemFlags, NULL, 0);
|
|
}
|
|
|
|
#ifndef SETUP
|
|
|
|
/* Stores the device path of the system partition in SysPartitionDevicePath and the device path of the system drive
|
|
in SysDriveDevicePath.
|
|
IMPORTANT: As this may take a very long time if called for the first time, it should be called only before performing
|
|
a dangerous operation (such as header backup restore or formatting a supposedly non-system device) never
|
|
at WM_INITDIALOG or any other GUI events -- instead call IsSystemDevicePath (path, hwndDlg, FALSE) for
|
|
very fast preliminary GUI checks; also note that right after the "Select Device" dialog exits with an OK
|
|
return code, you can use the global flags bSysPartitionSelected and bSysDriveSelected to see if the user
|
|
selected the system partition/device.
|
|
After this function completes successfully, the results are cached for the rest of the session and repeated
|
|
executions complete very fast. Returns TRUE if successful (otherwise FALSE). */
|
|
BOOL GetSysDevicePaths (HWND hwndDlg)
|
|
{
|
|
if (!bCachedSysDevicePathsValid
|
|
|| wcslen (SysPartitionDevicePath) <= 1
|
|
|| wcslen (SysDriveDevicePath) <= 1)
|
|
{
|
|
foreach (const HostDevice &device, GetAvailableHostDevices (false, true))
|
|
{
|
|
if (device.ContainsSystem)
|
|
StringCchCopyW (device.IsPartition ? SysPartitionDevicePath : SysDriveDevicePath, TC_MAX_PATH, device.Path.c_str());
|
|
}
|
|
|
|
if (IsOSAtLeast (WIN_7))
|
|
{
|
|
// Find extra boot partition
|
|
foreach (const HostDevice &drive, GetAvailableHostDevices (false, false))
|
|
{
|
|
if (drive.ContainsSystem)
|
|
{
|
|
foreach (const HostDevice &sysDrivePartition, drive.Partitions)
|
|
{
|
|
if (sysDrivePartition.Bootable)
|
|
{
|
|
if (sysDrivePartition.Size <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE)
|
|
ExtraBootPartitionDevicePath = sysDrivePartition.Path;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bCachedSysDevicePathsValid = 1;
|
|
}
|
|
|
|
return (bCachedSysDevicePathsValid
|
|
&& wcslen (SysPartitionDevicePath) > 1
|
|
&& wcslen (SysDriveDevicePath) > 1);
|
|
}
|
|
|
|
/* Determines whether the device path is the path of the system partition or of the system drive (or neither).
|
|
If bReliableRequired is TRUE, very fast execution is guaranteed, but the results cannot be relied upon.
|
|
If it's FALSE and the function is called for the first time, execution may take up to one minute but the
|
|
results are reliable.
|
|
IMPORTANT: As the execution may take a very long time if called for the first time with bReliableRequired set
|
|
to TRUE, it should be called with bReliableRequired set to TRUE only before performing a dangerous
|
|
operation (such as header backup restore or formatting a supposedly non-system device) never at
|
|
WM_INITDIALOG or any other GUI events (use IsSystemDevicePath(path, hwndDlg, FALSE) for fast
|
|
preliminary GUI checks; also note that right after the "Select Device" dialog exits with an OK
|
|
return code, you can use the global flags bSysPartitionSelected and bSysDriveSelected to see if the
|
|
user selected the system partition/device).
|
|
After this function completes successfully, the results are cached for the rest of the session, bReliableRequired
|
|
is ignored (TRUE implied), repeated executions complete very fast, and the results are always reliable.
|
|
Return codes:
|
|
1 - it is the system partition path (e.g. \Device\Harddisk0\Partition1)
|
|
2 - it is the system drive path (e.g. \Device\Harddisk0\Partition0)
|
|
3 - it is the extra boot partition path
|
|
0 - it's not the system partition/drive path
|
|
-1 - the result can't be determined, isn't reliable, or there was an error. */
|
|
int IsSystemDevicePath (const wchar_t *path, HWND hwndDlg, BOOL bReliableRequired)
|
|
{
|
|
if (!bCachedSysDevicePathsValid
|
|
&& bReliableRequired)
|
|
{
|
|
if (!GetSysDevicePaths (hwndDlg))
|
|
return -1;
|
|
}
|
|
|
|
if (wcslen (SysPartitionDevicePath) <= 1 || wcslen (SysDriveDevicePath) <= 1)
|
|
return -1;
|
|
|
|
if (!path)
|
|
return -1;
|
|
|
|
if (wcsncmp (path, SysPartitionDevicePath, max (wcslen(path), wcslen(SysPartitionDevicePath))) == 0)
|
|
return 1;
|
|
else if (wcsncmp (path, SysDriveDevicePath, max (wcslen(path), wcslen(SysDriveDevicePath))) == 0)
|
|
return 2;
|
|
else if (ExtraBootPartitionDevicePath == path)
|
|
return 3;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Determines whether the path points to a non-system partition on the system drive.
|
|
IMPORTANT: As this may take a very long time if called for the first time, it should be called
|
|
only before performing a dangerous operation, never at WM_INITDIALOG or any other GUI events.
|
|
Return codes:
|
|
0 - it isn't a non-system partition on the system drive
|
|
1 - it's a non-system partition on the system drive
|
|
-1 - the result can't be determined, isn't reliable, or there was an error. */
|
|
int IsNonSysPartitionOnSysDrive (const wchar_t *path)
|
|
{
|
|
wchar_t tmpPath [TC_MAX_PATH + 1];
|
|
int pos;
|
|
|
|
if (!GetSysDevicePaths (MainDlg))
|
|
return -1;
|
|
|
|
if (wcslen (SysPartitionDevicePath) <= 1 || wcslen (SysDriveDevicePath) <= 1)
|
|
return -1;
|
|
|
|
if (wcsncmp (path, SysPartitionDevicePath, max (wcslen(path), wcslen(SysPartitionDevicePath))) == 0
|
|
|| wcsncmp (path, SysDriveDevicePath, max (wcslen(path), wcslen(SysDriveDevicePath))) == 0)
|
|
{
|
|
// It is the system partition/drive path (it isn't a non-system partition)
|
|
return 0;
|
|
}
|
|
|
|
memset (tmpPath, 0, sizeof (tmpPath));
|
|
wcsncpy (tmpPath, path, ARRAYSIZE (tmpPath) - 1);
|
|
|
|
|
|
pos = (int) FindString ((const char*) tmpPath, (const char*) L"Partition", (int) wcslen (tmpPath) * 2, (int) wcslen (L"Partition") * 2, 0);
|
|
|
|
if (pos < 0)
|
|
return -1;
|
|
|
|
pos /= 2;
|
|
pos += (int) strlen ("Partition");
|
|
|
|
if (pos + 1 > ARRAYSIZE (tmpPath) - 1)
|
|
return -1;
|
|
|
|
tmpPath [pos] = L'0';
|
|
tmpPath [pos + 1] = 0;
|
|
|
|
if (wcsncmp (tmpPath, SysDriveDevicePath, max (wcslen(tmpPath), wcslen(SysDriveDevicePath))) == 0)
|
|
{
|
|
// It is a non-system partition on the system drive
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
// The partition is not on the system drive
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#endif //!SETUP
|
|
|
|
wstring GetSysEncryptionPretestInfo2String (void)
|
|
{
|
|
// This huge string is divided into smaller portions to make it easier for translators to
|
|
// re-translate it when a minor modification is made to it (the whole huge string will not be
|
|
// reverted to English, so they will have to translate only a small portion of it).
|
|
return (wstring (L"\n")
|
|
+ GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_1")
|
|
+ GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_2")
|
|
+ GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_3")
|
|
+ GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_4"));
|
|
}
|
|
|
|
|
|
wstring GetRescueDiskHelpString (void)
|
|
{
|
|
// This huge string is divided into smaller portions to make it easier for translators to
|
|
// re-translate it when a minor modification is made to it (the whole huge string will not be
|
|
// reverted to English, so they will have to translate only a small portion of it).
|
|
return (wstring (
|
|
GetString ("RESCUE_DISK_HELP_PORTION_1"))
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_2")
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_3")
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_4")
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_5")
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_6")
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_7")
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_8")
|
|
+ GetString ("RESCUE_DISK_HELP_PORTION_9"));
|
|
}
|
|
|
|
|
|
wstring GetDecoyOsInstructionsString (void)
|
|
{
|
|
// This huge string is divided into smaller portions to make it easier for translators to
|
|
// re-translate it when a minor modification is made to it (the whole huge string will not be
|
|
// reverted to English, so they will have to translate only a small portion of it).
|
|
return (wstring (
|
|
GetString ("DECOY_OS_INSTRUCTIONS_PORTION_1"))
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_2")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_3")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_4")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_5")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_6")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_7")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_8")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_9")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_10")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_11")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_12")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_13")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_14")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_15")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_16")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_17")
|
|
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_18"));
|
|
}
|
|
|
|
struct _TEXT_EDIT_DIALOG_PARAM {
|
|
BOOL ReadOnly;
|
|
std::string& Text;
|
|
const WCHAR* Title;
|
|
|
|
_TEXT_EDIT_DIALOG_PARAM (const _TEXT_EDIT_DIALOG_PARAM& other) : ReadOnly (other.ReadOnly), Text (other.Text), Title (other.Title) {}
|
|
_TEXT_EDIT_DIALOG_PARAM(BOOL _readOnly, const WCHAR* title, std::string& _text) : ReadOnly(_readOnly), Text(_text), Title(title) {}
|
|
_TEXT_EDIT_DIALOG_PARAM& operator=( const _TEXT_EDIT_DIALOG_PARAM& other) {
|
|
if (this != &other)
|
|
{
|
|
ReadOnly = other.ReadOnly;
|
|
Text = other.Text;
|
|
Title = other.Title;
|
|
}
|
|
return *this;
|
|
}
|
|
};
|
|
typedef struct _TEXT_EDIT_DIALOG_PARAM TEXT_INFO_DIALOG_PARAM,*TEXT_INFO_DIALOG_PARAM_PTR;
|
|
|
|
INT_PTR TextEditDialogBox (BOOL readOnly, HWND parent, const WCHAR* Title, std::string& text)
|
|
{
|
|
TEXT_INFO_DIALOG_PARAM pm(readOnly, Title, text);
|
|
return DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TEXT_EDIT_DLG), parent, (DLGPROC) TextEditDlgProc, (LPARAM) &pm);
|
|
}
|
|
|
|
BOOL CALLBACK TextEditDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
static int nID = 0;
|
|
static TEXT_INFO_DIALOG_PARAM_PTR prm;
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
prm = (TEXT_INFO_DIALOG_PARAM_PTR)lParam;
|
|
// increase size limit of rich edit control
|
|
SendMessage(GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), EM_EXLIMITTEXT, 0, -1);
|
|
|
|
SetWindowTextW (hwndDlg, prm->Title);
|
|
// Left margin for rich edit text field
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), EM_SETMARGINS, (WPARAM) EC_LEFTMARGIN, (LPARAM) CompensateXDPI (4));
|
|
|
|
if (prm->ReadOnly)
|
|
{
|
|
// switch rich edit control to ReadOnly
|
|
SendMessage(GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), ES_READONLY, TRUE, 0);
|
|
// hide cancel button
|
|
ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE);
|
|
}
|
|
|
|
SendMessage (hwndDlg, TC_APPMSG_LOAD_TEXT_BOX_CONTENT, 0, 0);
|
|
}
|
|
return 0;
|
|
|
|
case WM_COMMAND:
|
|
if (lw == IDOK )
|
|
{
|
|
if (!prm->ReadOnly)
|
|
{
|
|
prm->Text.resize(GetWindowTextLengthA (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT)) + 1);
|
|
GetWindowTextA (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), &(prm->Text)[0], (int) prm->Text.size());
|
|
}
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDOK);
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDCANCEL )
|
|
{
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
|
|
case TC_APPMSG_LOAD_TEXT_BOX_CONTENT:
|
|
{
|
|
SetWindowTextA (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), prm->Text.c_str());
|
|
}
|
|
return 0;
|
|
|
|
case WM_CLOSE:
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
INT_PTR TextInfoDialogBox (int nID)
|
|
{
|
|
return DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TEXT_INFO_DIALOG_BOX_DLG), MainDlg, (DLGPROC) TextInfoDialogBoxDlgProc, (LPARAM) nID);
|
|
}
|
|
|
|
BOOL CALLBACK TextInfoDialogBoxDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
static int nID = 0;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
nID = (int) lParam;
|
|
|
|
// increase size limit of rich edit control
|
|
SendMessage(GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), EM_EXLIMITTEXT, 0, -1);
|
|
|
|
// Left margin for rich edit text field
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), EM_SETMARGINS, (WPARAM) EC_LEFTMARGIN, (LPARAM) CompensateXDPI (4));
|
|
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_HIDE);
|
|
|
|
switch (nID)
|
|
{
|
|
case TC_TBXID_LEGAL_NOTICES:
|
|
LocalizeDialog (hwndDlg, "LEGAL_NOTICES_DLG_TITLE");
|
|
break;
|
|
|
|
case TC_TBXID_SYS_ENCRYPTION_PRETEST:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
|
|
break;
|
|
|
|
case TC_TBXID_SYS_ENC_RESCUE_DISK:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
|
|
break;
|
|
|
|
case TC_TBXID_DECOY_OS_INSTRUCTIONS:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
|
|
break;
|
|
|
|
case TC_TBXID_EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
|
|
break;
|
|
}
|
|
|
|
SendMessage (hwndDlg, TC_APPMSG_LOAD_TEXT_BOX_CONTENT, 0, 0);
|
|
}
|
|
return 0;
|
|
|
|
case WM_COMMAND:
|
|
if (lw == IDOK || lw == IDCANCEL)
|
|
{
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDC_PRINT)
|
|
{
|
|
switch (nID)
|
|
{
|
|
case TC_TBXID_SYS_ENCRYPTION_PRETEST:
|
|
PrintHardCopyTextUTF16 ((wchar_t *) GetSysEncryptionPretestInfo2String ().c_str(), L"Pre-Boot Troubleshooting", GetSysEncryptionPretestInfo2String ().length () * 2);
|
|
break;
|
|
|
|
case TC_TBXID_SYS_ENC_RESCUE_DISK:
|
|
PrintHardCopyTextUTF16 ((wchar_t *) GetRescueDiskHelpString ().c_str(), L"VeraCrypt Rescue Disk Help", GetRescueDiskHelpString ().length () * 2);
|
|
break;
|
|
|
|
case TC_TBXID_DECOY_OS_INSTRUCTIONS:
|
|
PrintHardCopyTextUTF16 ((wchar_t *) GetDecoyOsInstructionsString ().c_str(), L"How to Create Decoy OS", GetDecoyOsInstructionsString ().length () * 2);
|
|
break;
|
|
|
|
case TC_TBXID_EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS:
|
|
PrintHardCopyTextUTF16 (GetString ("EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS"), L"How to Remove Extra Boot Partition", wcslen (GetString ("EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS")) * 2);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case TC_APPMSG_LOAD_TEXT_BOX_CONTENT:
|
|
{
|
|
char *r = NULL;
|
|
|
|
switch (nID)
|
|
{
|
|
case TC_TBXID_LEGAL_NOTICES:
|
|
LocalizeDialog (hwndDlg, "LEGAL_NOTICES_DLG_TITLE");
|
|
r = GetLegalNotices ();
|
|
if (r != NULL)
|
|
{
|
|
SETTEXTEX TextInfo = {0};
|
|
|
|
TextInfo.flags = ST_SELECTION;
|
|
TextInfo.codepage = CP_ACP;
|
|
|
|
SendMessage(GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), EM_SETTEXTEX, (WPARAM)&TextInfo, (LPARAM)r);
|
|
free (r);
|
|
}
|
|
break;
|
|
|
|
case TC_TBXID_SYS_ENCRYPTION_PRETEST:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), (wchar_t *) GetSysEncryptionPretestInfo2String ().c_str());
|
|
break;
|
|
|
|
case TC_TBXID_SYS_ENC_RESCUE_DISK:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), (wchar_t *) GetRescueDiskHelpString ().c_str());
|
|
break;
|
|
|
|
case TC_TBXID_DECOY_OS_INSTRUCTIONS:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), (wchar_t *) GetDecoyOsInstructionsString ().c_str());
|
|
break;
|
|
|
|
case TC_TBXID_EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS:
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), GetString ("EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS"));
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
|
|
case WM_CLOSE:
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
char * GetLegalNotices ()
|
|
{
|
|
static char *resource;
|
|
static DWORD size;
|
|
char *buf = NULL;
|
|
|
|
if (resource == NULL)
|
|
resource = (char *) MapResource (L"Text", IDR_LICENSE, &size);
|
|
|
|
if (resource != NULL)
|
|
{
|
|
buf = (char *) malloc (size + 1);
|
|
if (buf != NULL)
|
|
{
|
|
memcpy (buf, resource, size);
|
|
buf[size] = 0;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
#ifndef SETUP
|
|
|
|
BOOL CALLBACK RawDevicesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static wchar_t *lpszFileName; // This is actually a pointer to a GLOBAL array
|
|
static vector <HostDevice> devices;
|
|
static map <int, HostDevice> itemToDeviceMap;
|
|
|
|
WORD lw = LOWORD (wParam);
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
LVCOLUMNW LvCol;
|
|
HWND hList = GetDlgItem (hwndDlg, IDC_DEVICELIST);
|
|
RawDevicesDlgParam* pDlgParam = (RawDevicesDlgParam *) lParam;
|
|
|
|
LocalizeDialog (hwndDlg, "IDD_RAWDEVICES_DLG");
|
|
|
|
SendMessage (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
|
|
LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_TWOCLICKACTIVATE|LVS_EX_LABELTIP
|
|
);
|
|
|
|
memset (&LvCol,0,sizeof(LvCol));
|
|
LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
|
|
LvCol.pszText = GetString ("DEVICE");
|
|
LvCol.cx = CompensateXDPI (186);
|
|
LvCol.fmt = LVCFMT_LEFT;
|
|
SendMessage (hList,LVM_INSERTCOLUMNW,0,(LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("DRIVE");
|
|
LvCol.cx = CompensateXDPI (38);
|
|
LvCol.fmt = LVCFMT_LEFT;
|
|
SendMessage (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("SIZE");
|
|
LvCol.cx = CompensateXDPI (64);
|
|
LvCol.fmt = LVCFMT_RIGHT;
|
|
SendMessage (hList,LVM_INSERTCOLUMNW,2,(LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("LABEL");
|
|
LvCol.cx = CompensateXDPI (128);
|
|
LvCol.fmt = LVCFMT_LEFT;
|
|
SendMessage (hList,LVM_INSERTCOLUMNW,3,(LPARAM)&LvCol);
|
|
|
|
devices.clear();
|
|
itemToDeviceMap.clear();
|
|
|
|
if (pDlgParam->devices.empty())
|
|
{
|
|
WaitCursor();
|
|
devices = GetAvailableHostDevices (false, true, false);
|
|
NormalCursor();
|
|
}
|
|
else
|
|
devices = pDlgParam->devices;
|
|
|
|
if (devices.empty())
|
|
{
|
|
MessageBoxW (hwndDlg, GetString ("RAWDEVICES"), lpszTitle, ICON_HAND);
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
|
|
int line = 1;
|
|
LVITEM item;
|
|
memset (&item, 0, sizeof (item));
|
|
item.mask = LVIF_TEXT;
|
|
|
|
foreach (const HostDevice &device, devices)
|
|
{
|
|
item.iSubItem = 1;
|
|
|
|
if (device.ContainsSystem)
|
|
{
|
|
if (device.IsPartition)
|
|
StringCbCopyW (SysPartitionDevicePath, sizeof (SysPartitionDevicePath), device.Path.c_str());
|
|
else
|
|
StringCbCopyW (SysDriveDevicePath, sizeof (SysDriveDevicePath), device.Path.c_str());
|
|
}
|
|
|
|
// Path
|
|
if (!device.IsPartition || device.DynamicVolume)
|
|
{
|
|
if (!device.Floppy && (device.Size == 0)
|
|
&& (device.IsPartition || device.Partitions.empty() || device.Partitions[0].Size == 0)
|
|
)
|
|
continue;
|
|
|
|
if (line > 1)
|
|
{
|
|
ListItemAdd (hList, item.iItem, L"");
|
|
item.iItem = line++;
|
|
}
|
|
|
|
if (device.Floppy || device.DynamicVolume)
|
|
{
|
|
ListItemAdd (hList, item.iItem, (wchar_t *) device.Path.c_str());
|
|
}
|
|
else
|
|
{
|
|
wchar_t s[1024];
|
|
if (device.Removable)
|
|
StringCbPrintfW (s, sizeof(s), L"%s %d", GetString ("REMOVABLE_DISK"), device.SystemNumber);
|
|
else
|
|
StringCbPrintfW (s, sizeof(s), L"%s %d", GetString ("HARDDISK"), device.SystemNumber);
|
|
|
|
if (!device.Partitions.empty())
|
|
StringCbCatW (s, sizeof(s), L":");
|
|
|
|
ListItemAdd (hList, item.iItem, s);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ListItemAdd (hList, item.iItem, (wchar_t *) device.Path.c_str());
|
|
}
|
|
|
|
itemToDeviceMap[item.iItem] = device;
|
|
|
|
// Size
|
|
if (device.Size != 0)
|
|
{
|
|
wchar_t size[100] = { 0 };
|
|
GetSizeString (device.Size, size, sizeof(size));
|
|
ListSubItemSet (hList, item.iItem, 2, size);
|
|
}
|
|
|
|
// Mount point
|
|
if (!device.MountPoint.empty())
|
|
ListSubItemSet (hList, item.iItem, 1, (wchar_t *) device.MountPoint.c_str());
|
|
|
|
// Label
|
|
if (!device.Name.empty())
|
|
ListSubItemSet (hList, item.iItem, 3, (wchar_t *) device.Name.c_str());
|
|
#ifdef TCMOUNT
|
|
else
|
|
{
|
|
bool useInExplorer = false;
|
|
wstring favoriteLabel = GetFavoriteVolumeLabel (device.Path, useInExplorer);
|
|
if (!favoriteLabel.empty())
|
|
ListSubItemSet (hList, item.iItem, 3, (wchar_t *) favoriteLabel.c_str());
|
|
}
|
|
#endif
|
|
|
|
item.iItem = line++;
|
|
}
|
|
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 2, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 3, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
|
|
lpszFileName = pDlgParam->pszFileName;
|
|
|
|
#ifdef VOLFORMAT
|
|
EnableWindow (GetDlgItem (hwndDlg, IDOK), FALSE);
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
case WM_NOTIFY:
|
|
// catch non-device line selected
|
|
if (msg == WM_NOTIFY && ((LPNMHDR) lParam)->code == LVN_ITEMCHANGED && (((LPNMLISTVIEW) lParam)->uNewState & LVIS_FOCUSED ))
|
|
{
|
|
BOOL bEnableOkButton = FALSE;
|
|
LVITEM LvItem;
|
|
memset(&LvItem,0,sizeof(LvItem));
|
|
LvItem.mask = LVIF_TEXT | LVIF_PARAM;
|
|
LvItem.iItem = ((LPNMLISTVIEW) lParam)->iItem;
|
|
LvItem.pszText = lpszFileName;
|
|
LvItem.cchTextMax = TC_MAX_PATH;
|
|
|
|
lpszFileName[0] = 0;
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_DEVICELIST), LVM_GETITEM, LvItem.iItem, (LPARAM) &LvItem);
|
|
if (lpszFileName[0] != 0 && lpszFileName[0] != ' ')
|
|
{
|
|
bEnableOkButton = TRUE;
|
|
#ifdef VOLFORMAT
|
|
if ( bInPlaceEncNonSysResumed && (WizardMode == WIZARD_MODE_NONSYS_DEVICE)
|
|
&& LvItem.iItem != -1 && itemToDeviceMap.find (LvItem.iItem) != itemToDeviceMap.end()
|
|
)
|
|
{
|
|
const HostDevice selectedDevice = itemToDeviceMap[LvItem.iItem];
|
|
if (selectedDevice.ContainsSystem)
|
|
{
|
|
bEnableOkButton = FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
EnableWindow (GetDlgItem ((HWND) hwndDlg, IDOK), bEnableOkButton);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (msg == WM_COMMAND && lw == IDOK || msg == WM_NOTIFY && ((NMHDR *)lParam)->code == LVN_ITEMACTIVATE)
|
|
{
|
|
int selectedItem = ListView_GetSelectionMark (GetDlgItem (hwndDlg, IDC_DEVICELIST));
|
|
|
|
if (selectedItem == -1 || itemToDeviceMap.find (selectedItem) == itemToDeviceMap.end())
|
|
return 1; // non-device line selected
|
|
|
|
const HostDevice selectedDevice = itemToDeviceMap[selectedItem];
|
|
StringCchCopyW (lpszFileName, TC_MAX_PATH, selectedDevice.Path.c_str());
|
|
|
|
#ifdef VOLFORMAT
|
|
if (selectedDevice.ContainsSystem && selectedDevice.IsPartition)
|
|
{
|
|
if (WizardMode != WIZARD_MODE_SYS_DEVICE)
|
|
{
|
|
if (bInPlaceEncNonSysResumed && (WizardMode == WIZARD_MODE_NONSYS_DEVICE))
|
|
{
|
|
// disable selection
|
|
return 1;
|
|
}
|
|
|
|
if (AskYesNo ("CONFIRM_SYSTEM_ENCRYPTION_MODE", hwndDlg) == IDNO)
|
|
{
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
|
|
bSysPartitionSelected = TRUE;
|
|
bSysDriveSelected = FALSE;
|
|
lpszFileName[0] = 0;
|
|
SwitchWizardToSysEncMode ();
|
|
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDOK);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
// This should never be the case because the Select Device dialog is not available in this wizard mode
|
|
bSysPartitionSelected = TRUE;
|
|
bSysDriveSelected = FALSE;
|
|
lpszFileName[0] = 0;
|
|
SwitchWizardToSysEncMode ();
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (!(selectedDevice.ContainsSystem && !selectedDevice.IsPartition))
|
|
{
|
|
if (bWarnDeviceFormatAdvanced
|
|
&& !bHiddenVolDirect
|
|
&& AskWarnNoYes("FORMAT_DEVICE_FOR_ADVANCED_ONLY", hwndDlg) == IDNO)
|
|
{
|
|
if (AskNoYes("CONFIRM_CHANGE_WIZARD_MODE_TO_FILE_CONTAINER", hwndDlg) == IDYES)
|
|
{
|
|
SwitchWizardToFileContainerMode ();
|
|
}
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
|
|
if (!bHiddenVolDirect)
|
|
bWarnDeviceFormatAdvanced = FALSE;
|
|
}
|
|
|
|
#else // #ifdef VOLFORMAT
|
|
|
|
bSysPartitionSelected = (selectedDevice.ContainsSystem && selectedDevice.IsPartition);
|
|
bSysDriveSelected = FALSE;
|
|
|
|
#endif // #ifdef VOLFORMAT
|
|
|
|
if (!selectedDevice.IsPartition && !selectedDevice.Floppy)
|
|
{
|
|
// Whole device selected
|
|
|
|
#ifdef VOLFORMAT
|
|
if (selectedDevice.ContainsSystem && !selectedDevice.IsPartition)
|
|
{
|
|
if (WizardMode != WIZARD_MODE_SYS_DEVICE)
|
|
{
|
|
if (bInPlaceEncNonSysResumed && (WizardMode == WIZARD_MODE_NONSYS_DEVICE))
|
|
{
|
|
// disable selection
|
|
return 1;
|
|
}
|
|
|
|
if (AskYesNo ("CONFIRM_SYSTEM_ENCRYPTION_MODE", hwndDlg) == IDNO)
|
|
{
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
|
|
bSysDriveSelected = TRUE;
|
|
bSysPartitionSelected = FALSE;
|
|
lpszFileName[0] = 0;
|
|
SwitchWizardToSysEncMode ();
|
|
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDOK);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
// This should never be the case because the Select Device dialog is not available in this wizard mode
|
|
bSysDriveSelected = TRUE;
|
|
bSysPartitionSelected = FALSE;
|
|
lpszFileName[0] = 0;
|
|
SwitchWizardToSysEncMode ();
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Disallow format if the device contains partitions, but not if the partition is virtual or system
|
|
if (!selectedDevice.IsVirtualPartition
|
|
&& !bHiddenVolDirect)
|
|
{
|
|
if (!selectedDevice.Partitions.empty())
|
|
{
|
|
EnableWindow (GetDlgItem (hwndDlg, IDOK), FALSE);
|
|
Error ("DEVICE_PARTITIONS_ERR_W_INPLACE_ENC_NOTE", hwndDlg);
|
|
return 1;
|
|
}
|
|
|
|
if (AskWarnNoYes ("WHOLE_NONSYS_DEVICE_ENC_CONFIRM", hwndDlg) == IDNO)
|
|
return 1;
|
|
}
|
|
#else // #ifdef VOLFORMAT
|
|
|
|
bSysDriveSelected = (selectedDevice.ContainsSystem && !selectedDevice.IsPartition);
|
|
bSysPartitionSelected = FALSE;
|
|
|
|
#endif // #ifdef VOLFORMAT
|
|
}
|
|
else
|
|
bSysDriveSelected = FALSE;
|
|
|
|
#ifdef VOLFORMAT
|
|
bRemovableHostDevice = selectedDevice.Removable;
|
|
#endif
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDOK);
|
|
return 1;
|
|
}
|
|
|
|
if ((msg == WM_COMMAND) && (lw == IDCANCEL))
|
|
{
|
|
NormalCursor ();
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif //!SETUP
|
|
|
|
BOOL DoDriverInstall (HWND hwndDlg)
|
|
{
|
|
#ifdef SETUP
|
|
if (SystemEncryptionUpdate)
|
|
return TRUE;
|
|
#endif
|
|
|
|
SC_HANDLE hManager, hService = NULL;
|
|
BOOL bOK = FALSE, bRet;
|
|
|
|
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hManager == NULL)
|
|
goto error;
|
|
|
|
#ifdef SETUP
|
|
StatusMessage (hwndDlg, "INSTALLING_DRIVER");
|
|
#endif
|
|
|
|
hService = CreateService (hManager, L"veracrypt", L"veracrypt",
|
|
SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_SYSTEM_START, SERVICE_ERROR_NORMAL,
|
|
L"System32\\drivers\\veracrypt.sys",
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if (hService == NULL)
|
|
goto error;
|
|
else
|
|
CloseServiceHandle (hService);
|
|
|
|
hService = OpenService (hManager, L"veracrypt", SERVICE_ALL_ACCESS);
|
|
if (hService == NULL)
|
|
goto error;
|
|
|
|
#ifdef SETUP
|
|
StatusMessage (hwndDlg, "STARTING_DRIVER");
|
|
#endif
|
|
|
|
bRet = StartService (hService, 0, NULL);
|
|
if (bRet == FALSE)
|
|
goto error;
|
|
|
|
bOK = TRUE;
|
|
|
|
error:
|
|
if (bOK == FALSE && GetLastError () != ERROR_SERVICE_ALREADY_RUNNING)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
MessageBoxW (hwndDlg, GetString ("DRIVER_INSTALL_FAILED"), lpszTitle, MB_ICONHAND);
|
|
}
|
|
else
|
|
bOK = TRUE;
|
|
|
|
if (hService != NULL)
|
|
CloseServiceHandle (hService);
|
|
|
|
if (hManager != NULL)
|
|
CloseServiceHandle (hManager);
|
|
|
|
return bOK;
|
|
}
|
|
|
|
|
|
// Install and start driver service and mark it for removal (non-install mode)
|
|
static int DriverLoad ()
|
|
{
|
|
HANDLE file;
|
|
WIN32_FIND_DATA find;
|
|
SC_HANDLE hManager, hService = NULL;
|
|
wchar_t driverPath[TC_MAX_PATH*2];
|
|
BOOL res;
|
|
wchar_t *tmp;
|
|
DWORD startType;
|
|
|
|
if (ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", L"Start", &startType) && startType == SERVICE_BOOT_START)
|
|
return ERR_PARAMETER_INCORRECT;
|
|
|
|
GetModuleFileName (NULL, driverPath, ARRAYSIZE (driverPath));
|
|
tmp = wcsrchr (driverPath, L'\\');
|
|
if (!tmp)
|
|
{
|
|
driverPath[0] = L'.';
|
|
driverPath[1] = 0;
|
|
}
|
|
else
|
|
*tmp = 0;
|
|
|
|
StringCbCatW (driverPath, sizeof(driverPath), !Is64BitOs () ? L"\\veracrypt.sys" : IsARM()? L"\\veracrypt-arm64.sys" : L"\\veracrypt-x64.sys");
|
|
|
|
file = FindFirstFile (driverPath, &find);
|
|
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
{
|
|
MessageBoxW (0, GetString ("DRIVER_NOT_FOUND"), lpszTitle, ICON_HAND);
|
|
return ERR_DONT_REPORT;
|
|
}
|
|
|
|
FindClose (file);
|
|
|
|
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hManager == NULL)
|
|
{
|
|
if (GetLastError () == ERROR_ACCESS_DENIED)
|
|
{
|
|
MessageBoxW (0, GetString ("ADMIN_PRIVILEGES_DRIVER"), lpszTitle, ICON_HAND);
|
|
return ERR_DONT_REPORT;
|
|
}
|
|
|
|
return ERR_OS_ERROR;
|
|
}
|
|
|
|
hService = OpenService (hManager, L"veracrypt", SERVICE_ALL_ACCESS);
|
|
if (hService != NULL)
|
|
{
|
|
// Remove stale service (driver is not loaded but service exists)
|
|
DeleteService (hService);
|
|
CloseServiceHandle (hService);
|
|
Sleep (500);
|
|
}
|
|
|
|
hService = CreateService (hManager, L"veracrypt", L"veracrypt",
|
|
SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
|
|
driverPath, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if (hService == NULL)
|
|
{
|
|
CloseServiceHandle (hManager);
|
|
return ERR_OS_ERROR;
|
|
}
|
|
|
|
res = StartService (hService, 0, NULL);
|
|
DeleteService (hService);
|
|
|
|
CloseServiceHandle (hManager);
|
|
CloseServiceHandle (hService);
|
|
|
|
return !res ? ERR_OS_ERROR : ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL DriverUnload ()
|
|
{
|
|
MOUNT_LIST_STRUCT driver;
|
|
int refCount;
|
|
int volumesMounted;
|
|
DWORD dwResult;
|
|
BOOL bResult;
|
|
|
|
SC_HANDLE hManager, hService = NULL;
|
|
BOOL bRet;
|
|
SERVICE_STATUS status;
|
|
int x;
|
|
BOOL driverUnloaded = FALSE;
|
|
|
|
if (hDriver == INVALID_HANDLE_VALUE)
|
|
return TRUE;
|
|
|
|
try
|
|
{
|
|
if (BootEncryption (NULL).GetStatus().DeviceFilterActive)
|
|
return FALSE;
|
|
}
|
|
catch (...) { }
|
|
|
|
// Test for mounted volumes
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_IS_ANY_VOLUME_MOUNTED, NULL, 0, &volumesMounted, sizeof (volumesMounted), &dwResult, NULL);
|
|
|
|
if (!bResult)
|
|
{
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES, NULL, 0, &driver, sizeof (driver), &dwResult, NULL);
|
|
if (bResult)
|
|
volumesMounted = driver.ulMountedDrives;
|
|
}
|
|
|
|
if (bResult)
|
|
{
|
|
if (volumesMounted != 0)
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
|
|
// Test for any applications attached to driver
|
|
refCount = GetDriverRefCount ();
|
|
|
|
if (refCount > 1)
|
|
return FALSE;
|
|
|
|
CloseHandle (hDriver);
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
|
|
// Stop driver service
|
|
|
|
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hManager == NULL)
|
|
goto error;
|
|
|
|
hService = OpenService (hManager, L"veracrypt", SERVICE_ALL_ACCESS);
|
|
if (hService == NULL)
|
|
goto error;
|
|
|
|
bRet = QueryServiceStatus (hService, &status);
|
|
if (bRet != TRUE)
|
|
goto error;
|
|
|
|
if (status.dwCurrentState != SERVICE_STOPPED)
|
|
{
|
|
ControlService (hService, SERVICE_CONTROL_STOP, &status);
|
|
|
|
for (x = 0; x < 10; x++)
|
|
{
|
|
bRet = QueryServiceStatus (hService, &status);
|
|
if (bRet != TRUE)
|
|
goto error;
|
|
|
|
if (status.dwCurrentState == SERVICE_STOPPED)
|
|
{
|
|
driverUnloaded = TRUE;
|
|
break;
|
|
}
|
|
|
|
Sleep (200);
|
|
}
|
|
}
|
|
else
|
|
driverUnloaded = TRUE;
|
|
|
|
error:
|
|
if (hService != NULL)
|
|
CloseServiceHandle (hService);
|
|
|
|
if (hManager != NULL)
|
|
CloseServiceHandle (hManager);
|
|
|
|
if (driverUnloaded)
|
|
{
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int DriverAttach (void)
|
|
{
|
|
/* Try to open a handle to the device driver. It will be closed later. */
|
|
|
|
#ifndef SETUP
|
|
|
|
int nLoadRetryCount = 0;
|
|
start:
|
|
|
|
#endif
|
|
|
|
hDriver = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (hDriver == INVALID_HANDLE_VALUE)
|
|
{
|
|
#ifndef SETUP
|
|
|
|
LoadSysEncSettings ();
|
|
|
|
if (!CreateDriverSetupMutex ())
|
|
{
|
|
// Another instance is already attempting to install, register or start the driver
|
|
|
|
while (!CreateDriverSetupMutex ())
|
|
{
|
|
Sleep (100); // Wait until the other instance finishes
|
|
}
|
|
|
|
// Try to open a handle to the driver again (keep the mutex in case the other instance failed)
|
|
goto start;
|
|
}
|
|
else
|
|
{
|
|
// No other instance is currently attempting to install, register or start the driver
|
|
|
|
if (SystemEncryptionStatus != SYSENC_STATUS_NONE)
|
|
{
|
|
// This is an inconsistent state. The config file indicates system encryption should be
|
|
// active, but the driver is not running. This may happen e.g. when the pretest fails and
|
|
// the user selects "Last Known Good Configuration" from the Windows boot menu.
|
|
// To fix this, we're going to reinstall the driver, start it, and register it for boot.
|
|
|
|
if (DoDriverInstall (NULL))
|
|
{
|
|
Sleep (1000);
|
|
hDriver = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
try
|
|
{
|
|
BootEncryption bootEnc (NULL);
|
|
bootEnc.RegisterBootDriver (bootEnc.GetHiddenOSCreationPhase() != TC_HIDDEN_OS_CREATION_PHASE_NONE ? true : false);
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (NULL);
|
|
}
|
|
}
|
|
|
|
CloseDriverSetupMutex ();
|
|
}
|
|
else
|
|
{
|
|
// Attempt to load the driver (non-install/portable mode)
|
|
load:
|
|
BOOL res = DriverLoad ();
|
|
|
|
CloseDriverSetupMutex ();
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
return res;
|
|
|
|
bPortableModeConfirmed = TRUE;
|
|
|
|
if (hDriver != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hDriver);
|
|
hDriver = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
}
|
|
|
|
if (bPortableModeConfirmed)
|
|
NotifyDriverOfPortableMode ();
|
|
}
|
|
|
|
#endif // #ifndef SETUP
|
|
|
|
if (hDriver == INVALID_HANDLE_VALUE)
|
|
return ERR_OS_ERROR;
|
|
}
|
|
|
|
CloseDriverSetupMutex ();
|
|
|
|
if (hDriver != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwResult;
|
|
|
|
BOOL bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &DriverVersion, sizeof (DriverVersion), &dwResult, NULL);
|
|
|
|
if (!bResult)
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_LEGACY_GET_DRIVER_VERSION, NULL, 0, &DriverVersion, sizeof (DriverVersion), &dwResult, NULL);
|
|
|
|
#ifndef SETUP // Don't check version during setup to allow removal of another version
|
|
if (bResult == FALSE)
|
|
{
|
|
return ERR_OS_ERROR;
|
|
}
|
|
else if (DriverVersion != VERSION_NUM)
|
|
{
|
|
// Unload an incompatbile version of the driver loaded in non-install mode and load the required version
|
|
if (IsNonInstallMode () && CreateDriverSetupMutex () && DriverUnload () && nLoadRetryCount++ < 3)
|
|
goto load;
|
|
|
|
#ifdef TCMOUNT
|
|
// don't fail in case of service. This solves issues during upgrade when system encryption is enabled
|
|
if (!ServiceMode)
|
|
#endif
|
|
{
|
|
CloseDriverSetupMutex ();
|
|
CloseHandle (hDriver);
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
return ERR_DRIVER_VERSION;
|
|
}
|
|
}
|
|
#else
|
|
if (!bResult)
|
|
DriverVersion = 0;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void ResetCurrentDirectory ()
|
|
{
|
|
wchar_t p[MAX_PATH];
|
|
if (!IsNonInstallMode () && SHGetFolderPath (NULL, CSIDL_PROFILE, NULL, 0, p) == ERROR_SUCCESS)
|
|
{
|
|
SetCurrentDirectory (p);
|
|
}
|
|
else
|
|
{
|
|
GetModPath (p, ARRAYSIZE (p));
|
|
SetCurrentDirectory (p);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL BrowseFiles (HWND hwndDlg, char *stringId, wchar_t *lpszFileName, BOOL keepHistory, BOOL saveMode, wchar_t *browseFilter)
|
|
{
|
|
return BrowseFilesInDir (hwndDlg, stringId, NULL, lpszFileName, keepHistory, saveMode, browseFilter);
|
|
}
|
|
|
|
|
|
BOOL BrowseFilesInDir (HWND hwndDlg, char *stringId, wchar_t *initialDir, wchar_t *lpszFileName, BOOL keepHistory, BOOL saveMode, wchar_t *browseFilter, const wchar_t *initialFileName, const wchar_t *defaultExtension)
|
|
{
|
|
OPENFILENAMEW ofn;
|
|
wchar_t file[TC_MAX_PATH] = { 0 };
|
|
wchar_t filter[1024];
|
|
BOOL status = FALSE;
|
|
|
|
CoInitialize (NULL);
|
|
|
|
ZeroMemory (&ofn, sizeof (ofn));
|
|
*lpszFileName = 0;
|
|
|
|
if (initialDir)
|
|
{
|
|
ofn.lpstrInitialDir = initialDir;
|
|
}
|
|
|
|
if (initialFileName)
|
|
StringCchCopyW (file, array_capacity (file), initialFileName);
|
|
|
|
ofn.lStructSize = sizeof (ofn);
|
|
ofn.hwndOwner = hwndDlg;
|
|
|
|
StringCbPrintfW (filter, sizeof(filter), L"%ls (*.*)%c*.*%c%ls (*.hc)%c*.hc%c%c",
|
|
GetString ("ALL_FILES"), 0, 0, GetString ("TC_VOLUMES"), 0, 0, 0);
|
|
ofn.lpstrFilter = browseFilter ? browseFilter : filter;
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = file;
|
|
ofn.nMaxFile = sizeof (file) / sizeof (file[0]);
|
|
ofn.lpstrTitle = GetString (stringId);
|
|
ofn.lpstrDefExt = defaultExtension;
|
|
ofn.Flags = OFN_HIDEREADONLY
|
|
| OFN_PATHMUSTEXIST
|
|
| (keepHistory ? 0 : OFN_DONTADDTORECENT)
|
|
| (saveMode ? OFN_OVERWRITEPROMPT : 0);
|
|
|
|
if (!keepHistory)
|
|
CleanLastVisitedMRU ();
|
|
|
|
SystemFileSelectorCallerThreadId = GetCurrentThreadId();
|
|
SystemFileSelectorCallPending = TRUE;
|
|
|
|
if (!saveMode)
|
|
{
|
|
if (!GetOpenFileNameW (&ofn))
|
|
goto ret;
|
|
}
|
|
else
|
|
{
|
|
if (!GetSaveFileNameW (&ofn))
|
|
goto ret;
|
|
}
|
|
|
|
SystemFileSelectorCallPending = FALSE;
|
|
|
|
StringCchCopyW (lpszFileName, MAX_PATH, file);
|
|
|
|
if (!keepHistory)
|
|
CleanLastVisitedMRU ();
|
|
|
|
status = TRUE;
|
|
|
|
ret:
|
|
SystemFileSelectorCallPending = FALSE;
|
|
ResetCurrentDirectory();
|
|
CoUninitialize();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
static wchar_t SelectMultipleFilesPath[131072];
|
|
static int SelectMultipleFilesOffset;
|
|
|
|
BOOL SelectMultipleFiles (HWND hwndDlg, const char *stringId, wchar_t *lpszFileName, size_t cbFileName,BOOL keepHistory)
|
|
{
|
|
OPENFILENAMEW ofn;
|
|
wchar_t filter[1024];
|
|
BOOL status = FALSE;
|
|
|
|
CoInitialize (NULL);
|
|
|
|
ZeroMemory (&ofn, sizeof (ofn));
|
|
|
|
SelectMultipleFilesPath[0] = 0;
|
|
*lpszFileName = 0;
|
|
ofn.lStructSize = sizeof (ofn);
|
|
ofn.hwndOwner = hwndDlg;
|
|
StringCbPrintfW (filter, sizeof(filter), L"%ls (*.*)%c*.*%c%ls (*.hc)%c*.hc%c%c",
|
|
GetString ("ALL_FILES"), 0, 0, GetString ("TC_VOLUMES"), 0, 0, 0);
|
|
ofn.lpstrFilter = filter;
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = SelectMultipleFilesPath;
|
|
ofn.nMaxFile = 0xffff * 2; // The size must not exceed 0xffff*2 due to a bug in Windows 2000 and XP SP1
|
|
ofn.lpstrTitle = GetString (stringId);
|
|
ofn.Flags = OFN_HIDEREADONLY
|
|
| OFN_EXPLORER
|
|
| OFN_PATHMUSTEXIST
|
|
| OFN_ALLOWMULTISELECT
|
|
| (keepHistory ? 0 : OFN_DONTADDTORECENT);
|
|
|
|
if (!keepHistory)
|
|
CleanLastVisitedMRU ();
|
|
|
|
SystemFileSelectorCallerThreadId = GetCurrentThreadId();
|
|
SystemFileSelectorCallPending = TRUE;
|
|
|
|
if (!GetOpenFileNameW (&ofn))
|
|
goto ret;
|
|
|
|
SystemFileSelectorCallPending = FALSE;
|
|
|
|
if (SelectMultipleFilesPath[ofn.nFileOffset - 1] != 0)
|
|
{
|
|
// Single file selected
|
|
StringCbCopyW (lpszFileName, cbFileName, SelectMultipleFilesPath);
|
|
SelectMultipleFilesOffset = 0;
|
|
SecureZeroMemory (SelectMultipleFilesPath, sizeof (SelectMultipleFilesPath));
|
|
}
|
|
else
|
|
{
|
|
// Multiple files selected
|
|
SelectMultipleFilesOffset = ofn.nFileOffset;
|
|
SelectMultipleFilesNext (lpszFileName, cbFileName);
|
|
}
|
|
|
|
if (!keepHistory)
|
|
CleanLastVisitedMRU ();
|
|
|
|
status = TRUE;
|
|
|
|
ret:
|
|
SystemFileSelectorCallPending = FALSE;
|
|
ResetCurrentDirectory();
|
|
CoUninitialize();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
BOOL SelectMultipleFilesNext (wchar_t *lpszFileName, size_t cbFileName)
|
|
{
|
|
if (SelectMultipleFilesOffset == 0)
|
|
return FALSE;
|
|
|
|
StringCbCopyW (lpszFileName, cbFileName,SelectMultipleFilesPath);
|
|
lpszFileName[TC_MAX_PATH - 1] = 0;
|
|
|
|
if (lpszFileName[wcslen (lpszFileName) - 1] != L'\\')
|
|
StringCbCatW (lpszFileName, cbFileName,L"\\");
|
|
|
|
StringCbCatW (lpszFileName, cbFileName,SelectMultipleFilesPath + SelectMultipleFilesOffset);
|
|
|
|
SelectMultipleFilesOffset += (int) wcslen (SelectMultipleFilesPath + SelectMultipleFilesOffset) + 1;
|
|
if (SelectMultipleFilesPath[SelectMultipleFilesOffset] == 0)
|
|
{
|
|
SelectMultipleFilesOffset = 0;
|
|
SecureZeroMemory (SelectMultipleFilesPath, sizeof (SelectMultipleFilesPath));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM pData)
|
|
{
|
|
switch(uMsg) {
|
|
case BFFM_INITIALIZED:
|
|
{
|
|
/* WParam is TRUE since we are passing a path.
|
|
It would be FALSE if we were passing a pidl. */
|
|
SendMessageW (hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)pData);
|
|
break;
|
|
}
|
|
|
|
case BFFM_SELCHANGED:
|
|
{
|
|
wchar_t szDir[TC_MAX_PATH];
|
|
|
|
/* Set the status window to the currently selected path. */
|
|
if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
|
|
{
|
|
SendMessage (hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL BrowseDirectories (HWND hwndDlg, char *lpszTitle, wchar_t *dirName)
|
|
{
|
|
BROWSEINFOW bi;
|
|
LPITEMIDLIST pidl;
|
|
LPMALLOC pMalloc;
|
|
BOOL bOK = FALSE;
|
|
|
|
CoInitialize (NULL);
|
|
|
|
if (SUCCEEDED (SHGetMalloc (&pMalloc)))
|
|
{
|
|
ZeroMemory (&bi, sizeof(bi));
|
|
bi.hwndOwner = hwndDlg;
|
|
bi.pszDisplayName = 0;
|
|
bi.lpszTitle = GetString (lpszTitle);
|
|
bi.pidlRoot = 0;
|
|
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
|
|
bi.lpfn = BrowseCallbackProc;
|
|
bi.lParam = (LPARAM)dirName;
|
|
|
|
pidl = SHBrowseForFolderW (&bi);
|
|
if (pidl != NULL)
|
|
{
|
|
if (SHGetPathFromIDList(pidl, dirName))
|
|
{
|
|
bOK = TRUE;
|
|
}
|
|
|
|
pMalloc->Free (pidl);
|
|
pMalloc->Release();
|
|
}
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
return bOK;
|
|
}
|
|
|
|
|
|
std::wstring GetWrongPasswordErrorMessage (HWND hwndDlg)
|
|
{
|
|
WCHAR szTmp[8192];
|
|
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_WRONG" : "PASSWORD_WRONG"));
|
|
if (CheckCapsLock (hwndDlg, TRUE))
|
|
StringCbCatW (szTmp, sizeof(szTmp), GetString ("PASSWORD_WRONG_CAPSLOCK_ON"));
|
|
|
|
#ifdef TCMOUNT
|
|
wchar_t szDevicePath [TC_MAX_PATH+1] = {0};
|
|
GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), szDevicePath, ARRAYSIZE (szDevicePath));
|
|
|
|
if (TCBootLoaderOnInactiveSysEncDrive (szDevicePath))
|
|
{
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_OR_MODE_WRONG" : "PASSWORD_OR_MODE_WRONG"));
|
|
|
|
if (CheckCapsLock (hwndDlg, TRUE))
|
|
StringCbCatW (szTmp, sizeof(szTmp), GetString ("PASSWORD_WRONG_CAPSLOCK_ON"));
|
|
|
|
StringCbCatW (szTmp, sizeof(szTmp), GetString ("SYSENC_MOUNT_WITHOUT_PBA_NOTE"));
|
|
}
|
|
#endif
|
|
|
|
wstring msg = szTmp;
|
|
|
|
#ifdef TCMOUNT
|
|
if (KeyFilesEnable && HiddenFilesPresentInKeyfilePath)
|
|
{
|
|
msg += GetString ("HIDDEN_FILES_PRESENT_IN_KEYFILE_PATH");
|
|
HiddenFilesPresentInKeyfilePath = FALSE;
|
|
}
|
|
#endif
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
void handleError (HWND hwndDlg, int code, const char* srcPos)
|
|
{
|
|
WCHAR szTmp[4096];
|
|
|
|
if (Silent) return;
|
|
|
|
switch (code & 0x0000FFFF)
|
|
{
|
|
case ERR_OS_ERROR:
|
|
handleWin32Error (hwndDlg, srcPos);
|
|
break;
|
|
case ERR_OUTOFMEMORY:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("OUTOFMEMORY"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
|
|
case ERR_PASSWORD_WRONG:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetWrongPasswordErrorMessage (hwndDlg).c_str(), srcPos).c_str(), lpszTitle, MB_ICONWARNING);
|
|
break;
|
|
|
|
case ERR_DRIVE_NOT_FOUND:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("NOT_FOUND"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_FILES_OPEN:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("OPENFILES_DRIVER"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_FILES_OPEN_LOCK:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("OPENFILES_LOCK"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_VOL_SIZE_WRONG:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_SIZE_WRONG"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_COMPRESSION_NOT_SUPPORTED:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("COMPRESSION_NOT_SUPPORTED"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_PASSWORD_CHANGE_VOL_TYPE:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("WRONG_VOL_TYPE"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_VOL_SEEKING:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_SEEKING"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_CIPHER_INIT_FAILURE:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("ERR_CIPHER_INIT_FAILURE"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_CIPHER_INIT_WEAK_KEY:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("ERR_CIPHER_INIT_WEAK_KEY"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_VOL_ALREADY_MOUNTED:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_ALREADY_MOUNTED"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_FILE_OPEN_FAILED:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("FILE_OPEN_FAILED"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_VOL_MOUNT_FAILED:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_MOUNT_FAILED"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_NO_FREE_DRIVES:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("NO_FREE_DRIVES"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
case ERR_ACCESS_DENIED:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("ACCESS_DENIED"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
|
|
case ERR_DRIVER_VERSION:
|
|
Error ("DRIVER_VERSION", hwndDlg);
|
|
break;
|
|
|
|
case ERR_NEW_VERSION_REQUIRED:
|
|
MessageBoxW (hwndDlg, AppendSrcPos (GetString ("NEW_VERSION_REQUIRED"), srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
|
|
case ERR_SELF_TESTS_FAILED:
|
|
Error ("ERR_SELF_TESTS_FAILED", hwndDlg);
|
|
break;
|
|
|
|
case ERR_VOL_FORMAT_BAD:
|
|
Error ("ERR_VOL_FORMAT_BAD", hwndDlg);
|
|
break;
|
|
|
|
case ERR_ENCRYPTION_NOT_COMPLETED:
|
|
Error ("ERR_ENCRYPTION_NOT_COMPLETED", hwndDlg);
|
|
break;
|
|
|
|
case ERR_NONSYS_INPLACE_ENC_INCOMPLETE:
|
|
Error ("ERR_NONSYS_INPLACE_ENC_INCOMPLETE", hwndDlg);
|
|
break;
|
|
|
|
case ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG:
|
|
Error ("ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG", hwndDlg);
|
|
break;
|
|
|
|
case ERR_PARAMETER_INCORRECT:
|
|
Error ("ERR_PARAMETER_INCORRECT", hwndDlg);
|
|
break;
|
|
|
|
case ERR_USER_ABORT:
|
|
case ERR_DONT_REPORT:
|
|
// A non-error
|
|
break;
|
|
|
|
case ERR_UNSUPPORTED_TRUECRYPT_FORMAT:
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("UNSUPPORTED_TRUECRYPT_FORMAT"), (code >> 24), (code >> 16) & 0x000000FF);
|
|
MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
break;
|
|
|
|
#ifndef SETUP
|
|
case ERR_RAND_INIT_FAILED:
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("INIT_RAND"), SRC_POS, GetLastError ());
|
|
MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, MB_ICONERROR);
|
|
break;
|
|
|
|
case ERR_CAPI_INIT_FAILED:
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("CAPI_RAND"), SRC_POS, CryptoAPILastError);
|
|
MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, MB_ICONERROR);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("ERR_UNKNOWN"), code);
|
|
MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, ICON_HAND);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CheckFileStreamWriteErrors (HWND hwndDlg, FILE *file, const wchar_t *fileName)
|
|
{
|
|
if (ferror (file))
|
|
{
|
|
wchar_t s[TC_MAX_PATH];
|
|
StringCbPrintfW (s, sizeof (s), GetString ("CANNOT_WRITE_FILE_X"), fileName);
|
|
ErrorDirect (s, hwndDlg);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static BOOL CALLBACK LocalizeDialogEnum( HWND hwnd, LPARAM font)
|
|
{
|
|
// Localization of controls
|
|
|
|
if (LocalizationActive)
|
|
{
|
|
int ctrlId = GetDlgCtrlID (hwnd);
|
|
if (ctrlId != 0)
|
|
{
|
|
WCHAR name[10] = { 0 };
|
|
GetClassNameW (hwnd, name, array_capacity (name));
|
|
|
|
if (_wcsicmp (name, L"Button") == 0 || _wcsicmp (name, L"Static") == 0)
|
|
{
|
|
wchar_t *str = (wchar_t *) GetDictionaryValueByInt (ctrlId);
|
|
if (str != NULL)
|
|
SetWindowTextW (hwnd, str);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Font
|
|
SendMessageW (hwnd, WM_SETFONT, (WPARAM) font, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void LocalizeDialog (HWND hwnd, char *stringId)
|
|
{
|
|
LastDialogId = stringId;
|
|
SetWindowLongPtrW (hwnd, GWLP_USERDATA, (LONG_PTR) 'VERA');
|
|
SendMessageW (hwnd, WM_SETFONT, (WPARAM) hUserFont, 0);
|
|
|
|
if (stringId == NULL)
|
|
SetWindowTextW (hwnd, L"VeraCrypt");
|
|
else
|
|
SetWindowTextW (hwnd, GetString (stringId));
|
|
|
|
if (hUserFont != 0)
|
|
EnumChildWindows (hwnd, LocalizeDialogEnum, (LPARAM) hUserFont);
|
|
}
|
|
|
|
void OpenVolumeExplorerWindow (int driveNo)
|
|
{
|
|
wchar_t dosName[5];
|
|
SHFILEINFO fInfo;
|
|
|
|
StringCbPrintfW (dosName, sizeof(dosName), L"%c:\\", (wchar_t) driveNo + L'A');
|
|
|
|
// Force explorer to discover the drive
|
|
SHGetFileInfo (dosName, 0, &fInfo, sizeof (fInfo), 0);
|
|
|
|
SafeOpenURL (dosName);
|
|
}
|
|
|
|
static BOOL explorerCloseSent;
|
|
static HWND explorerTopLevelWindow;
|
|
|
|
static BOOL CALLBACK CloseVolumeExplorerWindowsChildEnum (HWND hwnd, LPARAM driveStr)
|
|
{
|
|
WCHAR s[MAX_PATH];
|
|
SendMessageW (hwnd, WM_GETTEXT, array_capacity (s), (LPARAM) s);
|
|
|
|
if (wcsstr (s, (WCHAR *) driveStr) != NULL)
|
|
{
|
|
PostMessageW (explorerTopLevelWindow, WM_CLOSE, 0, 0);
|
|
explorerCloseSent = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL CALLBACK CloseVolumeExplorerWindowsEnum (HWND hwnd, LPARAM driveNo)
|
|
{
|
|
WCHAR driveStr[10];
|
|
WCHAR s[MAX_PATH];
|
|
|
|
StringCbPrintfW (driveStr, sizeof(driveStr), L"%c:\\", driveNo + L'A');
|
|
|
|
GetClassNameW (hwnd, s, array_capacity (s));
|
|
if (wcscmp (s, L"CabinetWClass") == 0)
|
|
{
|
|
GetWindowTextW (hwnd, s, array_capacity (s));
|
|
if (wcsstr (s, driveStr) != NULL)
|
|
{
|
|
PostMessageW (hwnd, WM_CLOSE, 0, 0);
|
|
explorerCloseSent = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
explorerTopLevelWindow = hwnd;
|
|
EnumChildWindows (hwnd, CloseVolumeExplorerWindowsChildEnum, (LPARAM) driveStr);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CloseVolumeExplorerWindows (HWND hwnd, int driveNo)
|
|
{
|
|
if (driveNo >= 0)
|
|
{
|
|
explorerCloseSent = FALSE;
|
|
EnumWindows (CloseVolumeExplorerWindowsEnum, (LPARAM) driveNo);
|
|
}
|
|
|
|
return explorerCloseSent;
|
|
}
|
|
|
|
BOOL UpdateDriveCustomLabel (int driveNo, wchar_t* effectiveLabel, BOOL bSetValue)
|
|
{
|
|
wchar_t wszRegPath[MAX_PATH];
|
|
wchar_t driveStr[] = {L'A' + (wchar_t) driveNo, 0};
|
|
HKEY hKey;
|
|
LSTATUS lStatus;
|
|
DWORD cbLabelLen = (DWORD) ((wcslen (effectiveLabel) + 1) * sizeof (wchar_t));
|
|
BOOL bToBeDeleted = FALSE;
|
|
|
|
StringCbPrintfW (wszRegPath, sizeof (wszRegPath), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons\\%s\\DefaultLabel", driveStr);
|
|
|
|
if (bSetValue)
|
|
lStatus = RegCreateKeyExW (HKEY_CURRENT_USER, wszRegPath, NULL, NULL, 0,
|
|
KEY_READ | KEY_WRITE | KEY_SET_VALUE, NULL, &hKey, NULL);
|
|
else
|
|
lStatus = RegOpenKeyExW (HKEY_CURRENT_USER, wszRegPath, 0, KEY_READ | KEY_WRITE | KEY_SET_VALUE, &hKey);
|
|
if (ERROR_SUCCESS == lStatus)
|
|
{
|
|
if (bSetValue)
|
|
lStatus = RegSetValueExW (hKey, NULL, NULL, REG_SZ, (LPCBYTE) effectiveLabel, cbLabelLen);
|
|
else
|
|
{
|
|
wchar_t storedLabel[34] = {0};
|
|
DWORD cbStoredLen = sizeof (storedLabel) - 1, dwType;
|
|
lStatus = RegQueryValueExW (hKey, NULL, NULL, &dwType, (LPBYTE) storedLabel, &cbStoredLen);
|
|
if ((ERROR_SUCCESS == lStatus) && (REG_SZ == dwType) && (0 == wcscmp(storedLabel, effectiveLabel)))
|
|
{
|
|
// same label stored. mark key for deletion
|
|
bToBeDeleted = TRUE;
|
|
}
|
|
}
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
if (bToBeDeleted)
|
|
{
|
|
StringCbPrintfW (wszRegPath, sizeof (wszRegPath), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons\\%s", driveStr);
|
|
lStatus = RegOpenKeyExW (HKEY_CURRENT_USER, wszRegPath, 0, KEY_READ | KEY_WRITE | KEY_SET_VALUE, &hKey);
|
|
if (ERROR_SUCCESS == lStatus)
|
|
{
|
|
lStatus = RegDeleteKeyW (hKey, L"DefaultLabel");
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
// delete drive letter of nothing else is present under it
|
|
RegDeleteKeyW (HKEY_CURRENT_USER, wszRegPath);
|
|
|
|
}
|
|
|
|
return (ERROR_SUCCESS == lStatus)? TRUE : FALSE;
|
|
}
|
|
|
|
wstring GetUserFriendlyVersionString (int version)
|
|
{
|
|
wchar_t szTmp [64];
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), L"%x", version);
|
|
|
|
wstring versionString (szTmp);
|
|
|
|
versionString.insert (version > 0xfff ? 2 : 1,L".");
|
|
|
|
return (versionString);
|
|
}
|
|
|
|
wstring IntToWideString (int val)
|
|
{
|
|
wchar_t szTmp [64];
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), L"%d", val);
|
|
|
|
return szTmp;
|
|
}
|
|
|
|
wstring ArrayToHexWideString (const unsigned char* pbData, int cbData)
|
|
{
|
|
static wchar_t* hexChar = L"0123456789ABCDEF";
|
|
wstring result;
|
|
if (pbData)
|
|
{
|
|
for (int i = 0; i < cbData; i++)
|
|
{
|
|
result += hexChar[pbData[i] >> 4];
|
|
result += hexChar[pbData[i] & 0x0F];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool HexToByte (wchar_t c, byte& b)
|
|
{
|
|
bool bRet = true;
|
|
if (c >= L'0' && c <= L'9')
|
|
b = (byte) (c - L'0');
|
|
else if (c >= L'a' && c <= L'z')
|
|
b = (byte) (c - L'a' + 10);
|
|
else if (c >= L'A' && c <= L'Z')
|
|
b = (byte) (c - L'A' + 10);
|
|
else
|
|
bRet = false;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
bool HexWideStringToArray (const wchar_t* hexStr, std::vector<byte>& arr)
|
|
{
|
|
byte b1, b2;
|
|
size_t i, len = wcslen (hexStr);
|
|
|
|
arr.clear();
|
|
if (len %2)
|
|
return false;
|
|
|
|
for (i = 0; i < len/2; i++)
|
|
{
|
|
if (!HexToByte (*hexStr++, b1) || !HexToByte (*hexStr++, b2))
|
|
return false;
|
|
arr.push_back (b1 << 4 | b2);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
wstring GetTempPathString ()
|
|
{
|
|
wchar_t tempPath[MAX_PATH];
|
|
DWORD tempLen = ::GetTempPath (ARRAYSIZE (tempPath), tempPath);
|
|
if (tempLen == 0 || tempLen > ARRAYSIZE (tempPath))
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
return wstring (tempPath);
|
|
}
|
|
|
|
void GetSizeString (unsigned __int64 size, wchar_t *str, size_t cbStr)
|
|
{
|
|
static wchar_t *b, *kb, *mb, *gb, *tb, *pb;
|
|
static int serNo;
|
|
|
|
if (b == NULL || serNo != LocalizationSerialNo)
|
|
{
|
|
serNo = LocalizationSerialNo;
|
|
kb = GetString ("KB");
|
|
mb = GetString ("MB");
|
|
gb = GetString ("GB");
|
|
tb = GetString ("TB");
|
|
pb = GetString ("PB");
|
|
b = GetString ("BYTE");
|
|
}
|
|
|
|
if (size > 1024I64*1024*1024*1024*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", size/1024/1024/1024/1024/1024, pb);
|
|
else if (size > 1024I64*1024*1024*1024*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024/1024/1024/1024), pb);
|
|
else if (size > 1024I64*1024*1024*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s",size/1024/1024/1024/1024, tb);
|
|
else if (size > 1024I64*1024*1024*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024/1024/1024), tb);
|
|
else if (size > 1024I64*1024*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s",size/1024/1024/1024, gb);
|
|
else if (size > 1024I64*1024*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024/1024), gb);
|
|
else if (size > 1024I64*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", size/1024/1024, mb);
|
|
else if (size > 1024I64*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024), mb);
|
|
else if (size >= 1024I64)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", size/1024, kb);
|
|
else
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", size, b);
|
|
}
|
|
|
|
#ifndef SETUP
|
|
void GetSpeedString (unsigned __int64 speed, wchar_t *str, size_t cbStr)
|
|
{
|
|
static wchar_t *b, *kb, *mb, *gb, *tb, *pb;
|
|
static int serNo;
|
|
|
|
if (b == NULL || serNo != LocalizationSerialNo)
|
|
{
|
|
serNo = LocalizationSerialNo;
|
|
kb = GetString ("KB_PER_SEC");
|
|
mb = GetString ("MB_PER_SEC");
|
|
gb = GetString ("GB_PER_SEC");
|
|
tb = GetString ("TB_PER_SEC");
|
|
pb = GetString ("PB_PER_SEC");
|
|
b = GetString ("B_PER_SEC");
|
|
}
|
|
|
|
if (speed > 1024I64*1024*1024*1024*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", speed/1024/1024/1024/1024/1024, pb);
|
|
else if (speed > 1024I64*1024*1024*1024*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024/1024/1024/1024), pb);
|
|
else if (speed > 1024I64*1024*1024*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s",speed/1024/1024/1024/1024, tb);
|
|
else if (speed > 1024I64*1024*1024*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024/1024/1024), tb);
|
|
else if (speed > 1024I64*1024*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s",speed/1024/1024/1024, gb);
|
|
else if (speed > 1024I64*1024*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024/1024), gb);
|
|
else if (speed > 1024I64*1024*99)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", speed/1024/1024, mb);
|
|
else if (speed > 1024I64*1024)
|
|
StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024), mb);
|
|
else if (speed > 1024I64)
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", speed/1024, kb);
|
|
else
|
|
StringCbPrintfW (str, cbStr, L"%I64d %s", speed, b);
|
|
}
|
|
|
|
static void ResetBenchmarkList (HWND hwndDlg)
|
|
{
|
|
LVCOLUMNW LvCol;
|
|
|
|
HWND hList = GetDlgItem (hwndDlg, IDC_RESULTS);
|
|
|
|
/* Render the results */
|
|
// delete data
|
|
SendMessage (hList, LVM_DELETEALLITEMS, 0, 0);
|
|
// Delete headers
|
|
SendMessageW (hList, LVM_DELETECOLUMN, 1, 0);
|
|
SendMessageW (hList, LVM_DELETECOLUMN, 1, 0);
|
|
SendMessageW (hList, LVM_DELETECOLUMN, 1, 0);
|
|
|
|
memset (&LvCol,0,sizeof(LvCol));
|
|
LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
|
|
switch(benchmarkType) {
|
|
case BENCHMARK_TYPE_ENCRYPTION:
|
|
// Create headers
|
|
LvCol.pszText = GetString ("ENCRYPTION");
|
|
LvCol.cx = CompensateXDPI (80);
|
|
LvCol.fmt = LVCFMT_RIGHT;
|
|
SendMessageW (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("DECRYPTION");
|
|
LvCol.cx = CompensateXDPI (80);
|
|
LvCol.fmt = LVCFMT_RIGHT;
|
|
SendMessageW (hList,LVM_INSERTCOLUMNW,2,(LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("MEAN");
|
|
LvCol.cx = CompensateXDPI (80);
|
|
LvCol.fmt = LVCFMT_RIGHT;
|
|
SendMessageW (hList,LVM_INSERTCOLUMNW,3,(LPARAM)&LvCol);
|
|
break;
|
|
case BENCHMARK_TYPE_HASH:
|
|
LvCol.pszText = GetString ("MEAN");
|
|
LvCol.cx = CompensateXDPI (80);
|
|
LvCol.fmt = LVCFMT_RIGHT;
|
|
SendMessageW (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol);
|
|
break;
|
|
case BENCHMARK_TYPE_PRF:
|
|
LvCol.pszText = GetString ("TIME");
|
|
LvCol.cx = CompensateXDPI (80);
|
|
LvCol.fmt = LVCFMT_RIGHT;
|
|
SendMessageW (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("ITERATIONS");
|
|
LvCol.cx = CompensateXDPI (80);
|
|
LvCol.fmt = LVCFMT_RIGHT;
|
|
SendMessageW (hList,LVM_INSERTCOLUMNW,2,(LPARAM)&LvCol);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void DisplayBenchmarkResults (HWND hwndDlg)
|
|
{
|
|
wchar_t item1[100]={0};
|
|
LVITEMW LvItem;
|
|
HWND hList = GetDlgItem (hwndDlg, IDC_RESULTS);
|
|
int ea, i;
|
|
BOOL unsorted = TRUE;
|
|
BENCHMARK_REC tmp_line;
|
|
|
|
ResetBenchmarkList (hwndDlg);
|
|
|
|
/* Sort the list */
|
|
|
|
switch (benchmarkSortMethod)
|
|
{
|
|
case BENCHMARK_SORT_BY_SPEED:
|
|
|
|
while (unsorted)
|
|
{
|
|
unsorted = FALSE;
|
|
for (i = 0; i < benchmarkTotalItems - 1; i++)
|
|
{
|
|
|
|
if (((benchmarkType == BENCHMARK_TYPE_PRF) && (benchmarkTable[i].meanBytesPerSec > benchmarkTable[i+1].meanBytesPerSec)) ||
|
|
((benchmarkType != BENCHMARK_TYPE_PRF) && (benchmarkTable[i].meanBytesPerSec < benchmarkTable[i+1].meanBytesPerSec))
|
|
)
|
|
{
|
|
unsorted = TRUE;
|
|
memcpy (&tmp_line, &benchmarkTable[i], sizeof(BENCHMARK_REC));
|
|
memcpy (&benchmarkTable[i], &benchmarkTable[i+1], sizeof(BENCHMARK_REC));
|
|
memcpy (&benchmarkTable[i+1], &tmp_line, sizeof(BENCHMARK_REC));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BENCHMARK_SORT_BY_NAME:
|
|
|
|
while (unsorted)
|
|
{
|
|
unsorted = FALSE;
|
|
for (i = 0; i < benchmarkTotalItems - 1; i++)
|
|
{
|
|
if (benchmarkTable[i].id > benchmarkTable[i+1].id)
|
|
{
|
|
unsorted = TRUE;
|
|
memcpy (&tmp_line, &benchmarkTable[i], sizeof(BENCHMARK_REC));
|
|
memcpy (&benchmarkTable[i], &benchmarkTable[i+1], sizeof(BENCHMARK_REC));
|
|
memcpy (&benchmarkTable[i+1], &tmp_line, sizeof(BENCHMARK_REC));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < benchmarkTotalItems; i++)
|
|
{
|
|
ea = benchmarkTable[i].id;
|
|
|
|
memset (&LvItem,0,sizeof(LvItem));
|
|
LvItem.mask = LVIF_TEXT;
|
|
LvItem.iItem = i;
|
|
LvItem.iSubItem = 0;
|
|
LvItem.pszText = (LPWSTR) benchmarkTable[i].name;
|
|
SendMessageW (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
|
|
switch(benchmarkType) {
|
|
case BENCHMARK_TYPE_ENCRYPTION:
|
|
GetSpeedString ((unsigned __int64) (benchmarkLastBufferSize / ((float) benchmarkTable[i].encSpeed / benchmarkPerformanceFrequency.QuadPart)), item1, sizeof(item1));
|
|
LvItem.iSubItem = 1;
|
|
LvItem.pszText = item1;
|
|
SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
|
|
|
|
GetSpeedString ((unsigned __int64) (benchmarkLastBufferSize / ((float) benchmarkTable[i].decSpeed / benchmarkPerformanceFrequency.QuadPart)), item1, sizeof(item1));
|
|
LvItem.iSubItem = 2;
|
|
LvItem.pszText = item1;
|
|
SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
|
|
|
|
GetSpeedString (benchmarkTable[i].meanBytesPerSec, item1, sizeof(item1));
|
|
LvItem.iSubItem = 3;
|
|
LvItem.pszText = item1;
|
|
SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
|
|
break;
|
|
case BENCHMARK_TYPE_HASH:
|
|
GetSpeedString (benchmarkTable[i].meanBytesPerSec, item1, sizeof(item1));
|
|
LvItem.iSubItem = 1;
|
|
LvItem.pszText = item1;
|
|
SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
|
|
break;
|
|
case BENCHMARK_TYPE_PRF:
|
|
swprintf_s (item1, sizeof(item1) / sizeof(item1[0]), L"%d ms", (int) benchmarkTable[i].meanBytesPerSec);
|
|
LvItem.iSubItem = 1;
|
|
LvItem.pszText = item1;
|
|
SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
|
|
swprintf_s (item1, sizeof(item1) / sizeof(item1[0]), L"%d", (int) benchmarkTable[i].decSpeed);
|
|
LvItem.iSubItem = 2;
|
|
LvItem.pszText = item1;
|
|
SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 2, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
SendMessageW(hList, LVM_SETCOLUMNWIDTH, 3, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
}
|
|
|
|
// specific implementation for support of benchmark operation in wait dialog mechanism
|
|
|
|
typedef struct
|
|
{
|
|
HWND hBenchDlg;
|
|
BOOL bStatus;
|
|
} BenchmarkThreadParam;
|
|
|
|
static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg);
|
|
|
|
void CALLBACK BenchmarkThreadProc(void* pArg, HWND hwndDlg)
|
|
{
|
|
BenchmarkThreadParam* pThreadParam = (BenchmarkThreadParam*) pArg;
|
|
|
|
pThreadParam->bStatus = PerformBenchmark (pThreadParam->hBenchDlg, hwndDlg);
|
|
}
|
|
|
|
static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
|
|
{
|
|
LARGE_INTEGER performanceCountStart, performanceCountEnd;
|
|
BYTE *lpTestBuffer = NULL;
|
|
PCRYPTO_INFO ci = NULL;
|
|
UINT64_STRUCT startDataUnitNo;
|
|
size_t cpuCount = GetCpuCount(NULL);
|
|
startDataUnitNo.Value = 0;
|
|
|
|
/* set priority to critical only when there are 2 or more CPUs on the system */
|
|
if (cpuCount > 1 && (benchmarkType != BENCHMARK_TYPE_ENCRYPTION))
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
|
|
|
ci = crypto_open ();
|
|
if (!ci)
|
|
return FALSE;
|
|
|
|
if (QueryPerformanceFrequency (&benchmarkPerformanceFrequency) == 0)
|
|
{
|
|
if (ci)
|
|
crypto_close (ci);
|
|
MessageBoxW (hwndDlg, GetString ("ERR_PERF_COUNTER"), lpszTitle, ICON_HAND);
|
|
return FALSE;
|
|
}
|
|
|
|
if (benchmarkType != BENCHMARK_TYPE_PRF)
|
|
{
|
|
lpTestBuffer = (BYTE *) _aligned_malloc(benchmarkBufferSize - (benchmarkBufferSize % 16), 16);
|
|
if (lpTestBuffer == NULL)
|
|
{
|
|
if (ci)
|
|
crypto_close (ci);
|
|
MessageBoxW (hwndDlg, GetString ("ERR_MEM_ALLOC"), lpszTitle, ICON_HAND);
|
|
return FALSE;
|
|
}
|
|
VirtualLock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16));
|
|
}
|
|
|
|
WaitCursor ();
|
|
benchmarkTotalItems = 0;
|
|
|
|
switch(benchmarkType) {
|
|
|
|
case BENCHMARK_TYPE_HASH:
|
|
/* Measures the speed at which each of the hash algorithms processes the message to produce
|
|
a single digest.
|
|
*/
|
|
{
|
|
BYTE digest [MAX_DIGESTSIZE];
|
|
WHIRLPOOL_CTX wctx;
|
|
blake2s_state bctx;
|
|
sha512_ctx s2ctx;
|
|
sha256_ctx s256ctx;
|
|
STREEBOG_CTX stctx;
|
|
|
|
int hid, i;
|
|
|
|
for (hid = FIRST_PRF_ID; hid <= LAST_PRF_ID; hid++)
|
|
{
|
|
if (QueryPerformanceCounter (&performanceCountStart) == 0)
|
|
goto counter_error;
|
|
|
|
for (i = 1; i <= 2; i++)
|
|
{
|
|
switch (hid)
|
|
{
|
|
|
|
case SHA512:
|
|
sha512_begin (&s2ctx);
|
|
sha512_hash (lpTestBuffer, benchmarkBufferSize, &s2ctx);
|
|
sha512_end ((unsigned char *) digest, &s2ctx);
|
|
break;
|
|
|
|
case SHA256:
|
|
sha256_begin (&s256ctx);
|
|
sha256_hash (lpTestBuffer, benchmarkBufferSize, &s256ctx);
|
|
sha256_end ((unsigned char *) digest, &s256ctx);
|
|
break;
|
|
|
|
case BLAKE2S:
|
|
blake2s_init(&bctx);
|
|
blake2s_update(&bctx, lpTestBuffer, benchmarkBufferSize);
|
|
blake2s_final(&bctx, (unsigned char *) digest);
|
|
break;
|
|
|
|
case WHIRLPOOL:
|
|
WHIRLPOOL_init (&wctx);
|
|
WHIRLPOOL_add (lpTestBuffer, benchmarkBufferSize, &wctx);
|
|
WHIRLPOOL_finalize (&wctx, (unsigned char *) digest);
|
|
break;
|
|
|
|
case STREEBOG:
|
|
STREEBOG_init(&stctx);
|
|
STREEBOG_add(&stctx, lpTestBuffer, benchmarkBufferSize);
|
|
STREEBOG_finalize(&stctx, (unsigned char *)digest);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (QueryPerformanceCounter (&performanceCountEnd) == 0)
|
|
goto counter_error;
|
|
|
|
benchmarkTable[benchmarkTotalItems].encSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
|
|
|
|
benchmarkTable[benchmarkTotalItems].decSpeed = benchmarkTable[benchmarkTotalItems].encSpeed;
|
|
benchmarkTable[benchmarkTotalItems].id = hid;
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (unsigned __int64) (benchmarkBufferSize / ((float) benchmarkTable[benchmarkTotalItems].encSpeed / benchmarkPerformanceFrequency.QuadPart / 2));
|
|
StringCbPrintfW (benchmarkTable[benchmarkTotalItems].name, sizeof(benchmarkTable[benchmarkTotalItems].name),L"%s", HashGetName(hid));
|
|
|
|
benchmarkTotalItems++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BENCHMARK_TYPE_PRF:
|
|
/* Measures the time that it takes for the PKCS-5 routine to derive a header key using
|
|
each of the implemented PRF algorithms.
|
|
*/
|
|
{
|
|
int thid, i;
|
|
char dk[MASTER_KEYDATA_SIZE];
|
|
char *tmp_salt = {"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x01\x23\x45\x67\x89\xAB\xCD\xEF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x01\x23\x45\x67\x89\xAB\xCD\xEF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"};
|
|
|
|
for (thid = FIRST_PRF_ID; thid <= LAST_PRF_ID; thid++)
|
|
{
|
|
if (benchmarkPreBoot && !benchmarkGPT && !HashForSystemEncryption (thid))
|
|
continue;
|
|
|
|
if (QueryPerformanceCounter (&performanceCountStart) == 0)
|
|
goto counter_error;
|
|
|
|
for (i = 1; i <= 2; i++)
|
|
{
|
|
switch (thid)
|
|
{
|
|
|
|
case SHA512:
|
|
/* PKCS-5 test with HMAC-SHA-512 used as the PRF */
|
|
derive_key_sha512 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
|
|
break;
|
|
|
|
case SHA256:
|
|
/* PKCS-5 test with HMAC-SHA-256 used as the PRF */
|
|
derive_key_sha256 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
|
|
break;
|
|
|
|
case BLAKE2S:
|
|
/* PKCS-5 test with HMAC-BLAKE2s used as the PRF */
|
|
derive_key_blake2s ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
|
|
break;
|
|
|
|
case WHIRLPOOL:
|
|
/* PKCS-5 test with HMAC-Whirlpool used as the PRF */
|
|
derive_key_whirlpool ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
|
|
break;
|
|
|
|
case STREEBOG:
|
|
/* PKCS-5 test with HMAC-STREEBOG used as the PRF */
|
|
derive_key_streebog("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (QueryPerformanceCounter (&performanceCountEnd) == 0)
|
|
goto counter_error;
|
|
|
|
benchmarkTable[benchmarkTotalItems].encSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
|
|
benchmarkTable[benchmarkTotalItems].id = thid;
|
|
benchmarkTable[benchmarkTotalItems].decSpeed = get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot);
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (unsigned __int64) (1000 * ((float) benchmarkTable[benchmarkTotalItems].encSpeed / benchmarkPerformanceFrequency.QuadPart / 2));
|
|
if (benchmarkPreBoot)
|
|
{
|
|
/* heuristics for boot times */
|
|
if (benchmarkGPT)
|
|
{
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 8) / 5;
|
|
}
|
|
else
|
|
{
|
|
if (thid == SHA256)
|
|
{
|
|
#ifdef _WIN64
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 26);
|
|
#else
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 24);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef _WIN64
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 21) / 5;
|
|
#else
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 18) / 5;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
StringCbPrintfW (benchmarkTable[benchmarkTotalItems].name, sizeof(benchmarkTable[benchmarkTotalItems].name),L"%s", get_pkcs5_prf_name (thid));
|
|
|
|
benchmarkTotalItems++;
|
|
}
|
|
}
|
|
break;
|
|
case BENCHMARK_TYPE_ENCRYPTION:
|
|
{
|
|
/* Encryption algorithm benchmarks */
|
|
|
|
// CPU "warm up" (an attempt to prevent skewed results on systems where CPU frequency
|
|
// gradually changes depending on CPU load).
|
|
ci->ea = EAGetFirst();
|
|
if (!EAInit (ci->ea, ci->master_keydata, ci->ks))
|
|
{
|
|
ci->mode = FIRST_MODE_OF_OPERATION_ID;
|
|
if (EAInitMode (ci, ci->k2))
|
|
{
|
|
int i;
|
|
#ifdef _WIN64
|
|
if (IsRamEncryptionEnabled ())
|
|
VcProtectKeys (ci, VcGetEncryptionID (ci));
|
|
#endif
|
|
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
EncryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
|
|
DecryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (ci->ea = EAGetFirst(); ci->ea != 0; ci->ea = EAGetNext(ci->ea))
|
|
{
|
|
if (!EAIsFormatEnabled (ci->ea))
|
|
continue;
|
|
|
|
if (ERR_CIPHER_INIT_FAILURE == EAInit (ci->ea, ci->master_keydata, ci->ks))
|
|
goto counter_error;
|
|
|
|
ci->mode = FIRST_MODE_OF_OPERATION_ID;
|
|
if (!EAInitMode (ci, ci->k2))
|
|
goto counter_error;
|
|
|
|
#ifdef _WIN64
|
|
if (IsRamEncryptionEnabled ())
|
|
VcProtectKeys (ci, VcGetEncryptionID (ci));
|
|
#endif
|
|
|
|
if (QueryPerformanceCounter (&performanceCountStart) == 0)
|
|
goto counter_error;
|
|
|
|
EncryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
|
|
|
|
if (QueryPerformanceCounter (&performanceCountEnd) == 0)
|
|
goto counter_error;
|
|
|
|
benchmarkTable[benchmarkTotalItems].encSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
|
|
|
|
if (QueryPerformanceCounter (&performanceCountStart) == 0)
|
|
goto counter_error;
|
|
|
|
DecryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
|
|
|
|
if (QueryPerformanceCounter (&performanceCountEnd) == 0)
|
|
goto counter_error;
|
|
|
|
benchmarkTable[benchmarkTotalItems].decSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
|
|
benchmarkTable[benchmarkTotalItems].id = ci->ea;
|
|
benchmarkTable[benchmarkTotalItems].meanBytesPerSec = ((unsigned __int64) (benchmarkBufferSize / ((float) benchmarkTable[benchmarkTotalItems].encSpeed / benchmarkPerformanceFrequency.QuadPart)) + (unsigned __int64) (benchmarkBufferSize / ((float) benchmarkTable[benchmarkTotalItems].decSpeed / benchmarkPerformanceFrequency.QuadPart))) / 2;
|
|
EAGetName (benchmarkTable[benchmarkTotalItems].name, 100, ci->ea, 1);
|
|
|
|
benchmarkTotalItems++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (ci)
|
|
crypto_close (ci);
|
|
|
|
if (lpTestBuffer)
|
|
{
|
|
VirtualUnlock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16));
|
|
|
|
_aligned_free(lpTestBuffer);
|
|
}
|
|
|
|
benchmarkLastBufferSize = benchmarkBufferSize;
|
|
|
|
DisplayBenchmarkResults(hBenchDlg);
|
|
|
|
EnableWindow (GetDlgItem (hBenchDlg, IDC_PERFORM_BENCHMARK), TRUE);
|
|
EnableWindow (GetDlgItem (hBenchDlg, IDCLOSE), TRUE);
|
|
|
|
NormalCursor ();
|
|
return TRUE;
|
|
|
|
counter_error:
|
|
|
|
if (ci)
|
|
crypto_close (ci);
|
|
|
|
if (lpTestBuffer)
|
|
{
|
|
VirtualUnlock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16));
|
|
|
|
_aligned_free(lpTestBuffer);
|
|
}
|
|
|
|
NormalCursor ();
|
|
|
|
EnableWindow (GetDlgItem (hBenchDlg, IDC_PERFORM_BENCHMARK), TRUE);
|
|
EnableWindow (GetDlgItem (hBenchDlg, IDCLOSE), TRUE);
|
|
|
|
MessageBoxW (hwndDlg, GetString ("ERR_PERF_COUNTER"), lpszTitle, ICON_HAND);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL CALLBACK BenchmarkDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
LPARAM nIndex;
|
|
static HWND hCboxSortMethod = NULL, hCboxBufferSize = NULL, hCboxList = NULL;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
LVCOLUMNW LvCol;
|
|
wchar_t s[128];
|
|
HWND hList = GetDlgItem (hwndDlg, IDC_RESULTS);
|
|
hCboxSortMethod = GetDlgItem (hwndDlg, IDC_BENCHMARK_SORT_METHOD);
|
|
hCboxBufferSize = GetDlgItem (hwndDlg, IDC_BENCHMARK_BUFFER_SIZE);
|
|
hCboxList = GetDlgItem (hwndDlg, IDC_BENCHMARK_LIST);
|
|
|
|
LocalizeDialog (hwndDlg, "IDD_BENCHMARK_DLG");
|
|
|
|
benchmarkBufferSize = BENCHMARK_DEFAULT_BUF_SIZE;
|
|
benchmarkSortMethod = BENCHMARK_SORT_BY_SPEED;
|
|
benchmarkType = BENCHMARK_TYPE_ENCRYPTION;
|
|
|
|
if (lParam)
|
|
{
|
|
benchmarkGPT = TRUE;
|
|
}
|
|
else
|
|
benchmarkGPT = FALSE;
|
|
|
|
SendMessage (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
|
|
LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_LABELTIP
|
|
);
|
|
|
|
memset (&LvCol,0,sizeof(LvCol));
|
|
LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
|
|
LvCol.pszText = GetString ("ALGORITHM");
|
|
LvCol.cx = CompensateXDPI (114);
|
|
LvCol.fmt = LVCFMT_LEFT;
|
|
SendMessage (hList,LVM_INSERTCOLUMNW,0,(LPARAM)&LvCol);
|
|
|
|
ResetBenchmarkList (hwndDlg);
|
|
|
|
/* Combo boxes */
|
|
|
|
// Sort method
|
|
|
|
SendMessage (hCboxSortMethod, CB_RESETCONTENT, 0, 0);
|
|
|
|
nIndex = SendMessageW (hCboxSortMethod, CB_ADDSTRING, 0, (LPARAM) GetString ("ALPHABETICAL_CATEGORIZED"));
|
|
SendMessage (hCboxSortMethod, CB_SETITEMDATA, nIndex, (LPARAM) 0);
|
|
|
|
nIndex = SendMessageW (hCboxSortMethod, CB_ADDSTRING, 0, (LPARAM) GetString ("MEAN_SPEED"));
|
|
SendMessage (hCboxSortMethod, CB_SETITEMDATA, nIndex, (LPARAM) 0);
|
|
|
|
SendMessage (hCboxSortMethod, CB_SETCURSEL, 1, 0); // Default sort method
|
|
|
|
// benchmark list
|
|
|
|
SendMessage (hCboxList, CB_RESETCONTENT, 0, 0);
|
|
|
|
nIndex = SendMessageW (hCboxList, CB_ADDSTRING, 0, (LPARAM) GetString ("ENCRYPTION_ALGORITHM"));
|
|
SendMessage (hCboxList, CB_SETITEMDATA, nIndex, (LPARAM) 0);
|
|
|
|
nIndex = SendMessageW (hCboxList, CB_ADDSTRING, 0, (LPARAM) GetString ("PKCS5_PRF"));
|
|
SendMessage (hCboxList, CB_SETITEMDATA, nIndex, (LPARAM) 0);
|
|
|
|
nIndex = SendMessageW (hCboxList, CB_ADDSTRING, 0, (LPARAM) GetString ("IDT_HASH_ALGO"));
|
|
SendMessage (hCboxList, CB_SETITEMDATA, nIndex, (LPARAM) 0);
|
|
|
|
SendMessage (hCboxList, CB_SETCURSEL, 0, 0); // Default: benchmark of encryption
|
|
|
|
// Buffer size
|
|
|
|
SendMessage (hCboxBufferSize, CB_RESETCONTENT, 0, 0);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"100 %s", GetString ("KB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 100 * BYTES_PER_KB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"500 %s", GetString ("KB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 500 * BYTES_PER_KB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"1 %s", GetString ("MB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 1 * BYTES_PER_MB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"5 %s", GetString ("MB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 5 * BYTES_PER_MB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"10 %s", GetString ("MB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 10 * BYTES_PER_MB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"50 %s", GetString ("MB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 50 * BYTES_PER_MB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"100 %s", GetString ("MB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 100 * BYTES_PER_MB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"200 %s", GetString ("MB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 200 * BYTES_PER_MB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"500 %s", GetString ("MB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 500 * BYTES_PER_MB);
|
|
|
|
StringCbPrintfW (s, sizeof(s), L"1 %s", GetString ("GB"));
|
|
nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
|
|
SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 1 * BYTES_PER_GB);
|
|
|
|
SendMessage (hCboxBufferSize, CB_SETCURSEL, 5, 0); // Default buffer size
|
|
|
|
|
|
uint32 driverConfig = ReadDriverConfigurationFlags();
|
|
int isAesHwSupported = HasAESNI();
|
|
|
|
SetDlgItemTextW (hwndDlg, IDC_HW_AES, (wstring (L" ") + (GetString (isAesHwSupported ? ((driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? "UISTR_DISABLED" : "UISTR_YES") : "NOT_APPLICABLE_OR_NOT_AVAILABLE"))).c_str());
|
|
|
|
ToHyperlink (hwndDlg, IDC_HW_AES_LABEL_LINK);
|
|
|
|
if (isAesHwSupported && (driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION))
|
|
{
|
|
Warning ("DISABLED_HW_AES_AFFECTS_PERFORMANCE", hwndDlg);
|
|
}
|
|
|
|
size_t cpuCount = GetCpuCount (NULL);
|
|
|
|
size_t nbrThreads = GetEncryptionThreadCount();
|
|
|
|
wchar_t nbrThreadsStr [300];
|
|
if (cpuCount < 2)
|
|
{
|
|
StringCbCopyW (nbrThreadsStr, sizeof(nbrThreadsStr), GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE"));
|
|
}
|
|
else if (nbrThreads < 2)
|
|
{
|
|
StringCbCopyW (nbrThreadsStr, sizeof(nbrThreadsStr), GetString ("UISTR_DISABLED"));
|
|
}
|
|
else
|
|
{
|
|
StringCbPrintfW (nbrThreadsStr, sizeof(nbrThreadsStr), GetString ("NUMBER_OF_THREADS"), nbrThreads);
|
|
}
|
|
|
|
SetDlgItemTextW (hwndDlg, IDC_PARALLELIZATION, (wstring (L" ") + nbrThreadsStr).c_str());
|
|
|
|
ToHyperlink (hwndDlg, IDC_PARALLELIZATION_LABEL_LINK);
|
|
|
|
if (nbrThreads < min (cpuCount, GetMaxEncryptionThreadCount())
|
|
&& cpuCount > 1)
|
|
{
|
|
Warning ("LIMITED_THREAD_COUNT_AFFECTS_PERFORMANCE", hwndDlg);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (lw)
|
|
{
|
|
case IDC_BENCHMARK_SORT_METHOD:
|
|
|
|
nIndex = SendMessage (hCboxSortMethod, CB_GETCURSEL, 0, 0);
|
|
if (nIndex != benchmarkSortMethod)
|
|
{
|
|
benchmarkSortMethod = (int) nIndex;
|
|
DisplayBenchmarkResults (hwndDlg);
|
|
}
|
|
return 1;
|
|
|
|
case IDC_BENCHMARK_LIST:
|
|
|
|
nIndex = SendMessage (hCboxList, CB_GETCURSEL, 0, 0);
|
|
if (nIndex != benchmarkType)
|
|
{
|
|
benchmarkType = (int) nIndex;
|
|
benchmarkTotalItems = 0;
|
|
ResetBenchmarkList (hwndDlg);
|
|
}
|
|
|
|
if (benchmarkType == BENCHMARK_TYPE_PRF)
|
|
{
|
|
ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_BUFFER_SIZE), SW_HIDE);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDT_BUFFER_SIZE), SW_HIDE);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDC_PIM), SW_SHOW);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDT_PIM), SW_SHOW);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_PREBOOT), SW_SHOW);
|
|
}
|
|
else
|
|
{
|
|
ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_BUFFER_SIZE), SW_SHOW);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDT_BUFFER_SIZE), SW_SHOW);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDC_PIM), SW_HIDE);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDT_PIM), SW_HIDE);
|
|
ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_PREBOOT), SW_HIDE);
|
|
}
|
|
return 1;
|
|
|
|
case IDC_PERFORM_BENCHMARK:
|
|
|
|
if (benchmarkType == BENCHMARK_TYPE_PRF)
|
|
{
|
|
benchmarkPim = GetPim (hwndDlg, IDC_PIM, 0);
|
|
benchmarkPreBoot = GetCheckBox (hwndDlg, IDC_BENCHMARK_PREBOOT);
|
|
}
|
|
else
|
|
{
|
|
nIndex = SendMessage (hCboxBufferSize, CB_GETCURSEL, 0, 0);
|
|
benchmarkBufferSize = (int) SendMessage (hCboxBufferSize, CB_GETITEMDATA, nIndex, 0);
|
|
}
|
|
|
|
BenchmarkThreadParam threadParam;
|
|
threadParam.hBenchDlg = hwndDlg;
|
|
threadParam.bStatus = FALSE;
|
|
|
|
WaitCursor ();
|
|
|
|
ShowWaitDialog (hwndDlg, TRUE, BenchmarkThreadProc, &threadParam);
|
|
|
|
NormalCursor ();
|
|
|
|
if (threadParam.bStatus == FALSE)
|
|
{
|
|
EndDialog (hwndDlg, IDCLOSE);
|
|
}
|
|
return 1;
|
|
|
|
case IDC_HW_AES_LABEL_LINK:
|
|
|
|
Applink ("hwacceleration");
|
|
return 1;
|
|
|
|
case IDC_PARALLELIZATION_LABEL_LINK:
|
|
|
|
Applink ("parallelization");
|
|
return 1;
|
|
|
|
case IDCLOSE:
|
|
case IDCANCEL:
|
|
|
|
EndDialog (hwndDlg, IDCLOSE);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
EndDialog (hwndDlg, IDCLOSE);
|
|
return 1;
|
|
|
|
break;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static BOOL CALLBACK RandomPoolEnrichementDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
WORD hw = HIWORD (wParam);
|
|
static unsigned char randPool [RNG_POOL_SIZE];
|
|
static unsigned char lastRandPool [RNG_POOL_SIZE];
|
|
static unsigned char maskRandPool [RNG_POOL_SIZE];
|
|
static BOOL bUseMask = FALSE;
|
|
static DWORD mouseEntropyGathered = 0xFFFFFFFF;
|
|
static DWORD mouseEventsInitialCount = 0;
|
|
/* max value of entropy needed to fill all random pool = 8 * RNG_POOL_SIZE = 2560 bits */
|
|
static const DWORD maxEntropyLevel = RNG_POOL_SIZE * 8;
|
|
static HWND hEntropyBar = NULL;
|
|
static wchar_t outputDispBuffer [RNG_POOL_SIZE * 3 + RANDPOOL_DISPLAY_ROWS + 2];
|
|
static BOOL bDisplayPoolContents = FALSE;
|
|
static BOOL bRandPoolDispAscii = FALSE;
|
|
int hash_algo = RandGetHashFunction();
|
|
int hid;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HWND hComboBox = GetDlgItem (hwndDlg, IDC_PRF_ID);
|
|
HCRYPTPROV hRngProv = NULL;
|
|
|
|
VirtualLock (randPool, sizeof(randPool));
|
|
VirtualLock (lastRandPool, sizeof(lastRandPool));
|
|
VirtualLock (outputDispBuffer, sizeof(outputDispBuffer));
|
|
VirtualLock (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
|
|
VirtualLock (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount));
|
|
VirtualLock (maskRandPool, sizeof(maskRandPool));
|
|
|
|
mouseEntropyGathered = 0xFFFFFFFF;
|
|
mouseEventsInitialCount = 0;
|
|
bUseMask = FALSE;
|
|
if (CryptAcquireContext (&hRngProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
|
{
|
|
if (CryptGenRandom (hRngProv, sizeof (maskRandPool), maskRandPool))
|
|
bUseMask = TRUE;
|
|
CryptReleaseContext (hRngProv, 0);
|
|
}
|
|
|
|
LocalizeDialog (hwndDlg, "IDD_RANDOM_POOL_ENRICHMENT");
|
|
|
|
SendMessage (hComboBox, CB_RESETCONTENT, 0, 0);
|
|
for (hid = FIRST_PRF_ID; hid <= LAST_PRF_ID; hid++)
|
|
{
|
|
if (!HashIsDeprecated (hid))
|
|
AddComboPair (hComboBox, HashGetName(hid), hid);
|
|
}
|
|
SelectAlgo (hComboBox, &hash_algo);
|
|
|
|
SetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS, bDisplayPoolContents);
|
|
|
|
SetTimer (hwndDlg, 0xfd, RANDPOOL_DISPLAY_REFRESH_INTERVAL, NULL);
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), WM_SETFONT, (WPARAM) hFixedDigitFont, (LPARAM) TRUE);
|
|
|
|
hEntropyBar = GetDlgItem (hwndDlg, IDC_ENTROPY_BAR);
|
|
SendMessage (hEntropyBar, PBM_SETRANGE32, 0, maxEntropyLevel);
|
|
SendMessage (hEntropyBar, PBM_SETSTEP, 1, 0);
|
|
SendMessage (hEntropyBar, PBM_SETSTATE, PBST_ERROR, 0);
|
|
return 1;
|
|
}
|
|
|
|
case WM_TIMER:
|
|
{
|
|
wchar_t tmp[4];
|
|
unsigned char tmpByte;
|
|
int col, row;
|
|
DWORD mouseEventsCounter;
|
|
|
|
RandpeekBytes (hwndDlg, randPool, sizeof (randPool), &mouseEventsCounter);
|
|
|
|
ProcessEntropyEstimate (hEntropyBar, &mouseEventsInitialCount, mouseEventsCounter, maxEntropyLevel, &mouseEntropyGathered);
|
|
|
|
if (memcmp (lastRandPool, randPool, sizeof(lastRandPool)) != 0)
|
|
{
|
|
outputDispBuffer[0] = 0;
|
|
|
|
for (row = 0; row < RANDPOOL_DISPLAY_ROWS; row++)
|
|
{
|
|
for (col = 0; col < RANDPOOL_DISPLAY_COLUMNS; col++)
|
|
{
|
|
if (bDisplayPoolContents)
|
|
{
|
|
tmpByte = randPool[row * RANDPOOL_DISPLAY_COLUMNS + col];
|
|
StringCbPrintfW (tmp, sizeof(tmp), bRandPoolDispAscii ? ((tmpByte >= 32 && tmpByte < 255 && tmpByte != L'&') ? L" %c " : L" . ") : L"%02X ", tmpByte);
|
|
}
|
|
else if (bUseMask)
|
|
{
|
|
/* use mask to compute a randomized ascii representation */
|
|
tmpByte = (randPool[row * RANDPOOL_DISPLAY_COLUMNS + col] -
|
|
lastRandPool[row * RANDPOOL_DISPLAY_COLUMNS + col]) ^ maskRandPool [row * RANDPOOL_DISPLAY_COLUMNS + col];
|
|
tmp[0] = (wchar_t) (((tmpByte >> 4) % 6) + L'*');
|
|
tmp[1] = (wchar_t) (((tmpByte & 0x0F) % 6) + L'*');
|
|
tmp[2] = L' ';
|
|
tmp[3] = 0;
|
|
}
|
|
else
|
|
{
|
|
StringCbCopyW (tmp, sizeof(tmp), L"** ");
|
|
}
|
|
|
|
StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), tmp);
|
|
}
|
|
StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), L"\n");
|
|
}
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), outputDispBuffer);
|
|
|
|
memcpy (lastRandPool, randPool, sizeof(lastRandPool));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
if (lw == IDC_CONTINUE)
|
|
lw = IDOK;
|
|
|
|
if (lw == IDOK || lw == IDCLOSE || lw == IDCANCEL)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (lw == IDC_PRF_ID && hw == CBN_SELCHANGE)
|
|
{
|
|
hid = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETCURSEL, 0, 0);
|
|
hash_algo = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETITEMDATA, hid, 0);
|
|
RandSetHashFunction (hash_algo);
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDC_DISPLAY_POOL_CONTENTS)
|
|
{
|
|
if (!(bDisplayPoolContents = GetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS)))
|
|
{
|
|
wchar_t tmp[RNG_POOL_SIZE+1];
|
|
|
|
wmemset (tmp, L' ', ARRAYSIZE(tmp));
|
|
tmp [RNG_POOL_SIZE] = 0;
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case WM_CLOSE:
|
|
{
|
|
wchar_t tmp[RNG_POOL_SIZE+1];
|
|
exit:
|
|
KillTimer (hwndDlg, 0xfd);
|
|
|
|
burn (randPool, sizeof(randPool));
|
|
burn (lastRandPool, sizeof(lastRandPool));
|
|
burn (outputDispBuffer, sizeof(outputDispBuffer));
|
|
burn (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
|
|
burn (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount));
|
|
burn (maskRandPool, sizeof(maskRandPool));
|
|
|
|
// Attempt to wipe the pool contents in the GUI text area
|
|
wmemset (tmp, L' ', RNG_POOL_SIZE);
|
|
tmp [RNG_POOL_SIZE] = 0;
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
|
|
|
|
if (msg == WM_COMMAND && lw == IDOK)
|
|
EndDialog (hwndDlg, IDOK);
|
|
else
|
|
EndDialog (hwndDlg, IDCLOSE);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Randinit is always called before UserEnrichRandomPool, so we don't need
|
|
* the extra Randinit call here since it will always succeed but we keep it
|
|
* for clarity purposes
|
|
*/
|
|
void UserEnrichRandomPool (HWND hwndDlg)
|
|
{
|
|
if ((0 == Randinit()) && !IsRandomPoolEnrichedByUser())
|
|
{
|
|
INT_PTR result = DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_RANDOM_POOL_ENRICHMENT), hwndDlg ? hwndDlg : MainDlg, (DLGPROC) RandomPoolEnrichementDlgProc, (LPARAM) 0);
|
|
SetRandomPoolEnrichedByUserStatus (result == IDOK);
|
|
}
|
|
}
|
|
|
|
|
|
/* Except in response to the WM_INITDIALOG message, the dialog box procedure
|
|
should return nonzero if it processes the message, and zero if it does
|
|
not. - see DialogProc */
|
|
BOOL CALLBACK KeyfileGeneratorDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
WORD hw = HIWORD (wParam);
|
|
static unsigned char randPool [RNG_POOL_SIZE];
|
|
static unsigned char lastRandPool [RNG_POOL_SIZE];
|
|
static unsigned char maskRandPool [RNG_POOL_SIZE];
|
|
static BOOL bUseMask = FALSE;
|
|
static DWORD mouseEntropyGathered = 0xFFFFFFFF;
|
|
static DWORD mouseEventsInitialCount = 0;
|
|
/* max value of entropy needed to fill all random pool = 8 * RNG_POOL_SIZE = 2560 bits */
|
|
static const DWORD maxEntropyLevel = RNG_POOL_SIZE * 8;
|
|
static HWND hEntropyBar = NULL;
|
|
static wchar_t outputDispBuffer [RNG_POOL_SIZE * 3 + RANDPOOL_DISPLAY_ROWS + 2];
|
|
static BOOL bDisplayPoolContents = FALSE;
|
|
static BOOL bRandPoolDispAscii = FALSE;
|
|
int hash_algo = RandGetHashFunction();
|
|
int hid;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HWND hComboBox = GetDlgItem (hwndDlg, IDC_PRF_ID);
|
|
HWND hSizeUnit = GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE_UNIT);
|
|
HCRYPTPROV hRngProv = NULL;
|
|
|
|
VirtualLock (randPool, sizeof(randPool));
|
|
VirtualLock (lastRandPool, sizeof(lastRandPool));
|
|
VirtualLock (outputDispBuffer, sizeof(outputDispBuffer));
|
|
VirtualLock (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
|
|
VirtualLock (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount));
|
|
VirtualLock (maskRandPool, sizeof(maskRandPool));
|
|
|
|
mouseEntropyGathered = 0xFFFFFFFF;
|
|
mouseEventsInitialCount = 0;
|
|
bUseMask = FALSE;
|
|
if (CryptAcquireContext (&hRngProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
|
{
|
|
if (CryptGenRandom (hRngProv, sizeof (maskRandPool), maskRandPool))
|
|
bUseMask = TRUE;
|
|
CryptReleaseContext (hRngProv, 0);
|
|
}
|
|
|
|
LocalizeDialog (hwndDlg, "IDD_KEYFILE_GENERATOR");
|
|
|
|
SendMessage (hComboBox, CB_RESETCONTENT, 0, 0);
|
|
for (hid = FIRST_PRF_ID; hid <= LAST_PRF_ID; hid++)
|
|
{
|
|
if (!HashIsDeprecated (hid))
|
|
AddComboPair (hComboBox, HashGetName(hid), hid);
|
|
}
|
|
SelectAlgo (hComboBox, &hash_algo);
|
|
|
|
// populate keyfiles size unit combo
|
|
SendMessage (hSizeUnit, CB_RESETCONTENT, 0, 0);
|
|
AddComboPair (hSizeUnit, GetString ("BYTES"), 0);
|
|
AddComboPair (hSizeUnit, GetString ("KB"), 1);
|
|
AddComboPair (hSizeUnit, GetString ("MB"), 2);
|
|
AddComboPair (hSizeUnit, GetString ("GB"), 3);
|
|
|
|
// set default keyfiles size unit
|
|
SendMessage (hSizeUnit, CB_SETCURSEL, 0, 0);
|
|
|
|
SetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS, bDisplayPoolContents);
|
|
hEntropyBar = GetDlgItem (hwndDlg, IDC_ENTROPY_BAR);
|
|
SendMessage (hEntropyBar, PBM_SETRANGE32, 0, maxEntropyLevel);
|
|
SendMessage (hEntropyBar, PBM_SETSTEP, 1, 0);
|
|
SendMessage (hEntropyBar, PBM_SETSTATE, PBST_ERROR, 0);
|
|
|
|
#ifndef VOLFORMAT
|
|
if (Randinit ())
|
|
{
|
|
handleError (hwndDlg, (CryptoAPILastError == ERROR_SUCCESS)? ERR_RAND_INIT_FAILED : ERR_CAPI_INIT_FAILED, SRC_POS);
|
|
EndDialog (hwndDlg, IDCLOSE);
|
|
}
|
|
#endif
|
|
SetTimer (hwndDlg, 0xfd, RANDPOOL_DISPLAY_REFRESH_INTERVAL, NULL);
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), WM_SETFONT, (WPARAM) hFixedDigitFont, (LPARAM) TRUE);
|
|
// 9-digit limit for the number of keyfiles (more than enough!)
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), EM_SETLIMITTEXT, (WPARAM) 9, 0);
|
|
SetWindowText(GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), L"1");
|
|
// maximum keyfile size is 1048576, so limit the edit control to 7 characters
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), EM_SETLIMITTEXT, (WPARAM) 7, 0);
|
|
SetWindowText(GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), L"64");
|
|
// set the maximum length of the keyfile base name to (TC_MAX_PATH - 1)
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), EM_SETLIMITTEXT, (WPARAM) (TC_MAX_PATH - 1), 0);
|
|
return 1;
|
|
}
|
|
|
|
case WM_TIMER:
|
|
{
|
|
wchar_t tmp[4];
|
|
unsigned char tmpByte;
|
|
int col, row;
|
|
DWORD mouseEventsCounter;
|
|
|
|
RandpeekBytes (hwndDlg, randPool, sizeof (randPool), &mouseEventsCounter);
|
|
|
|
ProcessEntropyEstimate (hEntropyBar, &mouseEventsInitialCount, mouseEventsCounter, maxEntropyLevel, &mouseEntropyGathered);
|
|
|
|
if (memcmp (lastRandPool, randPool, sizeof(lastRandPool)) != 0)
|
|
{
|
|
outputDispBuffer[0] = 0;
|
|
|
|
for (row = 0; row < RANDPOOL_DISPLAY_ROWS; row++)
|
|
{
|
|
for (col = 0; col < RANDPOOL_DISPLAY_COLUMNS; col++)
|
|
{
|
|
if (bDisplayPoolContents)
|
|
{
|
|
tmpByte = randPool[row * RANDPOOL_DISPLAY_COLUMNS + col];
|
|
StringCbPrintfW (tmp, sizeof(tmp), bRandPoolDispAscii ? ((tmpByte >= 32 && tmpByte < 255 && tmpByte != L'&') ? L" %c " : L" . ") : L"%02X ", tmpByte);
|
|
}
|
|
else if (bUseMask)
|
|
{
|
|
/* use mask to compute a randomized ASCII representation */
|
|
tmpByte = (randPool[row * RANDPOOL_DISPLAY_COLUMNS + col] -
|
|
lastRandPool[row * RANDPOOL_DISPLAY_COLUMNS + col]) ^ maskRandPool [row * RANDPOOL_DISPLAY_COLUMNS + col];
|
|
tmp[0] = (wchar_t) (((tmpByte >> 4) % 6) + L'*');
|
|
tmp[1] = (wchar_t) (((tmpByte & 0x0F) % 6) + L'*');
|
|
tmp[2] = L' ';
|
|
tmp[3] = 0;
|
|
}
|
|
else
|
|
{
|
|
StringCbCopyW (tmp, sizeof(tmp), L"** ");
|
|
}
|
|
|
|
StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), tmp);
|
|
}
|
|
StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), L"\n");
|
|
}
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), outputDispBuffer);
|
|
|
|
memcpy (lastRandPool, randPool, sizeof(lastRandPool));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
|
|
if (lw == IDCLOSE || lw == IDCANCEL)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (lw == IDC_PRF_ID && hw == CBN_SELCHANGE)
|
|
{
|
|
hid = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETCURSEL, 0, 0);
|
|
hash_algo = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETITEMDATA, hid, 0);
|
|
RandSetHashFunction (hash_algo);
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDC_DISPLAY_POOL_CONTENTS)
|
|
{
|
|
if (!(bDisplayPoolContents = GetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS)))
|
|
{
|
|
wchar_t tmp[RNG_POOL_SIZE+1];
|
|
|
|
wmemset (tmp, L' ', ARRAYSIZE(tmp));
|
|
tmp [RNG_POOL_SIZE] = 0;
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDC_KEYFILES_RANDOM_SIZE)
|
|
{
|
|
EnableWindow(GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), !GetCheckBox (hwndDlg, IDC_KEYFILES_RANDOM_SIZE));
|
|
EnableWindow(GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE_UNIT), !GetCheckBox (hwndDlg, IDC_KEYFILES_RANDOM_SIZE));
|
|
}
|
|
|
|
if (lw == IDC_GENERATE_AND_SAVE_KEYFILE)
|
|
{
|
|
wchar_t szNumber[16] = {0};
|
|
wchar_t szFileBaseName[TC_MAX_PATH];
|
|
wchar_t szDirName[TC_MAX_PATH];
|
|
wchar_t szFileName [2*TC_MAX_PATH + 16];
|
|
unsigned char *keyfile = NULL;
|
|
int fhKeyfile = -1, status;
|
|
long keyfilesCount = 0, i;
|
|
unsigned long long keyfilesSize = 0, remainingBytes = 0;
|
|
int selectedUnitIndex, selectedUnitFactor, loopIndex, rndBytesLength;
|
|
DWORD dwLastError = 0;
|
|
wchar_t* fileExtensionPtr = 0;
|
|
wchar_t szSuffix[32];
|
|
BOOL bRandomSize = GetCheckBox (hwndDlg, IDC_KEYFILES_RANDOM_SIZE);
|
|
|
|
if (!GetWindowText(GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), szNumber, ARRAYSIZE(szNumber)))
|
|
szNumber[0] = 0;
|
|
|
|
keyfilesCount = wcstoul(szNumber, NULL, 0);
|
|
if (keyfilesCount <= 0 || keyfilesCount == LONG_MAX)
|
|
{
|
|
Warning("KEYFILE_INCORRECT_NUMBER", hwndDlg);
|
|
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), TRUE);
|
|
return 1;
|
|
}
|
|
|
|
if (!bRandomSize)
|
|
{
|
|
if (!GetWindowText(GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), szNumber, ARRAYSIZE(szNumber)))
|
|
szNumber[0] = 0;
|
|
|
|
keyfilesSize = wcstoul(szNumber, NULL, 0);
|
|
// multiply by the unit factor
|
|
selectedUnitIndex = ComboBox_GetCurSel (GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE_UNIT));
|
|
if (selectedUnitIndex != CB_ERR)
|
|
{
|
|
selectedUnitFactor = (CK_SLOT_ID) ComboBox_GetItemData (GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE_UNIT), selectedUnitIndex);
|
|
for (loopIndex = 0; loopIndex < selectedUnitFactor; loopIndex++)
|
|
keyfilesSize *= 1024ULL;
|
|
}
|
|
|
|
if (keyfilesSize < 64)
|
|
{
|
|
Warning("KEYFILE_INCORRECT_SIZE", hwndDlg);
|
|
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), TRUE);
|
|
return 1;
|
|
}
|
|
|
|
remainingBytes = keyfilesSize;
|
|
}
|
|
|
|
if (!GetWindowText(GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), szFileBaseName, TC_MAX_PATH))
|
|
szFileBaseName[0] = 0;
|
|
|
|
// Trim trailing space
|
|
if (TrimWhiteSpace(szFileBaseName) == 0)
|
|
{
|
|
Warning("KEYFILE_EMPTY_BASE_NAME", hwndDlg);
|
|
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), TRUE);
|
|
return 1;
|
|
}
|
|
|
|
if (!IsValidFileName(szFileBaseName))
|
|
{
|
|
Warning("KEYFILE_INVALID_BASE_NAME", hwndDlg);
|
|
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), TRUE);
|
|
return 1;
|
|
}
|
|
|
|
fileExtensionPtr = wcsrchr(szFileBaseName, L'.');
|
|
|
|
/* Select directory */
|
|
if (!BrowseDirectories (hwndDlg, "SELECT_KEYFILE_GENERATION_DIRECTORY", szDirName))
|
|
return 1;
|
|
|
|
if (szDirName[wcslen(szDirName) - 1] != L'\\' && szDirName[wcslen(szDirName) - 1] != L'/')
|
|
StringCbCat(szDirName, sizeof(szDirName), L"\\");
|
|
|
|
WaitCursor();
|
|
|
|
keyfile = (unsigned char*) TCalloc(KEYFILE_MAX_READ_LEN);
|
|
|
|
for (i= 0; i < keyfilesCount; i++)
|
|
{
|
|
StringCbCopyW(szFileName, sizeof(szFileName), szDirName);
|
|
|
|
if (i > 0)
|
|
{
|
|
StringCbPrintfW(szSuffix, sizeof(szSuffix), L"_%d", i);
|
|
// Append the counter to the name
|
|
if (fileExtensionPtr)
|
|
{
|
|
StringCchCatN(szFileName, ARRAYSIZE(szFileName), szFileBaseName, (size_t) (fileExtensionPtr - szFileBaseName));
|
|
StringCbCat(szFileName, sizeof(szFileName), szSuffix);
|
|
StringCbCat(szFileName, sizeof(szFileName), fileExtensionPtr);
|
|
}
|
|
else
|
|
{
|
|
StringCbCat(szFileName, sizeof(szFileName), szFileBaseName);
|
|
StringCbCat(szFileName, sizeof(szFileName), szSuffix);
|
|
}
|
|
}
|
|
else
|
|
StringCbCat(szFileName, sizeof(szFileName), szFileBaseName);
|
|
|
|
// check if the file exists
|
|
if ((fhKeyfile = _wopen(szFileName, _O_RDONLY|_O_BINARY, _S_IREAD|_S_IWRITE)) != -1)
|
|
{
|
|
WCHAR s[4*TC_MAX_PATH] = {0};
|
|
|
|
_close (fhKeyfile);
|
|
|
|
StringCbPrintfW (s, sizeof(s), GetString ("KEYFILE_ALREADY_EXISTS"), szFileName);
|
|
status = AskWarnNoYesString (s, hwndDlg);
|
|
if (status == IDNO)
|
|
{
|
|
TCfree(keyfile);
|
|
NormalCursor();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* Conceive the file */
|
|
if ((fhKeyfile = _wopen(szFileName, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_BINARY, _S_IREAD|_S_IWRITE)) == -1)
|
|
{
|
|
TCfree(keyfile);
|
|
NormalCursor();
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
return 1;
|
|
}
|
|
|
|
if (bRandomSize)
|
|
{
|
|
/* Generate a random size */
|
|
if (!RandgetBytes (hwndDlg, (unsigned char*) &keyfilesSize, sizeof(keyfilesSize), FALSE))
|
|
{
|
|
_close (fhKeyfile);
|
|
DeleteFile (szFileName);
|
|
TCfree(keyfile);
|
|
NormalCursor();
|
|
return 1;
|
|
}
|
|
|
|
/* since random keyfilesSize < 1024 * 1024, we mask with 0x000FFFFF */
|
|
keyfilesSize = (unsigned long long) (((unsigned long) keyfilesSize) & 0x000FFFFF);
|
|
|
|
keyfilesSize %= ((KEYFILE_MAX_READ_LEN - 64) + 1);
|
|
keyfilesSize += 64;
|
|
|
|
remainingBytes = keyfilesSize;
|
|
}
|
|
|
|
do {
|
|
rndBytesLength = (int) min (remainingBytes, (unsigned long long) KEYFILE_MAX_READ_LEN);
|
|
|
|
/* Generate the keyfile */
|
|
if (!RandgetBytesFull (hwndDlg, keyfile, rndBytesLength, TRUE, TRUE))
|
|
{
|
|
_close (fhKeyfile);
|
|
DeleteFile (szFileName);
|
|
TCfree(keyfile);
|
|
NormalCursor();
|
|
return 1;
|
|
}
|
|
|
|
/* Write the keyfile */
|
|
status = _write (fhKeyfile, keyfile, rndBytesLength);
|
|
} while (status != -1 && (remainingBytes -= (unsigned long long) rndBytesLength) > 0);
|
|
|
|
/* save last error code */
|
|
if (status == -1)
|
|
dwLastError = GetLastError();
|
|
|
|
burn (keyfile, KEYFILE_MAX_READ_LEN);
|
|
_close (fhKeyfile);
|
|
|
|
if (status == -1)
|
|
{
|
|
TCfree(keyfile);
|
|
NormalCursor();
|
|
/* restore last error code */
|
|
SetLastError(dwLastError);
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
TCfree(keyfile);
|
|
NormalCursor();
|
|
|
|
Info("KEYFILE_CREATED", hwndDlg);
|
|
|
|
return 1;
|
|
}
|
|
return 0;
|
|
|
|
case WM_CLOSE:
|
|
{
|
|
wchar_t tmp[RNG_POOL_SIZE+1];
|
|
exit:
|
|
WaitCursor();
|
|
KillTimer (hwndDlg, 0xfd);
|
|
|
|
#ifndef VOLFORMAT
|
|
RandStop (FALSE);
|
|
#endif
|
|
/* Cleanup */
|
|
|
|
burn (randPool, sizeof(randPool));
|
|
burn (lastRandPool, sizeof(lastRandPool));
|
|
burn (outputDispBuffer, sizeof(outputDispBuffer));
|
|
burn (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
|
|
burn (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount));
|
|
burn (maskRandPool, sizeof(maskRandPool));
|
|
|
|
// Attempt to wipe the pool contents in the GUI text area
|
|
wmemset (tmp, L' ', RNG_POOL_SIZE);
|
|
tmp [RNG_POOL_SIZE] = 0;
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
|
|
|
|
EndDialog (hwndDlg, IDCLOSE);
|
|
NormalCursor ();
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* Except in response to the WM_INITDIALOG message, the dialog box procedure
|
|
should return nonzero if it processes the message, and zero if it does
|
|
not. - see DialogProc */
|
|
BOOL CALLBACK
|
|
CipherTestDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static int idTestCipher = -1; /* Currently selected cipher for the test vector facility (none = -1). */
|
|
static BOOL bXTSTestEnabled = FALSE;
|
|
|
|
PCRYPTO_INFO ci;
|
|
WORD lw = LOWORD (wParam);
|
|
WORD hw = HIWORD (wParam);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
int ea;
|
|
wchar_t buf[100];
|
|
|
|
LocalizeDialog (hwndDlg, "IDD_CIPHER_TEST_DLG");
|
|
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), WM_SETFONT, (WPARAM)hBoldFont, MAKELPARAM(TRUE,0));
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_KEY), EM_LIMITTEXT, 128,0);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_KEY), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT), EM_LIMITTEXT,64,0);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), EM_LIMITTEXT,64,0);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), EM_LIMITTEXT, 128,0);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), EM_LIMITTEXT,32,0);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
|
|
SetCheckBox (hwndDlg, IDC_XTS_MODE_ENABLED, bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_SECONDARY_KEY), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDT_SECONDARY_KEY), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_BLOCK_NUMBER), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
|
|
|
|
if (idTestCipher == -1)
|
|
idTestCipher = (int) lParam;
|
|
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_CIPHER), CB_RESETCONTENT, 0, 0);
|
|
for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea))
|
|
{
|
|
if (EAGetCipherCount (ea) == 1 && EAIsFormatEnabled (ea))
|
|
AddComboPair (GetDlgItem (hwndDlg, IDC_CIPHER), EAGetName (buf, ARRAYSIZE(buf),ea, 1), EAGetFirstCipher (ea));
|
|
}
|
|
|
|
ResetCipherTest(hwndDlg, idTestCipher);
|
|
|
|
SelectAlgo (GetDlgItem (hwndDlg, IDC_CIPHER), &idTestCipher);
|
|
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
|
|
if (hw == CBN_SELCHANGE && lw == IDC_CIPHER)
|
|
{
|
|
idTestCipher = (int) SendMessage (GetDlgItem (hwndDlg, IDC_CIPHER), CB_GETITEMDATA, SendMessage (GetDlgItem (hwndDlg, IDC_CIPHER), CB_GETCURSEL, 0, 0), 0);
|
|
ResetCipherTest(hwndDlg, idTestCipher);
|
|
SendMessage (hwndDlg, WM_INITDIALOG, 0, 0);
|
|
return 1;
|
|
}
|
|
|
|
if (hw == CBN_SELCHANGE && lw == IDC_KEY_SIZE)
|
|
{
|
|
// NOP
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDC_RESET)
|
|
{
|
|
ResetCipherTest(hwndDlg, idTestCipher);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDC_AUTO)
|
|
{
|
|
WaitCursor ();
|
|
if (!AutoTestAlgorithms())
|
|
{
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_SHOWNORMAL);
|
|
SetWindowTextW(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), GetString ("TESTS_FAILED"));
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_SHOWNORMAL);
|
|
SetWindowTextW(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), GetString ("TESTS_PASSED"));
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_REDTICK), SW_SHOWNORMAL);
|
|
}
|
|
NormalCursor ();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (lw == IDC_XTS_MODE_ENABLED)
|
|
{
|
|
bXTSTestEnabled = GetCheckBox (hwndDlg, IDC_XTS_MODE_ENABLED);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_SECONDARY_KEY), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDT_SECONDARY_KEY), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_BLOCK_NUMBER), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
|
|
if (bXTSTestEnabled)
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETCURSEL, 0,0);
|
|
}
|
|
|
|
if (lw == IDOK || lw == IDC_ENCRYPT || lw == IDC_DECRYPT)
|
|
{
|
|
CRYPTOPP_ALIGN_DATA(16) char key[128+1], inputtext[128+1], secondaryKey[64+1], dataUnitNo[16+1];
|
|
wchar_t szTmp[128+1];
|
|
int ks, pt, n, tlen, blockNo = 0;
|
|
BOOL bEncrypt;
|
|
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_REDTICK), SW_HIDE);
|
|
|
|
ks = (int) SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_GETCURSEL, 0,0);
|
|
ks = (int) SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_GETITEMDATA, ks,0);
|
|
pt = (int) SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_GETITEMDATA, 0,0);
|
|
|
|
bEncrypt = lw == IDC_ENCRYPT;
|
|
|
|
memset(key,0,sizeof(key));
|
|
memset(szTmp,0,sizeof(szTmp));
|
|
n = GetWindowText(GetDlgItem(hwndDlg, IDC_KEY), szTmp, ARRAYSIZE(szTmp));
|
|
if (n != ks * 2)
|
|
{
|
|
Warning ("TEST_KEY_SIZE", hwndDlg);
|
|
return 1;
|
|
}
|
|
|
|
for (n = 0; n < ks; n ++)
|
|
{
|
|
wchar_t szTmp2[3], *ptr;
|
|
long x;
|
|
|
|
szTmp2[2] = 0;
|
|
szTmp2[0] = szTmp[n * 2];
|
|
szTmp2[1] = szTmp[n * 2 + 1];
|
|
|
|
x = wcstol(szTmp2, &ptr, 16);
|
|
|
|
key[n] = (char) x;
|
|
}
|
|
|
|
memset(inputtext, 0, sizeof(inputtext));
|
|
memset(secondaryKey, 0, sizeof(secondaryKey));
|
|
memset(dataUnitNo, 0, sizeof(dataUnitNo));
|
|
memset(szTmp, 0, sizeof(szTmp));
|
|
|
|
if (bEncrypt)
|
|
{
|
|
n = GetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), szTmp, ARRAYSIZE(szTmp));
|
|
}
|
|
else
|
|
{
|
|
n = GetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), szTmp, ARRAYSIZE(szTmp));
|
|
}
|
|
|
|
if (n != pt * 2)
|
|
{
|
|
if (bEncrypt)
|
|
{
|
|
Warning ("TEST_PLAINTEXT_SIZE", hwndDlg);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
Warning ("TEST_CIPHERTEXT_SIZE", hwndDlg);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
for (n = 0; n < pt; n ++)
|
|
{
|
|
wchar_t szTmp2[3], *ptr;
|
|
long x;
|
|
|
|
szTmp2[2] = 0;
|
|
szTmp2[0] = szTmp[n * 2];
|
|
szTmp2[1] = szTmp[n * 2 + 1];
|
|
|
|
x = wcstol(szTmp2, &ptr, 16);
|
|
|
|
inputtext[n] = (char) x;
|
|
}
|
|
|
|
// XTS
|
|
if (bXTSTestEnabled)
|
|
{
|
|
// Secondary key
|
|
|
|
if (GetWindowText(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), szTmp, ARRAYSIZE(szTmp)) != 64)
|
|
{
|
|
Warning ("TEST_INCORRECT_SECONDARY_KEY_SIZE", hwndDlg);
|
|
return 1;
|
|
}
|
|
|
|
for (n = 0; n < 64; n ++)
|
|
{
|
|
wchar_t szTmp2[3], *ptr;
|
|
long x;
|
|
|
|
szTmp2[2] = 0;
|
|
szTmp2[0] = szTmp[n * 2];
|
|
szTmp2[1] = szTmp[n * 2 + 1];
|
|
|
|
x = wcstol(szTmp2, &ptr, 16);
|
|
|
|
secondaryKey[n] = (char) x;
|
|
}
|
|
|
|
// Data unit number
|
|
|
|
tlen = GetWindowText(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), szTmp, ARRAYSIZE(szTmp));
|
|
|
|
if (tlen > 16 || tlen < 1)
|
|
{
|
|
Warning ("TEST_INCORRECT_TEST_DATA_UNIT_SIZE", hwndDlg);
|
|
return 1;
|
|
}
|
|
|
|
LeftPadString (szTmp, tlen, 16, L'0');
|
|
|
|
for (n = 0; n < 16; n ++)
|
|
{
|
|
wchar_t szTmp2[3], *ptr;
|
|
long x;
|
|
|
|
szTmp2[2] = 0;
|
|
szTmp2[0] = szTmp[n * 2];
|
|
szTmp2[1] = szTmp[n * 2 + 1];
|
|
|
|
x = wcstol(szTmp2, &ptr, 16);
|
|
|
|
dataUnitNo[n] = (char) x;
|
|
}
|
|
|
|
// Block number
|
|
|
|
blockNo = (int) SendMessage (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_GETITEMDATA, SendMessage (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_GETCURSEL, 0, 0), 0);
|
|
} // if (bXTSTestEnabled)
|
|
|
|
|
|
/* Perform the actual tests */
|
|
|
|
if (ks != CB_ERR && pt != CB_ERR)
|
|
{
|
|
char tmp[128];
|
|
int tmpRetVal;
|
|
|
|
/* Copy the plain/ciphertext */
|
|
memcpy(tmp,inputtext, pt);
|
|
|
|
if (bXTSTestEnabled)
|
|
{
|
|
UINT64_STRUCT structDataUnitNo;
|
|
|
|
/* XTS mode */
|
|
|
|
ci = crypto_open ();
|
|
if (!ci)
|
|
return 1;
|
|
|
|
ci->mode = XTS;
|
|
|
|
for (ci->ea = EAGetFirst (); ci->ea != 0 ; ci->ea = EAGetNext (ci->ea))
|
|
if (EAGetCipherCount (ci->ea) == 1 && EAGetFirstCipher (ci->ea) == idTestCipher)
|
|
break;
|
|
|
|
if ((tmpRetVal = EAInit (ci->ea, (unsigned char *) key, ci->ks)) != ERR_SUCCESS)
|
|
{
|
|
handleError (hwndDlg, tmpRetVal, SRC_POS);
|
|
crypto_close (ci);
|
|
return 1;
|
|
}
|
|
|
|
memcpy (&ci->k2, secondaryKey, sizeof (secondaryKey));
|
|
if (!EAInitMode (ci, ci->k2))
|
|
{
|
|
crypto_close (ci);
|
|
return 1;
|
|
}
|
|
|
|
structDataUnitNo.Value = BE64(((unsigned __int64 *)dataUnitNo)[0]);
|
|
|
|
if (bEncrypt)
|
|
EncryptBufferXTS ((unsigned char *) tmp, pt, &structDataUnitNo, blockNo, (unsigned char *) (ci->ks), (unsigned char *) ci->ks2, idTestCipher);
|
|
else
|
|
DecryptBufferXTS ((unsigned char *) tmp, pt, &structDataUnitNo, blockNo, (unsigned char *) (ci->ks), (unsigned char *) ci->ks2, idTestCipher);
|
|
|
|
crypto_close (ci);
|
|
}
|
|
else
|
|
{
|
|
|
|
CipherInit2(idTestCipher, key, ks_tmp, ks);
|
|
|
|
if (bEncrypt)
|
|
{
|
|
EncipherBlock(idTestCipher, tmp, ks_tmp);
|
|
}
|
|
else
|
|
{
|
|
DecipherBlock(idTestCipher, tmp, ks_tmp);
|
|
}
|
|
|
|
}
|
|
*szTmp = 0;
|
|
|
|
for (n = 0; n < pt; n ++)
|
|
{
|
|
wchar_t szTmp2[3];
|
|
StringCbPrintfW(szTmp2, sizeof(szTmp2), L"%02x", (int)((unsigned char)tmp[n]));
|
|
StringCbCatW(szTmp, sizeof(szTmp), szTmp2);
|
|
}
|
|
|
|
if (bEncrypt)
|
|
SetWindowText(GetDlgItem(hwndDlg,IDC_CIPHERTEXT), szTmp);
|
|
else
|
|
SetWindowText(GetDlgItem(hwndDlg,IDC_PLAINTEXT), szTmp);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (lw == IDCLOSE || lw == IDCANCEL)
|
|
{
|
|
idTestCipher = -1;
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
idTestCipher = -1;
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ResetCipherTest(HWND hwndDlg, int idTestCipher)
|
|
{
|
|
int ndx;
|
|
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_REDTICK), SW_HIDE);
|
|
|
|
EnableWindow(GetDlgItem(hwndDlg,IDC_KEY_SIZE), FALSE);
|
|
|
|
/* Setup the keysize and plaintext sizes for the selected cipher */
|
|
|
|
SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_RESETCONTENT, 0,0);
|
|
SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_RESETCONTENT, 0,0);
|
|
SendMessage (GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_RESETCONTENT, 0,0);
|
|
|
|
ndx = (int) SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_ADDSTRING, 0,(LPARAM) L"64");
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 8);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETCURSEL, ndx,0);
|
|
|
|
for (ndx = 0; ndx < BLOCKS_PER_XTS_DATA_UNIT; ndx++)
|
|
{
|
|
wchar_t tmpStr [16];
|
|
|
|
StringCbPrintfW (tmpStr, sizeof(tmpStr), L"%d", ndx);
|
|
|
|
ndx = (int) SendMessage (GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_ADDSTRING, 0,(LPARAM) tmpStr);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_SETITEMDATA, ndx,(LPARAM) ndx);
|
|
}
|
|
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_SETCURSEL, 0, 0);
|
|
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), L"0000000000000000000000000000000000000000000000000000000000000000");
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), L"0");
|
|
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), L"0000000000000000");
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), L"0000000000000000");
|
|
|
|
if (idTestCipher == AES || idTestCipher == SERPENT || idTestCipher == TWOFISH || idTestCipher == CAMELLIA
|
|
|| idTestCipher == KUZNYECHIK
|
|
)
|
|
{
|
|
ndx = (int) SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) L"256");
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 32);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETCURSEL, ndx,0);
|
|
|
|
SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_RESETCONTENT, 0,0);
|
|
ndx = (int) SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_ADDSTRING, 0,(LPARAM) L"128");
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 16);
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETCURSEL, ndx,0);
|
|
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_KEY), L"0000000000000000000000000000000000000000000000000000000000000000");
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), L"00000000000000000000000000000000");
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), L"00000000000000000000000000000000");
|
|
}
|
|
}
|
|
|
|
#endif // #ifndef SETUP
|
|
|
|
|
|
BOOL CALLBACK MultiChoiceDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int nChoiceIDs [MAX_MULTI_CHOICES+1] = { IDC_MULTI_CHOICE_MSG, IDC_CHOICE1, IDC_CHOICE2, IDC_CHOICE3,
|
|
IDC_CHOICE4, IDC_CHOICE5, IDC_CHOICE6, IDC_CHOICE7, IDC_CHOICE8, IDC_CHOICE9, IDC_CHOICE10 };
|
|
int nBaseButtonWidth = 0;
|
|
int nBaseButtonHeight = 0;
|
|
int nActiveChoices = -1;
|
|
int nStr = 0;
|
|
int vertSubOffset, horizSubOffset, vertMsgHeightOffset;
|
|
int vertOffset = 0;
|
|
int nLongestButtonCaptionWidth = 6;
|
|
int nLongestButtonCaptionCharLen = 1;
|
|
int nTextGfxLineHeight = 0;
|
|
int nMainTextLenInChars = 0;
|
|
int newLineSeqCount = 0;
|
|
RECT rec, wrec, wtrec, trec;
|
|
BOOL bResolve;
|
|
|
|
WORD lw = LOWORD (wParam);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
char **pStr = (char **) ((MULTI_CHOICE_DLGPROC_PARAMS *) lParam)->strings;
|
|
char **pStrOrig = pStr;
|
|
wchar_t **pwStr = (wchar_t **) ((MULTI_CHOICE_DLGPROC_PARAMS *) lParam)->strings;
|
|
wchar_t **pwStrOrig = pwStr;
|
|
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
|
|
SetWindowPos (hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
SetWindowPos (hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
bResolve = (*pStr == NULL);
|
|
|
|
// Style
|
|
if (((MULTI_CHOICE_DLGPROC_PARAMS *) lParam)->bold)
|
|
{
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_MULTI_CHOICE_MSG), WM_SETFONT, (WPARAM) hUserBoldFont, (LPARAM) TRUE);
|
|
}
|
|
|
|
// Process the strings
|
|
pStr++;
|
|
pwStr++;
|
|
|
|
do
|
|
{
|
|
if (*pStr != 0)
|
|
{
|
|
SetWindowTextW (GetDlgItem(hwndDlg, nChoiceIDs[nStr]), bResolve ? GetString(*pStr) : *pwStr);
|
|
|
|
if (nStr > 0)
|
|
{
|
|
nLongestButtonCaptionWidth = max (
|
|
GetTextGfxWidth (GetDlgItem(hwndDlg, IDC_CHOICE1),
|
|
bResolve ? GetString(*pStr) : *pwStr,
|
|
hUserFont),
|
|
nLongestButtonCaptionWidth);
|
|
|
|
nLongestButtonCaptionCharLen = max (nLongestButtonCaptionCharLen,
|
|
(int) wcslen ((const wchar_t *) (bResolve ? GetString(*pStr) : *pwStr)));
|
|
}
|
|
|
|
nActiveChoices++;
|
|
pStr++;
|
|
pwStr++;
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(GetDlgItem(hwndDlg, nChoiceIDs[nStr]), SW_HIDE);
|
|
}
|
|
nStr++;
|
|
|
|
} while (nStr < MAX_MULTI_CHOICES+1);
|
|
|
|
// Length of main message in characters (not bytes)
|
|
nMainTextLenInChars = (int) wcslen ((const wchar_t *) (bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1)));
|
|
|
|
if (nMainTextLenInChars > 200
|
|
&& nMainTextLenInChars / nLongestButtonCaptionCharLen >= 10)
|
|
{
|
|
// As the main text is longer than 200 characters, we will "pad" the widest button caption with
|
|
// spaces (if it is not wide enough) so as to increase the width of the whole dialog window.
|
|
// Otherwise, it would look too tall (dialog boxes look better when they are more wide than tall).
|
|
nLongestButtonCaptionWidth = CompensateXDPI (max (
|
|
nLongestButtonCaptionWidth,
|
|
min (350, nMainTextLenInChars)));
|
|
}
|
|
|
|
// Get the window coords
|
|
GetWindowRect(hwndDlg, &wrec);
|
|
|
|
// Get the base button size
|
|
GetClientRect(GetDlgItem(hwndDlg, IDC_CHOICE1), &rec);
|
|
nBaseButtonWidth = rec.right + 2;
|
|
nBaseButtonHeight = rec.bottom + 2;
|
|
|
|
// Increase in width based on the gfx length of the widest button caption
|
|
horizSubOffset = min (CompensateXDPI (500), max (0, nLongestButtonCaptionWidth + CompensateXDPI (50) - nBaseButtonWidth));
|
|
|
|
// Vertical "title bar" offset
|
|
GetClientRect(hwndDlg, &wtrec);
|
|
vertOffset = wrec.bottom - wrec.top - wtrec.bottom - GetSystemMetrics(SM_CYFIXEDFRAME);
|
|
|
|
// Height/width of the message text
|
|
GetClientRect(GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG), &trec);
|
|
|
|
// Determine the number of newlines contained in the message text
|
|
{
|
|
int64 offset = -1;
|
|
|
|
do
|
|
{
|
|
offset = FindString ((char *) (bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1)),
|
|
(char *) L"\n",
|
|
nMainTextLenInChars * 2,
|
|
(int) wcslen (L"\n") * 2,
|
|
offset + 1);
|
|
|
|
newLineSeqCount++;
|
|
|
|
} while (offset != -1);
|
|
}
|
|
|
|
nTextGfxLineHeight = GetTextGfxHeight (GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG),
|
|
bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1),
|
|
hUserFont);
|
|
|
|
vertMsgHeightOffset = ((GetTextGfxWidth (GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG),
|
|
bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1),
|
|
hUserFont) / (trec.right + horizSubOffset) + 1) * nTextGfxLineHeight) - trec.bottom;
|
|
|
|
vertMsgHeightOffset = min (CompensateYDPI (350), vertMsgHeightOffset + newLineSeqCount * nTextGfxLineHeight + (trec.bottom + vertMsgHeightOffset) / 10); // As reserve, we are adding 10% and the number of lines equal to the number of newlines in the message
|
|
|
|
// Reduction in height according to the number of shown buttons
|
|
vertSubOffset = ((MAX_MULTI_CHOICES - nActiveChoices) * nBaseButtonHeight);
|
|
|
|
if (horizSubOffset > 0
|
|
|| vertMsgHeightOffset > 0
|
|
|| vertOffset > 0)
|
|
{
|
|
// Resize/move each button if necessary
|
|
for (nStr = 1; nStr < MAX_MULTI_CHOICES+1; nStr++)
|
|
{
|
|
GetWindowRect(GetDlgItem(hwndDlg, nChoiceIDs[nStr]), &rec);
|
|
|
|
MoveWindow (GetDlgItem(hwndDlg, nChoiceIDs[nStr]),
|
|
rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
|
|
rec.top - wrec.top - vertOffset + vertMsgHeightOffset,
|
|
nBaseButtonWidth + horizSubOffset,
|
|
nBaseButtonHeight,
|
|
TRUE);
|
|
}
|
|
|
|
// Resize/move the remaining GUI elements
|
|
GetWindowRect(GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG), &rec);
|
|
GetClientRect(GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG), &trec);
|
|
MoveWindow (GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG),
|
|
rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
|
|
rec.top - wrec.top - vertOffset,
|
|
trec.right + 2 + horizSubOffset,
|
|
trec.bottom + 2 + vertMsgHeightOffset,
|
|
TRUE);
|
|
|
|
GetWindowRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR1), &rec);
|
|
GetClientRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR1), &trec);
|
|
MoveWindow (GetDlgItem(hwndDlg, IDC_MC_DLG_HR1),
|
|
rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
|
|
rec.top - wrec.top - vertOffset,
|
|
trec.right + 2 + horizSubOffset,
|
|
trec.bottom + 2,
|
|
TRUE);
|
|
|
|
GetWindowRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR2), &rec);
|
|
GetClientRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR2), &trec);
|
|
MoveWindow (GetDlgItem(hwndDlg, IDC_MC_DLG_HR2),
|
|
rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
|
|
rec.top - wrec.top - vertOffset + vertMsgHeightOffset,
|
|
trec.right + 2 + horizSubOffset,
|
|
trec.bottom + 2,
|
|
TRUE);
|
|
}
|
|
|
|
// Resize the window according to number of shown buttons and the longest button caption
|
|
MoveWindow (hwndDlg,
|
|
wrec.left - horizSubOffset / 2,
|
|
wrec.top + vertSubOffset / 2 - vertMsgHeightOffset / 2,
|
|
wrec.right - wrec.left + horizSubOffset,
|
|
wrec.bottom - wrec.top - vertSubOffset + 1 + vertMsgHeightOffset,
|
|
TRUE);
|
|
|
|
DisableCloseButton (hwndDlg);
|
|
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
|
|
if (lw == IDCLOSE || lw == IDCANCEL)
|
|
{
|
|
EndDialog (hwndDlg, 0);
|
|
return 1;
|
|
}
|
|
|
|
for (nStr = 1; nStr < MAX_MULTI_CHOICES+1; nStr++)
|
|
{
|
|
if (lw == nChoiceIDs[nStr])
|
|
{
|
|
EndDialog (hwndDlg, nStr);
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
// This prevents the window from being closed by pressing Alt-F4 (the Close button is hidden).
|
|
// Note that the OS handles modal MessageBox() dialog windows the same way.
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL CheckCapsLock (HWND hwnd, BOOL quiet)
|
|
{
|
|
if ((GetKeyState(VK_CAPITAL) & 1) != 0)
|
|
{
|
|
if (!quiet)
|
|
{
|
|
MessageBoxW (hwnd, GetString ("CAPSLOCK_ON"), lpszTitle, MB_ICONEXCLAMATION);
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Checks whether the file extension is not used for executable files or similarly problematic, which often
|
|
// causes Windows and antivirus software to interfere with the container.
|
|
BOOL CheckFileExtension (wchar_t *fileName)
|
|
{
|
|
int i = 0;
|
|
wchar_t *ext = wcsrchr (fileName, L'.');
|
|
static wchar_t *problemFileExt[] = {
|
|
// These are protected by the Windows Resource Protection
|
|
L".asa", L".asp", L".aspx", L".ax", L".bas", L".bat", L".bin", L".cer", L".chm", L".clb", L".cmd", L".cnt", L".cnv",
|
|
L".com", L".cpl", L".cpx", L".crt", L".csh", L".dll", L".drv", L".dtd", L".exe", L".fxp", L".grp", L".h1s", L".hlp",
|
|
L".hta", L".ime", L".inf", L".ins", L".isp", L".its", L".js", L".jse", L".ksh", L".lnk", L".mad", L".maf", L".mag",
|
|
L".mam", L".man", L".maq", L".mar", L".mas", L".mat", L".mau", L".mav", L".maw", L".mda", L".mdb", L".mde", L".mdt",
|
|
L".mdw", L".mdz", L".msc", L".msi", L".msp", L".mst", L".mui", L".nls", L".ocx", L".ops", L".pal", L".pcd", L".pif",
|
|
L".prf", L".prg", L".pst", L".reg", L".scf", L".scr", L".sct", L".shb", L".shs", L".sys", L".tlb", L".tsp", L".url",
|
|
L".vb", L".vbe", L".vbs", L".vsmacros", L".vss", L".vst", L".vsw", L".ws", L".wsc", L".wsf", L".wsh", L".xsd", L".xsl",
|
|
// These additional file extensions are usually watched by antivirus programs
|
|
L".386", L".acm", L".ade", L".adp", L".ani", L".app", L".asd", L".asf", L".asx", L".awx", L".ax", L".boo", L".bz2", L".cdf",
|
|
L".class", L".dhtm", L".dhtml",L".dlo", L".emf", L".eml", L".flt", L".fot", L".gz", L".hlp", L".htm", L".html", L".ini",
|
|
L".j2k", L".jar", L".jff", L".jif", L".jmh", L".jng", L".jp2", L".jpe", L".jpeg", L".jpg", L".lsp", L".mod", L".nws",
|
|
L".obj", L".olb", L".osd", L".ov1", L".ov2", L".ov3", L".ovl", L".ovl", L".ovr", L".pdr", L".pgm", L".php", L".pkg",
|
|
L".pl", L".png", L".pot", L".pps", L".ppt", L".ps1", L".ps1xml", L".psc1", L".rar", L".rpl", L".rtf", L".sbf", L".script", L".sh", L".sha", L".shtm",
|
|
L".shtml", L".spl", L".swf", L".tar", L".tgz", L".tmp", L".ttf", L".vcs", L".vlm", L".vxd", L".vxo", L".wiz", L".wll", L".wmd",
|
|
L".wmf", L".wms", L".wmz", L".wpc", L".wsc", L".wsh", L".wwk", L".xhtm", L".xhtml", L".xl", L".xml", L".zip", L".7z", 0};
|
|
|
|
if (!ext)
|
|
return FALSE;
|
|
|
|
while (problemFileExt[i])
|
|
{
|
|
if (!_wcsicmp (ext, problemFileExt[i++]))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsTrueCryptFileExtension (wchar_t *fileName)
|
|
{
|
|
wchar_t *ext = wcsrchr (fileName, L'.');
|
|
if (ext && !_wcsicmp (ext, L".tc"))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
void CorrectFileName (wchar_t* fileName)
|
|
{
|
|
/* replace '/' by '\' */
|
|
size_t i, len = wcslen (fileName);
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if (fileName [i] == L'/')
|
|
fileName [i] = L'\\';
|
|
}
|
|
}
|
|
|
|
void CorrectFileName (std::wstring& fileName)
|
|
{
|
|
/* replace '/' by '\' */
|
|
size_t i, len = fileName.length();
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if (fileName [i] == L'/')
|
|
fileName [i] = L'\\';
|
|
}
|
|
}
|
|
|
|
void CorrectURL (wchar_t* fileName)
|
|
{
|
|
/* replace '\' by '/' */
|
|
size_t i, len = wcslen (fileName);
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if (fileName [i] == L'\\')
|
|
fileName [i] = L'/';
|
|
}
|
|
}
|
|
|
|
void IncreaseWrongPwdRetryCount (int count)
|
|
{
|
|
WrongPwdRetryCounter += count;
|
|
}
|
|
|
|
|
|
void ResetWrongPwdRetryCount (void)
|
|
{
|
|
WrongPwdRetryCounter = 0;
|
|
}
|
|
|
|
|
|
BOOL WrongPwdRetryCountOverLimit (void)
|
|
{
|
|
return (WrongPwdRetryCounter > TC_TRY_HEADER_BAK_AFTER_NBR_WRONG_PWD_TRIES);
|
|
}
|
|
|
|
DWORD GetUsedLogicalDrives (void)
|
|
{
|
|
DWORD dwUsedDrives = GetLogicalDrives();
|
|
if (!bShowDisconnectedNetworkDrives)
|
|
{
|
|
static DWORD g_dwLastMappedDrives = 0;
|
|
static time_t g_lastCallTime = 0;
|
|
|
|
EnterCriticalSection (&csWNetCalls);
|
|
|
|
finally_do ({ LeaveCriticalSection (&csWNetCalls); });
|
|
|
|
/* update values every 1 minute to reduce CPU consumption */
|
|
if ((time (NULL) - g_lastCallTime) > 60)
|
|
{
|
|
/* detect disconnected mapped network shares and removed
|
|
* their associated drives from the list
|
|
*/
|
|
WCHAR remotePath[512];
|
|
WCHAR drive[3] = {L'A', L':', 0};
|
|
DWORD dwLen, status;
|
|
g_dwLastMappedDrives = 0;
|
|
for (WCHAR i = 0; i <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; i++)
|
|
{
|
|
if ((dwUsedDrives & (1 << i)) == 0)
|
|
{
|
|
drive[0] = L'A' + i;
|
|
dwLen = ARRAYSIZE (remotePath);
|
|
status = WNetGetConnection (drive, remotePath, &dwLen);
|
|
if ((NO_ERROR == status) || (status == ERROR_CONNECTION_UNAVAIL))
|
|
{
|
|
/* this is a mapped network share, mark it as used */
|
|
g_dwLastMappedDrives |= (1 << i);
|
|
}
|
|
}
|
|
}
|
|
|
|
g_lastCallTime = time (NULL);
|
|
}
|
|
|
|
dwUsedDrives |= g_dwLastMappedDrives;
|
|
}
|
|
|
|
return dwUsedDrives;
|
|
}
|
|
|
|
|
|
int GetFirstAvailableDrive ()
|
|
{
|
|
DWORD dwUsedDrives = GetUsedLogicalDrives();
|
|
int i, drive;
|
|
|
|
/* let A: and B: be used as last resort since they can introduce side effects */
|
|
for (i = 2; i < 28; i++)
|
|
{
|
|
drive = (i < 26) ? i : (i - 26);
|
|
if (!(dwUsedDrives & 1 << drive))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int GetLastAvailableDrive ()
|
|
{
|
|
DWORD dwUsedDrives = GetUsedLogicalDrives();
|
|
int i;
|
|
|
|
for (i = 25; i >= 0; i--)
|
|
{
|
|
if (!(dwUsedDrives & 1 << i))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
BOOL IsDriveAvailable (int driveNo)
|
|
{
|
|
if (driveNo >= 0 && driveNo < 26)
|
|
return (GetUsedLogicalDrives() & (1 << driveNo)) == 0;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL IsDeviceMounted (wchar_t *deviceName)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
DWORD dwResult;
|
|
HANDLE dev = INVALID_HANDLE_VALUE;
|
|
|
|
if ((dev = CreateFile (deviceName,
|
|
GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
bResult = DeviceIoControl (dev, FSCTL_IS_VOLUME_MOUNTED, NULL, 0, NULL, 0, &dwResult, NULL);
|
|
CloseHandle (dev);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
int DriverUnmountVolume (HWND hwndDlg, int nDosDriveNo, BOOL forced)
|
|
{
|
|
UNMOUNT_STRUCT unmount;
|
|
DWORD dwResult;
|
|
VOLUME_PROPERTIES_STRUCT prop;
|
|
BOOL bResult;
|
|
WCHAR wszLabel[33] = {0};
|
|
BOOL bDriverSetLabel = FALSE;
|
|
|
|
memset (&prop, 0, sizeof(prop));
|
|
prop.driveNo = nDosDriveNo;
|
|
|
|
if ( DeviceIoControl (hDriver, TC_IOCTL_GET_VOLUME_PROPERTIES, &prop, sizeof (prop), &prop, sizeof (prop), &dwResult, NULL)
|
|
&& prop.driveNo == nDosDriveNo
|
|
)
|
|
{
|
|
memcpy (wszLabel, prop.wszLabel, sizeof (wszLabel));
|
|
bDriverSetLabel = prop.bDriverSetLabel;
|
|
}
|
|
|
|
unmount.nDosDriveNo = nDosDriveNo;
|
|
unmount.ignoreOpenFiles = forced;
|
|
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_DISMOUNT_VOLUME, &unmount,
|
|
sizeof (unmount), &unmount, sizeof (unmount), &dwResult, NULL);
|
|
|
|
if (bResult == FALSE)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
return 1;
|
|
}
|
|
else if ((unmount.nReturnCode == ERR_SUCCESS) && bDriverSetLabel && wszLabel[0])
|
|
UpdateDriveCustomLabel (nDosDriveNo, wszLabel, FALSE);
|
|
|
|
#ifdef TCMOUNT
|
|
|
|
if (unmount.nReturnCode == ERR_SUCCESS
|
|
&& unmount.HiddenVolumeProtectionTriggered
|
|
&& !VolumeNotificationsList.bHidVolDamagePrevReported [nDosDriveNo]
|
|
&& !Silent)
|
|
{
|
|
wchar_t msg[4096];
|
|
|
|
VolumeNotificationsList.bHidVolDamagePrevReported [nDosDriveNo] = TRUE;
|
|
StringCbPrintfW (msg, sizeof(msg), GetString ("DAMAGE_TO_HIDDEN_VOLUME_PREVENTED"), nDosDriveNo + L'A');
|
|
SetForegroundWindow (hwndDlg);
|
|
MessageBoxW (hwndDlg, msg, lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
#endif // #ifdef TCMOUNT
|
|
|
|
return unmount.nReturnCode;
|
|
}
|
|
|
|
|
|
void BroadcastDeviceChange (WPARAM message, int nDosDriveNo, DWORD driveMap)
|
|
{
|
|
DEV_BROADCAST_VOLUME dbv;
|
|
DWORD_PTR dwResult;
|
|
LONG eventId = 0;
|
|
int i;
|
|
|
|
if (DeviceChangeBroadcastDisabled)
|
|
return;
|
|
|
|
if (message == DBT_DEVICEARRIVAL)
|
|
eventId = SHCNE_DRIVEADD;
|
|
else if (message == DBT_DEVICEREMOVECOMPLETE)
|
|
eventId = SHCNE_DRIVEREMOVED;
|
|
else if (IsOSAtLeast (WIN_7) && message == DBT_DEVICEREMOVEPENDING) // Explorer on Windows 7 holds open handles of all drives when 'Computer' is expanded in navigation pane. SHCNE_DRIVEREMOVED must be used as DBT_DEVICEREMOVEPENDING is ignored.
|
|
eventId = SHCNE_DRIVEREMOVED;
|
|
|
|
if (driveMap == 0)
|
|
driveMap = (1 << nDosDriveNo);
|
|
|
|
if (eventId != 0)
|
|
{
|
|
for (i = 0; i < 26; i++)
|
|
{
|
|
if (driveMap & (1 << i))
|
|
{
|
|
wchar_t root[] = { (wchar_t) i + L'A', L':', L'\\', 0 };
|
|
SHChangeNotify (eventId, SHCNF_PATH, root, NULL);
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
dbv.dbcv_size = sizeof (dbv);
|
|
dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
|
|
dbv.dbcv_reserved = 0;
|
|
dbv.dbcv_unitmask = driveMap;
|
|
dbv.dbcv_flags = 0;
|
|
|
|
UINT timeOut = 1000;
|
|
|
|
// SHChangeNotify() works on Vista, so the Explorer does not require WM_DEVICECHANGE
|
|
if (CurrentOSMajor >= 6)
|
|
timeOut = 100;
|
|
|
|
IgnoreWmDeviceChange = TRUE;
|
|
SendMessageTimeout (HWND_BROADCAST, WM_DEVICECHANGE, message, (LPARAM)(&dbv), SMTO_ABORTIFHUNG, timeOut, &dwResult);
|
|
|
|
// Explorer prior Vista sometimes fails to register a new drive
|
|
if (CurrentOSMajor < 6 && message == DBT_DEVICEARRIVAL)
|
|
SendMessageTimeout (HWND_BROADCAST, WM_DEVICECHANGE, message, (LPARAM)(&dbv), SMTO_ABORTIFHUNG, 200, &dwResult);
|
|
|
|
IgnoreWmDeviceChange = FALSE;
|
|
}
|
|
|
|
static BOOL GetDeviceStorageProperty (HANDLE hDevice, STORAGE_PROPERTY_ID propertyId, DWORD dwDescSize, void* pDesc)
|
|
{
|
|
DWORD dwRet = NO_ERROR;
|
|
|
|
if (!pDesc)
|
|
return FALSE;
|
|
|
|
ZeroMemory (pDesc, dwDescSize);
|
|
|
|
// Set the input data structure
|
|
STORAGE_PROPERTY_QUERY storagePropertyQuery;
|
|
ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY));
|
|
storagePropertyQuery.PropertyId = propertyId;
|
|
storagePropertyQuery.QueryType = PropertyStandardQuery;
|
|
|
|
// Get the necessary output buffer size
|
|
STORAGE_DESCRIPTOR_HEADER descHeader = {0};
|
|
DWORD dwBytesReturned = 0;
|
|
BOOL bRet = ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
|
|
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
|
|
&descHeader, sizeof(STORAGE_DESCRIPTOR_HEADER),
|
|
&dwBytesReturned, NULL);
|
|
if (bRet)
|
|
{
|
|
if (dwBytesReturned == sizeof(STORAGE_DESCRIPTOR_HEADER))
|
|
{
|
|
unsigned char* outputBuffer = (unsigned char*) TCalloc (descHeader.Size);
|
|
bRet = ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
|
|
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
|
|
outputBuffer, descHeader.Size,
|
|
&dwBytesReturned, NULL);
|
|
if (bRet)
|
|
{
|
|
if (dwBytesReturned >= dwDescSize)
|
|
{
|
|
memcpy (pDesc, outputBuffer, dwDescSize);
|
|
((STORAGE_DESCRIPTOR_HEADER*)pDesc)->Version = dwDescSize;
|
|
((STORAGE_DESCRIPTOR_HEADER*)pDesc)->Size = dwDescSize;
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
dwRet = ERROR_UNHANDLED_ERROR;
|
|
}
|
|
}
|
|
else
|
|
dwRet = ::GetLastError();
|
|
TCfree (outputBuffer);
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
dwRet = ERROR_UNHANDLED_ERROR;
|
|
}
|
|
}
|
|
else
|
|
dwRet = ::GetLastError();
|
|
|
|
if (!bRet)
|
|
{
|
|
SetLastError (dwRet);
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GetPhysicalDriveStorageInformation(UINT nDriveNumber, STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR* pAlignmentDesc, STORAGE_ADAPTER_DESCRIPTOR* pAdapterDesc)
|
|
{
|
|
DWORD dwRet = NO_ERROR;
|
|
|
|
if (!pAlignmentDesc || pAdapterDesc)
|
|
{
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
// Format physical drive path (may be '\\.\PhysicalDrive0', '\\.\PhysicalDrive1' and so on).
|
|
TCHAR strDrivePath[512];
|
|
StringCbPrintf(strDrivePath, sizeof(strDrivePath), _T("\\\\.\\PhysicalDrive%u"), nDriveNumber);
|
|
|
|
// Get a handle to physical drive
|
|
HANDLE hDevice = ::CreateFile(strDrivePath, 0, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if(INVALID_HANDLE_VALUE == hDevice)
|
|
return FALSE;
|
|
|
|
BOOL bRet = (GetDeviceStorageProperty (hDevice, StorageAccessAlignmentProperty, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), pAlignmentDesc)
|
|
|| GetDeviceStorageProperty (hDevice, StorageAdapterProperty, sizeof (STORAGE_ADAPTER_DESCRIPTOR), pAdapterDesc))? TRUE : FALSE;
|
|
dwRet = ::GetLastError();
|
|
::CloseHandle(hDevice);
|
|
|
|
if (!bRet)
|
|
{
|
|
SetLastError (dwRet);
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
#ifndef SETUP
|
|
|
|
/************************************************************/
|
|
|
|
// implementation of the generic wait dialog mechanism
|
|
|
|
static UINT g_wmWaitDlg = ::RegisterWindowMessage(L"VeraCryptWaitDlgMessage");
|
|
|
|
typedef struct
|
|
{
|
|
HWND hwnd;
|
|
void* pArg;
|
|
WaitThreadProc callback;
|
|
} WaitThreadParam;
|
|
|
|
static void _cdecl WaitThread (void* pParam)
|
|
{
|
|
WaitThreadParam* pThreadParam = (WaitThreadParam*) pParam;
|
|
|
|
pThreadParam->callback(pThreadParam->pArg, pThreadParam->hwnd);
|
|
|
|
/* close the wait dialog */
|
|
PostMessage (pThreadParam->hwnd, g_wmWaitDlg, 0, 0);
|
|
}
|
|
|
|
BOOL CALLBACK WaitDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
WaitThreadParam* thParam = (WaitThreadParam*) lParam;
|
|
|
|
// set the progress bar type to MARQUEE (indefinite progress)
|
|
HWND hProgress = GetDlgItem (hwndDlg, IDC_WAIT_PROGRESS_BAR);
|
|
if (hProgress)
|
|
{
|
|
SetWindowLongPtrW (hProgress, GWL_STYLE, PBS_MARQUEE | GetWindowLongPtrW (hProgress, GWL_STYLE));
|
|
::SendMessageW(hProgress, PBM_SETMARQUEE, (WPARAM) TRUE, (LPARAM) 0);
|
|
}
|
|
|
|
thParam->hwnd = hwndDlg;
|
|
|
|
// For now, we don't have system menu is the resources but we leave this code
|
|
// if it is enabled in the future
|
|
HMENU hSysMenu = GetSystemMenu(hwndDlg, FALSE);
|
|
if (hSysMenu)
|
|
{
|
|
//disable the X
|
|
EnableMenuItem(hSysMenu,SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
|
|
|
|
// set icons
|
|
HICON hIcon = (HICON)::LoadImage(hInst, MAKEINTRESOURCE(IDI_TRUECRYPT_ICON), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
|
|
::SendMessage(hwndDlg, WM_SETICON, TRUE, (LPARAM)hIcon);
|
|
HICON hIconSmall = (HICON)::LoadImage(hInst, MAKEINTRESOURCE(IDI_TRUECRYPT_ICON), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
|
|
::SendMessage(hwndDlg, WM_SETICON, FALSE, (LPARAM)hIconSmall);
|
|
}
|
|
|
|
LocalizeDialog (hwndDlg, NULL);
|
|
_beginthread(WaitThread, 0, thParam);
|
|
return 0;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
|
|
if (lw == IDOK || lw == IDCANCEL)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
|
|
default:
|
|
if (msg == g_wmWaitDlg)
|
|
{
|
|
EndDialog (hwndDlg, IDOK);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// Based on source: https://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo?msg=5285754#xx5285754xx
|
|
void BringToForeground (HWND hWnd)
|
|
{
|
|
if(!::IsWindow(hWnd)) return;
|
|
HWND hCurrWnd = ::GetForegroundWindow();
|
|
DWORD dwThisTID = ::GetCurrentThreadId(),
|
|
dwCurrTID = ::GetWindowThreadProcessId(hCurrWnd,0);
|
|
// This structure will be used to create the keyboard
|
|
// input event.
|
|
INPUT ip;
|
|
|
|
if (hCurrWnd != hWnd)
|
|
{
|
|
if(dwThisTID != dwCurrTID)
|
|
{
|
|
// Set up a generic keyboard event.
|
|
ip.type = INPUT_KEYBOARD;
|
|
ip.ki.wScan = 0; // hardware scan code for key
|
|
ip.ki.time = 0;
|
|
ip.ki.dwExtraInfo = 0;
|
|
|
|
// Press the "A" key
|
|
ip.ki.wVk = VK_MENU; // virtual-key code for the "a" key
|
|
ip.ki.dwFlags = 0; // 0 for key press
|
|
SendInput(1, &ip, sizeof(INPUT));
|
|
|
|
::Sleep(250); //Sometimes SetForegroundWindow will fail and the window will flash instead of it being show. Sleeping for a bit seems to help.
|
|
}
|
|
|
|
::SetForegroundWindow(hWnd);
|
|
|
|
if(dwThisTID != dwCurrTID)
|
|
{
|
|
// Release the "A" key
|
|
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
|
|
SendInput(1, &ip, sizeof(INPUT));
|
|
}
|
|
}
|
|
|
|
#ifdef TCMOUNT
|
|
if (hWnd == MainDlg)
|
|
{
|
|
SetFocus (hWnd);
|
|
::SendMessage(hWnd, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hWnd, IDC_DRIVELIST), 1L);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static LRESULT CALLBACK ShowWaitDialogParentWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return DefWindowProcW (hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
|
|
void ShowWaitDialog(HWND hwnd, BOOL bUseHwndAsParent, WaitThreadProc callback, void* pArg)
|
|
{
|
|
BOOL bEffectiveHideWaitingDialog = bCmdHideWaitingDialogValid? bCmdHideWaitingDialog : bHideWaitingDialog;
|
|
WaitThreadParam threadParam;
|
|
threadParam.callback = callback;
|
|
threadParam.pArg = pArg;
|
|
|
|
if (WaitDialogDisplaying || bEffectiveHideWaitingDialog)
|
|
{
|
|
if (!WaitDialogDisplaying) WaitCursor ();
|
|
callback (pArg, hwnd);
|
|
if (!WaitDialogDisplaying) NormalCursor ();
|
|
}
|
|
else
|
|
{
|
|
const wchar_t *className = L"VeraCryptShowWaitDialogParent";
|
|
BOOL bIsForeground = FALSE;
|
|
HWND creatorWnd = hwnd? hwnd : MainDlg;
|
|
WaitDialogDisplaying = TRUE;
|
|
HWND hParent = NULL;
|
|
|
|
if (creatorWnd)
|
|
{
|
|
if (GetForegroundWindow () == creatorWnd)
|
|
bIsForeground = TRUE;
|
|
EnableWindow (creatorWnd, FALSE);
|
|
}
|
|
|
|
if (hwnd && bUseHwndAsParent)
|
|
hParent = hwnd;
|
|
else
|
|
{
|
|
/* create invisible window and use it as parent */
|
|
WNDCLASSEXW winClass;
|
|
|
|
memset (&winClass, 0, sizeof (winClass));
|
|
winClass.cbSize = sizeof (WNDCLASSEX);
|
|
winClass.lpfnWndProc = (WNDPROC) ShowWaitDialogParentWndProc;
|
|
winClass.hInstance = hInst;
|
|
winClass.lpszClassName = className;
|
|
RegisterClassExW (&winClass);
|
|
|
|
hParent = CreateWindowExW (WS_EX_TOOLWINDOW | WS_EX_LAYERED, className, L"VeraCrypt ShowWaitDialog Parent", 0, 0, 0, 1, 1, NULL, NULL, hInst, NULL);
|
|
if (hParent)
|
|
{
|
|
SetLayeredWindowAttributes (hParent, 0, 1, LWA_ALPHA);
|
|
ShowWindow (hParent, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
|
|
finally_do_arg2 (HWND, creatorWnd, BOOL, bIsForeground, { if (finally_arg) { EnableWindow(finally_arg, TRUE); if (finally_arg2) BringToForeground (finally_arg);}});
|
|
|
|
DialogBoxParamW (hInst,
|
|
MAKEINTRESOURCEW (IDD_STATIC_MODAL_WAIT_DLG), hParent,
|
|
(DLGPROC) WaitDlgProc, (LPARAM) &threadParam);
|
|
|
|
WaitDialogDisplaying = FALSE;
|
|
|
|
if (!(hwnd && bUseHwndAsParent))
|
|
{
|
|
if (hParent)
|
|
DestroyWindow (hParent);
|
|
UnregisterClassW (className, hInst);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef SETUP
|
|
/************************************************************************/
|
|
|
|
static BOOL PerformMountIoctl (MOUNT_STRUCT* pmount, LPDWORD pdwResult, BOOL useVolumeID, BYTE volumeID[VOLUME_ID_SIZE])
|
|
{
|
|
if (useVolumeID)
|
|
{
|
|
wstring devicePath = FindDeviceByVolumeID (volumeID, FALSE);
|
|
if (devicePath == L"")
|
|
{
|
|
if (pdwResult)
|
|
*pdwResult = 0;
|
|
SetLastError (ERROR_PATH_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
BOOL bDevice = FALSE;
|
|
CreateFullVolumePath (pmount->wszVolume, sizeof(pmount->wszVolume), devicePath.c_str(), &bDevice);
|
|
}
|
|
}
|
|
|
|
return DeviceIoControl (hDriver, TC_IOCTL_MOUNT_VOLUME, pmount,
|
|
sizeof (MOUNT_STRUCT), pmount, sizeof (MOUNT_STRUCT), pdwResult, NULL);
|
|
}
|
|
|
|
// specific definitions and implementation for support of mount operation
|
|
// in wait dialog mechanism
|
|
|
|
typedef struct
|
|
{
|
|
MOUNT_STRUCT* pmount;
|
|
BOOL useVolumeID;
|
|
BYTE volumeID[VOLUME_ID_SIZE];
|
|
BOOL* pbResult;
|
|
DWORD* pdwResult;
|
|
DWORD dwLastError;
|
|
} MountThreadParam;
|
|
|
|
void CALLBACK MountWaitThreadProc(void* pArg, HWND )
|
|
{
|
|
MountThreadParam* pThreadParam = (MountThreadParam*) pArg;
|
|
|
|
*(pThreadParam->pbResult) = PerformMountIoctl (pThreadParam->pmount, pThreadParam->pdwResult, pThreadParam->useVolumeID, pThreadParam->volumeID);
|
|
|
|
pThreadParam->dwLastError = GetLastError ();
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
// Use only cached passwords if password = NULL
|
|
//
|
|
// Returns:
|
|
// -1 = user aborted mount / error
|
|
// 0 = mount failed
|
|
// 1 = mount OK
|
|
// 2 = mount OK in shared mode
|
|
//
|
|
// Note that some code calling this relies on the content of the mountOptions struct
|
|
// to remain unmodified (don't remove the 'const' without proper revision).
|
|
|
|
int MountVolume (HWND hwndDlg,
|
|
int driveNo,
|
|
wchar_t *volumePath,
|
|
Password *password,
|
|
int pkcs5,
|
|
int pim,
|
|
BOOL truecryptMode,
|
|
BOOL cachePassword,
|
|
BOOL cachePim,
|
|
BOOL sharedAccess,
|
|
const MountOptions* const mountOptions,
|
|
BOOL quiet,
|
|
BOOL bReportWrongPassword)
|
|
{
|
|
MOUNT_STRUCT mount;
|
|
DWORD dwResult, dwLastError = ERROR_SUCCESS;
|
|
BOOL bResult, bDevice;
|
|
wchar_t root[MAX_PATH];
|
|
int favoriteMountOnArrivalRetryCount = 0;
|
|
BOOL useVolumeID = FALSE;
|
|
BYTE volumeID[VOLUME_ID_SIZE] = {0};
|
|
|
|
#ifdef TCMOUNT
|
|
if (mountOptions->PartitionInInactiveSysEncScope)
|
|
{
|
|
if (!CheckSysEncMountWithoutPBA (hwndDlg, volumePath, quiet))
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if (IsMountedVolume (volumePath))
|
|
{
|
|
if (!quiet)
|
|
Error ("VOL_ALREADY_MOUNTED", hwndDlg);
|
|
return -1;
|
|
}
|
|
|
|
if (!IsDriveAvailable (driveNo))
|
|
{
|
|
if (!quiet)
|
|
Error ("DRIVE_LETTER_UNAVAILABLE", hwndDlg);
|
|
|
|
return -1;
|
|
}
|
|
|
|
// If using cached passwords, check cache status first
|
|
if (password == NULL && (mountOptions->SkipCachedPasswords || IsPasswordCacheEmpty ()))
|
|
return 0;
|
|
|
|
ZeroMemory (&mount, sizeof (mount));
|
|
mount.bExclusiveAccess = sharedAccess ? FALSE : TRUE;
|
|
mount.SystemFavorite = MountVolumesAsSystemFavorite;
|
|
mount.UseBackupHeader = mountOptions->UseBackupHeader;
|
|
mount.RecoveryMode = mountOptions->RecoveryMode;
|
|
StringCbCopyW (mount.wszLabel, sizeof (mount.wszLabel), mountOptions->Label);
|
|
|
|
retry:
|
|
mount.nDosDriveNo = driveNo;
|
|
mount.bCache = cachePassword;
|
|
mount.bCachePim = cachePim;
|
|
|
|
mount.bPartitionInInactiveSysEncScope = FALSE;
|
|
|
|
if (password != NULL)
|
|
mount.VolumePassword = *password;
|
|
else
|
|
mount.VolumePassword.Length = 0;
|
|
|
|
if (!mountOptions->ReadOnly && mountOptions->ProtectHiddenVolume)
|
|
{
|
|
mount.ProtectedHidVolPassword = mountOptions->ProtectedHidVolPassword;
|
|
mount.bProtectHiddenVolume = TRUE;
|
|
mount.ProtectedHidVolPkcs5Prf = mountOptions->ProtectedHidVolPkcs5Prf;
|
|
mount.ProtectedHidVolPim = mountOptions->ProtectedHidVolPim;
|
|
}
|
|
else
|
|
mount.bProtectHiddenVolume = FALSE;
|
|
|
|
mount.bMountReadOnly = mountOptions->ReadOnly;
|
|
mount.bMountRemovable = mountOptions->Removable;
|
|
mount.bPreserveTimestamp = mountOptions->PreserveTimestamp;
|
|
|
|
if (mountOptions->DisableMountManager)
|
|
mount.bMountManager = FALSE;
|
|
else
|
|
mount.bMountManager = TRUE;
|
|
mount.pkcs5_prf = pkcs5;
|
|
mount.bTrueCryptMode = truecryptMode;
|
|
mount.VolumePim = pim;
|
|
|
|
wstring path = volumePath;
|
|
if (path.find (L"\\\\?\\") == 0)
|
|
{
|
|
// Remove \\?\ prefix
|
|
path = path.substr (4);
|
|
StringCchCopyW (volumePath, TC_MAX_PATH, path.c_str());
|
|
}
|
|
|
|
if (path.find (L"Volume{") == 0 && path.rfind (L"}\\") == path.size() - 2)
|
|
{
|
|
wstring resolvedPath = VolumeGuidPathToDevicePath (path);
|
|
|
|
if (!resolvedPath.empty())
|
|
StringCchCopyW (volumePath, TC_MAX_PATH, resolvedPath.c_str());
|
|
}
|
|
|
|
if ((path.length () >= 3) && (_wcsnicmp (path.c_str(), L"ID:", 3) == 0))
|
|
{
|
|
std::vector<byte> arr;
|
|
if ( (path.length() == (3 + 2*VOLUME_ID_SIZE))
|
|
&& HexWideStringToArray (path.c_str() + 3, arr)
|
|
&& (arr.size() == VOLUME_ID_SIZE)
|
|
)
|
|
{
|
|
useVolumeID = TRUE;
|
|
bDevice = TRUE;
|
|
memcpy (volumeID, &arr[0], VOLUME_ID_SIZE);
|
|
}
|
|
else
|
|
{
|
|
if (!quiet)
|
|
Error ("VOLUME_ID_INVALID", hwndDlg);
|
|
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
CreateFullVolumePath (mount.wszVolume, sizeof(mount.wszVolume), volumePath, &bDevice);
|
|
|
|
if (!bDevice)
|
|
{
|
|
// put default values
|
|
mount.BytesPerSector = 512;
|
|
mount.BytesPerPhysicalSector = 512;
|
|
mount.MaximumTransferLength = 65536;
|
|
mount.MaximumPhysicalPages = 17;
|
|
mount.AlignmentMask = 0;
|
|
|
|
// UNC path
|
|
if (path.find (L"\\\\") == 0)
|
|
{
|
|
StringCbCopyW (mount.wszVolume, sizeof (mount.wszVolume), (L"UNC" + path.substr (1)).c_str());
|
|
}
|
|
|
|
if (GetVolumePathName (volumePath, root, ARRAYSIZE (root) - 1))
|
|
{
|
|
DWORD bps, flags, d;
|
|
if (GetDiskFreeSpace (root, &d, &bps, &d, &d))
|
|
{
|
|
mount.BytesPerSector = bps;
|
|
mount.BytesPerPhysicalSector = bps;
|
|
}
|
|
|
|
if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
if ( (wcslen(root) >= 2)
|
|
&& (root[1] == L':')
|
|
&& (towupper(root[0]) >= L'A' && towupper(root[0]) <= L'Z')
|
|
)
|
|
{
|
|
wstring drivePath = L"\\\\.\\X:";
|
|
HANDLE dev = INVALID_HANDLE_VALUE;
|
|
VOLUME_DISK_EXTENTS extents = {0};
|
|
DWORD dwResult = 0;
|
|
drivePath[4] = root[0];
|
|
|
|
if ((dev = CreateFile (drivePath.c_str(),0, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (DeviceIoControl (dev, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &extents, sizeof(extents), &dwResult, NULL))
|
|
{
|
|
if (extents.NumberOfDiskExtents > 0)
|
|
{
|
|
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR accessDesc;
|
|
STORAGE_ADAPTER_DESCRIPTOR adapterDesc;
|
|
|
|
if (GetPhysicalDriveStorageInformation (extents.Extents[0].DiskNumber, &accessDesc, &adapterDesc))
|
|
{
|
|
if (accessDesc.Size >= sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR))
|
|
{
|
|
mount.BytesPerSector = accessDesc.BytesPerLogicalSector;
|
|
mount.BytesPerPhysicalSector = accessDesc.BytesPerPhysicalSector;
|
|
}
|
|
|
|
if (adapterDesc.Size >= sizeof (STORAGE_ADAPTER_DESCRIPTOR))
|
|
{
|
|
mount.MaximumTransferLength = adapterDesc.MaximumTransferLength;
|
|
mount.MaximumPhysicalPages = adapterDesc.MaximumPhysicalPages;
|
|
mount.AlignmentMask = adapterDesc.AlignmentMask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CloseHandle (dev);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read-only host filesystem
|
|
if (!mount.bMountReadOnly && GetVolumeInformation (root, NULL, 0, NULL, &d, &flags, NULL, 0))
|
|
mount.bMountReadOnly = (flags & FILE_READ_ONLY_VOLUME) != 0;
|
|
}
|
|
}
|
|
|
|
if (mountOptions->PartitionInInactiveSysEncScope)
|
|
{
|
|
if (mount.wszVolume == NULL || swscanf_s ((const wchar_t *) mount.wszVolume,
|
|
WIDE("\\Device\\Harddisk%d\\Partition"),
|
|
&mount.nPartitionInInactiveSysEncScopeDriveNo,
|
|
sizeof(mount.nPartitionInInactiveSysEncScopeDriveNo)) != 1)
|
|
{
|
|
if (!quiet)
|
|
Warning ("NO_SYSENC_PARTITION_SELECTED", hwndDlg);
|
|
return -1;
|
|
}
|
|
|
|
mount.bPartitionInInactiveSysEncScope = TRUE;
|
|
}
|
|
|
|
if (!quiet)
|
|
{
|
|
MountThreadParam mountThreadParam;
|
|
mountThreadParam.pmount = &mount;
|
|
mountThreadParam.useVolumeID = useVolumeID;
|
|
memcpy (mountThreadParam.volumeID, volumeID, VOLUME_ID_SIZE);
|
|
mountThreadParam.pbResult = &bResult;
|
|
mountThreadParam.pdwResult = &dwResult;
|
|
mountThreadParam.dwLastError = ERROR_SUCCESS;
|
|
|
|
ShowWaitDialog (hwndDlg, FALSE, MountWaitThreadProc, &mountThreadParam);
|
|
|
|
dwLastError = mountThreadParam.dwLastError;
|
|
}
|
|
else
|
|
{
|
|
bResult = PerformMountIoctl (&mount, &dwResult, useVolumeID, volumeID);
|
|
|
|
dwLastError = GetLastError ();
|
|
}
|
|
|
|
burn (&mount.VolumePassword, sizeof (mount.VolumePassword));
|
|
burn (&mount.ProtectedHidVolPassword, sizeof (mount.ProtectedHidVolPassword));
|
|
burn (&mount.pkcs5_prf, sizeof (mount.pkcs5_prf));
|
|
burn (&mount.bTrueCryptMode, sizeof (mount.bTrueCryptMode));
|
|
burn (&mount.ProtectedHidVolPkcs5Prf, sizeof (mount.ProtectedHidVolPkcs5Prf));
|
|
|
|
SetLastError (dwLastError);
|
|
if (bResult == FALSE)
|
|
{
|
|
// Volume already open by another process
|
|
if (GetLastError () == ERROR_SHARING_VIOLATION)
|
|
{
|
|
if (FavoriteMountOnArrivalInProgress && ++favoriteMountOnArrivalRetryCount < 10)
|
|
{
|
|
Sleep (500);
|
|
goto retry;
|
|
}
|
|
|
|
if (mount.bExclusiveAccess == FALSE)
|
|
{
|
|
if (!quiet)
|
|
Error ("FILE_IN_USE_FAILED", hwndDlg);
|
|
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
if (quiet)
|
|
{
|
|
mount.bExclusiveAccess = FALSE;
|
|
goto retry;
|
|
}
|
|
|
|
// Ask user
|
|
if (IDYES == AskWarnNoYes ("FILE_IN_USE", hwndDlg))
|
|
{
|
|
mount.bExclusiveAccess = FALSE;
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
if (!quiet && (!MultipleMountOperationInProgress || GetLastError() != ERROR_NOT_READY))
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
|
|
return -1;
|
|
}
|
|
|
|
if (mount.nReturnCode != 0)
|
|
{
|
|
if (mount.nReturnCode == ERR_PASSWORD_WRONG)
|
|
{
|
|
// Do not report wrong password, if not instructed to
|
|
if (bReportWrongPassword)
|
|
{
|
|
IncreaseWrongPwdRetryCount (1); // We increase the count here only if bReportWrongPassword is TRUE, because "Auto-Mount All Devices" and other callers do it separately
|
|
|
|
if (WrongPwdRetryCountOverLimit ()
|
|
&& !mount.UseBackupHeader)
|
|
{
|
|
// Retry using embedded header backup (if any)
|
|
mount.UseBackupHeader = TRUE;
|
|
goto retry;
|
|
}
|
|
|
|
if (bDevice && mount.bProtectHiddenVolume)
|
|
{
|
|
int driveNo;
|
|
|
|
if (swscanf (volumePath, L"\\Device\\Harddisk%d\\Partition", &driveNo) == 1)
|
|
{
|
|
OPEN_TEST_STRUCT openTestStruct;
|
|
memset (&openTestStruct, 0, sizeof (openTestStruct));
|
|
|
|
openTestStruct.bDetectTCBootLoader = TRUE;
|
|
StringCchPrintfW ((wchar_t *) openTestStruct.wszFileName, array_capacity (openTestStruct.wszFileName), L"\\Device\\Harddisk%d\\Partition0", driveNo);
|
|
|
|
DWORD dwResult;
|
|
if (DeviceIoControl (hDriver, TC_IOCTL_OPEN_TEST, &openTestStruct, sizeof (OPEN_TEST_STRUCT), &openTestStruct, sizeof (OPEN_TEST_STRUCT), &dwResult, NULL) && openTestStruct.TCBootLoaderDetected)
|
|
WarningDirect ((GetWrongPasswordErrorMessage (hwndDlg) + L"\n\n" + GetString ("HIDDEN_VOL_PROT_PASSWORD_US_KEYB_LAYOUT")).c_str(), hwndDlg);
|
|
else
|
|
handleError (hwndDlg, mount.nReturnCode, SRC_POS);
|
|
}
|
|
}
|
|
else
|
|
handleError (hwndDlg, mount.nReturnCode, SRC_POS);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!quiet)
|
|
handleError (hwndDlg, mount.nReturnCode, SRC_POS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Mount successful
|
|
|
|
if (mount.UseBackupHeader != mountOptions->UseBackupHeader
|
|
&& mount.UseBackupHeader)
|
|
{
|
|
if (bReportWrongPassword && !Silent)
|
|
Warning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK", hwndDlg);
|
|
}
|
|
|
|
LastMountedVolumeDirty = mount.FilesystemDirty;
|
|
|
|
if (mount.FilesystemDirty)
|
|
{
|
|
wchar_t msg[1024];
|
|
wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
|
|
StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_VOLUME_DIRTY"), mountPoint);
|
|
|
|
if (AskWarnYesNoStringTopmost (msg, hwndDlg) == IDYES)
|
|
CheckFilesystem (hwndDlg, driveNo, TRUE);
|
|
}
|
|
|
|
if (mount.VolumeMountedReadOnlyAfterAccessDenied
|
|
&& !Silent
|
|
&& !bDevice
|
|
&& !FileHasReadOnlyAttribute (volumePath)
|
|
&& !IsFileOnReadOnlyFilesystem (volumePath))
|
|
{
|
|
wchar_t msg[1024];
|
|
wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
|
|
StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_CONTAINER_FORCED_READ_ONLY"), mountPoint);
|
|
|
|
WarningDirect (msg, hwndDlg);
|
|
}
|
|
|
|
if (mount.VolumeMountedReadOnlyAfterAccessDenied
|
|
&& !Silent
|
|
&& bDevice)
|
|
{
|
|
wchar_t msg[1024];
|
|
wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
|
|
StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_DEVICE_FORCED_READ_ONLY"), mountPoint);
|
|
|
|
WarningDirect (msg, hwndDlg);
|
|
}
|
|
|
|
if (mount.VolumeMountedReadOnlyAfterDeviceWriteProtected
|
|
&& !Silent
|
|
&& wcsstr (volumePath, L"\\Device\\Harddisk") == volumePath)
|
|
{
|
|
wchar_t msg[1024];
|
|
wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
|
|
StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_DEVICE_FORCED_READ_ONLY_WRITE_PROTECTION"), mountPoint);
|
|
|
|
WarningDirect (msg, hwndDlg);
|
|
|
|
if (CurrentOSMajor >= 6
|
|
&& wcsstr (volumePath, L"\\Device\\HarddiskVolume") != volumePath
|
|
&& AskNoYes ("ASK_REMOVE_DEVICE_WRITE_PROTECTION", hwndDlg) == IDYES)
|
|
{
|
|
RemoveDeviceWriteProtection (hwndDlg, volumePath);
|
|
}
|
|
}
|
|
|
|
if (mount.wszLabel[0] && !mount.bDriverSetLabel)
|
|
{
|
|
// try setting the drive label on user-mode using registry
|
|
UpdateDriveCustomLabel (driveNo, mount.wszLabel, TRUE);
|
|
}
|
|
|
|
ResetWrongPwdRetryCount ();
|
|
|
|
BroadcastDeviceChange (DBT_DEVICEARRIVAL, driveNo, 0);
|
|
|
|
if (mount.bExclusiveAccess == FALSE)
|
|
return 2;
|
|
|
|
return 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
int nDosDriveNo;
|
|
BOOL forced;
|
|
int dismountMaxRetries;
|
|
DWORD retryDelay;
|
|
int* presult;
|
|
DWORD dwLastError;
|
|
} UnmountThreadParam;
|
|
|
|
void CALLBACK UnmountWaitThreadProc(void* pArg, HWND hwnd)
|
|
{
|
|
UnmountThreadParam* pThreadParam = (UnmountThreadParam*) pArg;
|
|
int dismountMaxRetries = pThreadParam->dismountMaxRetries;
|
|
DWORD retryDelay = pThreadParam->retryDelay;
|
|
|
|
do
|
|
{
|
|
*pThreadParam->presult = DriverUnmountVolume (hwnd, pThreadParam->nDosDriveNo, pThreadParam->forced);
|
|
|
|
if (*pThreadParam->presult == ERR_FILES_OPEN)
|
|
Sleep (retryDelay);
|
|
else
|
|
break;
|
|
|
|
} while (--dismountMaxRetries > 0);
|
|
|
|
pThreadParam->dwLastError = GetLastError ();
|
|
}
|
|
|
|
static BOOL UnmountVolumeBase (HWND hwndDlg, int nDosDriveNo, BOOL forceUnmount, BOOL ntfsFormatCase)
|
|
{
|
|
int result;
|
|
BOOL forced = forceUnmount;
|
|
int dismountMaxRetries = ntfsFormatCase? 5 : UNMOUNT_MAX_AUTO_RETRIES;
|
|
DWORD retryDelay = ntfsFormatCase? 2000: UNMOUNT_AUTO_RETRY_DELAY;
|
|
UnmountThreadParam param;
|
|
|
|
retry:
|
|
BroadcastDeviceChange (DBT_DEVICEREMOVEPENDING, nDosDriveNo, 0);
|
|
|
|
param.nDosDriveNo = nDosDriveNo;
|
|
param.forced = forced;
|
|
param.dismountMaxRetries = dismountMaxRetries;
|
|
param.retryDelay = retryDelay;
|
|
param.presult = &result;
|
|
|
|
if (Silent)
|
|
{
|
|
UnmountWaitThreadProc (¶m, hwndDlg);
|
|
}
|
|
else
|
|
{
|
|
ShowWaitDialog (hwndDlg, FALSE, UnmountWaitThreadProc, ¶m);
|
|
}
|
|
|
|
SetLastError (param.dwLastError);
|
|
|
|
if (result != 0)
|
|
{
|
|
if (result == ERR_FILES_OPEN && !Silent)
|
|
{
|
|
if (IDYES == AskWarnYesNoTopmost ("UNMOUNT_LOCK_FAILED", hwndDlg))
|
|
{
|
|
forced = TRUE;
|
|
goto retry;
|
|
}
|
|
|
|
if (IsOSAtLeast (WIN_7))
|
|
{
|
|
// Undo SHCNE_DRIVEREMOVED
|
|
wchar_t root[] = { (wchar_t) nDosDriveNo + L'A', L':', L'\\', 0 };
|
|
SHChangeNotify (SHCNE_DRIVEADD, SHCNF_PATH, root, NULL);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Error ("UNMOUNT_FAILED", hwndDlg);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BroadcastDeviceChange (DBT_DEVICEREMOVECOMPLETE, nDosDriveNo, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL UnmountVolume (HWND hwndDlg, int nDosDriveNo, BOOL forceUnmount)
|
|
{
|
|
return UnmountVolumeBase (hwndDlg, nDosDriveNo, forceUnmount, FALSE);
|
|
}
|
|
|
|
BOOL UnmountVolumeAfterFormatExCall (HWND hwndDlg, int nDosDriveNo)
|
|
{
|
|
return UnmountVolumeBase (hwndDlg, nDosDriveNo, FALSE, TRUE);
|
|
}
|
|
|
|
BOOL IsPasswordCacheEmpty (void)
|
|
{
|
|
DWORD dw;
|
|
return !DeviceIoControl (hDriver, TC_IOCTL_GET_PASSWORD_CACHE_STATUS, 0, 0, 0, 0, &dw, 0);
|
|
}
|
|
|
|
BOOL IsMountedVolumeID (BYTE volumeID[VOLUME_ID_SIZE])
|
|
{
|
|
MOUNT_LIST_STRUCT mlist;
|
|
DWORD dwResult;
|
|
int i;
|
|
|
|
memset (&mlist, 0, sizeof (mlist));
|
|
if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist,
|
|
sizeof (mlist), &mlist, sizeof (mlist), &dwResult,
|
|
NULL)
|
|
|| (mlist.ulMountedDrives >= (1 << 26))
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (mlist.ulMountedDrives)
|
|
{
|
|
for (i=0 ; i<26; i++)
|
|
{
|
|
if ((mlist.ulMountedDrives & (1 << i)) && (0 == memcmp (mlist.volumeID[i], volumeID, VOLUME_ID_SIZE)))
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsMountedVolume (const wchar_t *volname)
|
|
{
|
|
if ((wcslen (volname) == (3 + 2*VOLUME_ID_SIZE)) && _wcsnicmp (volname, L"ID:", 3) == 0)
|
|
{
|
|
/* Volume ID specified. Use it for matching mounted volumes. */
|
|
std::vector<byte> arr;
|
|
if (HexWideStringToArray (&volname[3], arr) && (arr.size() == VOLUME_ID_SIZE))
|
|
{
|
|
return IsMountedVolumeID (&arr[0]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MOUNT_LIST_STRUCT mlist;
|
|
DWORD dwResult;
|
|
int i;
|
|
wchar_t volume[TC_MAX_PATH*2+16];
|
|
|
|
StringCbCopyW (volume, sizeof(volume), volname);
|
|
|
|
if (wcsstr (volname, L"\\Device\\") != volname)
|
|
StringCbPrintfW(volume, sizeof(volume), L"\\??\\%s", volname);
|
|
|
|
wstring resolvedPath = VolumeGuidPathToDevicePath (volname);
|
|
if (!resolvedPath.empty())
|
|
StringCbCopyW (volume, sizeof (volume), resolvedPath.c_str());
|
|
|
|
memset (&mlist, 0, sizeof (mlist));
|
|
if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist,
|
|
sizeof (mlist), &mlist, sizeof (mlist), &dwResult,
|
|
NULL)
|
|
|| (mlist.ulMountedDrives >= (1 << 26))
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (mlist.ulMountedDrives)
|
|
{
|
|
for (i=0 ; i<26; i++)
|
|
{
|
|
if ((mlist.ulMountedDrives & (1 << i))
|
|
&& IsNullTerminateString (mlist.wszVolume[i], TC_MAX_PATH)
|
|
&& (0 == _wcsicmp ((wchar_t *) mlist.wszVolume[i], volume))
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int GetMountedVolumeDriveNo (wchar_t *volname)
|
|
{
|
|
MOUNT_LIST_STRUCT mlist;
|
|
DWORD dwResult;
|
|
int i;
|
|
wchar_t volume[TC_MAX_PATH*2+16];
|
|
|
|
if (volname == NULL)
|
|
return -1;
|
|
|
|
StringCbCopyW (volume, sizeof(volume), volname);
|
|
|
|
if (wcsstr (volname, L"\\Device\\") != volname)
|
|
StringCbPrintfW (volume, sizeof(volume), L"\\??\\%s", volname);
|
|
|
|
wstring resolvedPath = VolumeGuidPathToDevicePath (volname);
|
|
if (!resolvedPath.empty())
|
|
StringCbCopyW (volume, sizeof (volume), resolvedPath.c_str());
|
|
|
|
memset (&mlist, 0, sizeof (mlist));
|
|
if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist,
|
|
sizeof (mlist), &mlist, sizeof (mlist), &dwResult,
|
|
NULL)
|
|
|| (mlist.ulMountedDrives >= (1 << 26))
|
|
)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (mlist.ulMountedDrives)
|
|
{
|
|
for (i=0 ; i<26; i++)
|
|
{
|
|
if ((mlist.ulMountedDrives & (1 << i))
|
|
&& IsNullTerminateString (mlist.wszVolume[i], TC_MAX_PATH)
|
|
&& (0 == _wcsicmp ((wchar_t *) mlist.wszVolume[i], (WCHAR *)volume))
|
|
)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
#endif //!SETUP
|
|
|
|
BOOL IsAdmin (void)
|
|
{
|
|
return IsUserAnAdmin ();
|
|
}
|
|
|
|
|
|
BOOL IsBuiltInAdmin ()
|
|
{
|
|
HANDLE procToken;
|
|
DWORD size;
|
|
|
|
if (!IsAdmin() || !OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &procToken))
|
|
return FALSE;
|
|
|
|
finally_do_arg (HANDLE, procToken, { CloseHandle (finally_arg); });
|
|
|
|
if (GetTokenInformation (procToken, TokenUser, NULL, 0, &size) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
return FALSE;
|
|
|
|
TOKEN_USER *tokenUser = (TOKEN_USER *) malloc (size);
|
|
if (!tokenUser)
|
|
return FALSE;
|
|
|
|
finally_do_arg (void *, tokenUser, { free (finally_arg); });
|
|
|
|
if (!GetTokenInformation (procToken, TokenUser, tokenUser, size, &size))
|
|
return FALSE;
|
|
|
|
return IsWellKnownSid (tokenUser->User.Sid, WinAccountAdministratorSid);
|
|
}
|
|
|
|
|
|
BOOL IsUacSupported ()
|
|
{
|
|
HKEY hkey;
|
|
DWORD value = 1, size = sizeof (DWORD);
|
|
|
|
if (!IsOSAtLeast (WIN_VISTA))
|
|
return FALSE;
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx (hkey, L"EnableLUA", 0, 0, (LPBYTE) &value, &size) != ERROR_SUCCESS)
|
|
value = 1;
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
|
|
return value != 0;
|
|
}
|
|
|
|
|
|
BOOL ResolveSymbolicLink (const wchar_t *symLinkName, PWSTR targetName, size_t cbTargetName)
|
|
{
|
|
BOOL bResult;
|
|
DWORD dwResult;
|
|
RESOLVE_SYMLINK_STRUCT resolve;
|
|
|
|
memset (&resolve, 0, sizeof(resolve));
|
|
StringCbCopyW (resolve.symLinkName, sizeof(resolve.symLinkName), symLinkName);
|
|
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_RESOLVED_SYMLINK, &resolve,
|
|
sizeof (resolve), &resolve, sizeof (resolve), &dwResult,
|
|
NULL);
|
|
|
|
StringCbCopyW (targetName, cbTargetName, resolve.targetName);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL GetPartitionInfo (const wchar_t *deviceName, PPARTITION_INFORMATION rpartInfo)
|
|
{
|
|
BOOL bResult;
|
|
DWORD dwResult;
|
|
DISK_PARTITION_INFO_STRUCT dpi;
|
|
|
|
memset (&dpi, 0, sizeof(dpi));
|
|
StringCbCopyW ((PWSTR) &dpi.deviceName, sizeof(dpi.deviceName), deviceName);
|
|
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVE_PARTITION_INFO, &dpi,
|
|
sizeof (dpi), &dpi, sizeof (dpi), &dwResult, NULL);
|
|
|
|
memcpy (rpartInfo, &dpi.partInfo, sizeof (PARTITION_INFORMATION));
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL GetDeviceInfo (const wchar_t *deviceName, DISK_PARTITION_INFO_STRUCT *info)
|
|
{
|
|
DWORD dwResult;
|
|
|
|
memset (info, 0, sizeof(*info));
|
|
StringCbCopyW ((PWSTR) &info->deviceName, sizeof(info->deviceName), deviceName);
|
|
|
|
return DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVE_PARTITION_INFO, info, sizeof (*info), info, sizeof (*info), &dwResult, NULL);
|
|
}
|
|
|
|
#ifndef SETUP
|
|
BOOL GetDriveGeometry (const wchar_t *deviceName, PDISK_GEOMETRY_EX diskGeometry)
|
|
{
|
|
BOOL bResult;
|
|
DWORD dwResult;
|
|
DISK_GEOMETRY_EX_STRUCT dg;
|
|
|
|
memset (&dg, 0, sizeof(dg));
|
|
StringCbCopyW ((PWSTR) &dg.deviceName, sizeof(dg.deviceName), deviceName);
|
|
|
|
bResult = DeviceIoControl (hDriver, VC_IOCTL_GET_DRIVE_GEOMETRY_EX, &dg,
|
|
sizeof (dg), &dg, sizeof (dg), &dwResult, NULL);
|
|
|
|
if (bResult && (dwResult == sizeof (dg)) && dg.diskGeometry.BytesPerSector)
|
|
{
|
|
ZeroMemory (diskGeometry, sizeof (DISK_GEOMETRY_EX));
|
|
memcpy (&diskGeometry->Geometry, &dg.diskGeometry, sizeof (DISK_GEOMETRY));
|
|
diskGeometry->DiskSize.QuadPart = dg.DiskSize.QuadPart;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL GetPhysicalDriveGeometry (int driveNumber, PDISK_GEOMETRY_EX diskGeometry)
|
|
{
|
|
HANDLE hDev;
|
|
BOOL bResult = FALSE;
|
|
TCHAR devicePath[MAX_PATH];
|
|
|
|
StringCchPrintfW (devicePath, ARRAYSIZE (devicePath), L"\\\\.\\PhysicalDrive%d", driveNumber);
|
|
|
|
if ((hDev = CreateFileW (devicePath, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD bytesRead = 0;
|
|
|
|
ZeroMemory (diskGeometry, sizeof (DISK_GEOMETRY_EX));
|
|
BYTE dgBuffer[256];
|
|
|
|
if ( DeviceIoControl (hDev, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, dgBuffer, sizeof (dgBuffer), &bytesRead, NULL)
|
|
&& (bytesRead >= (sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER)))
|
|
&& ((PDISK_GEOMETRY_EX) dgBuffer)->Geometry.BytesPerSector)
|
|
{
|
|
memcpy (&diskGeometry->Geometry, &((PDISK_GEOMETRY_EX) dgBuffer)->Geometry, sizeof (DISK_GEOMETRY));
|
|
diskGeometry->DiskSize.QuadPart = ((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart;
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DISK_GEOMETRY geo;
|
|
if ( DeviceIoControl (hDev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, (LPVOID) &geo, sizeof (geo), &bytesRead, NULL)
|
|
&& (bytesRead >= sizeof (DISK_GEOMETRY))
|
|
&& geo.BytesPerSector)
|
|
{
|
|
memcpy (&diskGeometry->Geometry, &geo, sizeof (DISK_GEOMETRY));
|
|
diskGeometry->DiskSize.QuadPart = geo.Cylinders.QuadPart * geo.SectorsPerTrack * geo.TracksPerCylinder * geo.BytesPerSector;
|
|
bResult = TRUE;
|
|
|
|
if (CurrentOSMajor >= 6)
|
|
{
|
|
STORAGE_READ_CAPACITY storage = {0};
|
|
|
|
storage.Version = sizeof (STORAGE_READ_CAPACITY);
|
|
storage.Size = sizeof (STORAGE_READ_CAPACITY);
|
|
if (DeviceIoControl (hDev, IOCTL_STORAGE_READ_CAPACITY, NULL, 0, (LPVOID) &storage, sizeof (storage), &bytesRead, NULL)
|
|
&& (bytesRead >= sizeof (storage))
|
|
&& (storage.Size == sizeof (STORAGE_READ_CAPACITY))
|
|
)
|
|
{
|
|
diskGeometry->DiskSize.QuadPart = storage.DiskLength.QuadPart;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CloseHandle (hDev);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
#endif
|
|
|
|
// Returns drive letter number assigned to device (-1 if none)
|
|
int GetDiskDeviceDriveLetter (PWSTR deviceName)
|
|
{
|
|
int i;
|
|
WCHAR link[MAX_PATH];
|
|
WCHAR target[MAX_PATH];
|
|
WCHAR device[MAX_PATH];
|
|
|
|
if (!ResolveSymbolicLink (deviceName, device, sizeof(device)))
|
|
StringCchCopyW (device, MAX_PATH, deviceName);
|
|
|
|
for (i = 0; i < 26; i++)
|
|
{
|
|
WCHAR drive[] = { (WCHAR) i + L'A', L':', 0 };
|
|
|
|
StringCchCopyW (link, MAX_PATH, L"\\DosDevices\\");
|
|
StringCchCatW (link, MAX_PATH, drive);
|
|
|
|
if ( ResolveSymbolicLink (link, target, sizeof(target))
|
|
&& (wcscmp (device, target) == 0)
|
|
)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
// WARNING: This function does NOT provide 100% reliable results -- do NOT use it for critical/dangerous operations!
|
|
// Return values: 0 - filesystem does not appear empty, 1 - filesystem appears empty, -1 - an error occurred
|
|
int FileSystemAppearsEmpty (const wchar_t *devicePath)
|
|
{
|
|
float percentFreeSpace = 0.0;
|
|
__int64 occupiedBytes = 0;
|
|
|
|
if (GetStatsFreeSpaceOnPartition (devicePath, &percentFreeSpace, &occupiedBytes, TRUE) != -1)
|
|
{
|
|
if (occupiedBytes > BYTES_PER_GB && percentFreeSpace < 99.99 // "percentFreeSpace < 99.99" is needed because an NTFS filesystem larger than several terabytes can have more than 1GB of data in use, even if there are no files stored on it.
|
|
|| percentFreeSpace < 88) // A 24-MB NTFS filesystem has 11.5% of space in use even if there are no files stored on it.
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
return 1;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
// Returns the free space on the specified partition (volume) in bytes. If the 'occupiedBytes' pointer
|
|
// is not NULL, size of occupied space (in bytes) is written to the pointed location. In addition, if the
|
|
// 'percent' pointer is not NULL, % of free space is stored in the pointed location. If there's an error,
|
|
// returns -1.
|
|
__int64 GetStatsFreeSpaceOnPartition (const wchar_t *devicePath, float *percentFree, __int64 *occupiedBytes, BOOL silent)
|
|
{
|
|
WCHAR devPath [MAX_PATH];
|
|
int driveLetterNo = -1;
|
|
wchar_t szRootPath[4] = {0, L':', L'\\', 0};
|
|
ULARGE_INTEGER freeSpaceSize;
|
|
ULARGE_INTEGER totalNumberOfBytes;
|
|
ULARGE_INTEGER totalNumberOfFreeBytes;
|
|
|
|
StringCbCopyW (devPath, sizeof(devPath), devicePath);
|
|
|
|
driveLetterNo = GetDiskDeviceDriveLetter (devPath);
|
|
szRootPath[0] = (wchar_t) driveLetterNo + L'A';
|
|
|
|
|
|
if (!GetDiskFreeSpaceEx (szRootPath, &freeSpaceSize, &totalNumberOfBytes, &totalNumberOfFreeBytes))
|
|
{
|
|
if (!silent)
|
|
{
|
|
handleWin32Error (MainDlg, SRC_POS);
|
|
Error ("CANNOT_CALC_SPACE", MainDlg);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (percentFree != NULL || occupiedBytes != NULL)
|
|
{
|
|
// Determine occupied space and % of free space
|
|
|
|
PARTITION_INFORMATION partitionInfo;
|
|
|
|
if (!GetPartitionInfo (devicePath, &partitionInfo))
|
|
{
|
|
if (!silent)
|
|
{
|
|
handleWin32Error (MainDlg, SRC_POS);
|
|
Error ("CANT_GET_VOLSIZE", MainDlg);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if (occupiedBytes != NULL)
|
|
*occupiedBytes = partitionInfo.PartitionLength.QuadPart - freeSpaceSize.QuadPart;
|
|
|
|
if (percentFree != NULL)
|
|
*percentFree = (float) ((double) freeSpaceSize.QuadPart / (double) partitionInfo.PartitionLength.QuadPart * 100.0);
|
|
}
|
|
|
|
return freeSpaceSize.QuadPart;
|
|
}
|
|
|
|
|
|
// Returns -1 if there's an error.
|
|
__int64 GetDeviceSize (const wchar_t *devicePath)
|
|
{
|
|
PARTITION_INFORMATION partitionInfo;
|
|
|
|
if (!GetPartitionInfo (devicePath, &partitionInfo))
|
|
return -1;
|
|
|
|
return partitionInfo.PartitionLength.QuadPart;
|
|
}
|
|
|
|
|
|
HANDLE DismountDrive (wchar_t *devName, wchar_t *devicePath)
|
|
{
|
|
DWORD dwResult;
|
|
HANDLE hVolume;
|
|
BOOL bResult = FALSE;
|
|
int attempt = UNMOUNT_MAX_AUTO_RETRIES;
|
|
int driveLetterNo = -1;
|
|
WCHAR devPath [MAX_PATH];
|
|
|
|
StringCbCopyW (devPath, sizeof(devPath), devicePath);
|
|
driveLetterNo = GetDiskDeviceDriveLetter (devPath);
|
|
|
|
|
|
hVolume = CreateFile (devName, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (hVolume == INVALID_HANDLE_VALUE)
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
|
// Try to lock the volume first so that dismount is not forced.
|
|
// If we fail, we will dismount anyway even if it needs to be forced.
|
|
|
|
CloseVolumeExplorerWindows (MainDlg, driveLetterNo);
|
|
|
|
while (!(bResult = DeviceIoControl (hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
|
|
&& attempt > 0)
|
|
{
|
|
Sleep (UNMOUNT_AUTO_RETRY_DELAY);
|
|
attempt--;
|
|
}
|
|
|
|
|
|
// Try to dismount the volume
|
|
|
|
attempt = UNMOUNT_MAX_AUTO_RETRIES;
|
|
|
|
while (!(bResult = DeviceIoControl (hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
|
|
&& attempt > 0)
|
|
{
|
|
Sleep (UNMOUNT_AUTO_RETRY_DELAY);
|
|
attempt--;
|
|
}
|
|
|
|
if (!bResult)
|
|
CloseHandle (hVolume);
|
|
|
|
return (bResult ? hVolume : INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
BOOL DecompressZipToDir (const unsigned char *inputBuffer, DWORD inputLength, const wchar_t *destinationDir, ProgressFn progressFnPtr, HWND hwndDlg)
|
|
{
|
|
BOOL res = TRUE;
|
|
zip_error_t zerr;
|
|
zip_int64_t numFiles, i;
|
|
zip_stat_t sb;
|
|
zip_source_t* zsrc = zip_source_buffer_create (inputBuffer, inputLength, 0, &zerr);
|
|
if (!zsrc)
|
|
return FALSE;
|
|
zip_t* z = zip_open_from_source (zsrc, ZIP_CHECKCONS | ZIP_RDONLY, &zerr);
|
|
if (!z)
|
|
{
|
|
zip_source_free (zsrc);
|
|
return FALSE;
|
|
}
|
|
|
|
finally_do_arg (zip_t*, z, { zip_close (finally_arg); });
|
|
|
|
numFiles = zip_get_num_entries (z, 0);
|
|
if (numFiles <= 0)
|
|
return FALSE;
|
|
|
|
for (i = 0; (i < numFiles) && res; i++)
|
|
{
|
|
ZeroMemory (&sb, sizeof (sb));
|
|
if ((0 == zip_stat_index (z, i, 0, &sb)) && (sb.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) && (sb.size > 0))
|
|
{
|
|
std::wstring wname = Utf8StringToWide (sb.name);
|
|
CorrectFileName (wname);
|
|
|
|
std::wstring filePath = destinationDir + wname;
|
|
size_t pos = filePath.find_last_of (L"/\\");
|
|
// create the parent directory if it doesn't exist
|
|
if (pos != std::wstring::npos)
|
|
{
|
|
SHCreateDirectoryEx (NULL, filePath.substr (0, pos).c_str(), NULL);
|
|
}
|
|
|
|
zip_file_t *f = zip_fopen_index (z, i, 0);
|
|
if (f)
|
|
{
|
|
ByteArray buffer((ByteArray::size_type) sb.size);
|
|
|
|
zip_fread (f, buffer.data(), sb.size);
|
|
zip_fclose (f);
|
|
|
|
if (progressFnPtr)
|
|
progressFnPtr (hwndDlg, filePath.c_str());
|
|
|
|
res = SaveBufferToFile ((char *) buffer.data(), filePath.c_str(), (DWORD) buffer.size(), FALSE, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// Proper flush for Windows systems. Returns TRUE if successful.
|
|
BOOL TCFlushFile (FILE *f)
|
|
{
|
|
HANDLE hf = (HANDLE) _get_osfhandle (_fileno (f));
|
|
|
|
fflush (f);
|
|
|
|
if (hf == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
return FlushFileBuffers (hf) != 0;
|
|
}
|
|
|
|
|
|
// Prints a UTF-16 text (note that this involves a real printer, not a screen).
|
|
// textByteLen - length of the text in bytes
|
|
// title - printed as part of the page header and used as the filename for a temporary file
|
|
BOOL PrintHardCopyTextUTF16 (wchar_t *text, wchar_t *title, size_t textByteLen)
|
|
{
|
|
wchar_t cl [MAX_PATH*3] = {L"/p \""};
|
|
wchar_t path [MAX_PATH * 2] = { 0 };
|
|
wchar_t filename [MAX_PATH + 1] = { 0 };
|
|
|
|
StringCbCopyW (filename, sizeof(filename), title);
|
|
//strcat (filename, ".txt");
|
|
|
|
GetTempPath (ARRAYSIZE (path), path);
|
|
|
|
if (!FileExists (path))
|
|
{
|
|
StringCbCopyW (path, sizeof(path), GetConfigPath (filename));
|
|
|
|
if (wcslen(path) < 2)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
StringCbCatW (path, sizeof(path), filename);
|
|
}
|
|
|
|
// Write the Unicode signature
|
|
if (!SaveBufferToFile ("\xFF\xFE", path, 2, FALSE, FALSE))
|
|
{
|
|
_wremove (path);
|
|
return FALSE;
|
|
}
|
|
|
|
// Write the actual text
|
|
if (!SaveBufferToFile ((char *) text, path, (DWORD) textByteLen, TRUE, FALSE))
|
|
{
|
|
_wremove (path);
|
|
return FALSE;
|
|
}
|
|
|
|
StringCbCatW (cl, sizeof(cl), path);
|
|
StringCbCatW (cl, sizeof(cl), L"\"");
|
|
|
|
// Get the absolute path for notepad
|
|
if (GetWindowsDirectory(filename, MAX_PATH))
|
|
{
|
|
if (filename[wcslen (filename) - 1] != L'\\')
|
|
StringCbCatW (filename, sizeof(filename), L"\\");
|
|
StringCbCatW(filename, sizeof(filename), PRINT_TOOL);
|
|
}
|
|
else
|
|
StringCbCopyW(filename, sizeof(filename), L"C:\\Windows\\" PRINT_TOOL);
|
|
|
|
WaitCursor ();
|
|
ShellExecute (NULL, L"open", filename, cl, NULL, SW_HIDE);
|
|
Sleep (6000);
|
|
NormalCursor();
|
|
|
|
_wremove (path);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL IsNonInstallMode ()
|
|
{
|
|
HKEY hkey, hkeybis;
|
|
DWORD dw;
|
|
WCHAR szBuffer[512];
|
|
DWORD dwBufferSize = sizeof(szBuffer);
|
|
std::wstring msiProductGUID;
|
|
|
|
if (bPortableModeConfirmed)
|
|
return TRUE;
|
|
|
|
if (hDriver != INVALID_HANDLE_VALUE)
|
|
{
|
|
// The driver is running
|
|
if (DeviceIoControl (hDriver, TC_IOCTL_GET_PORTABLE_MODE_STATUS, NULL, 0, NULL, 0, &dw, 0))
|
|
{
|
|
bPortableModeConfirmed = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// This is also returned if we fail to determine the status (it does not mean that portable mode is disproved).
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The tests in this block are necessary because this function is in some cases called before DriverAttach().
|
|
|
|
HANDLE hDriverTmp = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (hDriverTmp == INVALID_HANDLE_VALUE)
|
|
{
|
|
// The driver was not found in the system path
|
|
|
|
wchar_t path[MAX_PATH * 2] = { 0 };
|
|
|
|
// We can't use GetConfigPath() here because it would call us back (indirect recursion)
|
|
if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_APPDATA, NULL, 0, path)))
|
|
{
|
|
StringCbCatW (path, MAX_PATH * 2, L"\\VeraCrypt\\");
|
|
StringCbCatW (path, MAX_PATH * 2, TC_APPD_FILENAME_SYSTEM_ENCRYPTION);
|
|
|
|
if (FileExists (path))
|
|
{
|
|
// To maintain consistency and safety, if the system encryption config file exits, we cannot
|
|
// allow portable mode. (This happens e.g. when the pretest fails and the user selects
|
|
// "Last Known Good Configuration" from the Windows boot menu.)
|
|
|
|
// However, if UAC elevation is needed, we have to confirm portable mode first (after we are elevated, we won't).
|
|
if (!IsAdmin () && IsUacSupported ())
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// As the driver was not found in the system path, we can predict that we will run in portable mode
|
|
return TRUE;
|
|
}
|
|
else
|
|
CloseHandle (hDriverTmp);
|
|
}
|
|
|
|
// The following test checks whether the MSI is installed, which means we're not in portable mode.
|
|
// The ProductGUID is read from registry.
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\VeraCrypt_MSI", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hkey) == ERROR_SUCCESS ||
|
|
RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\VeraCrypt_MSI", 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
if (ERROR_SUCCESS == RegQueryValueExW(hkey, L"ProductGuid", 0, NULL, (LPBYTE)szBuffer, &dwBufferSize))
|
|
{
|
|
msiProductGUID = szBuffer;
|
|
|
|
std::wstring regKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\";
|
|
regKey += msiProductGUID;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regKey.c_str(), 0, KEY_READ | KEY_WOW64_32KEY, &hkeybis) == ERROR_SUCCESS ||
|
|
RegOpenKeyEx(HKEY_LOCAL_MACHINE, regKey.c_str(), 0, KEY_READ, &hkeybis) == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hkeybis);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
// The following test may be unreliable in some cases (e.g. after the user selects restore "Last Known Good
|
|
// Configuration" from the Windows boot menu).
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", 0, KEY_READ | KEY_WOW64_32KEY, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey (hkey);
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LRESULT SetCheckBox (HWND hwndDlg, int dlgItem, BOOL state)
|
|
{
|
|
return SendDlgItemMessage (hwndDlg, dlgItem, BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
}
|
|
|
|
|
|
BOOL GetCheckBox (HWND hwndDlg, int dlgItem)
|
|
{
|
|
return IsButtonChecked (GetDlgItem (hwndDlg, dlgItem));
|
|
}
|
|
|
|
|
|
// Scroll the listview vertically so that the item with index of topMostVisibleItem is the topmost visible item.
|
|
void SetListScrollHPos (HWND hList, int topMostVisibleItem)
|
|
{
|
|
int testedPos = 0;
|
|
|
|
do
|
|
{
|
|
SendMessage (hList, LVM_SCROLL, 0, testedPos);
|
|
|
|
} while (ListView_GetTopIndex (hList) < topMostVisibleItem && ++testedPos < 10000);
|
|
}
|
|
|
|
|
|
// Adds or removes TrueCrypt.exe to/from the system startup sequence (with appropriate command line arguments)
|
|
void ManageStartupSeq (void)
|
|
{
|
|
if (!IsNonInstallMode ())
|
|
{
|
|
wchar_t regk [64];
|
|
|
|
GetStartupRegKeyName (regk, sizeof(regk));
|
|
|
|
if (bStartOnLogon || bMountDevicesOnLogon || bMountFavoritesOnLogon)
|
|
{
|
|
wchar_t exe[MAX_PATH * 2] = { L'"' };
|
|
|
|
GetModuleFileName (NULL, exe + 1, ARRAYSIZE (exe) - 1);
|
|
|
|
#ifdef VOLFORMAT
|
|
{
|
|
wchar_t *tmp = NULL;
|
|
|
|
if (tmp = wcsrchr (exe, L'\\'))
|
|
{
|
|
*tmp = 0;
|
|
StringCbCatW (exe, MAX_PATH * 2, L"\\VeraCrypt.exe");
|
|
}
|
|
}
|
|
#endif
|
|
StringCbCatW (exe, MAX_PATH * 2, L"\" /q preferences /a logon");
|
|
|
|
if (bMountDevicesOnLogon) StringCbCatW (exe, MAX_PATH * 2, L" /a devices");
|
|
if (bMountFavoritesOnLogon) StringCbCatW (exe, MAX_PATH * 2, L" /a favorites");
|
|
|
|
WriteRegistryString (regk, L"VeraCrypt", exe);
|
|
}
|
|
else
|
|
DeleteRegistryValue (regk, L"VeraCrypt");
|
|
}
|
|
}
|
|
|
|
|
|
// Adds or removes the VeraCrypt Volume Creation Wizard to/from the system startup sequence
|
|
void ManageStartupSeqWiz (BOOL bRemove, const wchar_t *arg)
|
|
{
|
|
wchar_t regk [64];
|
|
|
|
GetStartupRegKeyName (regk, sizeof(regk));
|
|
|
|
if (!bRemove)
|
|
{
|
|
size_t exeSize = (MAX_PATH * 2) + 3 + 20 + wcslen (arg); // enough room for all concatenation operations
|
|
wchar_t* exe = (wchar_t*) calloc(1, exeSize * sizeof (wchar_t));
|
|
exe[0] = L'"';
|
|
GetModuleFileName (NULL, exe + 1, (DWORD) (exeSize - 1));
|
|
|
|
#ifndef VOLFORMAT
|
|
{
|
|
wchar_t *tmp = NULL;
|
|
|
|
if (tmp = wcsrchr (exe, L'\\'))
|
|
{
|
|
*tmp = 0;
|
|
|
|
StringCchCatW (exe, exeSize, L"\\VeraCrypt Format.exe");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (wcslen (arg) > 0)
|
|
{
|
|
StringCchCatW (exe, exeSize, L"\" ");
|
|
StringCchCatW (exe, exeSize, arg);
|
|
}
|
|
|
|
WriteRegistryString (regk, L"VeraCrypt Format", exe);
|
|
|
|
free(exe);
|
|
}
|
|
else
|
|
DeleteRegistryValue (regk, L"VeraCrypt Format");
|
|
}
|
|
|
|
|
|
// Delete the last used Windows file selector path for TrueCrypt from the registry
|
|
void CleanLastVisitedMRU (void)
|
|
{
|
|
WCHAR exeFilename[MAX_PATH];
|
|
WCHAR *strToMatch;
|
|
|
|
WCHAR strTmp[4096];
|
|
WCHAR regPath[128];
|
|
WCHAR key[64];
|
|
int id, len;
|
|
|
|
GetModuleFileNameW (NULL, exeFilename, sizeof (exeFilename) / sizeof(exeFilename[0]));
|
|
strToMatch = wcsrchr (exeFilename, L'\\') + 1;
|
|
|
|
StringCbPrintfW (regPath, sizeof(regPath), L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisited%sMRU", IsOSAtLeast (WIN_VISTA) ? L"Pidl" : L"");
|
|
|
|
for (id = (IsOSAtLeast (WIN_VISTA) ? 0 : L'a'); id <= (IsOSAtLeast (WIN_VISTA) ? 1000 : L'z'); id++)
|
|
{
|
|
*strTmp = 0;
|
|
StringCbPrintfW (key, sizeof(key), (IsOSAtLeast (WIN_VISTA) ? L"%d" : L"%c"), id);
|
|
|
|
if ((len = ReadRegistryBytes (regPath, key, (char *) strTmp, sizeof (strTmp))) > 0)
|
|
{
|
|
if (_wcsicmp (strTmp, strToMatch) == 0)
|
|
{
|
|
char buf[65536], bufout[sizeof (buf)];
|
|
|
|
// Overwrite the entry with zeroes while keeping its original size
|
|
memset (strTmp, 0, len);
|
|
if (!WriteRegistryBytes (regPath, key, (char *) strTmp, len))
|
|
MessageBoxW (NULL, GetString ("CLEAN_WINMRU_FAILED"), lpszTitle, ICON_HAND);
|
|
|
|
DeleteRegistryValue (regPath, key);
|
|
|
|
// Remove ID from MRUList
|
|
if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
int *p = (int *)buf;
|
|
int *pout = (int *)bufout;
|
|
int l;
|
|
|
|
l = len = ReadRegistryBytes (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU", L"MRUListEx", buf, sizeof (buf));
|
|
while (l > 0)
|
|
{
|
|
l -= sizeof (int);
|
|
|
|
if (*p == id)
|
|
{
|
|
p++;
|
|
len -= sizeof (int);
|
|
continue;
|
|
}
|
|
*pout++ = *p++;
|
|
}
|
|
|
|
WriteRegistryBytes (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU", L"MRUListEx", bufout, len);
|
|
}
|
|
else
|
|
{
|
|
wchar_t *p = (wchar_t*) buf;
|
|
wchar_t *pout = (wchar_t*) bufout;
|
|
|
|
ReadRegistryString (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", L"MRUList", L"", (wchar_t*) buf, sizeof (buf));
|
|
while (*p)
|
|
{
|
|
if (*p == id)
|
|
{
|
|
p++;
|
|
continue;
|
|
}
|
|
*pout++ = *p++;
|
|
}
|
|
*pout++ = 0;
|
|
|
|
WriteRegistryString (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", L"MRUList", (wchar_t*) bufout);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef SETUP
|
|
void ClearHistory (HWND hwndDlgItem)
|
|
{
|
|
ArrowWaitCursor ();
|
|
|
|
ClearCombo (hwndDlgItem);
|
|
DumpCombo (hwndDlgItem, TRUE);
|
|
|
|
CleanLastVisitedMRU ();
|
|
|
|
NormalCursor ();
|
|
}
|
|
#endif // #ifndef SETUP
|
|
|
|
|
|
LRESULT ListItemAdd (HWND list, int index, const wchar_t *string)
|
|
{
|
|
LVITEM li;
|
|
memset (&li, 0, sizeof(li));
|
|
|
|
li.mask = LVIF_TEXT;
|
|
li.pszText = (wchar_t*) string;
|
|
li.iItem = index;
|
|
li.iSubItem = 0;
|
|
return ListView_InsertItem (list, &li);
|
|
}
|
|
|
|
|
|
LRESULT ListSubItemSet (HWND list, int index, int subIndex, const wchar_t *string)
|
|
{
|
|
LVITEM li;
|
|
memset (&li, 0, sizeof(li));
|
|
|
|
li.mask = LVIF_TEXT;
|
|
li.pszText = (wchar_t*) string;
|
|
li.iItem = index;
|
|
li.iSubItem = subIndex;
|
|
return ListView_SetItem (list, &li);
|
|
}
|
|
|
|
|
|
BOOL GetMountList (MOUNT_LIST_STRUCT *list)
|
|
{
|
|
DWORD dwResult;
|
|
MOUNT_LIST_STRUCT localList = {0};
|
|
|
|
if ( list && DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &localList,
|
|
sizeof (localList), &localList, sizeof (localList), &dwResult,
|
|
NULL)
|
|
&& (localList.ulMountedDrives < (1 << 26))
|
|
)
|
|
{
|
|
memcpy (list, &localList, sizeof (MOUNT_LIST_STRUCT));
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int GetDriverRefCount ()
|
|
{
|
|
DWORD dwResult;
|
|
BOOL bResult;
|
|
int refCount;
|
|
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DEVICE_REFCOUNT, &refCount, sizeof (refCount), &refCount,
|
|
sizeof (refCount), &dwResult, NULL);
|
|
|
|
if (bResult)
|
|
return refCount;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
wchar_t *GetModPath (wchar_t *path, int maxSize)
|
|
{
|
|
GetModuleFileName (NULL, path, maxSize);
|
|
wchar_t* ptr = wcsrchr (path, L'\\');
|
|
if (ptr)
|
|
ptr[1] = 0;
|
|
return path;
|
|
}
|
|
|
|
|
|
wchar_t *GetConfigPath (wchar_t *fileName)
|
|
{
|
|
static wchar_t path[MAX_PATH * 2] = { 0 };
|
|
|
|
if (IsNonInstallMode ())
|
|
{
|
|
GetModPath (path, ARRAYSIZE (path));
|
|
StringCchCatW (path, (MAX_PATH * 2), fileName);
|
|
|
|
return path;
|
|
}
|
|
|
|
if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path)))
|
|
{
|
|
StringCchCatW (path, (MAX_PATH * 2), L"\\VeraCrypt\\");
|
|
CreateDirectory (path, NULL);
|
|
StringCchCatW (path, (MAX_PATH * 2), fileName);
|
|
}
|
|
else
|
|
path[0] = 0;
|
|
|
|
return path;
|
|
}
|
|
|
|
|
|
wchar_t *GetProgramConfigPath (wchar_t *fileName)
|
|
{
|
|
static wchar_t path[MAX_PATH * 2] = { 0 };
|
|
|
|
if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path)))
|
|
{
|
|
StringCchCatW (path, (MAX_PATH * 2), L"\\VeraCrypt\\");
|
|
CreateDirectory (path, NULL);
|
|
StringCchCatW (path, (MAX_PATH * 2), fileName);
|
|
}
|
|
else
|
|
path[0] = 0;
|
|
|
|
return path;
|
|
}
|
|
|
|
|
|
std::wstring GetServiceConfigPath (const wchar_t *fileName, bool useLegacy)
|
|
{
|
|
wchar_t sysPath[TC_MAX_PATH];
|
|
|
|
if (Is64BitOs() && useLegacy)
|
|
{
|
|
typedef UINT (WINAPI *GetSystemWow64Directory_t) (LPWSTR lpBuffer, UINT uSize);
|
|
|
|
GetSystemWow64Directory_t getSystemWow64Directory = (GetSystemWow64Directory_t) GetProcAddress (GetModuleHandle (L"kernel32"), "GetSystemWow64DirectoryW");
|
|
getSystemWow64Directory (sysPath, ARRAYSIZE (sysPath));
|
|
}
|
|
else
|
|
GetSystemDirectory (sysPath, ARRAYSIZE (sysPath));
|
|
|
|
return wstring (sysPath) + L"\\" + fileName;
|
|
}
|
|
|
|
|
|
// Returns 0 if an error occurs or the drive letter (as an upper-case char) of the system partition (e.g. 'C');
|
|
wchar_t GetSystemDriveLetter (void)
|
|
{
|
|
wchar_t systemDir [MAX_PATH];
|
|
|
|
if (GetSystemDirectory (systemDir, ARRAYSIZE (systemDir)))
|
|
return (wchar_t) (towupper (systemDir [0]));
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
void TaskBarIconDisplayBalloonTooltip (HWND hwnd, wchar_t *headline, wchar_t *text, BOOL warning)
|
|
{
|
|
NOTIFYICONDATAW tnid;
|
|
|
|
ZeroMemory (&tnid, sizeof (tnid));
|
|
|
|
tnid.cbSize = sizeof (tnid);
|
|
tnid.hWnd = hwnd;
|
|
tnid.uID = IDI_TRUECRYPT_ICON;
|
|
//tnid.uVersion = (IsOSAtLeast (WIN_VISTA) ? NOTIFYICON_VERSION_4 : NOTIFYICON_VERSION);
|
|
|
|
//Shell_NotifyIconW (NIM_SETVERSION, &tnid);
|
|
|
|
tnid.uFlags = NIF_INFO;
|
|
tnid.dwInfoFlags = (warning ? NIIF_WARNING : NIIF_INFO);
|
|
tnid.uTimeout = (IsOSAtLeast (WIN_VISTA) ? 1000 : 5000); // in ms
|
|
|
|
StringCbCopyW (tnid.szInfoTitle, sizeof(tnid.szInfoTitle), headline);
|
|
StringCbCopyW (tnid.szInfo, sizeof(tnid.szInfo),text);
|
|
|
|
// Display the balloon tooltip quickly twice in a row to avoid the slow and unwanted "fade-in" phase
|
|
Shell_NotifyIconW (NIM_MODIFY, &tnid);
|
|
Shell_NotifyIconW (NIM_MODIFY, &tnid);
|
|
}
|
|
|
|
|
|
// Either of the pointers may be NULL
|
|
void InfoBalloon (char *headingStringId, char *textStringId, HWND hwnd)
|
|
{
|
|
if (Silent)
|
|
return;
|
|
|
|
TaskBarIconDisplayBalloonTooltip (hwnd,
|
|
headingStringId == NULL ? L"VeraCrypt" : GetString (headingStringId),
|
|
textStringId == NULL ? L" " : GetString (textStringId),
|
|
FALSE);
|
|
}
|
|
|
|
|
|
// Either of the pointers may be NULL
|
|
void InfoBalloonDirect (wchar_t *headingString, wchar_t *textString, HWND hwnd)
|
|
{
|
|
if (Silent)
|
|
return;
|
|
|
|
TaskBarIconDisplayBalloonTooltip (hwnd,
|
|
headingString == NULL ? L"VeraCrypt" : headingString,
|
|
textString == NULL ? L" " : textString,
|
|
FALSE);
|
|
}
|
|
|
|
|
|
// Either of the pointers may be NULL
|
|
void WarningBalloon (char *headingStringId, char *textStringId, HWND hwnd)
|
|
{
|
|
if (Silent)
|
|
return;
|
|
|
|
TaskBarIconDisplayBalloonTooltip (hwnd,
|
|
headingStringId == NULL ? L"VeraCrypt" : GetString (headingStringId),
|
|
textStringId == NULL ? L" " : GetString (textStringId),
|
|
TRUE);
|
|
}
|
|
|
|
|
|
// Either of the pointers may be NULL
|
|
void WarningBalloonDirect (wchar_t *headingString, wchar_t *textString, HWND hwnd)
|
|
{
|
|
if (Silent)
|
|
return;
|
|
|
|
TaskBarIconDisplayBalloonTooltip (hwnd,
|
|
headingString == NULL ? L"VeraCrypt" : headingString,
|
|
textString == NULL ? L" " : textString,
|
|
TRUE);
|
|
}
|
|
|
|
|
|
int Info (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONINFORMATION);
|
|
}
|
|
|
|
|
|
int InfoTopMost (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
int InfoDirect (const wchar_t *msg, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, msg, lpszTitle, MB_ICONINFORMATION);
|
|
}
|
|
|
|
|
|
int Warning (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING);
|
|
}
|
|
|
|
|
|
int WarningTopMost (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
int WarningDirect (const wchar_t *warnMsg, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, warnMsg, lpszTitle, MB_ICONWARNING);
|
|
}
|
|
|
|
int ErrorRetryCancel (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR | MB_RETRYCANCEL);
|
|
}
|
|
|
|
int ErrorTopMost (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
int ErrorDirect (const wchar_t *errMsg, HWND hwnd)
|
|
{
|
|
if (Silent) return 0;
|
|
return MessageBoxW (hwnd, errMsg, lpszTitle, MB_ICONERROR);
|
|
}
|
|
|
|
|
|
int AskYesNo (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1);
|
|
}
|
|
|
|
|
|
int AskYesNoString (const wchar_t *str, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, str, lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1);
|
|
}
|
|
|
|
|
|
int AskYesNoTopmost (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
int AskNoYes (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
|
|
}
|
|
|
|
int AskNoYesString (const wchar_t *string, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, string, lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
|
|
}
|
|
|
|
int AskOkCancel (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDCANCEL;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_OKCANCEL | MB_DEFBUTTON1);
|
|
}
|
|
|
|
|
|
int AskWarnYesNo (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1);
|
|
}
|
|
|
|
|
|
int AskWarnYesNoString (const wchar_t *string, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1);
|
|
}
|
|
|
|
|
|
int AskWarnYesNoTopmost (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
int AskWarnYesNoStringTopmost (const wchar_t *string, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
int AskWarnNoYes (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
|
|
}
|
|
|
|
|
|
int AskWarnNoYesString (const wchar_t *string, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
|
|
}
|
|
|
|
|
|
int AskWarnNoYesTopmost (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
int AskWarnOkCancel (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDCANCEL;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1);
|
|
}
|
|
|
|
|
|
int AskWarnCancelOk (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDCANCEL;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2);
|
|
}
|
|
|
|
|
|
int AskErrYesNo (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR | MB_YESNO | MB_DEFBUTTON1);
|
|
}
|
|
|
|
|
|
int AskErrNoYes (char *stringId, HWND hwnd)
|
|
{
|
|
if (Silent) return IDNO;
|
|
return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR | MB_YESNO | MB_DEFBUTTON2);
|
|
}
|
|
|
|
|
|
// The function accepts two input formats:
|
|
// Input format 1: {0, "MESSAGE_STRING_ID", "BUTTON_1_STRING_ID", ... "LAST_BUTTON_STRING_ID", 0};
|
|
// Input format 2: {L"", L"Message text", L"Button caption 1", ... L"Last button caption", 0};
|
|
// The second format is to be used if any of the strings contains format specification (e.g. %s, %d) or
|
|
// in any other cases where a string needs to be resolved before calling this function.
|
|
// The returned value is the ordinal number of the choice the user selected (1..MAX_MULTI_CHOICES)
|
|
int AskMultiChoice (void *strings[], BOOL bBold, HWND hwnd)
|
|
{
|
|
MULTI_CHOICE_DLGPROC_PARAMS params;
|
|
|
|
params.strings = &strings[0];
|
|
params.bold = bBold;
|
|
|
|
return (int) DialogBoxParamW (hInst,
|
|
MAKEINTRESOURCEW (IDD_MULTI_CHOICE_DLG), hwnd,
|
|
(DLGPROC) MultiChoiceDialogProc, (LPARAM) ¶ms);
|
|
}
|
|
|
|
|
|
BOOL ConfigWriteBegin ()
|
|
{
|
|
DWORD size;
|
|
if (ConfigFileHandle != NULL)
|
|
return FALSE;
|
|
|
|
if (ConfigBuffer == NULL)
|
|
ConfigBuffer = LoadFile (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), &size);
|
|
|
|
ConfigFileHandle = _wfopen (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), L"w,ccs=UTF-8");
|
|
if (ConfigFileHandle == NULL)
|
|
{
|
|
free (ConfigBuffer);
|
|
ConfigBuffer = NULL;
|
|
return FALSE;
|
|
}
|
|
XmlWriteHeader (ConfigFileHandle);
|
|
fputws (L"\n\t<configuration>", ConfigFileHandle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL ConfigWriteEnd (HWND hwnd)
|
|
{
|
|
char *xml = ConfigBuffer;
|
|
char key[128], value[2048];
|
|
|
|
if (ConfigFileHandle == NULL) return FALSE;
|
|
|
|
// Write unmodified values
|
|
while (xml && (xml = XmlFindElement (xml, "config")))
|
|
{
|
|
XmlGetAttributeText (xml, "key", key, sizeof (key));
|
|
XmlGetNodeText (xml, value, sizeof (value));
|
|
|
|
fwprintf (ConfigFileHandle, L"\n\t\t<config key=\"%hs\">%hs</config>", key, value);
|
|
xml++;
|
|
}
|
|
|
|
fputws (L"\n\t</configuration>", ConfigFileHandle);
|
|
XmlWriteFooter (ConfigFileHandle);
|
|
|
|
TCFlushFile (ConfigFileHandle);
|
|
|
|
CheckFileStreamWriteErrors (hwnd, ConfigFileHandle, TC_APPD_FILENAME_CONFIGURATION);
|
|
|
|
fclose (ConfigFileHandle);
|
|
ConfigFileHandle = NULL;
|
|
|
|
if (ConfigBuffer != NULL)
|
|
{
|
|
DWORD size;
|
|
free (ConfigBuffer);
|
|
ConfigBuffer = LoadFile (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), &size);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL ConfigWriteString (char *configKey, char *configValue)
|
|
{
|
|
char *c;
|
|
if (ConfigFileHandle == NULL)
|
|
return FALSE;
|
|
|
|
// Mark previous config value as updated
|
|
if (ConfigBuffer != NULL)
|
|
{
|
|
c = XmlFindElementByAttributeValue (ConfigBuffer, "config", "key", configKey);
|
|
if (c != NULL)
|
|
c[1] = '!';
|
|
}
|
|
|
|
return 0 != fwprintf (
|
|
ConfigFileHandle, L"\n\t\t<config key=\"%hs\">%hs</config>",
|
|
configKey, configValue);
|
|
}
|
|
|
|
BOOL ConfigWriteStringW (char *configKey, wchar_t *configValue)
|
|
{
|
|
char *c;
|
|
if (ConfigFileHandle == NULL)
|
|
return FALSE;
|
|
|
|
// Mark previous config value as updated
|
|
if (ConfigBuffer != NULL)
|
|
{
|
|
c = XmlFindElementByAttributeValue (ConfigBuffer, "config", "key", configKey);
|
|
if (c != NULL)
|
|
c[1] = '!';
|
|
}
|
|
|
|
return 0 != fwprintf (
|
|
ConfigFileHandle, L"\n\t\t<config key=\"%hs\">%ls</config>",
|
|
configKey, configValue);
|
|
}
|
|
|
|
BOOL ConfigWriteInt (char *configKey, int configValue)
|
|
{
|
|
char val[32];
|
|
StringCbPrintfA (val, sizeof(val), "%d", configValue);
|
|
return ConfigWriteString (configKey, val);
|
|
}
|
|
|
|
|
|
static BOOL ConfigRead (char *configKey, char *configValue, int maxValueSize)
|
|
{
|
|
DWORD size;
|
|
char *xml;
|
|
|
|
if (ConfigBuffer == NULL)
|
|
ConfigBuffer = LoadFile (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), &size);
|
|
|
|
xml = ConfigBuffer;
|
|
if (xml != NULL)
|
|
{
|
|
xml = XmlFindElementByAttributeValue (xml, "config", "key", configKey);
|
|
if (xml != NULL)
|
|
{
|
|
XmlGetNodeText (xml, configValue, maxValueSize);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int ConfigReadInt (char *configKey, int defaultValue)
|
|
{
|
|
char s[32];
|
|
|
|
if (ConfigRead (configKey, s, sizeof (s)))
|
|
return atoi (s);
|
|
else
|
|
return defaultValue;
|
|
}
|
|
|
|
|
|
char *ConfigReadString (char *configKey, char *defaultValue, char *str, int maxLen)
|
|
{
|
|
if (ConfigRead (configKey, str, maxLen))
|
|
return str;
|
|
else
|
|
{
|
|
StringCbCopyA (str, maxLen, defaultValue);
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
void ConfigReadCompareInt(char *configKey, int defaultValue, int* pOutputValue, BOOL bOnlyCheckModified, BOOL* pbModified)
|
|
{
|
|
int intValue = ConfigReadInt (configKey, defaultValue);
|
|
if (pOutputValue)
|
|
{
|
|
if (pbModified && (*pOutputValue != intValue))
|
|
*pbModified = TRUE;
|
|
if (!bOnlyCheckModified)
|
|
*pOutputValue = intValue;
|
|
}
|
|
}
|
|
|
|
void ConfigReadCompareString (char *configKey, char *defaultValue, char *str, int maxLen, BOOL bOnlyCheckModified, BOOL *pbModified)
|
|
{
|
|
char *strValue = (char*) malloc (maxLen);
|
|
if (strValue)
|
|
{
|
|
memcpy (strValue, str, maxLen);
|
|
|
|
ConfigReadString (configKey, defaultValue, strValue, maxLen);
|
|
|
|
if (pbModified && strcmp (str, strValue))
|
|
*pbModified = TRUE;
|
|
if (!bOnlyCheckModified)
|
|
memcpy(str, strValue, maxLen);
|
|
|
|
free (strValue);
|
|
}
|
|
else
|
|
{
|
|
/* allocation failed. Suppose that value changed */
|
|
if (pbModified)
|
|
*pbModified = TRUE;
|
|
if (!bOnlyCheckModified)
|
|
ConfigReadString (configKey, defaultValue, str, maxLen);
|
|
|
|
}
|
|
}
|
|
|
|
void OpenPageHelp (HWND hwndDlg, int nPage)
|
|
{
|
|
if (IsAdmin ())
|
|
{
|
|
if (FileExists (szHelpFile))
|
|
SafeOpenURL (szHelpFile);
|
|
else if (FileExists (szHelpFile2))
|
|
SafeOpenURL (szHelpFile2);
|
|
else
|
|
Applink ("help");
|
|
}
|
|
else
|
|
{
|
|
int r = (int)ShellExecuteW (NULL, L"open", szHelpFile, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
if (r == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
// Try the secondary help file
|
|
r = (int)ShellExecuteW (NULL, L"open", szHelpFile2, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
if (r == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
// Open local HTML help. It will fallback to online help if not found.
|
|
Applink ("help");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (r == SE_ERR_NOASSOC)
|
|
{
|
|
if (AskYesNo ("HELP_READER_ERROR", MainDlg) == IDYES)
|
|
OpenOnlineHelp ();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void OpenOnlineHelp ()
|
|
{
|
|
Applink ("onlinehelp");
|
|
}
|
|
|
|
|
|
#ifndef SETUP
|
|
|
|
void RestoreDefaultKeyFilesParam (void)
|
|
{
|
|
KeyFileRemoveAll (&FirstKeyFile);
|
|
if (defaultKeyFilesParam.FirstKeyFile != NULL)
|
|
{
|
|
KeyFileCloneAll (defaultKeyFilesParam.FirstKeyFile, &FirstKeyFile);
|
|
KeyFilesEnable = defaultKeyFilesParam.EnableKeyFiles;
|
|
}
|
|
else
|
|
KeyFilesEnable = FALSE;
|
|
}
|
|
|
|
|
|
BOOL LoadDefaultKeyFilesParam (void)
|
|
{
|
|
BOOL status = TRUE;
|
|
DWORD size;
|
|
char *defaultKeyfilesFile = LoadFile (GetConfigPath (TC_APPD_FILENAME_DEFAULT_KEYFILES), &size);
|
|
char *xml = defaultKeyfilesFile;
|
|
KeyFile *kf;
|
|
|
|
if (xml == NULL)
|
|
return FALSE;
|
|
|
|
KeyFileRemoveAll (&defaultKeyFilesParam.FirstKeyFile);
|
|
|
|
while (xml = XmlFindElement (xml, "keyfile"))
|
|
{
|
|
kf = (KeyFile *) malloc (sizeof (KeyFile));
|
|
if (kf)
|
|
{
|
|
char fileName [MAX_PATH + 1];
|
|
if (XmlGetNodeText (xml, fileName, sizeof (fileName)) != NULL)
|
|
{
|
|
std::wstring wszFileName = Utf8StringToWide(fileName);
|
|
StringCbCopyW (kf->FileName, sizeof (kf->FileName), wszFileName.c_str ());
|
|
defaultKeyFilesParam.FirstKeyFile = KeyFileAdd (defaultKeyFilesParam.FirstKeyFile, kf);
|
|
}
|
|
else
|
|
free (kf);
|
|
}
|
|
else
|
|
{
|
|
KeyFileRemoveAll (&defaultKeyFilesParam.FirstKeyFile);
|
|
status = FALSE;
|
|
break;
|
|
}
|
|
|
|
xml++;
|
|
}
|
|
|
|
free (defaultKeyfilesFile);
|
|
if (status)
|
|
KeyFilesEnable = defaultKeyFilesParam.EnableKeyFiles;
|
|
|
|
return status;
|
|
}
|
|
|
|
#endif /* #ifndef SETUP */
|
|
|
|
|
|
void Debug (char *format, ...)
|
|
{
|
|
char buf[1024];
|
|
va_list val;
|
|
|
|
va_start(val, format);
|
|
StringCbVPrintfA (buf, sizeof (buf), format, val);
|
|
va_end(val);
|
|
|
|
OutputDebugStringA (buf);
|
|
}
|
|
|
|
|
|
void DebugMsgBox (char *format, ...)
|
|
{
|
|
char buf[1024];
|
|
va_list val;
|
|
|
|
va_start(val, format);
|
|
StringCbVPrintfA (buf, sizeof (buf), format, val);
|
|
va_end(val);
|
|
|
|
MessageBoxA (MainDlg, buf, "VeraCrypt debug", 0);
|
|
}
|
|
|
|
BOOL IsSupportedOS ()
|
|
{
|
|
BOOL bRet = FALSE;
|
|
#ifdef SETUP
|
|
static const wchar_t* szWin7KBs[] = {L"KB3033929", L"KB4474419"};
|
|
static const wchar_t* szWinVistaKBs[] = {L"KB4039648", L"KB4474419"};
|
|
if (IsOSAtLeast(WIN_8))
|
|
bRet = TRUE;
|
|
else if (IsOSAtLeast(WIN_7))
|
|
{
|
|
if (OneOfKBsInstalled(szWin7KBs, 2))
|
|
bRet = TRUE;
|
|
else
|
|
MessageBoxW (NULL, L"SHA-2 support missing from Windows.\n\nPlease Install KB3033929 or KB4474419", lpszTitle, MB_ICONWARNING);
|
|
}
|
|
else if (IsOSAtLeast(WIN_VISTA))
|
|
{
|
|
if (OneOfKBsInstalled(szWinVistaKBs, 2))
|
|
bRet = TRUE;
|
|
else
|
|
MessageBoxW (NULL, L"SHA-2 support missing from Windows.\n\nPlease Install KB4039648 or KB4474419", lpszTitle, MB_ICONWARNING);
|
|
}
|
|
else if (IsOSAtLeast(WIN_XP))
|
|
bRet = TRUE;
|
|
#else
|
|
if (IsOSAtLeast(WIN_XP))
|
|
bRet = TRUE;
|
|
#endif
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL Is64BitOs()
|
|
{
|
|
#ifdef _WIN64
|
|
return TRUE;
|
|
#else
|
|
static BOOL isWow64 = FALSE;
|
|
static BOOL valid = FALSE;
|
|
typedef BOOL(__stdcall* LPFN_ISWOW64PROCESS) (HANDLE hProcess, PBOOL Wow64Process);
|
|
typedef BOOL(__stdcall* LPFN_ISWOW64PROCESS2)(
|
|
HANDLE hProcess,
|
|
USHORT* pProcessMachine,
|
|
USHORT* pNativeMachine
|
|
);
|
|
LPFN_ISWOW64PROCESS fnIsWow64Process;
|
|
LPFN_ISWOW64PROCESS2 fnIsWow64Process2;
|
|
|
|
if (valid)
|
|
return isWow64;
|
|
|
|
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(L"kernel32"), "IsWow64Process");
|
|
fnIsWow64Process2 = (LPFN_ISWOW64PROCESS2)GetProcAddress(GetModuleHandle(L"kernel32"), "IsWow64Process2");
|
|
|
|
if (fnIsWow64Process2)
|
|
{
|
|
USHORT processMachine, nativeMachine;
|
|
if (!fnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine))
|
|
isWow64 = FALSE;
|
|
else
|
|
{
|
|
if (IMAGE_FILE_MACHINE_ARM64 == nativeMachine || IMAGE_FILE_MACHINE_AMD64 == nativeMachine || IMAGE_FILE_MACHINE_IA64 == nativeMachine || IMAGE_FILE_MACHINE_ALPHA64 == nativeMachine)
|
|
isWow64 = TRUE;
|
|
}
|
|
}
|
|
else if (fnIsWow64Process != NULL)
|
|
{
|
|
if (!fnIsWow64Process(GetCurrentProcess(), &isWow64))
|
|
isWow64 = FALSE;
|
|
}
|
|
valid = TRUE;
|
|
return isWow64;
|
|
#endif
|
|
}
|
|
|
|
BOOL IsARM()
|
|
{
|
|
#if defined(_M_ARM) || defined(_M_ARM64)
|
|
return TRUE;
|
|
#else
|
|
static BOOL isARM = FALSE;
|
|
static BOOL valid = FALSE;
|
|
typedef BOOL(__stdcall* LPFN_ISWOW64PROCESS2)(
|
|
HANDLE hProcess,
|
|
USHORT* pProcessMachine,
|
|
USHORT* pNativeMachine
|
|
);
|
|
LPFN_ISWOW64PROCESS2 fnIsWow64Process2;
|
|
|
|
if (valid)
|
|
return isARM;
|
|
|
|
fnIsWow64Process2 = (LPFN_ISWOW64PROCESS2)GetProcAddress(GetModuleHandle(L"kernel32"), "IsWow64Process2");
|
|
if (fnIsWow64Process2)
|
|
{
|
|
USHORT processMachine, nativeMachine;
|
|
if (fnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine))
|
|
{
|
|
if (IMAGE_FILE_MACHINE_ARM64 == nativeMachine || IMAGE_FILE_MACHINE_ARM == nativeMachine)
|
|
isARM = TRUE;
|
|
else
|
|
isARM = FALSE;
|
|
valid = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!valid)
|
|
{
|
|
SYSTEM_INFO systemInfo;
|
|
GetNativeSystemInfo(&systemInfo);
|
|
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM || systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
|
|
isARM = TRUE;
|
|
else
|
|
isARM = FALSE;
|
|
}
|
|
valid = TRUE;
|
|
return isARM;
|
|
|
|
#endif
|
|
}
|
|
|
|
BOOL IsServerOS ()
|
|
{
|
|
OSVERSIONINFOEXW osVer;
|
|
osVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
|
|
GetVersionExW ((LPOSVERSIONINFOW) &osVer);
|
|
|
|
return (osVer.wProductType == VER_NT_SERVER || osVer.wProductType == VER_NT_DOMAIN_CONTROLLER);
|
|
}
|
|
|
|
|
|
// Returns TRUE, if the currently running operating system is installed in a hidden volume. If it's not, or if
|
|
// there's an error, returns FALSE.
|
|
BOOL IsHiddenOSRunning (void)
|
|
{
|
|
static BOOL statusCached = FALSE;
|
|
static BOOL hiddenOSRunning;
|
|
|
|
if (!statusCached)
|
|
{
|
|
try
|
|
{
|
|
hiddenOSRunning = BootEncryption (MainDlg).IsHiddenSystemRunning();
|
|
}
|
|
catch (...)
|
|
{
|
|
hiddenOSRunning = FALSE;
|
|
}
|
|
|
|
statusCached = TRUE;
|
|
}
|
|
|
|
return hiddenOSRunning;
|
|
}
|
|
|
|
|
|
BOOL EnableWow64FsRedirection (BOOL enable)
|
|
{
|
|
typedef BOOLEAN (__stdcall *Wow64EnableWow64FsRedirection_t) (BOOL enable);
|
|
Wow64EnableWow64FsRedirection_t wow64EnableWow64FsRedirection = (Wow64EnableWow64FsRedirection_t) GetProcAddress (GetModuleHandle (L"kernel32"), "Wow64EnableWow64FsRedirection");
|
|
|
|
if (!wow64EnableWow64FsRedirection)
|
|
return FALSE;
|
|
|
|
return wow64EnableWow64FsRedirection (enable);
|
|
}
|
|
|
|
|
|
BOOL RestartComputer (BOOL bShutdown)
|
|
{
|
|
TOKEN_PRIVILEGES tokenPrivil;
|
|
HANDLE hTkn;
|
|
|
|
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hTkn))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LookupPrivilegeValue (NULL, SE_SHUTDOWN_NAME, &tokenPrivil.Privileges[0].Luid);
|
|
tokenPrivil.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
tokenPrivil.PrivilegeCount = 1;
|
|
|
|
AdjustTokenPrivileges (hTkn, false, &tokenPrivil, 0, (PTOKEN_PRIVILEGES) NULL, 0);
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
CloseHandle(hTkn);
|
|
return false;
|
|
}
|
|
|
|
if (!ExitWindowsEx (bShutdown? EWX_POWEROFF: EWX_REBOOT,
|
|
SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED))
|
|
{
|
|
CloseHandle(hTkn);
|
|
return false;
|
|
}
|
|
|
|
CloseHandle(hTkn);
|
|
return true;
|
|
}
|
|
|
|
|
|
std::wstring GetWindowsEdition ()
|
|
{
|
|
wstring osname = L"win";
|
|
|
|
OSVERSIONINFOEXW osVer;
|
|
osVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
|
|
GetVersionExW ((LPOSVERSIONINFOW) &osVer);
|
|
|
|
BOOL home = (osVer.wSuiteMask & VER_SUITE_PERSONAL);
|
|
BOOL server = (osVer.wProductType == VER_NT_SERVER || osVer.wProductType == VER_NT_DOMAIN_CONTROLLER);
|
|
|
|
HKEY hkey;
|
|
wchar_t productName[300] = {0};
|
|
DWORD productNameSize = sizeof (productName);
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx (hkey, L"ProductName", 0, 0, (LPBYTE) &productName, &productNameSize) != ERROR_SUCCESS || productNameSize < 1)
|
|
productName[0] = 0;
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
|
|
switch (nCurrentOS)
|
|
{
|
|
case WIN_2000:
|
|
osname += L"2000";
|
|
break;
|
|
|
|
case WIN_XP:
|
|
case WIN_XP64:
|
|
osname += L"xp";
|
|
osname += home ? L"-home" : L"-pro";
|
|
break;
|
|
|
|
case WIN_SERVER_2003:
|
|
osname += L"2003";
|
|
break;
|
|
|
|
case WIN_VISTA:
|
|
osname += L"vista";
|
|
break;
|
|
|
|
case WIN_SERVER_2008:
|
|
osname += L"2008";
|
|
break;
|
|
|
|
case WIN_7:
|
|
osname += L"7";
|
|
break;
|
|
|
|
case WIN_SERVER_2008_R2:
|
|
osname += L"2008r2";
|
|
break;
|
|
|
|
default:
|
|
wstringstream s;
|
|
s << CurrentOSMajor << L"." << CurrentOSMinor;
|
|
osname += s.str();
|
|
break;
|
|
}
|
|
|
|
if (server)
|
|
osname += L"-server";
|
|
|
|
if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
if (home)
|
|
osname += L"-home";
|
|
else if (wcsstr (productName, L"Standard") != 0)
|
|
osname += L"-standard";
|
|
else if (wcsstr (productName, L"Professional") != 0)
|
|
osname += L"-pro";
|
|
else if (wcsstr (productName, L"Business") != 0)
|
|
osname += L"-business";
|
|
else if (wcsstr (productName, L"Enterprise") != 0)
|
|
osname += L"-enterprise";
|
|
else if (wcsstr (productName, L"Datacenter") != 0)
|
|
osname += L"-datacenter";
|
|
else if (wcsstr (productName, L"Ultimate") != 0)
|
|
osname += L"-ultimate";
|
|
}
|
|
|
|
if (GetSystemMetrics (SM_STARTER))
|
|
osname += L"-starter";
|
|
else if (wcsstr (productName, L"Basic") != 0)
|
|
osname += L"-basic";
|
|
|
|
if (Is64BitOs())
|
|
osname += IsARM()? L"-arm64" : L"-x64";
|
|
|
|
if (CurrentOSServicePack > 0)
|
|
{
|
|
wstringstream s;
|
|
s << L"-sp" << CurrentOSServicePack;
|
|
osname += s.str();
|
|
}
|
|
|
|
return osname;
|
|
}
|
|
|
|
#ifdef SETUP
|
|
extern wchar_t InstallationPath[TC_MAX_PATH];
|
|
#endif
|
|
|
|
void Applink (const char *dest)
|
|
{
|
|
wchar_t url [MAX_URL_LENGTH] = {0};
|
|
wchar_t page[TC_MAX_PATH] = {0};
|
|
wchar_t installDir[TC_MAX_PATH] = {0};
|
|
BOOL buildUrl = TRUE;
|
|
int r;
|
|
|
|
ArrowWaitCursor ();
|
|
|
|
#ifdef SETUP
|
|
StringCbCopyW (installDir, sizeof (installDir), InstallationPath);
|
|
#else
|
|
GetModPath (installDir, TC_MAX_PATH);
|
|
#endif
|
|
|
|
if (strcmp(dest, "donate") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Donation.html");
|
|
}
|
|
else if (strcmp(dest, "main") == 0)
|
|
{
|
|
StringCbCopyW (url, sizeof (url), TC_HOMEPAGE);
|
|
buildUrl = FALSE;
|
|
}
|
|
else if (strcmp(dest,"localizations") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Language%20Packs.html");
|
|
}
|
|
else if (strcmp(dest, "beginnerstutorial") == 0 || strcmp(dest,"tutorial") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Beginner%27s%20Tutorial.html");
|
|
}
|
|
else if (strcmp(dest, "releasenotes") == 0 || strcmp(dest, "history") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Release%20Notes.html");
|
|
}
|
|
else if (strcmp(dest, "hwacceleration") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Hardware%20Acceleration.html");
|
|
}
|
|
else if (strcmp(dest, "parallelization") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Parallelization.html");
|
|
}
|
|
else if (strcmp(dest, "help") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Documentation.html");
|
|
}
|
|
else if (strcmp(dest, "onlinehelp") == 0)
|
|
{
|
|
StringCbCopyW (url, sizeof (url),L"https://www.veracrypt.fr/en/Documentation.html");
|
|
buildUrl = FALSE;
|
|
}
|
|
else if (strcmp(dest, "keyfiles") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Keyfiles.html");
|
|
}
|
|
else if (strcmp(dest, "introcontainer") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Creating%20New%20Volumes.html");
|
|
}
|
|
else if (strcmp(dest, "introsysenc") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"System%20Encryption.html");
|
|
}
|
|
else if (strcmp(dest, "hiddensysenc") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"VeraCrypt%20Hidden%20Operating%20System.html");
|
|
}
|
|
else if (strcmp(dest, "sysencprogressinfo") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"System%20Encryption.html");
|
|
}
|
|
else if (strcmp(dest, "hiddenvolume") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Hidden%20Volume.html");
|
|
}
|
|
else if (strcmp(dest, "aes") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"AES.html");
|
|
}
|
|
else if (strcmp(dest, "serpent") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Serpent.html");
|
|
}
|
|
else if (strcmp(dest, "twofish") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Twofish.html");
|
|
}
|
|
else if (strcmp(dest, "kuznyechik") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Kuznyechik.html");
|
|
}
|
|
else if (strcmp(dest, "camellia") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Camellia.html");
|
|
}
|
|
else if (strcmp(dest, "cascades") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Cascades.html");
|
|
}
|
|
else if (strcmp(dest, "hashalgorithms") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Hash%20Algorithms.html");
|
|
}
|
|
else if (strcmp(dest, "isoburning") == 0)
|
|
{
|
|
StringCbCopyW (url, sizeof (url),L"https://cdburnerxp.se/en/home");
|
|
buildUrl = FALSE;
|
|
}
|
|
else if (strcmp(dest, "sysfavorites") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"System%20Favorite%20Volumes.html");
|
|
}
|
|
else if (strcmp(dest, "favorites") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Favorite%20Volumes.html");
|
|
}
|
|
else if (strcmp(dest, "hiddenvolprotection") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Protection%20of%20Hidden%20Volumes.html");
|
|
}
|
|
else if (strcmp(dest, "faq") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"FAQ.html");
|
|
}
|
|
else if (strcmp(dest, "downloads") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Downloads.html");
|
|
}
|
|
else if (strcmp(dest, "news") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"News.html");
|
|
}
|
|
else if (strcmp(dest, "contact") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Contact.html");
|
|
}
|
|
else if (strcmp(dest, "pim") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"Personal%20Iterations%20Multiplier%20%28PIM%29.html");
|
|
}
|
|
else
|
|
{
|
|
StringCbCopyW (url, sizeof (url),TC_APPLINK);
|
|
buildUrl = FALSE;
|
|
}
|
|
|
|
if (buildUrl)
|
|
{
|
|
StringCbPrintfW (url, sizeof (url), L"file:///%sdocs/html/en/%s", installDir, page);
|
|
CorrectURL (url);
|
|
}
|
|
|
|
if (IsOSAtLeast (WIN_VISTA) && IsAdmin ())
|
|
{
|
|
int openDone = 0;
|
|
if (buildUrl)
|
|
{
|
|
wchar_t pageFileName [TC_MAX_PATH] = {0};
|
|
DWORD cchUnescaped = ARRAYSIZE(pageFileName);
|
|
|
|
StringCbCopyW (pageFileName, sizeof(pageFileName), page);
|
|
/* remove escape sequences from the page name before calling FileExists function */
|
|
if (S_OK == UrlUnescapeWFn (pageFileName, pageFileName, &cchUnescaped, URL_UNESCAPE_INPLACE))
|
|
{
|
|
std::wstring pageFullPath = installDir;
|
|
pageFullPath += L"docs\\html\\en\\";
|
|
pageFullPath += pageFileName;
|
|
|
|
if (!FileExists (pageFullPath.c_str()))
|
|
{
|
|
// fallback to online resources
|
|
StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page);
|
|
SafeOpenURL (url);
|
|
openDone = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!openDone)
|
|
{
|
|
SafeOpenURL (url);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
r = (int) ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
if (((r == ERROR_FILE_NOT_FOUND) || (r == ERROR_PATH_NOT_FOUND)) && buildUrl)
|
|
{
|
|
// fallback to online resources
|
|
StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page);
|
|
ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
|
|
Sleep (200);
|
|
NormalCursor ();
|
|
}
|
|
|
|
|
|
wchar_t *RelativePath2Absolute (wchar_t *szFileName)
|
|
{
|
|
if (szFileName[0] != L'\\'
|
|
&& wcschr (szFileName, L':') == 0
|
|
&& wcsstr (szFileName, L"Volume{") != szFileName)
|
|
{
|
|
wchar_t path[MAX_PATH*2];
|
|
GetCurrentDirectory (MAX_PATH, path);
|
|
|
|
if (path[wcslen (path) - 1] != L'\\')
|
|
StringCbCatW (path, (MAX_PATH * 2), L"\\");
|
|
|
|
StringCbCatW (path, (MAX_PATH * 2), szFileName);
|
|
StringCbCopyW (szFileName, MAX_PATH + 1, path); // szFileName size is always at least (MAX_PATH + 1)
|
|
}
|
|
|
|
return szFileName;
|
|
}
|
|
|
|
|
|
void HandleDriveNotReadyError (HWND hwnd)
|
|
{
|
|
HKEY hkey = 0;
|
|
DWORD value = 0, size = sizeof (DWORD);
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\MountMgr",
|
|
0, KEY_READ, &hkey) != ERROR_SUCCESS)
|
|
return;
|
|
|
|
if (RegQueryValueEx (hkey, L"NoAutoMount", 0, 0, (LPBYTE) &value, &size) == ERROR_SUCCESS
|
|
&& value != 0)
|
|
{
|
|
Warning ("SYS_AUTOMOUNT_DISABLED", hwnd);
|
|
}
|
|
else if (nCurrentOS == WIN_VISTA && CurrentOSServicePack < 1)
|
|
Warning ("SYS_ASSIGN_DRIVE_LETTER", hwnd);
|
|
else
|
|
Warning ("DEVICE_NOT_READY_ERROR", hwnd);
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
|
|
|
|
BOOL CALLBACK CloseTCWindowsEnum (HWND hwnd, LPARAM lParam)
|
|
{
|
|
LONG_PTR userDataVal = GetWindowLongPtrW (hwnd, GWLP_USERDATA);
|
|
if ((userDataVal == (LONG_PTR) 'VERA') || (userDataVal == (LONG_PTR) 'TRUE')) // Prior to 1.0e, 'TRUE' was used for VeraCrypt dialogs
|
|
{
|
|
wchar_t name[1024] = { 0 };
|
|
GetWindowText (hwnd, name, ARRAYSIZE (name) - 1);
|
|
if (hwnd != MainDlg && wcsstr (name, L"VeraCrypt"))
|
|
{
|
|
PostMessage (hwnd, TC_APPMSG_CLOSE_BKG_TASK, 0, 0);
|
|
|
|
PostMessage (hwnd, WM_CLOSE, 0, 0);
|
|
|
|
if (lParam != 0)
|
|
*((BOOL *)lParam) = TRUE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CALLBACK FindTCWindowEnum (HWND hwnd, LPARAM lParam)
|
|
{
|
|
if (*(HWND *)lParam == hwnd)
|
|
return TRUE;
|
|
|
|
LONG_PTR userDataVal = GetWindowLongPtrW (hwnd, GWLP_USERDATA);
|
|
if ((userDataVal == (LONG_PTR) 'VERA') || (userDataVal == (LONG_PTR) 'TRUE')) // Prior to 1.0e, 'TRUE' was used for VeraCrypt dialogs
|
|
{
|
|
wchar_t name[32] = { 0 };
|
|
GetWindowText (hwnd, name, ARRAYSIZE (name) - 1);
|
|
if (hwnd != MainDlg && wcscmp (name, L"VeraCrypt") == 0)
|
|
{
|
|
if (lParam != 0)
|
|
*((HWND *)lParam) = hwnd;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BYTE *MapResource (wchar_t *resourceType, int resourceId, PDWORD size)
|
|
{
|
|
HGLOBAL hResL;
|
|
HRSRC hRes;
|
|
HINSTANCE hResInst = NULL;
|
|
|
|
#ifdef SETUP_DLL
|
|
// In case we're being called from the SetupDLL project, FindResource()
|
|
// and LoadResource() with NULL will fail since we're in a DLL. We need
|
|
// to call them with the HINSTANCE of the DLL instead, which we set in
|
|
// Setup.c of SetupDLL, DllMain() function.
|
|
hResInst = hInst;
|
|
#endif
|
|
|
|
hRes = FindResource (hResInst, MAKEINTRESOURCE(resourceId), resourceType);
|
|
hResL = LoadResource (hResInst, hRes);
|
|
|
|
if (size != NULL)
|
|
*size = SizeofResource (hResInst, hRes);
|
|
|
|
return (BYTE *) LockResource (hResL);
|
|
}
|
|
|
|
|
|
void InconsistencyResolved (char *techInfo)
|
|
{
|
|
wchar_t finalMsg[8024];
|
|
|
|
StringCbPrintfW (finalMsg, sizeof(finalMsg), GetString ("INCONSISTENCY_RESOLVED"), techInfo);
|
|
MessageBoxW (MainDlg, finalMsg, lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
void ReportUnexpectedState (const char *techInfo)
|
|
{
|
|
wchar_t finalMsg[8024];
|
|
|
|
StringCbPrintfW (finalMsg, sizeof(finalMsg), GetString ("UNEXPECTED_STATE"), techInfo);
|
|
MessageBoxW (MainDlg, finalMsg, lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
|
|
}
|
|
|
|
|
|
#ifndef SETUP
|
|
|
|
int OpenVolume (OpenVolumeContext *context, const wchar_t *volumePath, Password *password, int pkcs5_prf, int pim, BOOL truecryptMode, BOOL write, BOOL preserveTimestamps, BOOL useBackupHeader)
|
|
{
|
|
int status = ERR_PARAMETER_INCORRECT;
|
|
int volumeType;
|
|
wchar_t szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH];
|
|
wchar_t szDosDevice[TC_MAX_PATH];
|
|
char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
|
|
LARGE_INTEGER headerOffset;
|
|
DWORD dwResult;
|
|
DISK_GEOMETRY_EX deviceGeometry;
|
|
|
|
context->VolumeIsOpen = FALSE;
|
|
context->CryptoInfo = NULL;
|
|
context->HostFileHandle = INVALID_HANDLE_VALUE;
|
|
context->TimestampsValid = FALSE;
|
|
|
|
CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), volumePath, &context->IsDevice);
|
|
|
|
if (context->IsDevice)
|
|
{
|
|
status = FakeDosNameForDevice (szDiskFile, szDosDevice, sizeof(szDosDevice), szCFDevice, sizeof(szCFDevice), FALSE);
|
|
if (status != 0)
|
|
return status;
|
|
|
|
preserveTimestamps = FALSE;
|
|
|
|
if (!GetDriveGeometry (volumePath, &deviceGeometry))
|
|
{
|
|
status = ERR_OS_ERROR;
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
StringCbCopyW (szCFDevice, sizeof(szCFDevice), szDiskFile);
|
|
|
|
|
|
context->HostFileHandle = CreateFile (szCFDevice, GENERIC_READ | (write ? GENERIC_WRITE : (!context->IsDevice && preserveTimestamps? FILE_WRITE_ATTRIBUTES : 0)), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (context->HostFileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
status = ERR_OS_ERROR;
|
|
goto error;
|
|
}
|
|
|
|
if (context->IsDevice)
|
|
{
|
|
// Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise,
|
|
// the NTFS driver guards hidden sectors and prevents e.g. header backup restore after the user
|
|
// accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS, etc.)
|
|
|
|
DeviceIoControl (context->HostFileHandle, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwResult, NULL);
|
|
}
|
|
|
|
context->VolumeIsOpen = TRUE;
|
|
|
|
// Remember the container modification/creation date and time
|
|
if (!context->IsDevice && preserveTimestamps)
|
|
{
|
|
// ensure that Last Access and Last Write timestamps are not modified
|
|
FILETIME ftLastAccessTime;
|
|
ftLastAccessTime.dwHighDateTime = 0xFFFFFFFF;
|
|
ftLastAccessTime.dwLowDateTime = 0xFFFFFFFF;
|
|
|
|
SetFileTime (context->HostFileHandle, NULL, &ftLastAccessTime, NULL);
|
|
|
|
if (GetFileTime (context->HostFileHandle, &context->CreationTime, &context->LastAccessTime, &context->LastWriteTime) == 0)
|
|
context->TimestampsValid = FALSE;
|
|
else
|
|
context->TimestampsValid = TRUE;
|
|
}
|
|
|
|
// Determine host size
|
|
if (context->IsDevice)
|
|
{
|
|
PARTITION_INFORMATION diskInfo;
|
|
|
|
if (GetPartitionInfo (volumePath, &diskInfo))
|
|
{
|
|
context->HostSize = diskInfo.PartitionLength.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
BYTE dgBuffer[256];
|
|
|
|
if (!DeviceIoControl (context->HostFileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, dgBuffer, sizeof (dgBuffer), &dwResult, NULL))
|
|
{
|
|
DISK_GEOMETRY geo;
|
|
if (DeviceIoControl (context->HostFileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, (LPVOID) &geo, sizeof (geo), &dwResult, NULL))
|
|
{
|
|
((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart = geo.Cylinders.QuadPart * geo.SectorsPerTrack * geo.TracksPerCylinder * geo.BytesPerSector;
|
|
|
|
if (CurrentOSMajor >= 6)
|
|
{
|
|
STORAGE_READ_CAPACITY storage = {0};
|
|
|
|
storage.Version = sizeof (STORAGE_READ_CAPACITY);
|
|
storage.Size = sizeof (STORAGE_READ_CAPACITY);
|
|
if (DeviceIoControl (context->HostFileHandle, IOCTL_STORAGE_READ_CAPACITY, NULL, 0, (LPVOID) &storage, sizeof (storage), &dwResult, NULL))
|
|
{
|
|
((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart = storage.DiskLength.QuadPart;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERR_OS_ERROR;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
context->HostSize = ((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart;
|
|
}
|
|
|
|
if (context->HostSize == 0)
|
|
{
|
|
status = ERR_VOL_SIZE_WRONG;
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LARGE_INTEGER fileSize;
|
|
if (!GetFileSizeEx (context->HostFileHandle, &fileSize))
|
|
{
|
|
status = ERR_OS_ERROR;
|
|
goto error;
|
|
}
|
|
|
|
context->HostSize = fileSize.QuadPart;
|
|
}
|
|
|
|
for (volumeType = TC_VOLUME_TYPE_NORMAL; volumeType < TC_VOLUME_TYPE_COUNT; volumeType++)
|
|
{
|
|
// Seek the volume header
|
|
switch (volumeType)
|
|
{
|
|
case TC_VOLUME_TYPE_NORMAL:
|
|
headerOffset.QuadPart = useBackupHeader ? context->HostSize - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
|
|
break;
|
|
|
|
case TC_VOLUME_TYPE_HIDDEN:
|
|
if (TC_HIDDEN_VOLUME_HEADER_OFFSET + TC_VOLUME_HEADER_SIZE > context->HostSize)
|
|
continue;
|
|
|
|
headerOffset.QuadPart = useBackupHeader ? context->HostSize - TC_VOLUME_HEADER_SIZE : TC_HIDDEN_VOLUME_HEADER_OFFSET;
|
|
break;
|
|
|
|
}
|
|
|
|
if (!SetFilePointerEx ((HANDLE) context->HostFileHandle, headerOffset, NULL, FILE_BEGIN))
|
|
{
|
|
status = ERR_OS_ERROR;
|
|
goto error;
|
|
}
|
|
|
|
// Read volume header
|
|
DWORD bytesRead;
|
|
if (!ReadEffectiveVolumeHeader (context->IsDevice, context->HostFileHandle, (byte *) buffer, &bytesRead))
|
|
{
|
|
status = ERR_OS_ERROR;
|
|
goto error;
|
|
}
|
|
|
|
if (bytesRead != sizeof (buffer)
|
|
&& context->IsDevice)
|
|
{
|
|
// If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
|
|
// filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
|
|
// shorter than the partition). This can happen for example after the user quick-formats a dismounted
|
|
// partition-hosted TrueCrypt volume and then tries to read the embedded backup header.
|
|
|
|
memset (buffer, 0, sizeof (buffer));
|
|
}
|
|
|
|
// Decrypt volume header
|
|
status = ReadVolumeHeader (FALSE, buffer, password, pkcs5_prf, pim, truecryptMode, &context->CryptoInfo, NULL);
|
|
|
|
if (status == ERR_PASSWORD_WRONG)
|
|
continue; // Try next volume type
|
|
|
|
break;
|
|
}
|
|
|
|
if (status == ERR_SUCCESS)
|
|
return status;
|
|
|
|
error:
|
|
DWORD sysError = GetLastError ();
|
|
|
|
CloseVolume (context);
|
|
|
|
SetLastError (sysError);
|
|
return status;
|
|
}
|
|
|
|
|
|
void CloseVolume (OpenVolumeContext *context)
|
|
{
|
|
if (!context->VolumeIsOpen)
|
|
return;
|
|
|
|
if (context->HostFileHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (context->TimestampsValid)
|
|
SetFileTime (context->HostFileHandle, &context->CreationTime, &context->LastAccessTime, &context->LastWriteTime);
|
|
|
|
CloseHandle (context->HostFileHandle);
|
|
context->HostFileHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (context->CryptoInfo)
|
|
{
|
|
crypto_close (context->CryptoInfo);
|
|
context->CryptoInfo = NULL;
|
|
}
|
|
|
|
context->VolumeIsOpen = FALSE;
|
|
}
|
|
|
|
|
|
int ReEncryptVolumeHeader (HWND hwndDlg, char *buffer, BOOL bBoot, CRYPTO_INFO *cryptoInfo, Password *password, int pim, BOOL wipeMode)
|
|
{
|
|
CRYPTO_INFO *newCryptoInfo = NULL;
|
|
|
|
RandSetHashFunction (cryptoInfo->pkcs5);
|
|
|
|
if (Randinit() != ERR_SUCCESS)
|
|
{
|
|
if (CryptoAPILastError == ERROR_SUCCESS)
|
|
return ERR_RAND_INIT_FAILED;
|
|
else
|
|
return ERR_CAPI_INIT_FAILED;
|
|
}
|
|
|
|
UserEnrichRandomPool (NULL);
|
|
|
|
int status = CreateVolumeHeaderInMemory (hwndDlg, bBoot,
|
|
buffer,
|
|
cryptoInfo->ea,
|
|
cryptoInfo->mode,
|
|
password,
|
|
cryptoInfo->pkcs5,
|
|
pim,
|
|
(char *) cryptoInfo->master_keydata,
|
|
&newCryptoInfo,
|
|
cryptoInfo->VolumeSize.Value,
|
|
cryptoInfo->hiddenVolume ? cryptoInfo->hiddenVolumeSize : 0,
|
|
cryptoInfo->EncryptedAreaStart.Value,
|
|
cryptoInfo->EncryptedAreaLength.Value,
|
|
cryptoInfo->RequiredProgramVersion,
|
|
cryptoInfo->HeaderFlags,
|
|
cryptoInfo->SectorSize,
|
|
wipeMode);
|
|
|
|
if (newCryptoInfo != NULL)
|
|
crypto_close (newCryptoInfo);
|
|
|
|
return status;
|
|
}
|
|
|
|
#endif // !SETUP
|
|
|
|
|
|
BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
|
|
{
|
|
// GlobalMemoryStatusEx() cannot be used to determine if a paging file is active
|
|
|
|
wchar_t data[65536];
|
|
DWORD size = sizeof (data);
|
|
|
|
if (IsPagingFileWildcardActive())
|
|
return TRUE;
|
|
|
|
if (ReadLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", data, &size)
|
|
&& size > 24 && !checkNonWindowsPartitionsOnly)
|
|
return TRUE;
|
|
|
|
if (!IsAdmin())
|
|
AbortProcess ("UAC_INIT_ERROR");
|
|
|
|
for (wchar_t drive = L'C'; drive <= L'Z'; ++drive)
|
|
{
|
|
// Query geometry of the drive first to prevent "no medium" pop-ups
|
|
wstring drivePath = L"\\\\.\\X:";
|
|
drivePath[4] = drive;
|
|
|
|
if (checkNonWindowsPartitionsOnly)
|
|
{
|
|
wchar_t sysDir[MAX_PATH];
|
|
if (GetSystemDirectory (sysDir, ARRAYSIZE (sysDir)) != 0 && towupper (sysDir[0]) == drive)
|
|
continue;
|
|
}
|
|
|
|
HANDLE handle = CreateFile (drivePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
continue;
|
|
|
|
BYTE dgBuffer[256];
|
|
DWORD dwResult;
|
|
|
|
if (!DeviceIoControl (handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, dgBuffer, sizeof (dgBuffer), &dwResult, NULL)
|
|
&& !DeviceIoControl (handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, dgBuffer, sizeof (dgBuffer), &dwResult, NULL))
|
|
{
|
|
CloseHandle (handle);
|
|
continue;
|
|
}
|
|
|
|
CloseHandle (handle);
|
|
|
|
// Test if a paging file exists and is locked by another process
|
|
wstring path = L"X:\\pagefile.sys";
|
|
path[0] = drive;
|
|
|
|
handle = CreateFile (path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (handle != INVALID_HANDLE_VALUE)
|
|
CloseHandle (handle);
|
|
else if (GetLastError() == ERROR_SHARING_VIOLATION)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL IsPagingFileWildcardActive ()
|
|
{
|
|
wchar_t pagingFiles[65536];
|
|
DWORD size = sizeof (pagingFiles);
|
|
wchar_t *mmKey = L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management";
|
|
|
|
if (!ReadLocalMachineRegistryString (mmKey, L"PagingFiles", pagingFiles, &size))
|
|
{
|
|
size = sizeof (pagingFiles);
|
|
if (!ReadLocalMachineRegistryMultiString (mmKey, L"PagingFiles", pagingFiles, &size))
|
|
size = 0;
|
|
}
|
|
|
|
return size > 0 && wcsstr (pagingFiles, L"?:\\") == pagingFiles;
|
|
}
|
|
|
|
|
|
BOOL DisablePagingFile ()
|
|
{
|
|
wchar_t empty[] = { 0, 0 };
|
|
return WriteLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", empty, sizeof (empty));
|
|
}
|
|
|
|
|
|
std::wstring SingleStringToWide (const std::string &singleString)
|
|
{
|
|
if (singleString.empty())
|
|
return std::wstring();
|
|
|
|
WCHAR wbuf[65536];
|
|
int wideLen = MultiByteToWideChar (CP_ACP, 0, singleString.c_str(), -1, wbuf, array_capacity (wbuf) - 1);
|
|
|
|
// We don't throw exception here and only return empty string.
|
|
// All calls to this function use valid strings.
|
|
// throw_sys_if (wideLen == 0);
|
|
|
|
wbuf[wideLen] = 0;
|
|
return wbuf;
|
|
}
|
|
|
|
|
|
std::wstring Utf8StringToWide (const std::string &utf8String)
|
|
{
|
|
if (utf8String.empty())
|
|
return std::wstring();
|
|
|
|
WCHAR wbuf[65536];
|
|
int wideLen = MultiByteToWideChar (CP_UTF8, 0, utf8String.c_str(), -1, wbuf, array_capacity (wbuf) - 1);
|
|
throw_sys_if (wideLen == 0);
|
|
|
|
wbuf[wideLen] = 0;
|
|
return wbuf;
|
|
}
|
|
|
|
|
|
std::string WideToUtf8String (const std::wstring &wideString)
|
|
{
|
|
if (wideString.empty())
|
|
return std::string();
|
|
|
|
char buf[65536];
|
|
int len = WideCharToMultiByte (CP_UTF8, 0, wideString.c_str(), -1, buf, array_capacity (buf) - 1, NULL, NULL);
|
|
throw_sys_if (len == 0);
|
|
|
|
buf[len] = 0;
|
|
return buf;
|
|
}
|
|
|
|
|
|
#ifndef SETUP
|
|
|
|
BOOL CALLBACK SecurityTokenPasswordDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD lw = LOWORD (wParam);
|
|
static string *password;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
password = (string *) lParam;
|
|
LocalizeDialog (hwndDlg, "IDD_TOKEN_PASSWORD");
|
|
|
|
wchar_t s[1024];
|
|
StringCbPrintfW (s, sizeof(s), GetString ("ENTER_TOKEN_PASSWORD"), Utf8StringToWide (password->c_str()).c_str());
|
|
SetWindowTextW (GetDlgItem (hwndDlg, IDT_TOKEN_PASSWORD_INFO), s);
|
|
|
|
SendMessage (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD), EM_LIMITTEXT, SecurityToken::MaxPasswordLength, 0);
|
|
|
|
SetForegroundWindow (hwndDlg);
|
|
SetFocus (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD));
|
|
|
|
if (!bSecureDesktopOngoing)
|
|
{
|
|
PasswordEditDropTarget* pTarget = new PasswordEditDropTarget ();
|
|
if (pTarget->Register (hwndDlg))
|
|
{
|
|
SetWindowLongPtr (hwndDlg, DWLP_USER, (LONG_PTR) pTarget);
|
|
}
|
|
else
|
|
delete pTarget;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
case WM_COMMAND:
|
|
if (lw == IDCANCEL || lw == IDOK)
|
|
{
|
|
if (lw == IDOK)
|
|
{
|
|
wchar_t passwordWide[SecurityToken::MaxPasswordLength + 1];
|
|
|
|
if (GetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD), passwordWide, SecurityToken::MaxPasswordLength + 1) == 0)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
break;
|
|
}
|
|
|
|
char passwordUtf8[SecurityToken::MaxPasswordLength + 1];
|
|
|
|
int len = WideCharToMultiByte (CP_UTF8, 0, passwordWide, -1, passwordUtf8, array_capacity (passwordUtf8) - 1, nullptr, nullptr);
|
|
passwordUtf8[len] = 0;
|
|
*password = passwordUtf8;
|
|
|
|
burn (passwordWide, sizeof (passwordWide));
|
|
burn (passwordUtf8, sizeof (passwordUtf8));
|
|
}
|
|
|
|
// Attempt to wipe password stored in the input field buffer
|
|
wchar_t tmp[SecurityToken::MaxPasswordLength+1];
|
|
wmemset (tmp, 'X', SecurityToken::MaxPasswordLength);
|
|
tmp[SecurityToken::MaxPasswordLength] = 0;
|
|
SetWindowText (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD), tmp);
|
|
|
|
EndDialog (hwndDlg, lw);
|
|
}
|
|
return 1;
|
|
|
|
case WM_NCDESTROY:
|
|
{
|
|
/* unregister drap-n-drop support */
|
|
PasswordEditDropTarget* pTarget = (PasswordEditDropTarget*) GetWindowLongPtr (hwndDlg, DWLP_USER);
|
|
if (pTarget)
|
|
{
|
|
SetWindowLongPtr (hwndDlg, DWLP_USER, (LONG_PTR) 0);
|
|
pTarget->Revoke ();
|
|
pTarget->Release();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct NewSecurityTokenKeyfileDlgProcParams
|
|
{
|
|
CK_SLOT_ID SlotId;
|
|
string Name;
|
|
};
|
|
|
|
static BOOL CALLBACK NewSecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static NewSecurityTokenKeyfileDlgProcParams *newParams;
|
|
|
|
WORD lw = LOWORD (wParam);
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
LocalizeDialog (hwndDlg, "IDD_NEW_TOKEN_KEYFILE");
|
|
|
|
newParams = (NewSecurityTokenKeyfileDlgProcParams *) lParam;
|
|
|
|
WaitCursor();
|
|
finally_do ({ NormalCursor(); });
|
|
|
|
list <shared_ptr<TokenInfo>> tokens;
|
|
|
|
try
|
|
{
|
|
tokens = Token::GetAvailableTokens();
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (hwndDlg);
|
|
}
|
|
|
|
if (tokens.empty())
|
|
{
|
|
Error ("NO_TOKENS_FOUND", hwndDlg);
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
|
|
foreach (const shared_ptr<TokenInfo> token, tokens)
|
|
{
|
|
wstringstream tokenLabel;
|
|
tokenLabel << L"[" << token->SlotId << L"] " << token->Label;
|
|
|
|
AddComboPair (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), tokenLabel.str().c_str(), token->SlotId);
|
|
}
|
|
|
|
ComboBox_SetCurSel (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), 0);
|
|
|
|
SetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_KEYFILE_NAME), Utf8StringToWide (newParams->Name).c_str());
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
switch (lw)
|
|
{
|
|
case IDOK:
|
|
{
|
|
int selectedToken = ComboBox_GetCurSel (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN));
|
|
if (selectedToken == CB_ERR)
|
|
{
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
|
|
newParams->SlotId = (CK_SLOT_ID) ComboBox_GetItemData (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), selectedToken);
|
|
|
|
wchar_t name[1024];
|
|
if (GetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_KEYFILE_NAME), name, array_capacity (name)) != 0)
|
|
{
|
|
try
|
|
{
|
|
newParams->Name = WideToUtf8String (name);
|
|
}
|
|
catch (...) { }
|
|
}
|
|
|
|
EndDialog (hwndDlg, IDOK);
|
|
return 1;
|
|
}
|
|
|
|
case IDCANCEL:
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
|
|
if (HIWORD (wParam) == EN_CHANGE)
|
|
{
|
|
wchar_t name[2];
|
|
EnableWindow (GetDlgItem (hwndDlg, IDOK), (GetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_KEYFILE_NAME), name, array_capacity (name)) != 0));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void SecurityTokenKeyfileDlgFillList (HWND hwndDlg, const vector <shared_ptr<TokenKeyfile>> &keyfiles)
|
|
{
|
|
HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST);
|
|
LVITEMW lvItem;
|
|
int line = 0;
|
|
|
|
ListView_DeleteAllItems (tokenListControl);
|
|
|
|
foreach (const shared_ptr<TokenKeyfile> keyfile, keyfiles)
|
|
{
|
|
memset (&lvItem, 0, sizeof(lvItem));
|
|
lvItem.mask = LVIF_TEXT;
|
|
lvItem.iItem = line++;
|
|
|
|
wstringstream s;
|
|
s << keyfile->Token->SlotId;
|
|
|
|
ListItemAdd (tokenListControl, lvItem.iItem, (wchar_t *) s.str().c_str());
|
|
ListSubItemSet (tokenListControl, lvItem.iItem, 1, (wchar_t *) keyfile->Token->Label.c_str());
|
|
ListSubItemSet (tokenListControl, lvItem.iItem, 2, (wchar_t *) keyfile->Id.c_str());
|
|
}
|
|
|
|
BOOL selected = (ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST), -1, LVIS_SELECTED) != -1);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_EXPORT), selected);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_DELETE), selected);
|
|
}
|
|
|
|
|
|
static list <shared_ptr<TokenKeyfile>> SecurityTokenKeyfileDlgGetSelected (HWND hwndDlg, const vector <shared_ptr<TokenKeyfile>> &keyfiles)
|
|
{
|
|
HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST);
|
|
list <shared_ptr<TokenKeyfile>> selectedKeyfiles;
|
|
|
|
int itemId = -1;
|
|
while ((itemId = ListView_GetNextItem (tokenListControl, itemId, LVIS_SELECTED)) != -1)
|
|
{
|
|
selectedKeyfiles.push_back (keyfiles[itemId]);
|
|
}
|
|
|
|
return selectedKeyfiles;
|
|
}
|
|
|
|
|
|
BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static list <TokenKeyfilePath> *selectedTokenKeyfiles;
|
|
static vector <shared_ptr<TokenKeyfile>> keyfiles;
|
|
|
|
WORD lw = LOWORD (wParam);
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
selectedTokenKeyfiles = (list <TokenKeyfilePath> *) lParam;
|
|
|
|
LVCOLUMNW LvCol;
|
|
HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST);
|
|
|
|
LocalizeDialog (hwndDlg, selectedTokenKeyfiles ? "SELECT_TOKEN_KEYFILES" : "IDD_TOKEN_KEYFILES");
|
|
|
|
SendMessage (tokenListControl,LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
|
|
LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_TWOCLICKACTIVATE|LVS_EX_LABELTIP
|
|
);
|
|
|
|
memset (&LvCol, 0, sizeof(LvCol));
|
|
LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
|
|
LvCol.pszText = GetString ("TOKEN_SLOT_ID");
|
|
LvCol.cx = CompensateXDPI (40);
|
|
LvCol.fmt = LVCFMT_CENTER;
|
|
SendMessage (tokenListControl, LVM_INSERTCOLUMNW, 1, (LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("TOKEN_NAME");
|
|
LvCol.cx = CompensateXDPI (128);
|
|
LvCol.fmt = LVCFMT_LEFT;
|
|
SendMessage (tokenListControl, LVM_INSERTCOLUMNW, 2, (LPARAM)&LvCol);
|
|
|
|
LvCol.pszText = GetString ("TOKEN_DATA_OBJECT_LABEL");
|
|
LvCol.cx = CompensateXDPI (195);
|
|
LvCol.fmt = LVCFMT_LEFT;
|
|
SendMessage (tokenListControl, LVM_INSERTCOLUMNW, 3, (LPARAM)&LvCol);
|
|
|
|
keyfiles.clear();
|
|
|
|
try
|
|
{
|
|
WaitCursor();
|
|
finally_do ({ NormalCursor(); });
|
|
|
|
keyfiles = Token::GetAvailableKeyfiles(EMVSupportEnabled);
|
|
}
|
|
catch (UserAbort&)
|
|
{
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (hwndDlg);
|
|
|
|
if (keyfiles.empty())
|
|
{
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles);
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
case WM_NOTIFY:
|
|
if (msg == WM_COMMAND && lw == IDOK || msg == WM_NOTIFY && ((NMHDR *)lParam)->code == LVN_ITEMACTIVATE)
|
|
{
|
|
if (selectedTokenKeyfiles)
|
|
{
|
|
foreach (const shared_ptr<TokenKeyfile> &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles))
|
|
{
|
|
selectedTokenKeyfiles->push_back (TokenKeyfilePath (*keyfile));
|
|
}
|
|
}
|
|
|
|
EndDialog (hwndDlg, IDOK);
|
|
return 1;
|
|
}
|
|
|
|
if (msg == WM_NOTIFY && ((LPNMHDR) lParam)->code == LVN_ITEMCHANGED)
|
|
{
|
|
BOOL selected = (ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST), -1, LVIS_SELECTED) != -1);
|
|
BOOL deletable = selected;
|
|
// Multiple key files can be selected.
|
|
// Therefore, if one of them is not deletable, it means the delete button must be disabled for all.
|
|
foreach (const shared_ptr<TokenKeyfile> &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles))
|
|
{
|
|
if (!keyfile->Token->isEditable())
|
|
{
|
|
deletable = false;
|
|
break;
|
|
}
|
|
}
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_EXPORT), selected);
|
|
EnableWindow (GetDlgItem (hwndDlg, IDC_DELETE), deletable);
|
|
return 1;
|
|
}
|
|
|
|
if (msg == WM_COMMAND)
|
|
{
|
|
switch (lw)
|
|
{
|
|
case IDCANCEL:
|
|
EndDialog (hwndDlg, IDCANCEL);
|
|
return 1;
|
|
|
|
case IDC_IMPORT_KEYFILE:
|
|
{
|
|
wchar_t keyfilePath[TC_MAX_PATH];
|
|
|
|
if (BrowseFiles (hwndDlg, "SELECT_KEYFILE", keyfilePath, bHistory, FALSE, NULL))
|
|
{
|
|
DWORD keyfileSize;
|
|
byte *keyfileData = (byte *) LoadFile (keyfilePath, &keyfileSize);
|
|
if (!keyfileData)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
return 1;
|
|
}
|
|
|
|
if (keyfileSize != 0)
|
|
{
|
|
NewSecurityTokenKeyfileDlgProcParams newParams;
|
|
newParams.Name = WideToUtf8String (keyfilePath);
|
|
|
|
size_t lastBackSlash = newParams.Name.find_last_of ('\\');
|
|
if (lastBackSlash != string::npos)
|
|
newParams.Name = newParams.Name.substr (lastBackSlash + 1);
|
|
|
|
if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_NEW_TOKEN_KEYFILE), hwndDlg, (DLGPROC) NewSecurityTokenKeyfileDlgProc, (LPARAM) &newParams) == IDOK)
|
|
{
|
|
vector <byte> keyfileDataVector (keyfileSize);
|
|
memcpy (&keyfileDataVector.front(), keyfileData, keyfileSize);
|
|
|
|
try
|
|
{
|
|
WaitCursor();
|
|
finally_do ({ NormalCursor(); });
|
|
|
|
SecurityToken::CreateKeyfile (newParams.SlotId, keyfileDataVector, newParams.Name);
|
|
|
|
keyfiles = Token::GetAvailableKeyfiles(EMVSupportEnabled);
|
|
SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles);
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (hwndDlg);
|
|
}
|
|
|
|
burn (&keyfileDataVector.front(), keyfileSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError (ERROR_HANDLE_EOF);
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
}
|
|
|
|
burn (keyfileData, keyfileSize);
|
|
TCfree (keyfileData);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
case IDC_EXPORT:
|
|
{
|
|
try
|
|
{
|
|
foreach (const shared_ptr<TokenKeyfile> &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles))
|
|
{
|
|
wchar_t keyfilePath[TC_MAX_PATH];
|
|
|
|
if (!BrowseFiles (hwndDlg, "OPEN_TITLE", keyfilePath, bHistory, TRUE, NULL))
|
|
break;
|
|
|
|
{
|
|
WaitCursor();
|
|
finally_do ({ NormalCursor(); });
|
|
|
|
vector <byte> keyfileData;
|
|
|
|
keyfile->GetKeyfileData (keyfileData);
|
|
|
|
if (keyfileData.empty())
|
|
{
|
|
SetLastError (ERROR_HANDLE_EOF);
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
return 1;
|
|
}
|
|
|
|
finally_do_arg (vector <byte> *, &keyfileData, { burn (&finally_arg->front(), finally_arg->size()); });
|
|
|
|
if (!SaveBufferToFile ((char *) &keyfileData.front(), keyfilePath, (DWORD) keyfileData.size(), FALSE, FALSE))
|
|
throw SystemException (SRC_POS);
|
|
}
|
|
|
|
Info ("KEYFILE_EXPORTED", hwndDlg);
|
|
}
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (hwndDlg);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
case IDC_DELETE:
|
|
{
|
|
if (AskNoYes ("CONFIRM_SEL_FILES_DELETE", hwndDlg) == IDNO)
|
|
return 1;
|
|
|
|
try
|
|
{
|
|
WaitCursor();
|
|
finally_do ({ NormalCursor(); });
|
|
|
|
foreach (const shared_ptr<TokenKeyfile> keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles))
|
|
{
|
|
SecurityToken::DeleteKeyfile (dynamic_cast<SecurityTokenKeyfile&>(*keyfile.get()));
|
|
}
|
|
|
|
keyfiles = Token::GetAvailableKeyfiles(EMVSupportEnabled);
|
|
SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles);
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (hwndDlg);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern "C" BOOL IsThreadInSecureDesktop(DWORD dwThreadID)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
if (bSecureDesktopOngoing)
|
|
{
|
|
HDESK currentDesk = GetThreadDesktop (dwThreadID);
|
|
if (currentDesk)
|
|
{
|
|
LPWSTR szName = NULL;
|
|
DWORD dwLen = 0;
|
|
if (!GetUserObjectInformation (currentDesk, UOI_NAME, NULL, 0, &dwLen))
|
|
{
|
|
szName = (LPWSTR) malloc (dwLen);
|
|
if (szName)
|
|
{
|
|
if (GetUserObjectInformation (currentDesk, UOI_NAME, szName, dwLen, &dwLen))
|
|
{
|
|
if (0 == _wcsicmp (szName, SecureDesktopName))
|
|
bRet = TRUE;
|
|
}
|
|
free (szName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL InitSecurityTokenLibrary (HWND hwndDlg)
|
|
{
|
|
if (SecurityTokenLibraryPath[0] == 0)
|
|
{
|
|
Error ("NO_PKCS11_MODULE_SPECIFIED", hwndDlg);
|
|
return FALSE;
|
|
}
|
|
|
|
struct PinRequestHandler : public GetPinFunctor
|
|
{
|
|
HWND m_hwnd;
|
|
PinRequestHandler(HWND hwnd) : m_hwnd(hwnd) {}
|
|
virtual void operator() (string &str)
|
|
{
|
|
if (CmdTokenPin[0])
|
|
{
|
|
str = CmdTokenPin;
|
|
}
|
|
else
|
|
{
|
|
HWND hParent = IsWindow (m_hwnd)? m_hwnd : GetActiveWindow();
|
|
if (!hParent)
|
|
hParent = GetForegroundWindow ();
|
|
if (IsThreadInSecureDesktop(GetCurrentThreadId()) && !IsThreadInSecureDesktop(GetWindowThreadProcessId(hParent, NULL)))
|
|
hParent = GetActiveWindow ();
|
|
if (SecureDesktopDialogBoxParam (hInst, MAKEINTRESOURCEW (IDD_TOKEN_PASSWORD), hParent, (DLGPROC) SecurityTokenPasswordDlgProc, (LPARAM) &str) == IDCANCEL)
|
|
throw UserAbort (SRC_POS);
|
|
}
|
|
if (hCursor != NULL)
|
|
SetCursor (hCursor);
|
|
}
|
|
|
|
virtual void notifyIncorrectPin ()
|
|
{
|
|
// clear wrong PIN
|
|
burn (&CmdTokenPin, sizeof (CmdTokenPin));
|
|
}
|
|
};
|
|
|
|
struct WarningHandler : public SendExceptionFunctor
|
|
{
|
|
HWND m_hwnd;
|
|
WarningHandler(HWND hwnd) : m_hwnd(hwnd) {}
|
|
virtual void operator() (const Exception &e)
|
|
{
|
|
HWND hParent = IsWindow (m_hwnd)? m_hwnd : GetActiveWindow();
|
|
if (!hParent)
|
|
hParent = GetForegroundWindow ();
|
|
e.Show (hParent);
|
|
}
|
|
};
|
|
|
|
try
|
|
{
|
|
SecurityToken::InitLibrary (SecurityTokenLibraryPath, unique_ptr <GetPinFunctor> (new PinRequestHandler(MainDlg)), unique_ptr <SendExceptionFunctor> (new WarningHandler(MainDlg)));
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (hwndDlg);
|
|
Error ("PKCS11_MODULE_INIT_FAILED", hwndDlg);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
std::vector <HostDevice> GetAvailableHostDevices (bool noDeviceProperties, bool singleList, bool noFloppy, bool detectUnencryptedFilesystems)
|
|
{
|
|
vector <HostDevice> devices;
|
|
size_t dev0;
|
|
|
|
for (int devNumber = 0; devNumber < MAX_HOST_DRIVE_NUMBER; devNumber++)
|
|
{
|
|
for (int partNumber = 0; partNumber < MAX_HOST_PARTITION_NUMBER; partNumber++)
|
|
{
|
|
WCHAR devPath[32];
|
|
StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\Harddisk%d\\Partition%d", devNumber, partNumber);
|
|
|
|
OPEN_TEST_STRUCT openTest = {0};
|
|
if (!OpenDevice (devPath, &openTest, detectUnencryptedFilesystems && partNumber != 0, FALSE))
|
|
{
|
|
if (partNumber == 0)
|
|
break;
|
|
|
|
continue;
|
|
}
|
|
|
|
HostDevice device;
|
|
device.SystemNumber = devNumber;
|
|
device.Path = devPath;
|
|
|
|
PARTITION_INFORMATION partInfo;
|
|
|
|
if (GetPartitionInfo (devPath, &partInfo))
|
|
{
|
|
device.Bootable = partInfo.BootIndicator ? true : false;
|
|
device.Size = partInfo.PartitionLength.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
// retrieve size using DISK_GEOMETRY_EX
|
|
DISK_GEOMETRY_EX deviceGeometry = {0};
|
|
if ( GetDriveGeometry (devPath, &deviceGeometry)
|
|
|| ((partNumber == 0) && GetPhysicalDriveGeometry (devNumber, &deviceGeometry))
|
|
)
|
|
{
|
|
device.Size = (uint64) deviceGeometry.DiskSize.QuadPart;
|
|
}
|
|
}
|
|
|
|
device.HasUnencryptedFilesystem = (detectUnencryptedFilesystems && openTest.FilesystemDetected) ? true : false;
|
|
|
|
if (!noDeviceProperties)
|
|
{
|
|
DISK_GEOMETRY_EX geometry;
|
|
|
|
int driveNumber = GetDiskDeviceDriveLetter (devPath);
|
|
|
|
if (driveNumber >= 0)
|
|
{
|
|
device.MountPoint += (wchar_t) (driveNumber + L'A');
|
|
device.MountPoint += L":";
|
|
|
|
wchar_t name[64];
|
|
if (GetDriveLabel (driveNumber, name, sizeof (name)))
|
|
device.Name = name;
|
|
|
|
if (GetSystemDriveLetter() == L'A' + driveNumber)
|
|
device.ContainsSystem = true;
|
|
}
|
|
|
|
if (partNumber == 0 && GetDriveGeometry (devPath, &geometry))
|
|
device.Removable = (geometry.Geometry.MediaType == RemovableMedia);
|
|
}
|
|
|
|
if (partNumber == 0)
|
|
{
|
|
devices.push_back (device);
|
|
dev0 = devices.size() - 1;
|
|
}
|
|
else
|
|
{
|
|
// System creates a virtual partition1 for some storage devices without
|
|
// partition table. We try to detect this case by comparing sizes of
|
|
// partition0 and partition1. If they match, no partition of the device
|
|
// is displayed to the user to avoid confusion. Drive letter assigned by
|
|
// system to partition1 is assigned partition0
|
|
if (partNumber == 1 && devices[dev0].Size == device.Size)
|
|
{
|
|
devices[dev0].IsVirtualPartition = true;
|
|
devices[dev0].MountPoint = device.MountPoint;
|
|
devices[dev0].Name = device.Name;
|
|
devices[dev0].Path = device.Path;
|
|
devices[dev0].HasUnencryptedFilesystem = device.HasUnencryptedFilesystem;
|
|
break;
|
|
}
|
|
|
|
device.IsPartition = true;
|
|
device.SystemNumber = partNumber;
|
|
device.Removable = devices[dev0].Removable;
|
|
|
|
if (device.ContainsSystem)
|
|
devices[dev0].ContainsSystem = true;
|
|
|
|
if (singleList)
|
|
devices.push_back (device);
|
|
|
|
devices[dev0].Partitions.push_back (device);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Vista does not create partition links for dynamic volumes so it is necessary to scan \\Device\\HarddiskVolumeX devices
|
|
if (CurrentOSMajor >= 6)
|
|
{
|
|
for (int devNumber = 0; devNumber < 256; devNumber++)
|
|
{
|
|
WCHAR devPath[32];
|
|
StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\HarddiskVolume%d", devNumber);
|
|
|
|
OPEN_TEST_STRUCT openTest = {0};
|
|
if (!OpenDevice (devPath, &openTest, detectUnencryptedFilesystems, FALSE))
|
|
continue;
|
|
|
|
DISK_PARTITION_INFO_STRUCT info;
|
|
if (GetDeviceInfo (devPath, &info) && info.IsDynamic)
|
|
{
|
|
HostDevice device;
|
|
device.DynamicVolume = true;
|
|
device.IsPartition = true;
|
|
device.SystemNumber = devNumber;
|
|
device.Path = devPath;
|
|
device.Size = info.partInfo.PartitionLength.QuadPart;
|
|
device.HasUnencryptedFilesystem = (detectUnencryptedFilesystems && openTest.FilesystemDetected) ? true : false;
|
|
|
|
if (!noDeviceProperties)
|
|
{
|
|
int driveNumber = GetDiskDeviceDriveLetter (devPath);
|
|
|
|
if (driveNumber >= 0)
|
|
{
|
|
device.MountPoint += (wchar_t) (driveNumber + L'A');
|
|
device.MountPoint += L":";
|
|
|
|
wchar_t name[64];
|
|
if (GetDriveLabel (driveNumber, name, sizeof (name)))
|
|
device.Name = name;
|
|
|
|
if (GetSystemDriveLetter() == L'A' + driveNumber)
|
|
device.ContainsSystem = true;
|
|
}
|
|
}
|
|
|
|
devices.push_back (device);
|
|
}
|
|
}
|
|
}
|
|
|
|
return devices;
|
|
}
|
|
|
|
void AddDeviceToList (std::vector<HostDevice>& devices, int devNumber, int partNumber)
|
|
{
|
|
WCHAR devPath[64];
|
|
StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\Harddisk%d\\Partition%d", devNumber, partNumber);
|
|
|
|
HostDevice device;
|
|
device.SystemNumber = devNumber;
|
|
device.Path = devPath;
|
|
|
|
devices.push_back (device);
|
|
}
|
|
|
|
std::vector <HostDevice> GetHostRawDeviceList ()
|
|
{
|
|
std::vector <HostDevice> list;
|
|
HDEVINFO diskClassDevices;
|
|
GUID diskClassDeviceInterfaceGuid = GUID_DEVINTERFACE_DISK;
|
|
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData;
|
|
DWORD requiredSize;
|
|
DWORD deviceIndex;
|
|
|
|
STORAGE_DEVICE_NUMBER diskNumber;
|
|
DWORD bytesReturned;
|
|
|
|
diskClassDevices = SetupDiGetClassDevs( &diskClassDeviceInterfaceGuid,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_PRESENT |
|
|
DIGCF_DEVICEINTERFACE );
|
|
if ( INVALID_HANDLE_VALUE != diskClassDevices)
|
|
{
|
|
ZeroMemory( &deviceInterfaceData, sizeof( SP_DEVICE_INTERFACE_DATA ) );
|
|
deviceInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
|
|
deviceIndex = 0;
|
|
|
|
while ( SetupDiEnumDeviceInterfaces( diskClassDevices,
|
|
NULL,
|
|
&diskClassDeviceInterfaceGuid,
|
|
deviceIndex,
|
|
&deviceInterfaceData ) )
|
|
{
|
|
++deviceIndex;
|
|
|
|
if (!SetupDiGetDeviceInterfaceDetail( diskClassDevices,
|
|
&deviceInterfaceData,
|
|
NULL,
|
|
0,
|
|
&requiredSize,
|
|
NULL ) && ( ERROR_INSUFFICIENT_BUFFER == GetLastError()))
|
|
{
|
|
deviceInterfaceDetailData = ( PSP_DEVICE_INTERFACE_DETAIL_DATA ) malloc( requiredSize );
|
|
if (deviceInterfaceDetailData)
|
|
{
|
|
ZeroMemory( deviceInterfaceDetailData, requiredSize );
|
|
deviceInterfaceDetailData->cbSize = sizeof( SP_DEVICE_INTERFACE_DETAIL_DATA );
|
|
if (SetupDiGetDeviceInterfaceDetail( diskClassDevices,
|
|
&deviceInterfaceData,
|
|
deviceInterfaceDetailData,
|
|
requiredSize,
|
|
NULL,
|
|
NULL ))
|
|
{
|
|
HANDLE disk = CreateFile( deviceInterfaceDetailData->DevicePath,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
if ( INVALID_HANDLE_VALUE != disk)
|
|
{
|
|
if (DeviceIoControl( disk,
|
|
IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
|
NULL,
|
|
0,
|
|
&diskNumber,
|
|
sizeof( STORAGE_DEVICE_NUMBER ),
|
|
&bytesReturned,
|
|
NULL ))
|
|
{
|
|
HostDevice device;
|
|
device.Path = deviceInterfaceDetailData->DevicePath;
|
|
device.SystemNumber = diskNumber.DeviceNumber;
|
|
list.push_back (device);
|
|
}
|
|
|
|
CloseHandle( disk );
|
|
}
|
|
}
|
|
|
|
free (deviceInterfaceDetailData);
|
|
}
|
|
}
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList( diskClassDevices );
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
bool CompareDeviceList (const std::vector<HostDevice>& list1, const std::vector<HostDevice>& list2)
|
|
{
|
|
if (list1.size() != list2.size())
|
|
return false;
|
|
|
|
for (std::vector<HostDevice>::const_iterator It1 = list1.begin(); It1 != list1.end(); It1++)
|
|
{
|
|
bool bFound = false;
|
|
for (std::vector<HostDevice>::const_iterator It2 = list2.begin(); It2 != list2.end(); It2++)
|
|
{
|
|
if (It1->Path == It2->Path && It1->SystemNumber == It2->SystemNumber)
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void UpdateMountableHostDeviceList ()
|
|
{
|
|
ByteArray buffer(4096);
|
|
DWORD bytesReturned;
|
|
bool dynamicVolumesPresent = false;
|
|
|
|
EnterCriticalSection (&csMountableDevices);
|
|
finally_do ({ LeaveCriticalSection (&csMountableDevices); });
|
|
|
|
std::vector<HostDevice> newList = GetHostRawDeviceList ();
|
|
std::map<DWORD, bool> existingDevicesMap;
|
|
|
|
if (CompareDeviceList (newList, rawHostDeviceList))
|
|
return; //no change, return
|
|
|
|
// remove raw devices that don't exist anymore
|
|
for (std::vector<HostDevice>::iterator It = rawHostDeviceList.begin();
|
|
It != rawHostDeviceList.end();)
|
|
{
|
|
for (std::vector<HostDevice>::iterator newIt = newList.begin(); newIt != newList.end(); newIt++)
|
|
{
|
|
if (newIt->SystemNumber == It->SystemNumber)
|
|
{
|
|
existingDevicesMap[It->SystemNumber] = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (existingDevicesMap[It->SystemNumber])
|
|
It++;
|
|
else
|
|
{
|
|
It = rawHostDeviceList.erase (It);
|
|
}
|
|
}
|
|
|
|
// remove mountable devices that don't exist anymore
|
|
for (std::vector<HostDevice>::iterator It = mountableDevices.begin();
|
|
It != mountableDevices.end();)
|
|
{
|
|
if (existingDevicesMap[It->SystemNumber])
|
|
It++;
|
|
else
|
|
It = mountableDevices.erase (It);
|
|
}
|
|
|
|
// add new devices
|
|
for (std::vector<HostDevice>::iterator It = newList.begin(); It != newList.end(); It++)
|
|
{
|
|
if (existingDevicesMap[It->SystemNumber])
|
|
continue;
|
|
|
|
HANDLE disk = CreateFile( It->Path.c_str(),
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
if ( INVALID_HANDLE_VALUE != disk)
|
|
{
|
|
bool bIsDynamic = false;
|
|
bool bHasPartition = false;
|
|
if (DeviceIoControl(
|
|
disk,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
|
NULL,
|
|
0,
|
|
(LPVOID) buffer.data(),
|
|
(DWORD) buffer.size(),
|
|
(LPDWORD) &bytesReturned,
|
|
NULL) && (bytesReturned >= sizeof (DRIVE_LAYOUT_INFORMATION_EX)))
|
|
{
|
|
PDRIVE_LAYOUT_INFORMATION_EX layout = (PDRIVE_LAYOUT_INFORMATION_EX) buffer.data();
|
|
// sanity checks
|
|
if (layout->PartitionCount <= 256)
|
|
{
|
|
for (DWORD i = 0; i < layout->PartitionCount; i++)
|
|
{
|
|
if (layout->PartitionEntry[i].PartitionStyle == PARTITION_STYLE_MBR)
|
|
{
|
|
if (layout->PartitionEntry[i].Mbr.PartitionType == 0)
|
|
continue;
|
|
|
|
bHasPartition = true;
|
|
|
|
/* skip dynamic volume */
|
|
if (layout->PartitionEntry[i].Mbr.PartitionType == PARTITION_LDM)
|
|
{
|
|
bIsDynamic = true;
|
|
/* remove any partition that may have been added */
|
|
while (!mountableDevices.empty() && (mountableDevices.back().SystemNumber == It->SystemNumber))
|
|
mountableDevices.pop_back ();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (layout->PartitionEntry[i].PartitionStyle == PARTITION_STYLE_GPT)
|
|
{
|
|
if (IsEqualGUID(layout->PartitionEntry[i].Gpt.PartitionType, PARTITION_ENTRY_UNUSED_GUID))
|
|
continue;
|
|
|
|
bHasPartition = true;
|
|
|
|
/* skip dynamic volume */
|
|
if ( IsEqualGUID(layout->PartitionEntry[i].Gpt.PartitionType, PARTITION_LDM_METADATA_GUID)
|
|
|| IsEqualGUID(layout->PartitionEntry[i].Gpt.PartitionType, PARTITION_LDM_DATA_GUID)
|
|
)
|
|
{
|
|
bIsDynamic = true;
|
|
/* remove any partition that may have been added */
|
|
while (!mountableDevices.empty() && (mountableDevices.back().SystemNumber == It->SystemNumber))
|
|
mountableDevices.pop_back ();
|
|
break;
|
|
}
|
|
}
|
|
|
|
WCHAR path[MAX_PATH];
|
|
StringCbPrintfW (path, sizeof(path), L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%d", It->SystemNumber, layout->PartitionEntry[i].PartitionNumber);
|
|
HANDLE handle = CreateFile( path,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
if ((handle != INVALID_HANDLE_VALUE) || (GetLastError () == ERROR_ACCESS_DENIED))
|
|
{
|
|
AddDeviceToList (mountableDevices, It->SystemNumber, layout->PartitionEntry[i].PartitionNumber);
|
|
if (handle != INVALID_HANDLE_VALUE)
|
|
CloseHandle (handle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bIsDynamic)
|
|
dynamicVolumesPresent = true;
|
|
|
|
if (!bHasPartition)
|
|
AddDeviceToList (mountableDevices, It->SystemNumber, 0);
|
|
|
|
CloseHandle (disk);
|
|
}
|
|
}
|
|
|
|
rawHostDeviceList = newList;
|
|
|
|
// Starting from Vista, Windows does not create partition links for dynamic volumes so it is necessary to scan \\Device\\HarddiskVolumeX devices
|
|
if (dynamicVolumesPresent && (CurrentOSMajor >= 6))
|
|
{
|
|
for (int devNumber = 0; devNumber < 256; devNumber++)
|
|
{
|
|
WCHAR devPath[32];
|
|
StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\HarddiskVolume%d", devNumber);
|
|
|
|
OPEN_TEST_STRUCT openTest = {0};
|
|
if (!OpenDevice (devPath, &openTest, FALSE, FALSE))
|
|
continue;
|
|
|
|
DISK_PARTITION_INFO_STRUCT info;
|
|
if (GetDeviceInfo (devPath, &info) && info.IsDynamic)
|
|
{
|
|
HostDevice device;
|
|
device.SystemNumber = devNumber;
|
|
device.Path = devPath;
|
|
|
|
mountableDevices.push_back (device);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wstring FindDeviceByVolumeID (const BYTE volumeID [VOLUME_ID_SIZE], BOOL bFromService)
|
|
{
|
|
/* if it is already mounted, get the real path name used for mounting */
|
|
MOUNT_LIST_STRUCT mlist;
|
|
DWORD dwResult;
|
|
|
|
memset (&mlist, 0, sizeof (mlist));
|
|
if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist,
|
|
sizeof (mlist), &mlist, sizeof (mlist), &dwResult,
|
|
NULL)
|
|
|| (mlist.ulMountedDrives >= (1 << 26))
|
|
)
|
|
{
|
|
return L"";
|
|
}
|
|
|
|
if (mlist.ulMountedDrives)
|
|
{
|
|
for (int i=0 ; i < 26; i++)
|
|
{
|
|
if ((mlist.ulMountedDrives & (1 << i)) && (0 == memcmp (mlist.volumeID[i], volumeID, VOLUME_ID_SIZE)))
|
|
{
|
|
if (IsNullTerminateString (mlist.wszVolume[i], TC_MAX_PATH))
|
|
return mlist.wszVolume[i];
|
|
else
|
|
return L"";
|
|
}
|
|
}
|
|
}
|
|
|
|
/* not mounted. Look for it in the local drives*/
|
|
|
|
if (bFromService)
|
|
{
|
|
for (int devNumber = 0; devNumber < MAX_HOST_DRIVE_NUMBER; devNumber++)
|
|
{
|
|
for (int partNumber = 0; partNumber < MAX_HOST_PARTITION_NUMBER; partNumber++)
|
|
{
|
|
WCHAR devPath[32];
|
|
StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\Harddisk%d\\Partition%d", devNumber, partNumber);
|
|
|
|
OPEN_TEST_STRUCT openTest = {0};
|
|
if (OpenDevice (devPath, &openTest, TRUE, TRUE)
|
|
&& (openTest.VolumeIDComputed[TC_VOLUME_TYPE_NORMAL] && openTest.VolumeIDComputed[TC_VOLUME_TYPE_HIDDEN])
|
|
)
|
|
{
|
|
if ( (0 == memcmp (volumeID, openTest.volumeIDs[TC_VOLUME_TYPE_NORMAL], VOLUME_ID_SIZE))
|
|
|| (0 == memcmp (volumeID, openTest.volumeIDs[TC_VOLUME_TYPE_HIDDEN], VOLUME_ID_SIZE))
|
|
)
|
|
{
|
|
return devPath;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static std::vector<HostDevice> volumeIdCandidates;
|
|
|
|
EnterCriticalSection (&csMountableDevices);
|
|
if (!NeedPeriodicDeviceListUpdate)
|
|
UpdateMountableHostDeviceList ();
|
|
std::vector<HostDevice> newDevices = mountableDevices;
|
|
LeaveCriticalSection (&csMountableDevices);
|
|
|
|
EnterCriticalSection (&csVolumeIdCandidates);
|
|
finally_do ({ LeaveCriticalSection (&csVolumeIdCandidates); });
|
|
|
|
/* remove any devices that don't exist anymore */
|
|
for (std::vector<HostDevice>::iterator It = volumeIdCandidates.begin();
|
|
It != volumeIdCandidates.end();)
|
|
{
|
|
bool bFound = false;
|
|
for (std::vector<HostDevice>::iterator newIt = newDevices.begin();
|
|
newIt != newDevices.end(); newIt++)
|
|
{
|
|
if (It->Path == newIt->Path)
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bFound)
|
|
It++;
|
|
else
|
|
It = volumeIdCandidates.erase (It);
|
|
}
|
|
|
|
/* Add newly inserted devices and compute their VolumeID */
|
|
for (std::vector<HostDevice>::iterator newIt = newDevices.begin();
|
|
newIt != newDevices.end(); newIt++)
|
|
{
|
|
bool bFound = false;
|
|
|
|
for (std::vector<HostDevice>::iterator It = volumeIdCandidates.begin();
|
|
It != volumeIdCandidates.end(); It++)
|
|
{
|
|
if (It->Path == newIt->Path)
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
/* new device/partition. Compute its Volume IDs */
|
|
OPEN_TEST_STRUCT openTest = {0};
|
|
if (OpenDevice (newIt->Path.c_str(), &openTest, TRUE, TRUE)
|
|
&& (openTest.VolumeIDComputed[TC_VOLUME_TYPE_NORMAL] && openTest.VolumeIDComputed[TC_VOLUME_TYPE_HIDDEN])
|
|
)
|
|
{
|
|
memcpy (newIt->VolumeIDs, openTest.volumeIDs, sizeof (newIt->VolumeIDs));
|
|
newIt->HasVolumeIDs = true;
|
|
}
|
|
else
|
|
newIt->HasVolumeIDs = false;
|
|
volumeIdCandidates.push_back (*newIt);
|
|
}
|
|
}
|
|
|
|
for (std::vector<HostDevice>::iterator It = volumeIdCandidates.begin();
|
|
It != volumeIdCandidates.end(); It++)
|
|
{
|
|
if ( It->HasVolumeIDs &&
|
|
( (0 == memcmp (volumeID, It->VolumeIDs[TC_VOLUME_TYPE_NORMAL], VOLUME_ID_SIZE))
|
|
|| (0 == memcmp (volumeID, It->VolumeIDs[TC_VOLUME_TYPE_HIDDEN], VOLUME_ID_SIZE))
|
|
)
|
|
)
|
|
{
|
|
return It->Path;
|
|
}
|
|
}
|
|
}
|
|
|
|
return L"";
|
|
}
|
|
|
|
#endif // !SETUP
|
|
|
|
BOOL FileHasReadOnlyAttribute (const wchar_t *path)
|
|
{
|
|
DWORD attributes = GetFileAttributes (path);
|
|
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_READONLY) != 0;
|
|
}
|
|
|
|
|
|
BOOL IsFileOnReadOnlyFilesystem (const wchar_t *path)
|
|
{
|
|
wchar_t root[MAX_PATH];
|
|
if (!GetVolumePathName (path, root, ARRAYSIZE (root)))
|
|
return FALSE;
|
|
|
|
DWORD flags, d;
|
|
if (!GetVolumeInformation (root, NULL, 0, NULL, &d, &flags, NULL, 0))
|
|
return FALSE;
|
|
|
|
return (flags & FILE_READ_ONLY_VOLUME) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
void CheckFilesystem (HWND hwndDlg, int driveNo, BOOL fixErrors)
|
|
{
|
|
wchar_t msg[1024], param[1024], cmdPath[MAX_PATH];
|
|
wchar_t driveRoot[] = { L'A' + (wchar_t) driveNo, L':', 0 };
|
|
|
|
if (fixErrors && AskWarnYesNo ("FILESYS_REPAIR_CONFIRM_BACKUP", hwndDlg) == IDNO)
|
|
return;
|
|
|
|
StringCbPrintfW (msg, sizeof(msg), GetString (fixErrors ? "REPAIRING_FS" : "CHECKING_FS"), driveRoot);
|
|
StringCbPrintfW (param, sizeof(param), fixErrors ? L"/C echo %s & chkdsk %s /F /X & pause" : L"/C echo %s & chkdsk %s & pause", msg, driveRoot);
|
|
|
|
if (GetSystemDirectoryW(cmdPath, MAX_PATH))
|
|
{
|
|
StringCbCatW(cmdPath, sizeof(cmdPath), L"\\cmd.exe");
|
|
}
|
|
else
|
|
StringCbCopyW(cmdPath, sizeof(cmdPath), L"C:\\Windows\\System32\\cmd.exe");
|
|
|
|
ShellExecuteW (NULL, (!IsAdmin() && IsUacSupported()) ? L"runas" : L"open", cmdPath, param, NULL, SW_SHOW);
|
|
}
|
|
|
|
BOOL BufferContainsPattern (const byte *buffer, size_t bufferSize, const byte *pattern, size_t patternSize)
|
|
{
|
|
if (bufferSize < patternSize)
|
|
return FALSE;
|
|
|
|
bufferSize -= patternSize;
|
|
|
|
for (size_t i = 0; i < bufferSize; ++i)
|
|
{
|
|
if (memcmp (buffer + i, pattern, patternSize) == 0)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL BufferContainsString (const byte *buffer, size_t bufferSize, const char *str)
|
|
{
|
|
return BufferContainsPattern (buffer, bufferSize, (const byte*) str, strlen (str));
|
|
}
|
|
|
|
BOOL BufferContainsWideString (const byte *buffer, size_t bufferSize, const wchar_t *str)
|
|
{
|
|
return BufferContainsPattern (buffer, bufferSize, (const byte*) str, 2 * wcslen (str));
|
|
}
|
|
|
|
|
|
#ifndef SETUP
|
|
|
|
int AskNonSysInPlaceEncryptionResume (HWND hwndDlg, BOOL *pbDecrypt)
|
|
{
|
|
if (AskWarnYesNo ("NONSYS_INPLACE_ENC_RESUME_PROMPT", hwndDlg) == IDYES)
|
|
{
|
|
char *tmpStr[] = {0,
|
|
"CHOOSE_ENCRYPT_OR_DECRYPT",
|
|
"ENCRYPT",
|
|
"DECRYPT",
|
|
"IDCANCEL",
|
|
0};
|
|
|
|
switch (AskMultiChoice ((void **) tmpStr, FALSE, hwndDlg))
|
|
{
|
|
case 1:
|
|
*pbDecrypt = FALSE;
|
|
return IDYES;
|
|
case 2:
|
|
*pbDecrypt = TRUE;
|
|
return IDYES;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
char *multiChoiceStr[] = { 0, "ASK_NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL", "DO_NOT_PROMPT_ME", "KEEP_PROMPTING_ME", 0 };
|
|
|
|
switch (AskMultiChoice ((void **) multiChoiceStr, FALSE, hwndDlg))
|
|
{
|
|
case 1:
|
|
RemoveNonSysInPlaceEncNotifications();
|
|
Warning ("NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL_NOTE", hwndDlg);
|
|
break;
|
|
|
|
default:
|
|
// NOP
|
|
break;
|
|
}
|
|
|
|
return IDNO;
|
|
}
|
|
|
|
#endif // !SETUP
|
|
|
|
|
|
BOOL RemoveDeviceWriteProtection (HWND hwndDlg, wchar_t *devicePath)
|
|
{
|
|
int driveNumber;
|
|
int partitionNumber;
|
|
|
|
wchar_t temp[MAX_PATH*2];
|
|
wchar_t cmdBatch[MAX_PATH*2];
|
|
wchar_t diskpartScript[MAX_PATH*2];
|
|
|
|
if (swscanf (devicePath, L"\\Device\\Harddisk%d\\Partition%d", &driveNumber, &partitionNumber) != 2)
|
|
return FALSE;
|
|
|
|
if (GetTempPath (ARRAYSIZE (temp), temp) == 0)
|
|
return FALSE;
|
|
|
|
StringCbPrintfW (cmdBatch, sizeof (cmdBatch), L"%s\\VeraCrypt_Write_Protection_Removal.cmd", temp);
|
|
StringCbPrintfW (diskpartScript, sizeof (diskpartScript), L"%s\\VeraCrypt_Write_Protection_Removal.diskpart", temp);
|
|
|
|
FILE *f = _wfopen (cmdBatch, L"w");
|
|
if (!f)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
return FALSE;
|
|
}
|
|
|
|
fwprintf (f, L"@diskpart /s \"%s\"\n@pause\n@del \"%s\" \"%s\"", diskpartScript, diskpartScript, cmdBatch);
|
|
|
|
CheckFileStreamWriteErrors (hwndDlg, f, cmdBatch);
|
|
fclose (f);
|
|
|
|
f = _wfopen (diskpartScript, L"w");
|
|
if (!f)
|
|
{
|
|
handleWin32Error (hwndDlg, SRC_POS);
|
|
DeleteFile (cmdBatch);
|
|
return FALSE;
|
|
}
|
|
|
|
fwprintf (f, L"select disk %d\nattributes disk clear readonly\n", driveNumber);
|
|
|
|
if (partitionNumber != 0)
|
|
fwprintf (f, L"select partition %d\nattributes volume clear readonly\n", partitionNumber);
|
|
|
|
fwprintf (f, L"exit\n");
|
|
|
|
CheckFileStreamWriteErrors (hwndDlg, f, diskpartScript);
|
|
fclose (f);
|
|
|
|
ShellExecute (NULL, (!IsAdmin() && IsUacSupported()) ? L"runas" : L"open", cmdBatch, NULL, NULL, SW_SHOW);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static LRESULT CALLBACK EnableElevatedCursorChangeWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return DefWindowProcW (hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
|
|
void EnableElevatedCursorChange (HWND parent)
|
|
{
|
|
// Create a transparent window to work around a UAC issue preventing change of the cursor
|
|
if (UacElevated)
|
|
{
|
|
const wchar_t *className = L"VeraCryptEnableElevatedCursorChange";
|
|
WNDCLASSEXW winClass;
|
|
HWND hWnd;
|
|
|
|
memset (&winClass, 0, sizeof (winClass));
|
|
winClass.cbSize = sizeof (WNDCLASSEX);
|
|
winClass.lpfnWndProc = (WNDPROC) EnableElevatedCursorChangeWndProc;
|
|
winClass.hInstance = hInst;
|
|
winClass.lpszClassName = className;
|
|
RegisterClassExW (&winClass);
|
|
|
|
hWnd = CreateWindowExW (WS_EX_TOOLWINDOW | WS_EX_LAYERED, className, L"VeraCrypt UAC", 0, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), parent, NULL, hInst, NULL);
|
|
if (hWnd)
|
|
{
|
|
SetLayeredWindowAttributes (hWnd, 0, 1, LWA_ALPHA);
|
|
ShowWindow (hWnd, SW_SHOWNORMAL);
|
|
|
|
DestroyWindow (hWnd);
|
|
}
|
|
UnregisterClassW (className, hInst);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL DisableFileCompression (HANDLE file)
|
|
{
|
|
USHORT format;
|
|
DWORD bytesOut;
|
|
|
|
if (!DeviceIoControl (file, FSCTL_GET_COMPRESSION, NULL, 0, &format, sizeof (format), &bytesOut, NULL))
|
|
return FALSE;
|
|
|
|
if (format == COMPRESSION_FORMAT_NONE)
|
|
return TRUE;
|
|
|
|
format = COMPRESSION_FORMAT_NONE;
|
|
return DeviceIoControl (file, FSCTL_SET_COMPRESSION, &format, sizeof (format), NULL, 0, &bytesOut, NULL);
|
|
}
|
|
|
|
#ifndef SETUP
|
|
BOOL VolumePathExists (const wchar_t *volumePath)
|
|
{
|
|
OPEN_TEST_STRUCT openTest = {0};
|
|
wchar_t upperCasePath[TC_MAX_PATH + 1];
|
|
|
|
UpperCaseCopy (upperCasePath, sizeof(upperCasePath), volumePath);
|
|
|
|
if (wcsstr (upperCasePath, L"\\DEVICE\\") == upperCasePath)
|
|
return OpenDevice (volumePath, &openTest, FALSE, FALSE);
|
|
|
|
wstring path = volumePath;
|
|
if (path.find (L"\\\\?\\Volume{") == 0 && path.rfind (L"}\\") == path.size() - 2)
|
|
{
|
|
wchar_t devicePath[TC_MAX_PATH];
|
|
if (QueryDosDevice (path.substr (4, path.size() - 5).c_str(), devicePath, TC_MAX_PATH) != 0)
|
|
return TRUE;
|
|
}
|
|
|
|
if (_waccess (volumePath, 0) == 0)
|
|
return TRUE;
|
|
else
|
|
{
|
|
DWORD dwResult = GetLastError ();
|
|
if (dwResult == ERROR_SHARING_VIOLATION)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL IsWindowsIsoBurnerAvailable ()
|
|
{
|
|
wchar_t path[MAX_PATH*2] = { 0 };
|
|
|
|
if (!IsOSAtLeast (WIN_7))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_SYSTEM, NULL, 0, path)))
|
|
{
|
|
StringCbCatW (path, MAX_PATH*2, L"\\" ISO_BURNER_TOOL);
|
|
|
|
return (FileExists (path));
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL LaunchWindowsIsoBurner (HWND hwnd, const wchar_t *isoPath)
|
|
{
|
|
wchar_t path[MAX_PATH*2] = { 0 };
|
|
int r;
|
|
|
|
if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_SYSTEM, NULL, 0, path)))
|
|
StringCbCatW (path, MAX_PATH*2, L"\\" ISO_BURNER_TOOL);
|
|
else
|
|
StringCbCopyW (path, MAX_PATH*2, L"C:\\Windows\\System32\\" ISO_BURNER_TOOL);
|
|
|
|
r = (int) ShellExecute (hwnd, L"open", path, (wstring (L"\"") + isoPath + L"\"").c_str(), NULL, SW_SHOWNORMAL);
|
|
|
|
if (r <= 32)
|
|
{
|
|
SetLastError (r);
|
|
handleWin32Error (hwnd, SRC_POS);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
std::wstring VolumeGuidPathToDevicePath (std::wstring volumeGuidPath)
|
|
{
|
|
if (volumeGuidPath.find (L"\\\\?\\") == 0)
|
|
volumeGuidPath = volumeGuidPath.substr (4);
|
|
|
|
if (volumeGuidPath.find (L"Volume{") != 0 || volumeGuidPath.rfind (L"}\\") != volumeGuidPath.size() - 2)
|
|
return wstring();
|
|
|
|
wchar_t volDevPath[TC_MAX_PATH];
|
|
if (QueryDosDevice (volumeGuidPath.substr (0, volumeGuidPath.size() - 1).c_str(), volDevPath, TC_MAX_PATH) == 0)
|
|
return wstring();
|
|
|
|
wstring partitionPath = HarddiskVolumePathToPartitionPath (volDevPath);
|
|
|
|
return partitionPath.empty() ? volDevPath : partitionPath;
|
|
}
|
|
|
|
|
|
std::wstring HarddiskVolumePathToPartitionPath (const std::wstring &harddiskVolumePath)
|
|
{
|
|
for (int driveNumber = 0; driveNumber < MAX_HOST_DRIVE_NUMBER; driveNumber++)
|
|
{
|
|
for (int partNumber = 0; partNumber < MAX_HOST_PARTITION_NUMBER; partNumber++)
|
|
{
|
|
wchar_t partitionPath[TC_MAX_PATH];
|
|
StringCchPrintfW (partitionPath, ARRAYSIZE (partitionPath), L"\\Device\\Harddisk%d\\Partition%d", driveNumber, partNumber);
|
|
|
|
wchar_t resolvedPath[TC_MAX_PATH];
|
|
if (ResolveSymbolicLink (partitionPath, resolvedPath, sizeof(resolvedPath)))
|
|
{
|
|
if (harddiskVolumePath == resolvedPath)
|
|
return partitionPath;
|
|
}
|
|
else if (partNumber == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return wstring();
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOL IsApplicationInstalled (const wchar_t *appName, BOOL b32bitApp)
|
|
{
|
|
const wchar_t *uninstallRegName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
|
|
BOOL installed = FALSE;
|
|
HKEY unistallKey;
|
|
LONG res = RegOpenKeyEx (HKEY_LOCAL_MACHINE, uninstallRegName, 0, KEY_READ | (b32bitApp? KEY_WOW64_32KEY: KEY_WOW64_64KEY), &unistallKey);
|
|
if (res != ERROR_SUCCESS)
|
|
{
|
|
SetLastError (res);
|
|
return FALSE;
|
|
}
|
|
|
|
wchar_t regName[1024];
|
|
DWORD regNameSize = ARRAYSIZE (regName);
|
|
DWORD index = 0;
|
|
while (RegEnumKeyEx (unistallKey, index++, regName, ®NameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (wcsstr (regName, L"{") == regName)
|
|
{
|
|
regNameSize = sizeof (regName);
|
|
if (!ReadLocalMachineRegistryStringNonReflected ((wstring (uninstallRegName) + L"\\" + regName).c_str(), L"DisplayName", regName, ®NameSize, b32bitApp))
|
|
regName[0] = 0;
|
|
}
|
|
|
|
if (_wcsicmp (regName, appName) == 0)
|
|
{
|
|
installed = TRUE;
|
|
break;
|
|
}
|
|
|
|
regNameSize = sizeof (regName);
|
|
}
|
|
|
|
RegCloseKey (unistallKey);
|
|
return installed;
|
|
}
|
|
|
|
|
|
std::wstring FindLatestFileOrDirectory (const std::wstring &directory, const wchar_t *namePattern, bool findDirectory, bool findFile)
|
|
{
|
|
wstring name;
|
|
ULARGE_INTEGER latestTime;
|
|
latestTime.QuadPart = 0;
|
|
WIN32_FIND_DATA findData;
|
|
|
|
HANDLE find = FindFirstFile ((directory + L"\\" + namePattern).c_str(), &findData);
|
|
if (find != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
if (wcscmp (findData.cFileName, L".") == 0 || wcscmp (findData.cFileName, L"..") == 0)
|
|
continue;
|
|
|
|
ULARGE_INTEGER writeTime;
|
|
writeTime.LowPart = findData.ftLastWriteTime.dwLowDateTime;
|
|
writeTime.HighPart = findData.ftLastWriteTime.dwHighDateTime;
|
|
|
|
if ((!findFile && !(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
|| (!findDirectory && (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
|
|
continue;
|
|
|
|
if (latestTime.QuadPart < writeTime.QuadPart)
|
|
{
|
|
latestTime = writeTime;
|
|
name = findData.cFileName;
|
|
}
|
|
}
|
|
while (FindNextFile (find, &findData));
|
|
|
|
FindClose (find);
|
|
}
|
|
|
|
if (name.empty())
|
|
return name;
|
|
|
|
return wstring (directory) + L"\\" + name;
|
|
}
|
|
|
|
int GetPim (HWND hwndDlg, UINT ctrlId, int defaultPim)
|
|
{
|
|
int pim = defaultPim;
|
|
HWND hCtrl = GetDlgItem (hwndDlg, ctrlId);
|
|
if (IsWindowEnabled (hCtrl) && IsWindowVisible (hCtrl))
|
|
{
|
|
wchar_t szTmp[MAX_PIM + 1] = {0};
|
|
if (GetDlgItemText (hwndDlg, ctrlId, szTmp, MAX_PIM + 1) > 0)
|
|
{
|
|
wchar_t* endPtr = NULL;
|
|
pim = wcstol(szTmp, &endPtr, 10);
|
|
if (pim < 0 || endPtr == szTmp || !endPtr || *endPtr != L'\0')
|
|
pim = defaultPim;
|
|
}
|
|
}
|
|
return pim;
|
|
}
|
|
|
|
void SetPim (HWND hwndDlg, UINT ctrlId, int pim)
|
|
{
|
|
if (pim > 0)
|
|
{
|
|
wchar_t szTmp[MAX_PIM + 1];
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), L"%d", pim);
|
|
SetDlgItemText (hwndDlg, ctrlId, szTmp);
|
|
}
|
|
else
|
|
SetDlgItemText (hwndDlg, ctrlId, L"");
|
|
}
|
|
|
|
BOOL GetPassword (HWND hwndDlg, UINT ctrlID, char* passValue, int bufSize, BOOL bLegacyPassword, BOOL bShowError)
|
|
{
|
|
wchar_t tmp [MAX_PASSWORD + 1];
|
|
int utf8Len;
|
|
BOOL bRet = FALSE;
|
|
|
|
GetWindowText (GetDlgItem (hwndDlg, ctrlID), tmp, ARRAYSIZE (tmp));
|
|
if ((bLegacyPassword || bUseLegacyMaxPasswordLength) && (lstrlen (tmp) > MAX_LEGACY_PASSWORD))
|
|
wmemset (&tmp[MAX_LEGACY_PASSWORD], 0, MAX_PASSWORD + 1 - MAX_LEGACY_PASSWORD);
|
|
utf8Len = WideCharToMultiByte (CP_UTF8, 0, tmp, -1, passValue, bufSize, NULL, NULL);
|
|
burn (tmp, sizeof (tmp));
|
|
if (utf8Len > 0)
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
passValue [0] = 0;
|
|
if (bShowError)
|
|
{
|
|
if (GetLastError () == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
DWORD dwTextSize = (DWORD) wcslen (GetString ("PASSWORD_UTF8_TOO_LONG")) + 16;
|
|
WCHAR* szErrorText = (WCHAR*) malloc (dwTextSize * sizeof (WCHAR));
|
|
|
|
// bufSize is equal to maximum password length plus one
|
|
StringCchPrintf (szErrorText, dwTextSize, GetString ("PASSWORD_UTF8_TOO_LONG"), (bufSize - 1));
|
|
|
|
ErrorDirect (szErrorText, hwndDlg);
|
|
|
|
free (szErrorText);
|
|
}
|
|
else
|
|
Error ("PASSWORD_UTF8_INVALID", hwndDlg);
|
|
SetFocus (GetDlgItem(hwndDlg, ctrlID));
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void SetPassword (HWND hwndDlg, UINT ctrlID, char* passValue)
|
|
{
|
|
wchar_t tmp [MAX_PASSWORD + 1] = {0};
|
|
MultiByteToWideChar (CP_UTF8, 0, passValue, -1, tmp, MAX_PASSWORD + 1);
|
|
SetWindowText ( GetDlgItem (hwndDlg, ctrlID), tmp);
|
|
burn (tmp, sizeof (tmp));
|
|
}
|
|
|
|
void HandleShowPasswordFieldAction (HWND hwndDlg, UINT checkBoxId, UINT edit1Id, UINT edit2Id)
|
|
{
|
|
if ((EditPasswordChar == 0) && GetCheckBox (hwndDlg, checkBoxId))
|
|
{
|
|
EditPasswordChar = (WCHAR) SendMessageW (GetDlgItem (hwndDlg, edit1Id), EM_GETPASSWORDCHAR, 0, 0);
|
|
}
|
|
|
|
SendMessageW (GetDlgItem (hwndDlg, edit1Id),
|
|
EM_SETPASSWORDCHAR,
|
|
GetCheckBox (hwndDlg, checkBoxId) ? 0 : EditPasswordChar,
|
|
0);
|
|
InvalidateRect (GetDlgItem (hwndDlg, edit1Id), NULL, TRUE);
|
|
|
|
if (edit2Id)
|
|
{
|
|
SendMessageW (GetDlgItem (hwndDlg, edit2Id),
|
|
EM_SETPASSWORDCHAR,
|
|
GetCheckBox (hwndDlg, checkBoxId) ? 0 : EditPasswordChar,
|
|
0);
|
|
InvalidateRect (GetDlgItem (hwndDlg, edit2Id), NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
void RegisterDriverInf (bool registerFilter, const string& filter, const string& filterReg, HWND ParentWindow, HKEY regKey)
|
|
{
|
|
wstring infFileName = GetTempPathString() + L"\\veracrypt_driver_setup.inf";
|
|
|
|
File infFile (infFileName, false, true);
|
|
finally_do_arg (wstring, infFileName, { DeleteFile (finally_arg.c_str()); });
|
|
|
|
string infTxt = "[veracrypt]\r\n"
|
|
+ string (registerFilter ? "Add" : "Del") + "Reg=veracrypt_reg\r\n\r\n"
|
|
"[veracrypt_reg]\r\n"
|
|
"HKR,,\"" + filterReg + "\",0x0001" + string (registerFilter ? "0008" : "8002") + ",\"" + filter + "\"\r\n";
|
|
|
|
infFile.Write ((byte *) infTxt.c_str(), (DWORD) infTxt.size());
|
|
infFile.Close();
|
|
|
|
HINF hInf = SetupOpenInfFileWFn (infFileName.c_str(), NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
|
|
throw_sys_if (hInf == INVALID_HANDLE_VALUE);
|
|
finally_do_arg (HINF, hInf, { SetupCloseInfFileFn (finally_arg); });
|
|
|
|
throw_sys_if (!SetupInstallFromInfSectionWFn (ParentWindow, hInf, L"veracrypt", SPINST_REGISTRY, regKey, NULL, 0, NULL, NULL, NULL, NULL));
|
|
}
|
|
|
|
HKEY OpenDeviceClassRegKey (const GUID *deviceClassGuid)
|
|
{
|
|
return SetupDiOpenClassRegKeyFn (deviceClassGuid, KEY_READ | KEY_WRITE);
|
|
}
|
|
|
|
LSTATUS DeleteRegistryKey (HKEY hKey, LPCTSTR keyName)
|
|
{
|
|
return SHDeleteKeyWFn(hKey, keyName);
|
|
}
|
|
|
|
HIMAGELIST CreateImageList(int cx, int cy, UINT flags, int cInitial, int cGrow)
|
|
{
|
|
return ImageList_CreateFn(cx, cy, flags, cInitial, cGrow);
|
|
}
|
|
|
|
int AddBitmapToImageList(HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
|
|
{
|
|
return ImageList_AddFn(himl, hbmImage, hbmMask);
|
|
}
|
|
|
|
HRESULT VCStrDupW(LPCWSTR psz, LPWSTR *ppwsz)
|
|
{
|
|
return SHStrDupWFn (psz, ppwsz);
|
|
}
|
|
|
|
|
|
void ProcessEntropyEstimate (HWND hProgress, DWORD* pdwInitialValue, DWORD dwCounter, DWORD dwMaxLevel, DWORD* pdwEntropy)
|
|
{
|
|
/* conservative estimate: 1 mouse move event brings 1 bit of entropy
|
|
* https://security.stackexchange.com/questions/32844/for-how-much-time-should-i-randomly-move-the-mouse-for-generating-encryption-key/32848#32848
|
|
*/
|
|
if (*pdwEntropy == 0xFFFFFFFF)
|
|
{
|
|
*pdwInitialValue = dwCounter;
|
|
*pdwEntropy = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( *pdwEntropy < dwMaxLevel
|
|
&& (dwCounter >= *pdwInitialValue)
|
|
&& (dwCounter - *pdwInitialValue) <= dwMaxLevel)
|
|
*pdwEntropy = dwCounter - *pdwInitialValue;
|
|
else
|
|
*pdwEntropy = dwMaxLevel;
|
|
|
|
if (IsOSAtLeast (WIN_VISTA))
|
|
{
|
|
int state = PBST_ERROR;
|
|
if (*pdwEntropy >= (dwMaxLevel/2))
|
|
state = PBST_NORMAL;
|
|
else if (*pdwEntropy >= (dwMaxLevel/4))
|
|
state = PBST_PAUSED;
|
|
|
|
SendMessage (hProgress, PBM_SETSTATE, state, 0);
|
|
}
|
|
|
|
SendMessage (hProgress, PBM_SETPOS,
|
|
(WPARAM) (*pdwEntropy),
|
|
0);
|
|
}
|
|
}
|
|
|
|
void AllowMessageInUIPI (UINT msg)
|
|
{
|
|
if (ChangeWindowMessageFilterFn)
|
|
{
|
|
ChangeWindowMessageFilterFn (msg, MSGFLT_ADD);
|
|
}
|
|
}
|
|
|
|
BOOL IsRepeatedByteArray (byte value, const byte* buffer, size_t bufferSize)
|
|
{
|
|
if (buffer && bufferSize)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < bufferSize; i++)
|
|
{
|
|
if (*buffer++ != value)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef SETUP
|
|
|
|
BOOL TranslateVolumeID (HWND hwndDlg, wchar_t* pathValue, size_t cchPathValue)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
size_t pathLen = pathValue? wcslen (pathValue) : 0;
|
|
if ((pathLen >= 3) && (_wcsnicmp (pathValue, L"ID:", 3) == 0))
|
|
{
|
|
std::vector<byte> arr;
|
|
if ( (pathLen == (3 + 2*VOLUME_ID_SIZE))
|
|
&& HexWideStringToArray (pathValue + 3, arr)
|
|
&& (arr.size() == VOLUME_ID_SIZE)
|
|
)
|
|
{
|
|
std::wstring devicePath = FindDeviceByVolumeID (&arr[0], FALSE);
|
|
if (devicePath.length() > 0)
|
|
StringCchCopyW (pathValue, cchPathValue, devicePath.c_str());
|
|
else
|
|
{
|
|
if (!Silent && !MultipleMountOperationInProgress)
|
|
Error ("VOLUME_ID_NOT_FOUND", hwndDlg);
|
|
SetLastError (ERROR_PATH_NOT_FOUND);
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!Silent)
|
|
Error ("VOLUME_ID_INVALID", hwndDlg);
|
|
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOL CopyTextToClipboard (LPCWSTR txtValue)
|
|
{
|
|
size_t txtLen = wcslen(txtValue);
|
|
HGLOBAL hdst;
|
|
LPWSTR dst;
|
|
BOOL bRet = FALSE;
|
|
|
|
// Allocate string for cwd
|
|
hdst = GlobalAlloc(GMEM_MOVEABLE, (txtLen + 1) * sizeof(WCHAR));
|
|
if (hdst)
|
|
{
|
|
dst = (LPWSTR)GlobalLock(hdst);
|
|
wmemcpy(dst, txtValue, txtLen + 1);
|
|
GlobalUnlock(hdst);
|
|
|
|
if (OpenClipboard(NULL))
|
|
{
|
|
EmptyClipboard();
|
|
SetClipboardData(CF_UNICODETEXT, hdst);
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL GetFreeDriveLetter(WCHAR* pCh) {
|
|
DWORD dwUsedDrives = GetLogicalDrives();
|
|
WCHAR l;
|
|
for (l = L'A'; l <= L'Z'; l++) {
|
|
if ((dwUsedDrives & 1) == 0) {
|
|
*pCh = l;
|
|
return TRUE;
|
|
}
|
|
dwUsedDrives = dwUsedDrives >> 1;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL SetPrivilege(LPTSTR szPrivilegeName, BOOL bEnable)
|
|
{
|
|
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))
|
|
{
|
|
tkp.PrivilegeCount = 1;
|
|
tkp.Privileges[0].Attributes = bEnable? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED;
|
|
|
|
bRet = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL);
|
|
dwLastError = GetLastError ();
|
|
if ( ERROR_SUCCESS != dwLastError)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
dwLastError = GetLastError ();
|
|
|
|
CloseHandle(hToken);
|
|
}
|
|
else
|
|
dwLastError = GetLastError ();
|
|
|
|
SetLastError (dwLastError);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL DeleteDirectory (const wchar_t* szDirName)
|
|
{
|
|
BOOL bStatus = RemoveDirectory (szDirName);
|
|
if (!bStatus)
|
|
{
|
|
/* force removal of the non empty directory */
|
|
wchar_t szOpPath[TC_MAX_PATH + 1] = {0};
|
|
SHFILEOPSTRUCTW op;
|
|
|
|
StringCchCopyW(szOpPath, ARRAYSIZE(szOpPath)-1, szDirName);
|
|
ZeroMemory(&op, sizeof(op));
|
|
op.wFunc = FO_DELETE;
|
|
op.pFrom = szOpPath;
|
|
op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR;
|
|
|
|
if ((0 == SHFileOperation(&op)) && (!op.fAnyOperationsAborted))
|
|
bStatus = TRUE;
|
|
}
|
|
return bStatus;
|
|
}
|
|
|
|
#if defined (TCMOUNT) || defined (VOLFORMAT)
|
|
/*********************************************************************/
|
|
|
|
static BOOL GenerateRandomString (HWND hwndDlg, LPTSTR szName, DWORD maxCharsCount)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
int alreadyInitialized = 0;
|
|
if (RandinitWithCheck (&alreadyInitialized) != 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);
|
|
|
|
/* If RNG was not initialized before us, then stop it in order to
|
|
* stop the fast poll thread which consumes CPU. Next time a critical operation
|
|
* that requires RNG is performed, it will be initialized again.
|
|
*
|
|
* We do this because since the addition of secure desktop support, every time
|
|
* secure desktop is displayed, the RNG fast poll thread was started even if the
|
|
* user will never perform any critical operation that requires random bytes.
|
|
*/
|
|
if (!alreadyInitialized)
|
|
{
|
|
RandStop (FALSE);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
HDESK hDesk;
|
|
LPCWSTR szDesktopName;
|
|
HINSTANCE hInstance;
|
|
LPCWSTR lpTemplateName;
|
|
DLGPROC lpDialogFunc;
|
|
LPARAM dwInitParam;
|
|
INT_PTR retValue;
|
|
} SecureDesktopThreadParam;
|
|
|
|
typedef struct
|
|
{
|
|
LPCWSTR szVCDesktopName;
|
|
HDESK hVcDesktop;
|
|
volatile BOOL* pbStopMonitoring;
|
|
} SecureDesktopMonitoringThreadParam;
|
|
|
|
#define SECUREDESKTOP_MONOTIR_PERIOD 500
|
|
|
|
// This thread checks if VeraCrypt secure desktop is the one that has user input
|
|
// and if it is not then it will call SwitchDesktop to make it the input desktop
|
|
static unsigned int __stdcall SecureDesktopMonitoringThread( LPVOID lpThreadParameter )
|
|
{
|
|
SecureDesktopMonitoringThreadParam* pMonitorParam = (SecureDesktopMonitoringThreadParam*) lpThreadParameter;
|
|
if (pMonitorParam)
|
|
{
|
|
volatile BOOL* pbStopMonitoring = pMonitorParam->pbStopMonitoring;
|
|
LPCWSTR szVCDesktopName = pMonitorParam->szVCDesktopName;
|
|
HDESK hVcDesktop = pMonitorParam->hVcDesktop;
|
|
|
|
while (!*pbStopMonitoring)
|
|
{
|
|
// check that our secure desktop is still the input desktop
|
|
// otherwise, switch to it
|
|
BOOL bPerformSwitch = FALSE;
|
|
HDESK currentDesk = OpenInputDesktop (0, FALSE, GENERIC_READ);
|
|
if (currentDesk)
|
|
{
|
|
LPWSTR szName = NULL;
|
|
DWORD dwLen = 0;
|
|
if (!GetUserObjectInformation (currentDesk, UOI_NAME, NULL, 0, &dwLen))
|
|
{
|
|
szName = (LPWSTR) malloc (dwLen);
|
|
if (szName)
|
|
{
|
|
if (GetUserObjectInformation (currentDesk, UOI_NAME, szName, dwLen, &dwLen))
|
|
{
|
|
if (0 != _wcsicmp (szName, szVCDesktopName))
|
|
bPerformSwitch = TRUE;
|
|
}
|
|
free (szName);
|
|
}
|
|
}
|
|
CloseDesktop (currentDesk);
|
|
}
|
|
|
|
if (bPerformSwitch)
|
|
SwitchDesktop (hVcDesktop);
|
|
|
|
Sleep (SECUREDESKTOP_MONOTIR_PERIOD);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static DWORD WINAPI SecureDesktopThread(LPVOID lpThreadParameter)
|
|
{
|
|
volatile BOOL bStopMonitoring = FALSE;
|
|
HANDLE hMonitoringThread = NULL;
|
|
unsigned int monitoringThreadID = 0;
|
|
SecureDesktopThreadParam* pParam = (SecureDesktopThreadParam*) lpThreadParameter;
|
|
SecureDesktopMonitoringThreadParam monitorParam;
|
|
HDESK hOriginalDesk = GetThreadDesktop (GetCurrentThreadId ());
|
|
BOOL bNewDesktopSet = FALSE;
|
|
|
|
// wait for SwitchDesktop to succeed before using it for current thread
|
|
while (true)
|
|
{
|
|
if (SwitchDesktop (pParam->hDesk))
|
|
{
|
|
bNewDesktopSet = TRUE;
|
|
break;
|
|
}
|
|
Sleep (SECUREDESKTOP_MONOTIR_PERIOD);
|
|
}
|
|
|
|
if (bNewDesktopSet)
|
|
{
|
|
SetThreadDesktop (pParam->hDesk);
|
|
|
|
// create the thread that will ensure that VeraCrypt secure desktop has always user input
|
|
monitorParam.szVCDesktopName = pParam->szDesktopName;
|
|
monitorParam.hVcDesktop = pParam->hDesk;
|
|
monitorParam.pbStopMonitoring = &bStopMonitoring;
|
|
hMonitoringThread = (HANDLE) _beginthreadex (NULL, 0, SecureDesktopMonitoringThread, (LPVOID) &monitorParam, 0, &monitoringThreadID);
|
|
}
|
|
|
|
pParam->retValue = DialogBoxParamW (pParam->hInstance, pParam->lpTemplateName,
|
|
NULL, pParam->lpDialogFunc, pParam->dwInitParam);
|
|
|
|
if (hMonitoringThread)
|
|
{
|
|
bStopMonitoring = TRUE;
|
|
|
|
WaitForSingleObject (hMonitoringThread, INFINITE);
|
|
CloseHandle (hMonitoringThread);
|
|
}
|
|
|
|
if (bNewDesktopSet)
|
|
{
|
|
SetThreadDesktop (hOriginalDesk);
|
|
SwitchDesktop (hOriginalDesk);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void GetCtfMonProcessIdList (map<DWORD, BOOL>& 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 && !IsThreadInSecureDesktop(GetCurrentThreadId()))
|
|
{
|
|
EnterCriticalSection (&csSecureDesktop);
|
|
bSecureDesktopOngoing = TRUE;
|
|
finally_do ({ bSecureDesktopOngoing = FALSE; LeaveCriticalSection (&csSecureDesktop); });
|
|
|
|
if (GenerateRandomString (hWndParent, szDesktopName, 64))
|
|
{
|
|
map<DWORD, BOOL> ctfmonBeforeList, ctfmonAfterList;
|
|
DWORD desktopAccess = DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS;
|
|
HDESK hSecureDesk;
|
|
|
|
HDESK hInputDesk = NULL;
|
|
|
|
// wait for the input desktop to be available before switching to
|
|
// secure desktop. Under Windows 10, the user session can be started
|
|
// in the background even before the user has authenticated and in this
|
|
// case, we wait for the user to be really authenticated before starting
|
|
// secure desktop mechanism
|
|
|
|
while (!(hInputDesk = OpenInputDesktop (0, TRUE, GENERIC_READ)))
|
|
{
|
|
Sleep (SECUREDESKTOP_MONOTIR_PERIOD);
|
|
}
|
|
|
|
CloseDesktop (hInputDesk);
|
|
|
|
// get the initial list of ctfmon.exe processes before creating new desktop
|
|
GetCtfMonProcessIdList (ctfmonBeforeList);
|
|
|
|
hSecureDesk = CreateDesktop (szDesktopName, NULL, NULL, 0, desktopAccess, NULL);
|
|
if (hSecureDesk)
|
|
{
|
|
SecureDesktopThreadParam param;
|
|
|
|
param.hDesk = hSecureDesk;
|
|
param.szDesktopName = szDesktopName;
|
|
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)
|
|
{
|
|
StringCbCopy(SecureDesktopName, sizeof (SecureDesktopName), szDesktopName);
|
|
|
|
WaitForSingleObject (hThread, INFINITE);
|
|
CloseHandle (hThread);
|
|
|
|
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<DWORD, BOOL>::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
|
|
|
|
void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, BOOL* pbInstallPathDetermined)
|
|
{
|
|
HKEY hkey;
|
|
BOOL bInstallPathDetermined = FALSE;
|
|
wchar_t path[MAX_PATH+20];
|
|
ITEMIDLIST *itemList;
|
|
|
|
memset (szInstallPath, 0, cchSize * sizeof (wchar_t));
|
|
|
|
// Determine if VeraCrypt is already installed and try to determine its "Program Files" location
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", 0, KEY_READ | KEY_WOW64_32KEY, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
/* Default 'UninstallString' registry strings written by VeraCrypt:
|
|
------------------------------------------------------------------------------------
|
|
5.0+ "C:\Program Files\VeraCrypt\VeraCrypt Setup.exe" /u
|
|
*/
|
|
|
|
wchar_t rv[MAX_PATH*4];
|
|
DWORD size = sizeof (rv);
|
|
if (RegQueryValueEx (hkey, L"UninstallString", 0, 0, (LPBYTE) &rv, &size) == ERROR_SUCCESS && wcsrchr (rv, L'/'))
|
|
{
|
|
size_t len = 0;
|
|
|
|
// Cut and paste the location (path) where VeraCrypt is installed to InstallationPath
|
|
if (rv[0] == L'"')
|
|
{
|
|
len = wcsrchr (rv, L'/') - rv - 2;
|
|
StringCchCopyNW (szInstallPath, cchSize, rv + 1, len);
|
|
szInstallPath [len] = 0;
|
|
bInstallPathDetermined = TRUE;
|
|
|
|
if (szInstallPath [wcslen (szInstallPath) - 1] != L'\\')
|
|
{
|
|
len = wcsrchr (szInstallPath, L'\\') - szInstallPath;
|
|
szInstallPath [len] = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
RegCloseKey (hkey);
|
|
}
|
|
|
|
if (!bInstallPathDetermined)
|
|
{
|
|
/* VeraCrypt is not installed or it wasn't possible to determine where it is installed. */
|
|
|
|
// Default "Program Files" path.
|
|
SHGetSpecialFolderLocation (hwndDlg, CSIDL_PROGRAM_FILES, &itemList);
|
|
SHGetPathFromIDList (itemList, path);
|
|
|
|
if (Is64BitOs())
|
|
{
|
|
// Use a unified default installation path (registry redirection of %ProgramFiles% does not work if the installation path is user-selectable)
|
|
wstring s = path;
|
|
size_t p = s.find (L" (x86)");
|
|
if (p != wstring::npos)
|
|
{
|
|
s = s.substr (0, p);
|
|
if (_waccess (s.c_str(), 0) != -1)
|
|
StringCbCopyW (path, sizeof (path), s.c_str());
|
|
}
|
|
}
|
|
|
|
StringCbCatW (path, sizeof(path), L"\\VeraCrypt\\");
|
|
StringCbCopyW (szInstallPath, cchSize, path);
|
|
}
|
|
|
|
// Make sure the path ends with a backslash
|
|
if (szInstallPath [wcslen (szInstallPath) - 1] != L'\\')
|
|
{
|
|
StringCbCatW (szInstallPath, cchSize, L"\\");
|
|
}
|
|
|
|
if (pbInstallPathDetermined)
|
|
*pbInstallPathDetermined = bInstallPathDetermined;
|
|
}
|
|
|
|
BOOL GetSetupconfigLocation (wchar_t* path, DWORD cchSize)
|
|
{
|
|
wchar_t szShell32Path[MAX_PATH] = {0};
|
|
HMODULE hShell32 = NULL;
|
|
BOOL bResult = FALSE;
|
|
|
|
path[0] = 0;
|
|
|
|
if (GetSystemDirectory(szShell32Path, MAX_PATH))
|
|
StringCchCatW (szShell32Path, MAX_PATH, L"\\Shell32.dll");
|
|
else
|
|
StringCchCopyW (szShell32Path, MAX_PATH, L"C:\\Windows\\System32\\Shell32.dll");
|
|
|
|
hShell32 = LoadLibrary (szShell32Path);
|
|
if (hShell32)
|
|
{
|
|
SHGETKNOWNFOLDERPATH SHGetKnownFolderPathFn = (SHGETKNOWNFOLDERPATH) GetProcAddress (hShell32, "SHGetKnownFolderPath");
|
|
if (SHGetKnownFolderPathFn)
|
|
{
|
|
wchar_t* pszUsersPath = NULL;
|
|
if (S_OK == SHGetKnownFolderPathFn (FOLDERID_UserProfiles, 0, NULL, &pszUsersPath))
|
|
{
|
|
StringCchPrintfW (path, cchSize, L"%s\\Default\\AppData\\Local\\Microsoft\\Windows\\WSUS\\", pszUsersPath);
|
|
CoTaskMemFree (pszUsersPath);
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
FreeLibrary (hShell32);
|
|
}
|
|
|
|
if (!bResult && CurrentOSMajor >= 10)
|
|
{
|
|
StringCchPrintfW (path, cchSize, L"%c:\\Users\\Default\\AppData\\Local\\Microsoft\\Windows\\WSUS\\", szShell32Path[0]);
|
|
bResult = TRUE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL BufferHasPattern (const unsigned char* buffer, size_t bufferLen, const void* pattern, size_t patternLen)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
if (patternLen <= bufferLen)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i <= (bufferLen - patternLen); ++i)
|
|
{
|
|
if (memcmp (&buffer[i], pattern, patternLen) == 0)
|
|
{
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/* Implementation borrowed from KeePassXC source code (https://github.com/keepassxreboot/keepassxc/blob/release/2.4.0/src/core/Bootstrap.cpp#L150)
|
|
*
|
|
* Reduce current user acess rights for this process to the minimum in order to forbid non-admin users from reading the process memory.
|
|
*/
|
|
BOOL EnableProcessProtection()
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
|
|
// Process token and user
|
|
HANDLE hToken = NULL;
|
|
PTOKEN_USER pTokenUser = NULL;
|
|
DWORD cbBufferSize = 0;
|
|
|
|
// Access control list
|
|
PACL pACL = NULL;
|
|
DWORD cbACL = 0;
|
|
|
|
// Acces mask
|
|
DWORD dwAccessMask = SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE; // same as protected process
|
|
|
|
if (IsAdmin ())
|
|
{
|
|
// if we are running elevated, we allow CreateProcessXXX calls alongside PROCESS_DUP_HANDLE and PROCESS_QUERY_INFORMATION in order to be able
|
|
// to implement secure way to open URLs (cf RunAsDesktopUser)
|
|
// we are still protecting against memory access from non-admon processes
|
|
dwAccessMask |= PROCESS_CREATE_PROCESS | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
|
|
}
|
|
|
|
// Open the access token associated with the calling process
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Retrieve the token information in a TOKEN_USER structure
|
|
GetTokenInformation(hToken, TokenUser, NULL, 0, &cbBufferSize);
|
|
|
|
pTokenUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap(), 0, cbBufferSize);
|
|
if (pTokenUser == NULL) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, cbBufferSize, &cbBufferSize)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!IsValidSid(pTokenUser->User.Sid)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Calculate the amount of memory that must be allocated for the DACL
|
|
cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pTokenUser->User.Sid);
|
|
|
|
// Create and initialize an ACL
|
|
pACL = (PACL) HeapAlloc(GetProcessHeap(), 0, cbACL);
|
|
if (pACL == NULL) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Add allowed access control entries, everything else is denied
|
|
if (!AddAccessAllowedAce(
|
|
pACL,
|
|
ACL_REVISION,
|
|
dwAccessMask,
|
|
pTokenUser->User.Sid // pointer to the trustee's SID
|
|
)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Set discretionary access control list
|
|
bSuccess = (ERROR_SUCCESS == SetSecurityInfo(GetCurrentProcess(), // object handle
|
|
SE_KERNEL_OBJECT, // type of object
|
|
DACL_SECURITY_INFORMATION, // change only the objects DACL
|
|
NULL,
|
|
NULL, // do not change owner or group
|
|
pACL, // DACL specified
|
|
NULL // do not change SACL
|
|
))? TRUE: FALSE;
|
|
|
|
Cleanup:
|
|
|
|
if (pACL != NULL) {
|
|
HeapFree(GetProcessHeap(), 0, pACL);
|
|
}
|
|
if (pTokenUser != NULL) {
|
|
HeapFree(GetProcessHeap(), 0, pTokenUser);
|
|
}
|
|
if (hToken != NULL) {
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
// Based on sample code from:
|
|
// https://blogs.msdn.microsoft.com/aaron_margosis/2009/06/06/faq-how-do-i-start-a-program-as-the-desktop-user-from-an-elevated-app/
|
|
// start a program non-elevated as the desktop user from an elevated app
|
|
|
|
static bool RunAsDesktopUser(
|
|
__in const wchar_t * szApp,
|
|
__in wchar_t * szCmdLine)
|
|
{
|
|
HANDLE hThreadToken = NULL, hShellProcess = NULL, hShellProcessToken = NULL, hPrimaryToken = NULL;
|
|
HWND hwnd = NULL;
|
|
DWORD dwPID = 0;
|
|
BOOL ret;
|
|
DWORD dwLastErr;
|
|
STARTUPINFOW si;
|
|
PROCESS_INFORMATION pi;
|
|
bool retval = false;
|
|
SecureZeroMemory(&si, sizeof(si));
|
|
SecureZeroMemory(&pi, sizeof(pi));
|
|
si.cb = sizeof(si);
|
|
|
|
// locate CreateProcessWithTokenW in Advapi32.dll
|
|
if (!CreateProcessWithTokenWPtr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ImpersonateSelf (SecurityImpersonation))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!OpenThreadToken (GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &hThreadToken))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
TOKEN_PRIVILEGES tkp;
|
|
tkp.PrivilegeCount = 1;
|
|
LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid);
|
|
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
if (!SetThreadToken(NULL, NULL))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
AdjustTokenPrivileges(hThreadToken, FALSE, &tkp, 0, NULL, NULL);
|
|
dwLastErr = GetLastError();
|
|
if (ERROR_SUCCESS != dwLastErr)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// From this point down, we have handles to close, so make sure to clean up.
|
|
|
|
// Get an HWND representing the desktop shell.
|
|
// CAVEATS: This will fail if the shell is not running (crashed or terminated), or the default shell has been
|
|
// replaced with a custom shell. This also won't return what you probably want if Explorer has been terminated and
|
|
// restarted elevated.
|
|
hwnd = GetShellWindow();
|
|
if (NULL == hwnd)
|
|
{
|
|
dwLastErr = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get the PID of the desktop shell process.
|
|
GetWindowThreadProcessId(hwnd, &dwPID);
|
|
if (0 == dwPID)
|
|
{
|
|
dwLastErr = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
// Open the desktop shell process in order to query it (get the token)
|
|
hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
|
|
if (!hShellProcess)
|
|
{
|
|
dwLastErr = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get the process token of the desktop shell.
|
|
ret = OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken);
|
|
if (!ret)
|
|
{
|
|
dwLastErr = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
// Duplicate the shell's process token to get a primary token.
|
|
// Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation).
|
|
const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID;
|
|
ret = DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken);
|
|
if (!ret)
|
|
{
|
|
dwLastErr = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
// Start the target process with the new token.
|
|
ret = CreateProcessWithTokenWPtr(
|
|
hPrimaryToken,
|
|
0,
|
|
szApp,
|
|
szCmdLine,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi);
|
|
if (!ret)
|
|
{
|
|
dwLastErr = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
// Make sure to close HANDLEs return in the PROCESS_INFORMATION.
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
|
|
retval = true;
|
|
|
|
cleanup:
|
|
// Clean up resources
|
|
if (hShellProcessToken) CloseHandle(hShellProcessToken);
|
|
if (hPrimaryToken) CloseHandle(hPrimaryToken);
|
|
if (hShellProcess) CloseHandle(hShellProcess);
|
|
if (hThreadToken) CloseHandle(hThreadToken);
|
|
|
|
if (!RevertToSelf())
|
|
return false;
|
|
|
|
if (!retval)
|
|
SetLastError (dwLastErr);
|
|
return retval;
|
|
}
|
|
|
|
// This function checks if the process is running with elevated privileges or not
|
|
BOOL IsElevated()
|
|
{
|
|
DWORD dwSize = 0;
|
|
HANDLE hToken = NULL;
|
|
TOKEN_ELEVATION tokenInformation;
|
|
BOOL bReturn = FALSE;
|
|
|
|
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
|
{
|
|
if(GetTokenInformation(hToken, TokenElevation, &tokenInformation, sizeof(TOKEN_ELEVATION), &dwSize))
|
|
{
|
|
if (tokenInformation.TokenIsElevated)
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
// Based on code from:
|
|
// https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appplatform/ExecInExplorer/ExecInExplorer.cpp
|
|
HRESULT GetShellViewForDesktop(REFIID riid, void **ppv)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
IShellWindows *psw;
|
|
HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HWND hwnd;
|
|
IDispatch* pdisp;
|
|
VARIANT vEmpty = {}; // VT_EMPTY
|
|
if (S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &pdisp))
|
|
{
|
|
IShellBrowser *psb;
|
|
hr = IUnknown_QueryServicePtr(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IShellView *psv;
|
|
hr = psb->QueryActiveShellView(&psv);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = psv->QueryInterface(riid, ppv);
|
|
psv->Release();
|
|
}
|
|
psb->Release();
|
|
}
|
|
pdisp->Release();
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
psw->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetShellDispatchFromView(IShellView *psv, REFIID riid, void **ppv)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
IDispatch *pdispBackground;
|
|
HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IShellFolderViewDual *psfvd;
|
|
hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IDispatch *pdisp;
|
|
hr = psfvd->get_Application(&pdisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pdisp->QueryInterface(riid, ppv);
|
|
pdisp->Release();
|
|
}
|
|
psfvd->Release();
|
|
}
|
|
pdispBackground->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ShellExecInExplorerProcess(PCWSTR pszFile)
|
|
{
|
|
IShellView *psv;
|
|
CoInitialize(NULL);
|
|
HRESULT hr = GetShellViewForDesktop(IID_PPV_ARGS(&psv));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IShellDispatch2 *psd;
|
|
hr = GetShellDispatchFromView(psv, IID_PPV_ARGS(&psd));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrFile = SysAllocString(pszFile);
|
|
hr = bstrFile ? S_OK : E_OUTOFMEMORY;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT vtEmpty = {}; // VT_EMPTY
|
|
hr = psd->ShellExecuteW(bstrFile, vtEmpty, vtEmpty, vtEmpty, vtEmpty);
|
|
SysFreeString(bstrFile);
|
|
}
|
|
psd->Release();
|
|
}
|
|
psv->Release();
|
|
}
|
|
CoUninitialize();
|
|
return hr;
|
|
}
|
|
|
|
// This function always loads a URL in a non-privileged mode
|
|
// If current process has admin privileges, we execute the command "rundll32 url.dll,FileProtocolHandler URL" as non-elevated
|
|
// Use this security mechanism only starting from Windows Vista and only if we can get the window of the Shell's desktop since
|
|
// we rely on the Shell to be already running in a non-privileges mode. If the Shell is not running or if it has been modified,
|
|
// then we can't protect the user in such non standard environment
|
|
void SafeOpenURL (LPCWSTR szUrl)
|
|
{
|
|
BOOL bFallback = TRUE;
|
|
if (IsOSAtLeast (WIN_VISTA) && IsUacSupported() && IsAdmin () && IsElevated() && GetShellWindow())
|
|
{
|
|
WCHAR szRunDllPath[TC_MAX_PATH];
|
|
WCHAR szUrlDllPath[TC_MAX_PATH];
|
|
WCHAR szSystemPath[TC_MAX_PATH];
|
|
LPWSTR szCommandLine = new WCHAR[1024];
|
|
|
|
if (!GetSystemDirectory(szSystemPath, MAX_PATH))
|
|
StringCbCopyW(szSystemPath, sizeof(szSystemPath), L"C:\\Windows\\System32");
|
|
|
|
StringCbPrintfW(szRunDllPath, sizeof(szRunDllPath), L"%s\\%s", szSystemPath, L"rundll32.exe");
|
|
StringCbPrintfW(szUrlDllPath, sizeof(szUrlDllPath), L"%s\\%s", szSystemPath, L"url.dll");
|
|
StringCchPrintfW(szCommandLine, 1024, L"%s %s,FileProtocolHandler %s", szRunDllPath, szUrlDllPath, szUrl);
|
|
|
|
if (RunAsDesktopUser (NULL, szCommandLine))
|
|
{
|
|
bFallback = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// fallback to IShellDispatch2::ShellExecuteW
|
|
if (SUCCEEDED(ShellExecInExplorerProcess(szUrl)))
|
|
{
|
|
bFallback = FALSE;
|
|
}
|
|
}
|
|
|
|
delete [] szCommandLine;
|
|
}
|
|
|
|
if (bFallback)
|
|
{
|
|
ShellExecuteW (NULL, L"open", szUrl, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
|
|
#if !defined(SETUP) && defined(_WIN64)
|
|
|
|
#define RtlGenRandom SystemFunction036
|
|
extern "C" BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
|
|
|
|
void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed)
|
|
{
|
|
LARGE_INTEGER iSeed;
|
|
SYSTEMTIME sysTime;
|
|
byte digest[WHIRLPOOL_DIGESTSIZE];
|
|
WHIRLPOOL_CTX tctx;
|
|
size_t count;
|
|
|
|
while (cbRandSeed)
|
|
{
|
|
WHIRLPOOL_init (&tctx);
|
|
// we hash current content of digest buffer which is uninitialized the first time
|
|
WHIRLPOOL_add (digest, WHIRLPOOL_DIGESTSIZE, &tctx);
|
|
|
|
// we use various time information as source of entropy
|
|
GetSystemTime (&sysTime);
|
|
WHIRLPOOL_add ((unsigned char *) &sysTime, sizeof(sysTime), &tctx);
|
|
if (QueryPerformanceCounter (&iSeed))
|
|
WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
|
|
if (QueryPerformanceFrequency (&iSeed))
|
|
WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
|
|
|
|
/* use Windows random generator as entropy source */
|
|
if (RtlGenRandom (digest, sizeof (digest)))
|
|
WHIRLPOOL_add (digest, sizeof(digest), &tctx);
|
|
|
|
/* use JitterEntropy library to get good quality random bytes based on CPU timing jitter */
|
|
if (0 == jent_entropy_init ())
|
|
{
|
|
struct rand_data *ec = jent_entropy_collector_alloc (1, 0);
|
|
if (ec)
|
|
{
|
|
ssize_t rndLen = jent_read_entropy (ec, (char*) digest, sizeof (digest));
|
|
if (rndLen > 0)
|
|
WHIRLPOOL_add (digest, (unsigned int) rndLen, &tctx);
|
|
jent_entropy_collector_free (ec);
|
|
}
|
|
}
|
|
|
|
// use RDSEED or RDRAND from CPU as source of entropy if enabled
|
|
if ( IsCpuRngEnabled() &&
|
|
( (HasRDSEED() && RDSEED_getBytes (digest, sizeof (digest)))
|
|
|| (HasRDRAND() && RDRAND_getBytes (digest, sizeof (digest)))
|
|
))
|
|
{
|
|
WHIRLPOOL_add (digest, sizeof(digest), &tctx);
|
|
}
|
|
WHIRLPOOL_finalize (&tctx, digest);
|
|
|
|
count = VC_MIN (cbRandSeed, sizeof (digest));
|
|
|
|
// copy digest value to seed buffer
|
|
memcpy (pbRandSeed, digest, count);
|
|
cbRandSeed -= count;
|
|
pbRandSeed += count;
|
|
}
|
|
|
|
FAST_ERASE64 (digest, sizeof (digest));
|
|
FAST_ERASE64 (&iSeed.QuadPart, 8);
|
|
burn (&sysTime, sizeof(sysTime));
|
|
burn (&tctx, sizeof(tctx));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* GetBitLockerEncryptionStatus: retuns the BitLocker encryption status of a given drive.
|
|
*/
|
|
|
|
typedef enum BitLockerProtectionState
|
|
{
|
|
BL_State_FullyDecrypted = 0,
|
|
BL_State_FullyEncrypted = 1,
|
|
BL_State_EncryptionInProgress = 2,
|
|
BL_State_DecryptionInProgress = 3,
|
|
BL_State_EncryptionSuspended = 4,
|
|
BL_State_DecryptionSuspended = 5,
|
|
BL_State_FullyEncryptedWipeInProgress = 6,
|
|
BL_State_FullyEncryptedWipeSuspended = 7
|
|
} BitLockerProtectionState;
|
|
|
|
typedef HRESULT (WINAPI *SHCreateItemFromParsingNameFn)(
|
|
PCWSTR pszPath,
|
|
IBindCtx* pbc,
|
|
REFIID riid,
|
|
void** ppv
|
|
);
|
|
|
|
typedef HRESULT (WINAPI *PSGetPropertyKeyFromNameFn)(
|
|
_In_ PCWSTR pszName,
|
|
_Out_ PROPERTYKEY* ppropkey);
|
|
|
|
|
|
/*
|
|
Code derived from https://stackoverflow.com/questions/23841973/how-to-tell-if-drive-is-bitlocker-encrypted-without-admin-privilege/47192128#47192128
|
|
*/
|
|
BitLockerEncryptionStatus GetBitLockerEncryptionStatus(WCHAR driveLetter)
|
|
{
|
|
HRESULT hr;
|
|
BitLockerEncryptionStatus blStatus = BL_Status_Unknown;
|
|
wchar_t szDllPath[MAX_PATH] = { 0 };
|
|
HMODULE hShell32 = NULL;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
if (GetSystemDirectory(szDllPath, MAX_PATH))
|
|
StringCchCatW(szDllPath, MAX_PATH, L"\\Shell32.dll");
|
|
else
|
|
StringCchCopyW(szDllPath, MAX_PATH, L"C:\\Windows\\System32\\Shell32.dll");
|
|
|
|
hShell32 = LoadLibrary(szDllPath);
|
|
if (hShell32)
|
|
{
|
|
SHCreateItemFromParsingNameFn SHCreateItemFromParsingNamePtr = (SHCreateItemFromParsingNameFn)GetProcAddress(hShell32, "SHCreateItemFromParsingName");
|
|
if (SHCreateItemFromParsingNamePtr)
|
|
{
|
|
HMODULE hPropsys = NULL;
|
|
|
|
if (GetSystemDirectory(szDllPath, MAX_PATH))
|
|
StringCchCatW(szDllPath, MAX_PATH, L"\\Propsys.dll");
|
|
else
|
|
StringCchCopyW(szDllPath, MAX_PATH, L"C:\\Windows\\System32\\Propsys.dll");
|
|
|
|
hPropsys = LoadLibrary(szDllPath);
|
|
if (hPropsys)
|
|
{
|
|
PSGetPropertyKeyFromNameFn PSGetPropertyKeyFromNamePtr = (PSGetPropertyKeyFromNameFn)GetProcAddress(hPropsys, "PSGetPropertyKeyFromName");
|
|
if (PSGetPropertyKeyFromNamePtr)
|
|
{
|
|
WCHAR parsingName[3] = {driveLetter, L':', 0};
|
|
IShellItem2* drive = NULL;
|
|
hr = SHCreateItemFromParsingNamePtr(parsingName, NULL, IID_PPV_ARGS(&drive));
|
|
if (SUCCEEDED(hr)) {
|
|
PROPERTYKEY pKey;
|
|
hr = PSGetPropertyKeyFromNamePtr(L"System.Volume.BitLockerProtection", &pKey);
|
|
if (SUCCEEDED(hr)) {
|
|
PROPVARIANT prop;
|
|
PropVariantInit(&prop);
|
|
hr = drive->GetProperty(pKey, &prop);
|
|
if (SUCCEEDED(hr)) {
|
|
int status = prop.intVal;
|
|
if (status == BL_State_FullyEncrypted || status == BL_State_DecryptionInProgress || status == BL_State_DecryptionSuspended)
|
|
blStatus = BL_Status_Protected;
|
|
else
|
|
blStatus = BL_Status_Unprotected;
|
|
}
|
|
}
|
|
}
|
|
if (drive)
|
|
drive->Release();
|
|
}
|
|
|
|
FreeLibrary(hPropsys);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
blStatus = BL_Status_Unprotected; // before Vista, there was no Bitlocker
|
|
}
|
|
|
|
FreeLibrary(hShell32);
|
|
}
|
|
|
|
CoUninitialize();
|
|
return blStatus;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static CLIPFORMAT g_supportedFormats[] = { CF_UNICODETEXT, CF_TEXT, CF_OEMTEXT};
|
|
|
|
//*************************************************************
|
|
// GenericDropTarget
|
|
//*************************************************************
|
|
GenericDropTarget::GenericDropTarget(CLIPFORMAT* pFormats, size_t count)
|
|
: m_DropTargetWnd(NULL),
|
|
m_dwRefCount(1),
|
|
m_KeyState(0L),
|
|
m_Data(NULL)
|
|
{
|
|
m_DropPoint.x = 0;
|
|
m_DropPoint.y = 0;
|
|
|
|
if (pFormats && count)
|
|
{
|
|
for (size_t i = 0; i < count; i++)
|
|
{
|
|
m_SupportedFormat.push_back (pFormats[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
GenericDropTarget::~GenericDropTarget()
|
|
{
|
|
}
|
|
|
|
HRESULT GenericDropTarget::QueryInterface(REFIID iid, void **ppvObject)
|
|
{
|
|
if(ppvObject == NULL)
|
|
return E_FAIL;
|
|
|
|
if (iid == IID_IUnknown)
|
|
{
|
|
AddRef();
|
|
(*ppvObject) = this;
|
|
return S_OK;
|
|
}
|
|
// compare guids fast and dirty
|
|
if (IsEqualGUID (iid, IID_IDropTarget))
|
|
{
|
|
AddRef();
|
|
(*ppvObject) = this;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
ULONG GenericDropTarget::AddRef(void)
|
|
{
|
|
return (ULONG) InterlockedIncrement (&m_dwRefCount);
|
|
}
|
|
|
|
ULONG GenericDropTarget::Release(void)
|
|
{
|
|
if (InterlockedDecrement (&m_dwRefCount) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return (ULONG) m_dwRefCount;
|
|
}
|
|
|
|
//*************************************************************
|
|
// Register
|
|
// Called by whom implements us so we can serve
|
|
//*************************************************************
|
|
BOOL GenericDropTarget::Register(HWND hWnd)
|
|
{
|
|
if(NULL == hWnd)
|
|
return FALSE;
|
|
|
|
OleInitialize(NULL);
|
|
|
|
// required: these MUST be strong locked
|
|
CoLockObjectExternal(this, TRUE, 0);
|
|
|
|
// this is ok, we have it
|
|
DWORD hRes = ::RegisterDragDrop(hWnd, this);
|
|
if(SUCCEEDED(hRes))
|
|
{
|
|
// keep
|
|
m_DropTargetWnd = hWnd;
|
|
return TRUE;
|
|
}
|
|
|
|
// unlock
|
|
CoLockObjectExternal(this, FALSE, 0);
|
|
|
|
// bye bye COM
|
|
OleUninitialize();
|
|
|
|
// wont accept data now
|
|
return FALSE;
|
|
}
|
|
|
|
//*************************************************************
|
|
// Revoke
|
|
// Unregister us as a target
|
|
//*************************************************************
|
|
void GenericDropTarget::Revoke()
|
|
{
|
|
if(NULL == m_DropTargetWnd)
|
|
return;
|
|
|
|
RevokeDragDrop(m_DropTargetWnd);
|
|
|
|
m_DropTargetWnd = NULL;
|
|
|
|
// unlock
|
|
CoLockObjectExternal(this, FALSE, 0);
|
|
|
|
// bye bye COM
|
|
OleUninitialize();
|
|
}
|
|
|
|
//*************************************************************
|
|
// DragEnter
|
|
//*************************************************************
|
|
HRESULT GenericDropTarget::DragEnter(struct IDataObject *pDataObject, unsigned long grfKeyState, struct _POINTL pMouse, unsigned long * pDropEffect)
|
|
{
|
|
if(pDataObject == NULL)
|
|
return E_FAIL; // must have data
|
|
|
|
// keep point
|
|
m_DropPoint.x = pMouse.x;
|
|
m_DropPoint.y = pMouse.y;
|
|
|
|
// keep key
|
|
m_KeyState = grfKeyState;
|
|
|
|
// call top
|
|
*pDropEffect = GotEnter();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//*************************************************************
|
|
// DragOver
|
|
// Coming over!
|
|
//*************************************************************
|
|
HRESULT GenericDropTarget::DragOver(unsigned long grfKeyState, struct _POINTL pMouse, unsigned long *pEffect)
|
|
{
|
|
// keep point
|
|
m_DropPoint.x = pMouse.x;
|
|
m_DropPoint.y = pMouse.y;
|
|
|
|
// keep key
|
|
m_KeyState = grfKeyState;
|
|
|
|
// call top
|
|
*pEffect = GotDrag();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//*************************************************************
|
|
// DragLeave
|
|
// Free! At last!
|
|
//*************************************************************
|
|
HRESULT GenericDropTarget::DragLeave(void)
|
|
{
|
|
GotLeave();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//*************************************************************
|
|
// Drop
|
|
//*************************************************************
|
|
HRESULT GenericDropTarget::Drop(struct IDataObject *pDataObject, unsigned long grfKeyState, struct _POINTL pMouse, unsigned long *pdwEffect)
|
|
{
|
|
if(NULL == pDataObject)
|
|
return E_FAIL;
|
|
|
|
// do final effect
|
|
*pdwEffect = DROPEFFECT_COPY;
|
|
|
|
// Check the data
|
|
FORMATETC iFormat;
|
|
ZeroMemory(&iFormat, sizeof(FORMATETC));
|
|
|
|
STGMEDIUM iMedium;
|
|
ZeroMemory(&iMedium, sizeof(STGMEDIUM));
|
|
|
|
HRESULT hRes;
|
|
size_t i;
|
|
bool bFound = false;
|
|
|
|
for (i = 0; i < m_SupportedFormat.size(); i++)
|
|
{
|
|
// data
|
|
iFormat.cfFormat = m_SupportedFormat[i];
|
|
iFormat.dwAspect = DVASPECT_CONTENT;
|
|
iFormat.lindex = -1; // give me all baby
|
|
iFormat.tymed = TYMED_HGLOBAL; // want mem
|
|
|
|
hRes = pDataObject->GetData(&iFormat, &iMedium);
|
|
if(SUCCEEDED(hRes))
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
return hRes;
|
|
|
|
// we have the data, get it
|
|
BYTE *iMem = (BYTE *)::GlobalLock(iMedium.hGlobal);
|
|
|
|
// pass over
|
|
m_Data = iMem;
|
|
|
|
// keep point
|
|
m_DropPoint.x = pMouse.x;
|
|
m_DropPoint.y = pMouse.y;
|
|
|
|
// keep key
|
|
m_KeyState = grfKeyState;
|
|
|
|
// notify parent of drop
|
|
GotDrop(m_SupportedFormat[i]);
|
|
|
|
::GlobalUnlock(iMedium.hGlobal);
|
|
|
|
// free data
|
|
if(iMedium.pUnkForRelease != NULL)
|
|
iMedium.pUnkForRelease->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//*************************************************************
|
|
// Stub implementation
|
|
// Real stuff would be done in parent
|
|
//*************************************************************
|
|
void GenericDropTarget::GotDrop(CLIPFORMAT format)
|
|
{
|
|
}
|
|
|
|
DWORD GenericDropTarget::GotDrag(void)
|
|
{
|
|
return DROPEFFECT_LINK;
|
|
}
|
|
|
|
void GenericDropTarget::GotLeave(void)
|
|
{
|
|
}
|
|
|
|
DWORD GenericDropTarget::GotEnter(void)
|
|
{
|
|
return DROPEFFECT_LINK;
|
|
}
|
|
|
|
// ************************************************************
|
|
// PasswordEditDropTarget
|
|
// Constructor
|
|
// ************************************************************
|
|
PasswordEditDropTarget::PasswordEditDropTarget() : GenericDropTarget (g_supportedFormats, ARRAYSIZE (g_supportedFormats))
|
|
{
|
|
|
|
}
|
|
|
|
// ************************************************************
|
|
// GotDrag
|
|
|
|
// ************************************************************
|
|
DWORD PasswordEditDropTarget::GotDrag(void)
|
|
{
|
|
return GotEnter();
|
|
}
|
|
|
|
// ************************************************************
|
|
// GotLeave
|
|
// ************************************************************
|
|
void PasswordEditDropTarget::GotLeave(void)
|
|
{
|
|
}
|
|
|
|
// ************************************************************
|
|
// GotEnter
|
|
// ************************************************************
|
|
DWORD PasswordEditDropTarget::GotEnter(void)
|
|
{
|
|
TCHAR szClassName[64];
|
|
DWORD dwStyles;
|
|
int maxLen;
|
|
HWND hChild = WindowFromPoint (m_DropPoint);
|
|
// check that we are on password edit control (we use maximum length to correctly identify password fields since they don't always have ES_PASSWORD style (if the the user checked show password)
|
|
if (hChild && GetClassName (hChild, szClassName, ARRAYSIZE (szClassName)) && (0 == _tcsicmp (szClassName, _T("EDIT")))
|
|
&& (dwStyles = GetWindowLongPtr (hChild, GWL_STYLE)) && !(dwStyles & ES_NUMBER)
|
|
&& (maxLen = (int) SendMessage (hChild, EM_GETLIMITTEXT, 0, 0)) && (maxLen == MAX_PASSWORD || maxLen == MAX_LEGACY_PASSWORD)
|
|
)
|
|
{
|
|
return DROPEFFECT_COPY;
|
|
}
|
|
|
|
return DROPEFFECT_LINK;
|
|
}
|
|
|
|
// ************************************************************
|
|
// GotDrop
|
|
// Called if we have a drop text drop here.
|
|
//
|
|
// ************************************************************
|
|
void PasswordEditDropTarget::GotDrop(CLIPFORMAT format)
|
|
{
|
|
// value contains the material itself
|
|
if(m_Data)
|
|
{
|
|
TCHAR szClassName[64];
|
|
DWORD dwStyles;
|
|
int maxLen;
|
|
HWND hChild = WindowFromPoint (m_DropPoint);
|
|
if (hChild && GetClassName (hChild, szClassName, ARRAYSIZE (szClassName)) && (0 == _tcsicmp (szClassName, _T("EDIT")))
|
|
&& (dwStyles = GetWindowLongPtr (hChild, GWL_STYLE)) && !(dwStyles & ES_NUMBER)
|
|
&& (maxLen = (int) SendMessage (hChild, EM_GETLIMITTEXT, 0, 0)) && (maxLen == MAX_PASSWORD || maxLen == MAX_LEGACY_PASSWORD)
|
|
)
|
|
{
|
|
WCHAR* wszText;
|
|
int wlen;
|
|
bool bFree = false;
|
|
// get the text
|
|
if (format == CF_UNICODETEXT)
|
|
{
|
|
wszText = (WCHAR *)m_Data;
|
|
}
|
|
else
|
|
{
|
|
char *iText = (char *)m_Data;
|
|
wlen = MultiByteToWideChar ((format == CF_OEMTEXT)? CP_OEMCP : CP_ACP, 0, iText, -1, NULL, 0);
|
|
wszText = new WCHAR[wlen];
|
|
if (wszText)
|
|
{
|
|
wlen = MultiByteToWideChar (CP_ACP, 0, iText, -1, wszText, wlen);
|
|
bFree = true;
|
|
}
|
|
}
|
|
|
|
WCHAR* pchData = wszText;
|
|
int txtlen = 0;
|
|
bool bTruncated = false;
|
|
|
|
// remove any appended \r or \n
|
|
while (*pchData)
|
|
{
|
|
if (*pchData == '\r' || *pchData == '\n')
|
|
break;
|
|
else
|
|
{
|
|
txtlen++;
|
|
pchData++;
|
|
}
|
|
}
|
|
|
|
if (txtlen)
|
|
{
|
|
if (txtlen > maxLen)
|
|
{
|
|
bTruncated = true;
|
|
txtlen = maxLen;
|
|
}
|
|
|
|
SetFocus (hChild);
|
|
|
|
wszText[txtlen] = 0;
|
|
SetWindowText(hChild , wszText);
|
|
|
|
if (bTruncated)
|
|
{
|
|
EDITBALLOONTIP ebt;
|
|
DWORD dwTextSize = (DWORD) wcslen (GetString ("PASSWORD_PASTED_TRUNCATED")) + 16;
|
|
WCHAR* szErrorText = (WCHAR*) malloc (dwTextSize * sizeof (WCHAR));
|
|
|
|
StringCchPrintf (szErrorText, dwTextSize, GetString ("PASSWORD_PASTED_TRUNCATED"), maxLen);
|
|
|
|
ebt.cbStruct = sizeof( EDITBALLOONTIP );
|
|
ebt.pszText = szErrorText;
|
|
ebt.pszTitle = lpszTitle;
|
|
ebt.ttiIcon = TTI_WARNING_LARGE; // tooltip warning icon
|
|
|
|
SendMessage(hChild, EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt);
|
|
|
|
MessageBeep (0xFFFFFFFF);
|
|
|
|
free (szErrorText);
|
|
}
|
|
}
|
|
|
|
if (bFree)
|
|
{
|
|
burn (wszText, wlen * sizeof (WCHAR));
|
|
delete [] wszText;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Query the status of Hibernate and Fast Startup
|
|
*/
|
|
|
|
typedef BOOLEAN (WINAPI *GetPwrCapabilitiesFn)(
|
|
PSYSTEM_POWER_CAPABILITIES lpspc
|
|
);
|
|
|
|
BOOL GetHibernateStatus (BOOL& bHibernateEnabled, BOOL& bHiberbootEnabled)
|
|
{
|
|
wchar_t szPowrProfPath[MAX_PATH] = {0};
|
|
HMODULE hPowrProf = NULL;
|
|
BOOL bResult = FALSE;
|
|
|
|
bHibernateEnabled = bHiberbootEnabled = FALSE;
|
|
|
|
if (GetSystemDirectory(szPowrProfPath, MAX_PATH))
|
|
StringCchCatW (szPowrProfPath, MAX_PATH, L"\\PowrProf.dll");
|
|
else
|
|
StringCchCopyW (szPowrProfPath, MAX_PATH, L"C:\\Windows\\System32\\PowrProf.dll");
|
|
|
|
hPowrProf = LoadLibrary (szPowrProfPath);
|
|
if (hPowrProf)
|
|
{
|
|
GetPwrCapabilitiesFn GetPwrCapabilitiesPtr = (GetPwrCapabilitiesFn) GetProcAddress (hPowrProf, "GetPwrCapabilities");
|
|
if ( GetPwrCapabilitiesPtr)
|
|
{
|
|
SYSTEM_POWER_CAPABILITIES spc;
|
|
BOOLEAN bRet = GetPwrCapabilitiesPtr (&spc);
|
|
if (bRet)
|
|
{
|
|
DWORD dwHibernateEnabled = 0;
|
|
DWORD dwHiberbootEnabled = 0;
|
|
|
|
if (spc.SystemS4)
|
|
{
|
|
dwHibernateEnabled = 1;
|
|
if(!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Control\\Power", L"HibernateEnabled", &dwHibernateEnabled))
|
|
{
|
|
// starting from Windows 10 1809 (Build 17763), HibernateEnabledDefault is used when HibernateEnabled is absent
|
|
if (IsOSVersionAtLeast (WIN_10, 0) && CurrentOSBuildNumber >= 17763)
|
|
ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Control\\Power", L"HibernateEnabledDefault", &dwHibernateEnabled);
|
|
}
|
|
}
|
|
|
|
// check if Fast Startup / Hybrid Boot is enabled
|
|
#if _MSC_VER >= 1900
|
|
if (IsOSVersionAtLeast (WIN_8, 0) && spc.Hiberboot)
|
|
#else
|
|
if (IsOSVersionAtLeast(WIN_8, 0) && spc.spare2[0])
|
|
#endif
|
|
{
|
|
dwHiberbootEnabled = 1;
|
|
ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power", L"HiberbootEnabled", &dwHiberbootEnabled);
|
|
}
|
|
|
|
if (dwHibernateEnabled)
|
|
bHibernateEnabled = TRUE;
|
|
else
|
|
bHibernateEnabled = FALSE;
|
|
|
|
if (dwHiberbootEnabled)
|
|
bHiberbootEnabled = TRUE;
|
|
else
|
|
bHiberbootEnabled = FALSE;
|
|
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
|
|
FreeLibrary (hPowrProf);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/* return TRUE if Windows is in Test Signing mode */
|
|
/* ref: https://social.msdn.microsoft.com/Forums/Windowsapps/en-US/e6c1be93-7003-4594-b8e4-18ab4a75d273/detecting-testsigning-onoff-via-api */
|
|
BOOL IsTestSigningModeEnabled ()
|
|
{
|
|
BOOL bEnabled = FALSE;
|
|
NtQuerySystemInformationFn NtQuerySystemInformationPtr = (NtQuerySystemInformationFn) GetProcAddress (GetModuleHandle (L"ntdll.dll"), "NtQuerySystemInformation");
|
|
if(NtQuerySystemInformationPtr)
|
|
{
|
|
SYSTEM_CODEINTEGRITY_INFORMATION info = {0};
|
|
ULONG cbReturnedData = 0;
|
|
info.Length = sizeof(info);
|
|
if ( (NtQuerySystemInformationPtr((SYSTEM_INFORMATION_CLASS) SYSTEMCODEINTEGRITYINFORMATION, &info, sizeof(info), &cbReturnedData) >= 0)
|
|
&& (cbReturnedData == sizeof(info))
|
|
)
|
|
{
|
|
if ((info.CodeIntegrityOptions & (CODEINTEGRITY_OPTION_TESTSIGN | CODEINTEGRITY_OPTION_ENABLED)) == (CODEINTEGRITY_OPTION_TESTSIGN | CODEINTEGRITY_OPTION_ENABLED))
|
|
{
|
|
bEnabled = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bEnabled;
|
|
}
|
|
|
|
// Adapted from https://docs.microsoft.com/en-us/windows/win32/wmisdk/example-creating-a-wmi-application
|
|
bool GetKbList (std::vector<std::wstring>& kbList)
|
|
{
|
|
HRESULT hres;
|
|
kbList.clear();
|
|
|
|
// Initialize COM.
|
|
hres = CoInitialize(NULL);
|
|
if (FAILED(hres))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Initialize
|
|
hres = CoInitializeSecurity(
|
|
NULL,
|
|
-1, // COM negotiates service
|
|
NULL, // Authentication services
|
|
NULL, // Reserved
|
|
RPC_C_AUTHN_LEVEL_DEFAULT, // authentication
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation
|
|
NULL, // Authentication info
|
|
EOAC_NONE, // Additional capabilities
|
|
NULL // Reserved
|
|
);
|
|
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
CoUninitialize();
|
|
return false;
|
|
}
|
|
|
|
// Obtain the initial locator to Windows Management
|
|
// on a particular host computer.
|
|
IWbemLocator *pLoc = 0;
|
|
|
|
hres = CoCreateInstance(
|
|
CLSID_WbemLocator,
|
|
0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemLocator, (LPVOID *) &pLoc);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
CoUninitialize();
|
|
return false;
|
|
}
|
|
|
|
IWbemServices *pSvc = 0;
|
|
|
|
// Connect to the root\cimv2 namespace with the
|
|
// current user and obtain pointer pSvc
|
|
// to make IWbemServices calls.
|
|
|
|
hres = pLoc->ConnectServer(
|
|
|
|
_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
|
|
NULL, // User name
|
|
NULL, // User password
|
|
0, // Locale
|
|
NULL, // Security flags
|
|
0, // Authority
|
|
0, // Context object
|
|
&pSvc // IWbemServices proxy
|
|
);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
pLoc->Release();
|
|
CoUninitialize();
|
|
return false;
|
|
}
|
|
|
|
// Set the IWbemServices proxy so that impersonation
|
|
// of the user (client) occurs.
|
|
hres = CoSetProxyBlanket(
|
|
|
|
pSvc, // the proxy to set
|
|
RPC_C_AUTHN_WINNT, // authentication service
|
|
RPC_C_AUTHZ_NONE, // authorization service
|
|
NULL, // Server principal name
|
|
RPC_C_AUTHN_LEVEL_CALL, // authentication level
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
|
|
NULL, // client identity
|
|
EOAC_NONE // proxy capabilities
|
|
);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
pSvc->Release();
|
|
pLoc->Release();
|
|
CoUninitialize();
|
|
return false;
|
|
}
|
|
|
|
|
|
// Use the IWbemServices pointer to make requests of WMI.
|
|
// Make requests here:
|
|
|
|
// query for all installed KBs
|
|
IEnumWbemClassObject* pEnumerator = NULL;
|
|
hres = pSvc->ExecQuery(
|
|
bstr_t("WQL"),
|
|
bstr_t("SELECT * FROM Win32_QuickFixEngineering"),
|
|
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
NULL,
|
|
&pEnumerator);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
pSvc->Release();
|
|
pLoc->Release();
|
|
CoUninitialize();
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
IWbemClassObject *pclsObj;
|
|
ULONG uReturn = 0;
|
|
|
|
while (pEnumerator)
|
|
{
|
|
hres = pEnumerator->Next(WBEM_INFINITE, 1,
|
|
&pclsObj, &uReturn);
|
|
|
|
if(0 == uReturn)
|
|
{
|
|
break;
|
|
}
|
|
|
|
VARIANT vtProp;
|
|
|
|
// Get the value of the "hotfixid" property
|
|
hres = pclsObj->Get(L"hotfixid", 0, &vtProp, 0, 0);
|
|
if (SUCCEEDED(hres) && (V_VT(&vtProp) == VT_BSTR))
|
|
{
|
|
kbList.push_back(vtProp.bstrVal);
|
|
}
|
|
VariantClear(&vtProp);
|
|
|
|
pclsObj->Release();
|
|
pclsObj = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
// Cleanup
|
|
// ========
|
|
|
|
pSvc->Release();
|
|
pLoc->Release();
|
|
pEnumerator->Release();
|
|
|
|
CoUninitialize();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OneOfKBsInstalled (const wchar_t* szKBs[], int count)
|
|
{
|
|
std::vector<std::wstring> kbList;
|
|
bool bRet = GetKbList(kbList);
|
|
if (bRet)
|
|
{
|
|
// at least one of the given KBs must be present
|
|
bool bFound = false;
|
|
|
|
for (size_t j = 0; j < kbList.size(); j++)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (_wcsicmp(szKBs[i], kbList[j].c_str()) == 0)
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bFound)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
bRet = bFound;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
#endif // VC_COMREG
|