mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2025-11-11 02:58:02 -06:00
3534 lines
114 KiB
C
3534 lines
114 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-2025 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 <SrRestorePtApi.h>
|
|
#include <io.h>
|
|
#include <propkey.h>
|
|
#include <propvarutil.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <tchar.h>
|
|
#include <Setupapi.h>
|
|
|
|
#include "Apidrvr.h"
|
|
#include "BootEncryption.h"
|
|
#include "Boot/Windows/BootCommon.h"
|
|
#include "Combo.h"
|
|
#include "ComSetup.h"
|
|
#include "Dlgcode.h"
|
|
#include "Language.h"
|
|
#include "Registry.h"
|
|
#include "Resource.h"
|
|
|
|
#include "Dir.h"
|
|
#include "Setup.h"
|
|
|
|
#include "../Common/Resource.h"
|
|
|
|
#pragma comment(lib, "Shlwapi.lib")
|
|
|
|
using namespace VeraCrypt;
|
|
|
|
#pragma warning( disable : 4201 )
|
|
#pragma warning( disable : 4115 )
|
|
|
|
#include <shlobj.h>
|
|
|
|
#pragma warning( default : 4201 )
|
|
#pragma warning( default : 4115 )
|
|
|
|
#include <Strsafe.h>
|
|
|
|
#include <Msi.h>
|
|
#include <MsiQuery.h>
|
|
#include <wtsapi32.h>
|
|
|
|
#include <cstdarg>
|
|
#if !defined(va_copy)
|
|
#define va_copy(d, s) ((d) = (s))
|
|
#endif
|
|
|
|
typedef enum
|
|
{
|
|
MSI_INFO_LEVEL = 0,
|
|
MSI_WARNING_LEVEL,
|
|
MSI_ERROR_LEVEL
|
|
} eMSILogLevel;
|
|
|
|
#define WAIT_PERIOD 3
|
|
|
|
wchar_t InstallationPath[TC_MAX_PATH];
|
|
|
|
BOOL bUninstall = FALSE;
|
|
BOOL bDowngrade = FALSE;
|
|
BOOL bUninstallInProgress = FALSE;
|
|
BOOL PortableMode = FALSE;
|
|
BOOL UnloadDriver = TRUE;
|
|
|
|
BOOL Rollback = FALSE;
|
|
BOOL bReinstallMode = FALSE;
|
|
BOOL bUpgrade = FALSE;
|
|
BOOL bPossiblyFirstTimeInstall = FALSE;
|
|
BOOL bDevm = FALSE;
|
|
BOOL SystemEncryptionUpdate = FALSE;
|
|
BOOL bRestartRequired = FALSE;
|
|
BOOL bDisableSwapFiles = FALSE;
|
|
BOOL bSystemRestore = TRUE;
|
|
HMODULE volatile SystemRestoreDll = 0;
|
|
|
|
BOOL bPromptFastStartup = FALSE;
|
|
BOOL bPromptReleaseNotes = FALSE;
|
|
BOOL bPromptTutorial = FALSE;
|
|
BOOL bUpdateRescueDisk = FALSE;
|
|
BOOL bRepairMode = FALSE;
|
|
BOOL bUserSetLanguage = FALSE;
|
|
|
|
/*
|
|
BOOL bMakePackage = FALSE;
|
|
BOOL bDone = FALSE;
|
|
|
|
BOOL bForAllUsers = TRUE;
|
|
BOOL bRegisterFileExt = TRUE;
|
|
BOOL bAddToStartMenu = TRUE;
|
|
BOOL bDesktopIcon = TRUE;
|
|
BOOL bDesktopIconStatusDetermined = FALSE;
|
|
|
|
*/
|
|
|
|
/* **************************************************************************** */
|
|
|
|
/* Defined in this file, but a little bit late */
|
|
BOOL IsSystemRestoreEnabled ();
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
BOOL ForceCopyFile (LPCWSTR szSrcFile, LPCWSTR szDestFile)
|
|
{
|
|
BOOL bRet = CopyFileW (szSrcFile, szDestFile, FALSE);
|
|
if (!bRet)
|
|
{
|
|
wstring renamedPath = szDestFile;
|
|
renamedPath += VC_FILENAME_RENAMED_SUFFIX;
|
|
|
|
/* rename the locked file in order to be able to create a new one */
|
|
if (MoveFileExW (szDestFile, renamedPath.c_str(), MOVEFILE_REPLACE_EXISTING))
|
|
{
|
|
bRet = CopyFileW (szSrcFile, szDestFile, FALSE);
|
|
if (bRet)
|
|
{
|
|
/* delete the renamed file when the machine reboots */
|
|
MoveFileEx (renamedPath.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
|
}
|
|
else
|
|
{
|
|
/* restore the original file name */
|
|
MoveFileEx (renamedPath.c_str(), szDestFile, MOVEFILE_REPLACE_EXISTING);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
BOOL ForceDeleteFile (LPCWSTR szFileName)
|
|
{
|
|
if (!DeleteFile (szFileName))
|
|
{
|
|
/* delete the renamed file when the machine reboots */
|
|
return MoveFileEx (szFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
BOOL StatDeleteFile (wchar_t *lpszFile, BOOL bCheckForOldFile)
|
|
{
|
|
struct __stat64 st;
|
|
|
|
if (bCheckForOldFile)
|
|
{
|
|
wchar_t szOldPath[MAX_PATH + 1];
|
|
StringCbCopyW (szOldPath, sizeof(szOldPath), lpszFile);
|
|
StringCbCatW (szOldPath, sizeof(szOldPath), VC_FILENAME_RENAMED_SUFFIX);
|
|
|
|
if (_wstat64 (szOldPath, &st) == 0)
|
|
{
|
|
ForceDeleteFile (szOldPath);
|
|
}
|
|
}
|
|
|
|
if (_wstat64 (lpszFile, &st) == 0)
|
|
return ForceDeleteFile (lpszFile);
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
BOOL StatRemoveDirectory (wchar_t *lpszDir)
|
|
{
|
|
struct __stat64 st;
|
|
|
|
if (_wstat64 (lpszDir, &st) == 0)
|
|
{
|
|
return DeleteDirectory (lpszDir);
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
void StatusMessage (HWND hwndDlg, char *stringId)
|
|
{
|
|
if (Rollback)
|
|
return;
|
|
|
|
SendMessageW (GetDlgItem (hwndDlg, IDC_LOG_WINDOW), LB_ADDSTRING, 0, (LPARAM) GetString (stringId));
|
|
|
|
SendDlgItemMessage (hwndDlg, IDC_LOG_WINDOW, LB_SETTOPINDEX,
|
|
SendDlgItemMessage (hwndDlg, IDC_LOG_WINDOW, LB_GETCOUNT, 0, 0) - 1, 0);
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
void DetermineUpgradeDowngradeStatus (BOOL bCloseDriverHandle, LONG *driverVersionPtr)
|
|
{
|
|
LONG driverVersion = VERSION_NUM;
|
|
int status = 0;
|
|
|
|
if (hDriver == INVALID_HANDLE_VALUE)
|
|
status = DriverAttach();
|
|
|
|
if ((status == 0) && (hDriver != INVALID_HANDLE_VALUE))
|
|
{
|
|
DWORD dwResult;
|
|
BOOL bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &driverVersion, sizeof (driverVersion), &dwResult, NULL);
|
|
|
|
bUpgrade = (bResult && driverVersion <= VERSION_NUM);
|
|
bDowngrade = (bResult && driverVersion > VERSION_NUM);
|
|
bReinstallMode = (bResult && driverVersion == VERSION_NUM);
|
|
|
|
PortableMode = DeviceIoControl (hDriver, TC_IOCTL_GET_PORTABLE_MODE_STATUS, NULL, 0, NULL, 0, &dwResult, NULL);
|
|
|
|
if (bCloseDriverHandle)
|
|
{
|
|
CloseHandle (hDriver);
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
*driverVersionPtr = driverVersion;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
BOOL IsSystemRestoreEnabled ()
|
|
{
|
|
BOOL bEnabled = FALSE;
|
|
HKEY hKey;
|
|
DWORD dwValue = 0, cbValue = sizeof (DWORD);
|
|
wchar_t szRegPath[MAX_PATH];
|
|
GetRestorePointRegKeyName (szRegPath, sizeof (szRegPath));
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, szRegPath, 0, KEY_READ | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
if ( (ERROR_SUCCESS == RegQueryValueEx (hKey, L"RPSessionInterval", NULL, NULL, (LPBYTE) &dwValue, &cbValue))
|
|
&& (dwValue == 1)
|
|
)
|
|
{
|
|
bEnabled = TRUE;
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
return bEnabled;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
static void RecursiveSetOwner (HKEY hKey, PSECURITY_DESCRIPTOR pSD)
|
|
{
|
|
LSTATUS status = 0;
|
|
DWORD dwIndex = 0, dwMaxNameLen = 0, dwNameLen = 0, numberSubKeys = 0;
|
|
HKEY hSubKey;
|
|
|
|
if ( (ERROR_SUCCESS == status) && (ERROR_SUCCESS == RegQueryInfoKey(hKey, NULL, NULL, NULL, &numberSubKeys, &dwMaxNameLen, NULL, NULL, NULL, NULL, NULL, NULL))
|
|
&& (numberSubKeys >= 1)
|
|
)
|
|
{
|
|
dwMaxNameLen++;
|
|
wchar_t* szNameValue = new wchar_t[dwMaxNameLen];
|
|
while (true)
|
|
{
|
|
dwNameLen = dwMaxNameLen;
|
|
status = RegEnumKeyExW (hKey, dwIndex++, szNameValue, &dwNameLen, NULL, NULL, NULL, NULL);
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
status = RegOpenKeyExW (hKey, szNameValue, 0, WRITE_OWNER | KEY_READ , &hSubKey);
|
|
if (ERROR_SUCCESS == status)
|
|
{
|
|
RecursiveSetOwner (hSubKey, pSD);
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
delete [] szNameValue;
|
|
}
|
|
|
|
RegSetKeySecurity (hKey, OWNER_SECURITY_INFORMATION, pSD);
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
static void RecursiveSetDACL (HKEY hKey, const wchar_t* SubKeyName, PSECURITY_DESCRIPTOR pSD)
|
|
{
|
|
HKEY hSubKey;
|
|
DWORD dwIndex = 0, dwMaxNameLen = 0, dwNameLen = 0, numberSubKeys = 0;
|
|
LSTATUS status = RegOpenKeyExW(hKey, SubKeyName, 0, WRITE_DAC | KEY_READ /*| ACCESS_SYSTEM_SECURITY*/, &hSubKey);
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
status = RegSetKeySecurity (hSubKey, DACL_SECURITY_INFORMATION, pSD);
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hSubKey);
|
|
status = RegOpenKeyExW(hKey, SubKeyName, 0, WRITE_DAC | KEY_READ , &hSubKey);
|
|
}
|
|
|
|
if ( (ERROR_SUCCESS == status)
|
|
&& (ERROR_SUCCESS == RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &numberSubKeys, &dwMaxNameLen, NULL, NULL, NULL, NULL, NULL, NULL))
|
|
&& (numberSubKeys >= 1)
|
|
)
|
|
{
|
|
dwMaxNameLen++;
|
|
wchar_t* szNameValue = new wchar_t[dwMaxNameLen];
|
|
while (true)
|
|
{
|
|
dwNameLen = dwMaxNameLen;
|
|
status = RegEnumKeyExW (hSubKey, dwIndex++, szNameValue, &dwNameLen, NULL, NULL, NULL, NULL);
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
RecursiveSetDACL (hSubKey, szNameValue, pSD);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
delete [] szNameValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
static void AllowKeyAccess(HKEY Key,const wchar_t* SubKeyName)
|
|
{
|
|
LSTATUS RegResult;
|
|
HKEY SvcKey = NULL;
|
|
DWORD dwLength = 0;
|
|
HANDLE Token = NULL;
|
|
PTOKEN_USER pTokenUser = NULL;
|
|
std::string sNewSD;
|
|
|
|
RegResult = RegOpenKeyExW(Key, SubKeyName, 0, WRITE_OWNER | KEY_READ, &SvcKey);
|
|
if (RegResult==ERROR_SUCCESS)
|
|
{
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
|
|
{
|
|
if (!GetTokenInformation(Token, TokenUser, pTokenUser, 0, &dwLength))
|
|
{
|
|
if (GetLastError() ==ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
pTokenUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
|
|
if (pTokenUser)
|
|
{
|
|
if (GetTokenInformation(Token, TokenUser, pTokenUser, dwLength, &dwLength))
|
|
{
|
|
SECURITY_DESCRIPTOR SecDesc;
|
|
if ( InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION)
|
|
&& SetSecurityDescriptorDacl(&SecDesc, TRUE, NULL, FALSE) // NULL DACL: full access to everyone
|
|
&& SetSecurityDescriptorOwner(&SecDesc, pTokenUser->User.Sid, FALSE)
|
|
)
|
|
{
|
|
RecursiveSetOwner(SvcKey, &SecDesc);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey(SvcKey);
|
|
}
|
|
|
|
if (pTokenUser)
|
|
{
|
|
PSID pSid = pTokenUser->User.Sid;
|
|
DWORD dwAclSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + ::GetLengthSid(pSid) - sizeof(DWORD);
|
|
PACL pDacl = (PACL) new BYTE[dwAclSize];
|
|
if (pDacl)
|
|
{
|
|
if (TRUE == ::InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
|
|
{
|
|
if (TRUE == AddAccessAllowedAceEx(pDacl, ACL_REVISION, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, WRITE_DAC | KEY_ALL_ACCESS, pSid))
|
|
{
|
|
SECURITY_DESCRIPTOR SecDesc;
|
|
if (TRUE == ::InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
if (TRUE == ::SetSecurityDescriptorDacl(&SecDesc, TRUE, pDacl, FALSE))
|
|
{
|
|
RecursiveSetDACL (Key, SubKeyName, &SecDesc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete [] pDacl;
|
|
}
|
|
}
|
|
|
|
if (pTokenUser)
|
|
HeapFree(GetProcessHeap(), 0, pTokenUser);
|
|
if (Token)
|
|
CloseHandle(Token);
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c
|
|
*/
|
|
void SearchAndDeleteRegistrySubString (HKEY hKey, const wchar_t *subKey, const wchar_t *str, BOOL bEnumSubKeys, const wchar_t* enumMatchSubStr)
|
|
{
|
|
HKEY hSubKey = 0;
|
|
LSTATUS status = 0;
|
|
DWORD dwIndex = 0, dwType, dwValueNameLen, dwDataLen;
|
|
std::list<std::wstring> subKeysList;
|
|
size_t subStringLength = str? wcslen(str) : 0;
|
|
|
|
if (bEnumSubKeys)
|
|
{
|
|
DWORD dwMaxNameLen = 0;
|
|
if (ERROR_SUCCESS == RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, &dwMaxNameLen, NULL, NULL, NULL, NULL, NULL, NULL))
|
|
{
|
|
dwMaxNameLen++;
|
|
wchar_t* szNameValue = new wchar_t[dwMaxNameLen];
|
|
dwIndex = 0;
|
|
while (true)
|
|
{
|
|
dwValueNameLen = dwMaxNameLen;
|
|
status = RegEnumKeyExW (hKey, dwIndex++, szNameValue, &dwValueNameLen, NULL, NULL, NULL, NULL);
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
if (enumMatchSubStr && !wcsstr(szNameValue, enumMatchSubStr))
|
|
continue;
|
|
std::wstring entryName = szNameValue;
|
|
entryName += L"\\";
|
|
entryName += subKey;
|
|
entryName += L"\\";
|
|
subKeysList.push_back(entryName);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
delete [] szNameValue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
subKeysList.push_back(subKey);
|
|
}
|
|
|
|
for (std::list<std::wstring>::iterator ItSubKey = subKeysList.begin(); ItSubKey != subKeysList.end(); ItSubKey++)
|
|
{
|
|
// if the string to search for is empty, delete the sub key, otherwise, look for matching value and delete them
|
|
if (subStringLength == 0)
|
|
{
|
|
if (ERROR_ACCESS_DENIED == DeleteRegistryKey (hKey, ItSubKey->c_str()))
|
|
{
|
|
// grant permission to delete
|
|
AllowKeyAccess (hKey, ItSubKey->c_str());
|
|
|
|
// try again
|
|
DeleteRegistryKey (hKey, ItSubKey->c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RegOpenKeyExW (hKey, ItSubKey->c_str(), 0, KEY_ALL_ACCESS, &hSubKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwMaxNameLen = 0, dwMaxDataLen = 0;
|
|
if (ERROR_SUCCESS == RegQueryInfoKey(hSubKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwMaxNameLen, &dwMaxDataLen, NULL, NULL))
|
|
{
|
|
dwMaxNameLen++;
|
|
wchar_t* szNameValue = new wchar_t[dwMaxNameLen];
|
|
LPBYTE pbData = new BYTE[dwMaxDataLen];
|
|
|
|
std::list<std::wstring> foundEntries;
|
|
dwIndex = 0;
|
|
do
|
|
{
|
|
dwValueNameLen = dwMaxNameLen;
|
|
dwDataLen = dwMaxDataLen;
|
|
status = RegEnumValueW(hSubKey, dwIndex++, szNameValue, &dwValueNameLen, NULL, &dwType, pbData, &dwDataLen);
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
if ( (wcslen(szNameValue) >= subStringLength && wcsstr(szNameValue, str))
|
|
|| (dwType == REG_SZ && wcslen((wchar_t*) pbData) >= subStringLength && wcsstr((wchar_t*) pbData, str))
|
|
)
|
|
{
|
|
foundEntries.push_back(szNameValue);
|
|
}
|
|
}
|
|
} while ((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA)); // we ignore ERROR_MORE_DATA errors since
|
|
// we are sure to use the correct sizes
|
|
|
|
// delete the entries
|
|
if (!foundEntries.empty())
|
|
{
|
|
for (std::list<std::wstring>::iterator It = foundEntries.begin();
|
|
It != foundEntries.end(); It++)
|
|
{
|
|
RegDeleteValueW (hSubKey, It->c_str());
|
|
}
|
|
}
|
|
|
|
delete [] szNameValue;
|
|
delete [] pbData;
|
|
}
|
|
|
|
|
|
RegCloseKey (hSubKey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* **************************************************************************** */
|
|
|
|
// Adds a line to the log file of the installer.
|
|
void MSILog(MSIHANDLE hInstall, eMSILogLevel level, const wchar_t* zcFormat, ...)
|
|
{
|
|
std::wstring wszMessage;
|
|
|
|
// initialize use of the variable argument array
|
|
va_list vaArgs;
|
|
va_start(vaArgs, zcFormat);
|
|
|
|
// reliably acquire the size
|
|
// from a copy of the variable argument array
|
|
// and a functionally reliable call to mock the formatting
|
|
va_list vaArgsCopy;
|
|
va_copy(vaArgsCopy, vaArgs);
|
|
const int iLen = vswprintf(NULL, 0, zcFormat, vaArgsCopy);
|
|
va_end(vaArgsCopy);
|
|
|
|
// return a formatted string without risking memory mismanagement
|
|
// and without assuming any compiler or platform specific behavior
|
|
std::vector<wchar_t> zc(iLen + 1);
|
|
vswprintf(zc.data(), zc.size(), zcFormat, vaArgs);
|
|
va_end(vaArgs);
|
|
|
|
wszMessage.assign(zc.data(), iLen);
|
|
|
|
#ifdef TEST_HARNESS
|
|
if (!hInstall)
|
|
{
|
|
MessageBox(NULL, pszMessage, wszMessage.c_str(), 0);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
PMSIHANDLE hRecord = MsiCreateRecord(1);
|
|
// field 0 is the template
|
|
MsiRecordSetString(hRecord, 0, (level == MSI_INFO_LEVEL) ? L"VeraCryptCustomAction_INFO: [1]" : ((level == MSI_WARNING_LEVEL) ? L"VeraCryptCustomAction_WARNING: [1]" : L"VeraCryptCustomAction_ERROR: [1]"));
|
|
// field 1, to be placed in [1] placeholder
|
|
MsiRecordSetString(hRecord, 1, wszMessage.c_str());
|
|
// send message to running installer
|
|
MsiProcessMessage(hInstall, INSTALLMESSAGE_INFO, hRecord);
|
|
}
|
|
|
|
// Adds a line to the log file of the installer and shows a popup.
|
|
// Since MsiProcessMessage() takes the UILEVEL into account,
|
|
// this won't cause a deadlock in case of a silent install.
|
|
void MSILogAndShow(MSIHANDLE hInstall, eMSILogLevel level, const wchar_t* zcFormat, ...)
|
|
{
|
|
std::wstring wszMessage;
|
|
|
|
// initialize use of the variable argument array
|
|
va_list vaArgs;
|
|
va_start(vaArgs, zcFormat);
|
|
|
|
// reliably acquire the size
|
|
// from a copy of the variable argument array
|
|
// and a functionally reliable call to mock the formatting
|
|
va_list vaArgsCopy;
|
|
va_copy(vaArgsCopy, vaArgs);
|
|
const int iLen = vswprintf(NULL, 0, zcFormat, vaArgsCopy);
|
|
va_end(vaArgsCopy);
|
|
|
|
// return a formatted string without risking memory mismanagement
|
|
// and without assuming any compiler or platform specific behavior
|
|
std::vector<wchar_t> zc(iLen + 1);
|
|
vswprintf(zc.data(), zc.size(), zcFormat, vaArgs);
|
|
va_end(vaArgs);
|
|
|
|
wszMessage.assign(zc.data(), iLen);
|
|
|
|
#ifdef TEST_HARNESS
|
|
if (!hInstall)
|
|
{
|
|
MessageBox(NULL, pszMessage, wszMessage.c_str(), 0);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
PMSIHANDLE hRecord0 = MsiCreateRecord(1);
|
|
// field 0 is the template
|
|
MsiRecordSetString(hRecord0, 0, (level == MSI_INFO_LEVEL) ? L"VeraCryptCustomAction_INFO: [1]" : ((level == MSI_WARNING_LEVEL) ? L"VeraCryptCustomAction_WARNING: [1]" : L"VeraCryptCustomAction_ERROR: [1]"));
|
|
// field 1, to be placed in [1] placeholder
|
|
MsiRecordSetString(hRecord0, 1, wszMessage.c_str());
|
|
// send message to running installer
|
|
MsiProcessMessage(hInstall, INSTALLMESSAGE_INFO, hRecord0);
|
|
|
|
PMSIHANDLE hRecord1 = MsiCreateRecord(0);
|
|
MsiRecordSetString(hRecord1, 0, wszMessage.c_str());
|
|
if (level == MSI_INFO_LEVEL)
|
|
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_INFO + MB_OK), hRecord1);
|
|
else if (level == MSI_WARNING_LEVEL)
|
|
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord1);
|
|
else
|
|
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord1);
|
|
}
|
|
|
|
/* **************************************************************************** */
|
|
|
|
/*
|
|
* Defined in Dlgcode.c.
|
|
*/
|
|
extern void ExceptionHandlerThread (void *threadArg);
|
|
extern LONG __stdcall ExceptionHandler (EXCEPTION_POINTERS *ep);
|
|
extern void InvalidParameterHandler (const wchar_t *expression, const wchar_t *function, const wchar_t *file, unsigned int line, uintptr_t reserved);
|
|
extern BOOL SystemFileSelectorCallPending;
|
|
extern DWORD SystemFileSelectorCallerThreadId;
|
|
|
|
/* **************************************************************************** */
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, Applink() , but
|
|
* removed unnecessary code.
|
|
*/
|
|
void Applink_Dll (MSIHANDLE hInstaller, 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;
|
|
|
|
StringCbCopyW (installDir, sizeof (installDir), InstallationPath);
|
|
|
|
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, "sm4") == 0)
|
|
{
|
|
StringCbCopyW (page, sizeof (page),L"SM4.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);
|
|
}
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Applink_Dll: url(%s)", url);
|
|
|
|
if (IsAdmin ())
|
|
{
|
|
// TODO: FileExists always returns FALSE
|
|
// This is due to the fact that waccess does not like url encoded as 'file:///%sdocs/html/en/%s'.
|
|
// It fails with '0x0000007B: The filename, directory name, or volume label syntax is incorrect.'.
|
|
if (buildUrl && !FileExists (url))
|
|
{
|
|
// fallbacl to online resources
|
|
StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page);
|
|
SafeOpenURL (url);
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
// fallbacl to online resources
|
|
StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page);
|
|
ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, CheckCapsLock(), but
|
|
* replaced MessageBoxW() with MSILogAndShow().
|
|
*/
|
|
BOOL CheckCapsLock_Dll (MSIHANDLE hInstaller, BOOL quiet)
|
|
{
|
|
if ((GetKeyState(VK_CAPITAL) & 1) != 0)
|
|
{
|
|
MSILogAndShow(hInstaller, MSI_WARNING_LEVEL, GetString ("CAPSLOCK_ON"));
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, GetWrongPasswordErrorMessage(), but
|
|
* replaced CheckCapsLock() with CheckCapsLock_Dll().
|
|
*/
|
|
std::wstring GetWrongPasswordErrorMessage_Dll (MSIHANDLE hInstaller)
|
|
{
|
|
WCHAR szTmp[8192];
|
|
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_WRONG" : "PASSWORD_WRONG"));
|
|
if (CheckCapsLock_Dll (hInstaller, TRUE))
|
|
StringCbCatW (szTmp, sizeof(szTmp), GetString ("PASSWORD_WRONG_CAPSLOCK_ON"));
|
|
|
|
wstring msg = szTmp;
|
|
return msg;
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, HandleDriveNotReadyError(), but
|
|
* replaced Warning() with MSILogAndShow().
|
|
*/
|
|
void HandleDriveNotReadyError_Dll (MSIHANDLE hInstaller)
|
|
{
|
|
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)
|
|
{
|
|
MSILogAndShow (hInstaller, MSI_WARNING_LEVEL, GetString("SYS_AUTOMOUNT_DISABLED"));
|
|
}
|
|
else
|
|
MSILogAndShow (hInstaller, MSI_WARNING_LEVEL, GetString("DEVICE_NOT_READY_ERROR"));
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, handleWin32Error(), but
|
|
* replaced ErrorDirect(), Error() and MessageBoxW with MSILogAndShow(),
|
|
* replaced HandleDriveNotReadyError() with HandleDriveNotReadyError_Dll().
|
|
*/
|
|
DWORD handleWin32Error_Dll (MSIHANDLE hInstaller, const char* srcPos)
|
|
{
|
|
PWSTR lpMsgBuf;
|
|
DWORD dwError = GetLastError ();
|
|
wchar_t szErrorValue[32];
|
|
wchar_t* pszDesc;
|
|
|
|
if (dwError == 0 || dwError == ERROR_INVALID_WINDOW_HANDLE)
|
|
return dwError;
|
|
|
|
// Access denied
|
|
if (dwError == ERROR_ACCESS_DENIED && !IsAdmin ())
|
|
{
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("ERR_ACCESS_DENIED"), srcPos).c_str ());
|
|
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;
|
|
}
|
|
|
|
MSILogAndShow (hInstaller, MSI_INFO_LEVEL, AppendSrcPos (pszDesc, srcPos).c_str ());
|
|
if (lpMsgBuf) LocalFree (lpMsgBuf);
|
|
|
|
// User-friendly hardware error explanation
|
|
if (IsDiskError (dwError))
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString("ERR_HARDWARE_ERROR"));
|
|
|
|
// Device not ready
|
|
if (dwError == ERROR_NOT_READY)
|
|
HandleDriveNotReadyError_Dll(hInstaller);
|
|
|
|
SetLastError (dwError); // Preserve the original error code
|
|
|
|
return dwError;
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, handleError(), but
|
|
* replaced ErrorDirect(), Error() and MessageBoxW with MSILogAndShow(),
|
|
* replaced handleWin32Error() with handleWin32Error_Dll().
|
|
*/
|
|
void handleError_Dll (MSIHANDLE hInstaller, int code, const char* srcPos)
|
|
{
|
|
WCHAR szTmp[4096];
|
|
|
|
switch (code & 0x0000FFFF)
|
|
{
|
|
case ERR_OS_ERROR:
|
|
handleWin32Error_Dll (hInstaller, srcPos);
|
|
break;
|
|
case ERR_OUTOFMEMORY:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("OUTOFMEMORY"), srcPos).c_str());
|
|
break;
|
|
|
|
case ERR_PASSWORD_WRONG:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetWrongPasswordErrorMessage_Dll (hInstaller).c_str(), srcPos).c_str());
|
|
break;
|
|
|
|
case ERR_DRIVE_NOT_FOUND:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("NOT_FOUND"), srcPos).c_str());
|
|
break;
|
|
case ERR_FILES_OPEN:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("OPENFILES_DRIVER"), srcPos).c_str());
|
|
break;
|
|
case ERR_FILES_OPEN_LOCK:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("OPENFILES_LOCK"), srcPos).c_str());
|
|
break;
|
|
case ERR_VOL_SIZE_WRONG:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("VOL_SIZE_WRONG"), srcPos).c_str());
|
|
break;
|
|
case ERR_COMPRESSION_NOT_SUPPORTED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("COMPRESSION_NOT_SUPPORTED"), srcPos).c_str());
|
|
break;
|
|
case ERR_PASSWORD_CHANGE_VOL_TYPE:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("WRONG_VOL_TYPE"), srcPos).c_str());
|
|
break;
|
|
case ERR_VOL_SEEKING:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("VOL_SEEKING"), srcPos).c_str());
|
|
break;
|
|
case ERR_CIPHER_INIT_FAILURE:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("ERR_CIPHER_INIT_FAILURE"), srcPos).c_str());
|
|
break;
|
|
case ERR_CIPHER_INIT_WEAK_KEY:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("ERR_CIPHER_INIT_WEAK_KEY"), srcPos).c_str());
|
|
break;
|
|
case ERR_VOL_ALREADY_MOUNTED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("VOL_ALREADY_MOUNTED"), srcPos).c_str());
|
|
break;
|
|
case ERR_FILE_OPEN_FAILED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("FILE_OPEN_FAILED"), srcPos).c_str());
|
|
break;
|
|
case ERR_VOL_MOUNT_FAILED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("VOL_MOUNT_FAILED"), srcPos).c_str());
|
|
break;
|
|
case ERR_NO_FREE_DRIVES:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("NO_FREE_DRIVES"), srcPos).c_str());
|
|
break;
|
|
case ERR_ACCESS_DENIED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("ACCESS_DENIED"), srcPos).c_str());
|
|
break;
|
|
|
|
case ERR_DRIVER_VERSION:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString("DRIVER_VERSION"));
|
|
break;
|
|
|
|
case ERR_NEW_VERSION_REQUIRED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (GetString ("NEW_VERSION_REQUIRED"), srcPos).c_str());
|
|
break;
|
|
|
|
case ERR_SELF_TESTS_FAILED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString("ERR_SELF_TESTS_FAILED"));
|
|
break;
|
|
|
|
case ERR_VOL_FORMAT_BAD:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString ("ERR_VOL_FORMAT_BAD"));
|
|
break;
|
|
|
|
case ERR_ENCRYPTION_NOT_COMPLETED:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString ("ERR_ENCRYPTION_NOT_COMPLETED"));
|
|
break;
|
|
|
|
case ERR_NONSYS_INPLACE_ENC_INCOMPLETE:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString ("ERR_NONSYS_INPLACE_ENC_INCOMPLETE"));
|
|
break;
|
|
|
|
case ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString ("ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG"));
|
|
break;
|
|
|
|
case ERR_PARAMETER_INCORRECT:
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString ("ERR_PARAMETER_INCORRECT"));
|
|
break;
|
|
|
|
case ERR_USER_ABORT:
|
|
case ERR_DONT_REPORT:
|
|
// A non-error
|
|
break;
|
|
|
|
default:
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("ERR_UNKNOWN"), code);
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, AppendSrcPos (szTmp, srcPos).c_str());
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, LoadSystemDll() , but
|
|
* replaced AbortProcess() with MSILogAndShow() + return,
|
|
*/
|
|
static void LoadSystemDll_Dll (MSIHANDLE hInstaller, 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_Dll (hInstaller, srcPos);
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString ("INIT_DLL"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, handleWin32Error(), but
|
|
* replaced AbortProcess() with MSILogAndShow() + return,
|
|
*/
|
|
BOOL IsPagingFileActive_Dll (MSIHANDLE hInstaller, 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())
|
|
{
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString("UAC_INIT_ERROR"));
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Same as in Dlgcode.c, DoDriverInstall(), but
|
|
* replaced StatusMessage() with MSILog().
|
|
*/
|
|
BOOL DoDriverInstall_Dll (MSIHANDLE hInstaller)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin DoDriverInstall_Dll");
|
|
|
|
SC_HANDLE hManager, hService = NULL;
|
|
BOOL bOK = FALSE, bRet;
|
|
|
|
#ifdef SETUP
|
|
if (SystemEncryptionUpdate)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"SystemEncryptionUpdate == TRUE");
|
|
bOK = TRUE;
|
|
goto end;
|
|
}
|
|
#endif
|
|
|
|
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hManager == NULL)
|
|
goto error;
|
|
|
|
#ifdef SETUP
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString("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
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString("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_Dll (hInstaller, SRC_POS);
|
|
MSILogAndShow(hInstaller, MSI_ERROR_LEVEL, GetString("DRIVER_INSTALL_FAILED"));
|
|
}
|
|
else
|
|
bOK = TRUE;
|
|
|
|
if (hService != NULL)
|
|
CloseServiceHandle (hService);
|
|
|
|
if (hManager != NULL)
|
|
CloseServiceHandle (hManager);
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End DoDriverInstall_Dll");
|
|
return bOK;
|
|
}
|
|
|
|
/* **************************************************************************** */
|
|
|
|
/*
|
|
* Same as in Setup.c, StartStopService(), but
|
|
* replaced StatusMessage() with MSILog().
|
|
*/
|
|
BOOL StartStopService_Dll (MSIHANDLE hInstaller, wchar_t *lpszService, BOOL bStart, DWORD argc, LPCWSTR* argv)
|
|
{
|
|
SC_HANDLE hManager, hService = NULL;
|
|
BOOL bOK = FALSE, bRet;
|
|
SERVICE_STATUS status = {0};
|
|
int x;
|
|
DWORD dwExpectedState = bStart? SERVICE_RUNNING : SERVICE_STOPPED;
|
|
|
|
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hManager == NULL)
|
|
goto error;
|
|
|
|
hService = OpenService (hManager, lpszService, SERVICE_ALL_ACCESS);
|
|
if (hService == NULL)
|
|
goto error;
|
|
|
|
if (bStart)
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"STARTING %s", lpszService);
|
|
else
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"STOPPING %s", lpszService);
|
|
|
|
if (bStart)
|
|
{
|
|
if (!StartService (hService, argc, argv) && (GetLastError () != ERROR_SERVICE_ALREADY_RUNNING))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"Failed to start %s. Error 0x%.8X", lpszService, GetLastError ());
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
ControlService (hService, SERVICE_CONTROL_STOP, &status);
|
|
|
|
for (x = 0; x < WAIT_PERIOD; x++)
|
|
{
|
|
bRet = QueryServiceStatus (hService, &status);
|
|
if (bRet != TRUE)
|
|
goto error;
|
|
|
|
if (status.dwCurrentState == dwExpectedState)
|
|
break;
|
|
|
|
Sleep (1000);
|
|
}
|
|
|
|
bRet = QueryServiceStatus (hService, &status);
|
|
if (bRet != TRUE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"Failed to query status of %s. Error 0x%.8X", lpszService, GetLastError ());
|
|
goto error;
|
|
}
|
|
|
|
if (status.dwCurrentState != dwExpectedState)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"Current state of %s (0x%.8X) is different from expected one (0x%.8X).", lpszService, status.dwCurrentState, dwExpectedState);
|
|
goto error;
|
|
}
|
|
|
|
bOK = TRUE;
|
|
|
|
error:
|
|
|
|
if (bOK == FALSE && GetLastError () == ERROR_SERVICE_DOES_NOT_EXIST)
|
|
{
|
|
bOK = TRUE;
|
|
}
|
|
|
|
if (hService != NULL)
|
|
CloseServiceHandle (hService);
|
|
|
|
if (hManager != NULL)
|
|
CloseServiceHandle (hManager);
|
|
|
|
return bOK;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c, SetSystemRestorePoint(), but
|
|
* replaced StatusMessage() with MSILog().
|
|
*/
|
|
static void SetSystemRestorePoint_Dll (MSIHANDLE hInstaller, BOOL finalize)
|
|
{
|
|
static RESTOREPOINTINFO RestPtInfo;
|
|
static STATEMGRSTATUS SMgrStatus;
|
|
static BOOL failed = FALSE;
|
|
static BOOL (__stdcall *_SRSetRestorePoint)(PRESTOREPOINTINFO, PSTATEMGRSTATUS);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin SetSystemRestorePoint_Dll");
|
|
|
|
if (!SystemRestoreDll)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"SystemRestoreDll NULL");
|
|
goto end;
|
|
}
|
|
|
|
_SRSetRestorePoint = (BOOL (__stdcall *)(PRESTOREPOINTINFO, PSTATEMGRSTATUS))GetProcAddress (SystemRestoreDll,"SRSetRestorePointW");
|
|
if (_SRSetRestorePoint == 0)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"_SRSetRestorePoint NULL");
|
|
FreeLibrary (SystemRestoreDll);
|
|
SystemRestoreDll = 0;
|
|
goto end;
|
|
}
|
|
|
|
if (!finalize)
|
|
{
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString("CREATING_SYS_RESTORE"));
|
|
|
|
RestPtInfo.dwEventType = BEGIN_SYSTEM_CHANGE;
|
|
RestPtInfo.dwRestorePtType = bUninstall ? APPLICATION_UNINSTALL : APPLICATION_INSTALL | DEVICE_DRIVER_INSTALL;
|
|
RestPtInfo.llSequenceNumber = 0;
|
|
StringCbCopyW (RestPtInfo.szDescription, sizeof(RestPtInfo.szDescription), bUninstall ? L"VeraCrypt uninstallation" : L"VeraCrypt installation");
|
|
|
|
if(!_SRSetRestorePoint (&RestPtInfo, &SMgrStatus))
|
|
{
|
|
MSILog (hInstaller, MSI_ERROR_LEVEL, GetString("FAILED_SYS_RESTORE"));
|
|
failed = TRUE;
|
|
}
|
|
}
|
|
else if (!failed)
|
|
{
|
|
RestPtInfo.dwEventType = END_SYSTEM_CHANGE;
|
|
RestPtInfo.llSequenceNumber = SMgrStatus.llSequenceNumber;
|
|
|
|
if(!_SRSetRestorePoint(&RestPtInfo, &SMgrStatus))
|
|
{
|
|
MSILog (hInstaller, MSI_ERROR_LEVEL, GetString("FAILED_SYS_RESTORE"));
|
|
}
|
|
}
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End SetSystemRestorePoint_Dll");
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c, DoDriverUnload(), but
|
|
* replaced AbortProcess() and AbortProcessSilent() with MSILogAndShow() + return,
|
|
* replaced Error(), MessageBoxW() with MSILogAndShow(),
|
|
* replaced StatusMessage() with MSILog(),
|
|
* replaced handleWin32Error() with handleWin32Error_Dll().
|
|
*/
|
|
BOOL DoDriverUnload_Dll (MSIHANDLE hInstaller, HWND hwnd)
|
|
{
|
|
BOOL bOK = TRUE;
|
|
int status = 0;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin DoDriverUnload_Dll");
|
|
|
|
status = DriverAttach ();
|
|
if (status != 0)
|
|
{
|
|
if (status == ERR_OS_ERROR && GetLastError () != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
handleWin32Error_Dll (hInstaller, SRC_POS);
|
|
MSILogAndShow(hInstaller, MSI_ERROR_LEVEL, GetString("NODRIVER"));
|
|
bOK = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
if (status != ERR_OS_ERROR)
|
|
{
|
|
handleError_Dll (hInstaller, status, SRC_POS);
|
|
MSILogAndShow(hInstaller, MSI_ERROR_LEVEL, GetString("NODRIVER"));
|
|
bOK = FALSE;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (hDriver != INVALID_HANDLE_VALUE)
|
|
{
|
|
LONG driverVersion = VERSION_NUM;
|
|
int refCount;
|
|
DWORD dwResult;
|
|
BOOL bResult;
|
|
|
|
// Try to determine if it's upgrade (and not reinstall, downgrade, or first-time install).
|
|
DetermineUpgradeDowngradeStatus (FALSE, &driverVersion);
|
|
|
|
// Test for encrypted boot drive
|
|
try
|
|
{
|
|
BootEncryption bootEnc (hwnd);
|
|
if (bootEnc.GetDriverServiceStartType() == SERVICE_BOOT_START)
|
|
{
|
|
try
|
|
{
|
|
// Check hidden OS update consistency
|
|
if (IsHiddenOSRunning())
|
|
{
|
|
if (bootEnc.GetInstalledBootLoaderVersion() != VERSION_NUM)
|
|
{
|
|
if (AskWarnNoYes ("UPDATE_TC_IN_DECOY_OS_FIRST", hwnd) == IDNO)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"User denied request");
|
|
bOK = FALSE;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (...) { }
|
|
|
|
if (bUninstallInProgress && !bootEnc.GetStatus().DriveMounted)
|
|
{
|
|
try { bootEnc.RegisterFilterDriver (false, BootEncryption::DriveFilter); } catch (...) { }
|
|
try { bootEnc.RegisterFilterDriver (false, BootEncryption::VolumeFilter); } catch (...) { }
|
|
try { bootEnc.RegisterFilterDriver (false, BootEncryption::DumpFilter); } catch (...) { }
|
|
bootEnc.SetDriverServiceStartType (SERVICE_SYSTEM_START);
|
|
}
|
|
else if (bUninstallInProgress || bDowngrade)
|
|
{
|
|
MSILogAndShow(hInstaller, MSI_ERROR_LEVEL, (bDowngrade ? GetString("SETUP_FAILED_BOOT_DRIVE_ENCRYPTED_DOWNGRADE") : GetString("SETUP_FAILED_BOOT_DRIVE_ENCRYPTED")));
|
|
bOK = FALSE;
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
if (CurrentOSMajor == 6 && CurrentOSMinor == 0 && CurrentOSServicePack < 1)
|
|
{
|
|
MSILogAndShow(hInstaller, MSI_ERROR_LEVEL, GetString("SYS_ENCRYPTION_UPGRADE_UNSUPPORTED_ON_VISTA_SP0"));
|
|
bOK = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
// check if we are upgrading a system encrypted with unsupported algorithms
|
|
if (bootEnc.IsUsingUnsupportedAlgorithm(driverVersion))
|
|
{
|
|
MSILogAndShow(hInstaller, MSI_ERROR_LEVEL, GetString("SYS_ENCRYPTION_UPGRADE_UNSUPPORTED_ALGORITHM"));
|
|
bOK = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
SystemEncryptionUpdate = TRUE;
|
|
PortableMode = FALSE;
|
|
}
|
|
}
|
|
}
|
|
catch (...) { }
|
|
|
|
if (!bUninstall
|
|
&& (bUpgrade || SystemEncryptionUpdate)
|
|
&& (!bDevm || SystemEncryptionUpdate))
|
|
{
|
|
UnloadDriver = FALSE;
|
|
}
|
|
|
|
if (PortableMode && !SystemEncryptionUpdate)
|
|
UnloadDriver = TRUE;
|
|
|
|
if (UnloadDriver)
|
|
{
|
|
int volumesMounted = 0;
|
|
|
|
// Check mounted volumes
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_IS_ANY_VOLUME_MOUNTED, NULL, 0, &volumesMounted, sizeof (volumesMounted), &dwResult, NULL);
|
|
|
|
if (bResult)
|
|
{
|
|
if (volumesMounted != 0)
|
|
{
|
|
bOK = FALSE;
|
|
MSILogAndShow(hInstaller, MSI_WARNING_LEVEL, GetString ("UNMOUNT_ALL_FIRST"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bOK = FALSE;
|
|
handleWin32Error_Dll (hInstaller, SRC_POS);
|
|
}
|
|
}
|
|
|
|
// Try to close all open TC windows
|
|
if (bOK)
|
|
{
|
|
BOOL TCWindowClosed = FALSE;
|
|
|
|
EnumWindows (CloseTCWindowsEnum, (LPARAM) &TCWindowClosed);
|
|
|
|
if (TCWindowClosed)
|
|
Sleep (2000);
|
|
|
|
// stop service
|
|
if (SystemEncryptionUpdate)
|
|
{
|
|
StartStopService_Dll (hInstaller, TC_SYSTEM_FAVORITES_SERVICE_NAME, FALSE, 0, NULL);
|
|
}
|
|
}
|
|
|
|
// Test for any applications attached to driver
|
|
if (!bUpgrade)
|
|
{
|
|
bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DEVICE_REFCOUNT, &refCount, sizeof (refCount), &refCount,
|
|
sizeof (refCount), &dwResult, NULL);
|
|
|
|
if (bOK && bResult && refCount > 1)
|
|
{
|
|
MSILogAndShow(hInstaller, MSI_WARNING_LEVEL, GetString ("CLOSE_TC_FIRST"));
|
|
bOK = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!bOK || UnloadDriver)
|
|
{
|
|
CloseHandle (hDriver);
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Note that the driver may have already been unloaded during this session (e.g. retry after an error, etc.) so it is not
|
|
// guaranteed that the user is installing VeraCrypt for the first time now (we also cannot know if the user has already
|
|
// installed and used VeraCrypt on another system before).
|
|
bPossiblyFirstTimeInstall = TRUE;
|
|
}
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End DoDriverUnload_Dll");
|
|
return bOK;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c, DoServiceUninstall(), but
|
|
* replaced AbortProcess() and AbortProcessSilent() with MSILogAndShow() + return,
|
|
* replaced Error(), MessageBoxW() with MSILogAndShow(),
|
|
* replaced StatusMessage() with MSILog(),
|
|
* replaced handleWin32Error() with handleWin32Error_Dll().
|
|
*/
|
|
BOOL DoServiceUninstall_Dll (MSIHANDLE hInstaller, HWND hwndDlg, wchar_t *lpszService)
|
|
{
|
|
SC_HANDLE hManager, hService = NULL;
|
|
BOOL bOK = FALSE, bRet;
|
|
SERVICE_STATUS status;
|
|
BOOL firstTry = TRUE;
|
|
int x;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin DoServiceUninstall_Dll");
|
|
|
|
memset (&status, 0, sizeof (status)); /* Keep VC6 quiet */
|
|
|
|
retry:
|
|
|
|
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hManager == NULL)
|
|
goto error;
|
|
|
|
hService = OpenService (hManager, lpszService, SERVICE_ALL_ACCESS);
|
|
if (hService == NULL)
|
|
goto error;
|
|
|
|
if (wcscmp (L"veracrypt", lpszService) == 0)
|
|
{
|
|
try
|
|
{
|
|
BootEncryption bootEnc (hwndDlg);
|
|
if (bootEnc.GetDriverServiceStartType() == SERVICE_BOOT_START)
|
|
{
|
|
try { bootEnc.RegisterFilterDriver (false, BootEncryption::DriveFilter); } catch (...) { }
|
|
try { bootEnc.RegisterFilterDriver (false, BootEncryption::VolumeFilter); } catch (...) { }
|
|
try { bootEnc.RegisterFilterDriver (false, BootEncryption::DumpFilter); } catch (...) { }
|
|
}
|
|
}
|
|
catch (...) { }
|
|
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString("STOPPING_DRIVER"));
|
|
}
|
|
else
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, L"STOPPING %s", lpszService);
|
|
|
|
for (x = 0; x < WAIT_PERIOD; x++)
|
|
{
|
|
bRet = QueryServiceStatus (hService, &status);
|
|
if (bRet != TRUE)
|
|
goto error;
|
|
|
|
if (status.dwCurrentState != SERVICE_START_PENDING &&
|
|
status.dwCurrentState != SERVICE_STOP_PENDING &&
|
|
status.dwCurrentState != SERVICE_CONTINUE_PENDING)
|
|
break;
|
|
|
|
Sleep (1000);
|
|
}
|
|
|
|
if (status.dwCurrentState != SERVICE_STOPPED)
|
|
{
|
|
bRet = ControlService (hService, SERVICE_CONTROL_STOP, &status);
|
|
if (bRet == FALSE)
|
|
goto try_delete;
|
|
|
|
for (x = 0; x < WAIT_PERIOD; x++)
|
|
{
|
|
bRet = QueryServiceStatus (hService, &status);
|
|
if (bRet != TRUE)
|
|
goto error;
|
|
|
|
if (status.dwCurrentState != SERVICE_START_PENDING &&
|
|
status.dwCurrentState != SERVICE_STOP_PENDING &&
|
|
status.dwCurrentState != SERVICE_CONTINUE_PENDING)
|
|
break;
|
|
|
|
Sleep (1000);
|
|
}
|
|
|
|
if (status.dwCurrentState != SERVICE_STOPPED && status.dwCurrentState != SERVICE_STOP_PENDING)
|
|
goto error;
|
|
}
|
|
|
|
try_delete:
|
|
|
|
if (wcscmp (L"veracrypt", lpszService) == 0)
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString("REMOVING_DRIVER"));
|
|
else
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", lpszService);
|
|
|
|
if (hService != NULL)
|
|
{
|
|
CloseServiceHandle (hService);
|
|
hService = NULL;
|
|
}
|
|
|
|
if (hManager != NULL)
|
|
{
|
|
CloseServiceHandle (hManager);
|
|
hManager = NULL;
|
|
}
|
|
|
|
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hManager == NULL)
|
|
goto error;
|
|
|
|
hService = OpenService (hManager, lpszService, SERVICE_ALL_ACCESS);
|
|
if (hService == NULL)
|
|
goto error;
|
|
|
|
bRet = DeleteService (hService);
|
|
if (bRet == FALSE)
|
|
{
|
|
if (firstTry && GetLastError () == ERROR_SERVICE_MARKED_FOR_DELETE)
|
|
{
|
|
// Second try for an eventual no-install driver instance
|
|
CloseServiceHandle (hService);
|
|
CloseServiceHandle (hManager);
|
|
hService = NULL;
|
|
hManager = NULL;
|
|
|
|
Sleep(1000);
|
|
firstTry = FALSE;
|
|
goto retry;
|
|
}
|
|
|
|
goto error;
|
|
}
|
|
|
|
bOK = TRUE;
|
|
|
|
error:
|
|
|
|
if (bOK == FALSE && GetLastError ()!= ERROR_SERVICE_DOES_NOT_EXIST)
|
|
{
|
|
handleWin32Error_Dll (hInstaller, SRC_POS);
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString("DRIVER_UINSTALL_FAILED"));
|
|
}
|
|
else
|
|
bOK = TRUE;
|
|
|
|
if (hService != NULL)
|
|
CloseServiceHandle (hService);
|
|
|
|
if (hManager != NULL)
|
|
CloseServiceHandle (hManager);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End DoServiceUninstall_Dll");
|
|
return bOK;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c, DoRegUninstall(), but
|
|
* replaced StatusMessage() with MSILog(),
|
|
* removed unnecessary code that is done by MSI.
|
|
*/
|
|
BOOL DoRegUninstall_Dll (MSIHANDLE hInstaller, BOOL bRemoveDeprecated)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin DoRegUninstall_Dll");
|
|
|
|
wchar_t regk [64];
|
|
typedef LSTATUS (WINAPI *RegDeleteKeyExWFn) (HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,WORD Reserved);
|
|
RegDeleteKeyExWFn RegDeleteKeyExWPtr = NULL;
|
|
HMODULE hAdvapiDll = LoadLibrary (L"Advapi32.dll");
|
|
if (hAdvapiDll)
|
|
{
|
|
RegDeleteKeyExWPtr = (RegDeleteKeyExWFn) GetProcAddress(hAdvapiDll, "RegDeleteKeyExW");
|
|
}
|
|
|
|
// Unregister COM servers
|
|
if (!bRemoveDeprecated)
|
|
{
|
|
if (!UnregisterComServers (InstallationPath))
|
|
MSILog (hInstaller, MSI_ERROR_LEVEL, GetString("COM_DEREG_FAILED"));
|
|
}
|
|
|
|
if (!bRemoveDeprecated)
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString("REMOVING_REG"));
|
|
|
|
/* The following is done by MSI, so we skip it */
|
|
/*
|
|
if (RegDeleteKeyExWPtr)
|
|
{
|
|
RegDeleteKeyExWPtr (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", KEY_WOW64_32KEY, 0);
|
|
RegDeleteKeyExWPtr (HKEY_CURRENT_USER, L"Software\\VeraCrypt", KEY_WOW64_32KEY, 0);
|
|
}
|
|
else
|
|
{
|
|
RegDeleteKey (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt");
|
|
RegDeleteKey (HKEY_LOCAL_MACHINE, L"Software\\VeraCrypt");
|
|
}
|
|
RegDeleteKey (HKEY_LOCAL_MACHINE, L"Software\\Classes\\VeraCryptVolume\\Shell\\open\\command");
|
|
RegDeleteKey (HKEY_LOCAL_MACHINE, L"Software\\Classes\\VeraCryptVolume\\Shell\\open");
|
|
RegDeleteKey (HKEY_LOCAL_MACHINE, L"Software\\Classes\\VeraCryptVolume\\Shell");
|
|
RegDeleteKey (HKEY_LOCAL_MACHINE, L"Software\\Classes\\VeraCryptVolume\\DefaultIcon");
|
|
RegDeleteKey (HKEY_LOCAL_MACHINE, L"Software\\Classes\\VeraCryptVolume");
|
|
*/
|
|
|
|
if (!bRemoveDeprecated)
|
|
{
|
|
HKEY hKey;
|
|
|
|
GetStartupRegKeyName (regk, sizeof(regk));
|
|
DeleteRegistryValue (regk, L"VeraCrypt");
|
|
|
|
// The following is done by MSI, so we skip it
|
|
// DeleteRegistryKey (HKEY_LOCAL_MACHINE, L"Software\\Classes\\.hc");
|
|
|
|
// enable the SE_TAKE_OWNERSHIP_NAME privilege for this operation
|
|
SetPrivilege (SE_TAKE_OWNERSHIP_NAME, TRUE);
|
|
|
|
// clean MuiCache list from VeraCrypt entries
|
|
SearchAndDeleteRegistrySubString (HKEY_CLASSES_ROOT, L"Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache", L"VeraCrypt", FALSE, NULL);
|
|
|
|
// clean other VeraCrypt entries from all users
|
|
SearchAndDeleteRegistrySubString (HKEY_USERS, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\.hc", NULL, TRUE, NULL);
|
|
SearchAndDeleteRegistrySubString (HKEY_USERS, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Compatibility Assistant\\Persisted", L"VeraCrypt", TRUE, NULL);
|
|
SearchAndDeleteRegistrySubString (HKEY_USERS, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartPage\\NewShortcuts", L"VeraCrypt", TRUE, NULL);
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM", 0, KEY_ALL_ACCESS | WRITE_DAC | WRITE_OWNER, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
SearchAndDeleteRegistrySubString (hKey, L"Enum\\Root\\LEGACY_VERACRYPT", NULL, TRUE, L"ControlSet");
|
|
SearchAndDeleteRegistrySubString (hKey, L"services\\veracrypt", NULL, TRUE, L"ControlSet");
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
// disable the SE_TAKE_OWNERSHIP_NAME privilege for this operation
|
|
SetPrivilege (SE_TAKE_OWNERSHIP_NAME, FALSE);
|
|
|
|
// The following is done by MSI, so we skip it
|
|
//SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
|
|
}
|
|
|
|
if (hAdvapiDll)
|
|
FreeLibrary (hAdvapiDll);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End DoRegUninstall_Dll");
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Same as in Setup.c, UpgradeBootLoader(), but
|
|
* replaced StatusMessage() with MSILog().
|
|
*/
|
|
BOOL UpgradeBootLoader_Dll (MSIHANDLE hInstaller, HWND hwndDlg)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin UpgradeBootLoader_Dll");
|
|
|
|
BOOL bOK = FALSE, bNeedUnloadDriver = FALSE;
|
|
int status;
|
|
|
|
if (!SystemEncryptionUpdate)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"SystemEncryptionUpdate == FALSE");
|
|
bOK = TRUE;
|
|
goto end;
|
|
}
|
|
|
|
if (hDriver == INVALID_HANDLE_VALUE)
|
|
{
|
|
status = DriverAttach();
|
|
if ((status == 0) && (hDriver != INVALID_HANDLE_VALUE))
|
|
{
|
|
bNeedUnloadDriver = TRUE;
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"UpgradeBootLoader_Dll: failed to attach to driver");
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
BootEncryption bootEnc (hwndDlg);
|
|
uint64 bootLoaderVersion = bootEnc.GetInstalledBootLoaderVersion();
|
|
if ((bootLoaderVersion < VERSION_NUM) || (bReinstallMode && (bootLoaderVersion == VERSION_NUM)))
|
|
{
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString("INSTALLER_UPDATING_BOOT_LOADER"));
|
|
|
|
// this is done by the service now
|
|
//bootEnc.InstallBootLoader (true);
|
|
|
|
if (bootEnc.GetInstalledBootLoaderVersion() <= TC_RESCUE_DISK_UPGRADE_NOTICE_MAX_VERSION)
|
|
{
|
|
bUpdateRescueDisk = TRUE;
|
|
MSILog (hInstaller, MSI_INFO_LEVEL, GetString(IsHiddenOSRunning() ? "BOOT_LOADER_UPGRADE_OK_HIDDEN_OS" : "BOOT_LOADER_UPGRADE_OK"));
|
|
}
|
|
}
|
|
bOK = TRUE;
|
|
goto end;
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
e.Show (hwndDlg);
|
|
}
|
|
catch (...) { }
|
|
|
|
MSILog (hInstaller, MSI_ERROR_LEVEL, GetString("BOOT_LOADER_UPGRADE_FAILED"));
|
|
|
|
end:
|
|
if (bNeedUnloadDriver)
|
|
{
|
|
CloseHandle (hDriver);
|
|
hDriver = INVALID_HANDLE_VALUE;
|
|
}
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End UpgradeBootLoader_Dll");
|
|
return bOK;
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function DoApplicationDataUninstall(), but
|
|
* replaced StatusMessage() and RemoveMessage() with MSILog().
|
|
*/
|
|
BOOL DoApplicationDataUninstall_Dll (MSIHANDLE hInstaller)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin DoApplicationDataUninstall");
|
|
|
|
wchar_t path[MAX_PATH];
|
|
wchar_t path2[MAX_PATH];
|
|
BOOL bOK = TRUE;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, GetString("REMOVING_APPDATA"));
|
|
|
|
SHGetFolderPath (NULL, CSIDL_APPDATA, NULL, 0, path);
|
|
StringCbCatW (path, sizeof(path), L"\\VeraCrypt\\");
|
|
|
|
// Delete favorite volumes file
|
|
StringCbPrintfW (path2, sizeof(path2), L"%s%s", path, TC_APPD_FILENAME_FAVORITE_VOLUMES);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path2);
|
|
StatDeleteFile (path2, FALSE);
|
|
|
|
// Delete keyfile defaults
|
|
StringCbPrintfW (path2, sizeof(path2), L"%s%s", path, TC_APPD_FILENAME_DEFAULT_KEYFILES);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path2);
|
|
StatDeleteFile (path2, FALSE);
|
|
|
|
// Delete history file
|
|
StringCbPrintfW (path2, sizeof(path2), L"%s%s", path, TC_APPD_FILENAME_HISTORY);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path2);
|
|
StatDeleteFile (path2, FALSE);
|
|
|
|
// Delete configuration file
|
|
StringCbPrintfW (path2, sizeof(path2), L"%s%s", path, TC_APPD_FILENAME_CONFIGURATION);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path2);
|
|
StatDeleteFile (path2, FALSE);
|
|
|
|
// Delete system encryption configuration file
|
|
StringCbPrintfW (path2, sizeof(path2), L"%s%s", path, TC_APPD_FILENAME_SYSTEM_ENCRYPTION);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path2);
|
|
StatDeleteFile (path2, FALSE);
|
|
|
|
SHGetFolderPath (NULL, CSIDL_APPDATA, NULL, 0, path);
|
|
StringCbCatW (path, sizeof(path), L"\\VeraCrypt");
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path);
|
|
if (!StatRemoveDirectory (path))
|
|
{
|
|
handleWin32Error_Dll (hInstaller, SRC_POS);
|
|
bOK = FALSE;
|
|
}
|
|
|
|
// remove VeraCrypt under common appdata
|
|
if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path)))
|
|
{
|
|
StringCbCatW (path, sizeof(path), L"\\VeraCrypt");
|
|
|
|
// Delete original bootloader
|
|
StringCbPrintfW (path2, sizeof(path2), L"%s\\%s", path, TC_SYS_BOOT_LOADER_BACKUP_NAME);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path2);
|
|
StatDeleteFile (path2, FALSE);
|
|
|
|
// remove VeraCrypt folder
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"REMOVING %s", path);
|
|
StatRemoveDirectory (path);
|
|
}
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End DoApplicationDataUninstall");
|
|
return bOK;
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function DoUninstall(), but
|
|
* removed uninstall of files and registry as it will be
|
|
* done by MSI.
|
|
*/
|
|
BOOL DoUninstall_Dll (MSIHANDLE hInstaller, HWND hwndDlg)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin DoUninstall_Dll");
|
|
|
|
BOOL bOK = TRUE;
|
|
BOOL bTempSkipSysRestore = FALSE;
|
|
|
|
if (DoDriverUnload_Dll (hInstaller, hwndDlg) == FALSE)
|
|
{
|
|
bOK = FALSE;
|
|
bTempSkipSysRestore = TRUE; // Volumes are possibly mounted; defer System Restore point creation for this uninstall attempt.
|
|
}
|
|
else
|
|
{
|
|
if (!Rollback && bSystemRestore && !bTempSkipSysRestore)
|
|
SetSystemRestorePoint_Dll (hInstaller, FALSE);
|
|
|
|
if (DoServiceUninstall_Dll (hInstaller, hwndDlg, L"veracrypt") == FALSE)
|
|
{
|
|
bOK = FALSE;
|
|
}
|
|
else if (DoRegUninstall_Dll (hInstaller, FALSE) == FALSE)
|
|
{
|
|
bOK = FALSE;
|
|
}
|
|
/* Following skipped because done by MSI */
|
|
/*
|
|
else if (DoFilesInstall ((HWND) hwndDlg, InstallationPath) == FALSE)
|
|
{
|
|
bOK = FALSE;
|
|
}
|
|
else if (DoShortcutsUninstall (hwndDlg, InstallationPath) == FALSE)
|
|
{
|
|
bOK = FALSE;
|
|
}
|
|
*/
|
|
else if (!DoApplicationDataUninstall_Dll (hInstaller))
|
|
{
|
|
bOK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Deprecated service
|
|
DoServiceUninstall_Dll (hInstaller, hwndDlg, L"VeraCryptService");
|
|
}
|
|
}
|
|
|
|
if (Rollback)
|
|
goto end;
|
|
|
|
if (bSystemRestore && !bTempSkipSysRestore)
|
|
SetSystemRestorePoint_Dll (hInstaller, TRUE);
|
|
|
|
if (!bOK)
|
|
bUninstallInProgress = FALSE;
|
|
|
|
end:
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End DoUninstall_Dll");
|
|
return bOK;
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function InitApp(), but
|
|
* replaced unnecessary calls,
|
|
* forced english as language,
|
|
* replaced LoadLanguageFile() with LoadLanguageFromResource() to be able to set bForceSilent.
|
|
*/
|
|
BOOL InitDll (MSIHANDLE hInstaller)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin InitDll");
|
|
|
|
BOOL bOK = TRUE;
|
|
|
|
InitOSVersionInfo();
|
|
InitGlobalLocks ();
|
|
|
|
SetErrorMode (SetErrorMode (0) | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
|
|
|
// Force language to english to read strings from the default Language.xml embedded in the DLL.
|
|
SetPreferredLangId ("en");
|
|
bUserSetLanguage = TRUE;
|
|
LoadLanguageFromResource (0, FALSE, TRUE);
|
|
|
|
SetUnhandledExceptionFilter (ExceptionHandler);
|
|
_set_invalid_parameter_handler (InvalidParameterHandler);
|
|
RemoteSession = GetSystemMetrics (SM_REMOTESESSION) != 0;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End InitDll");
|
|
return bOK;
|
|
}
|
|
|
|
/* **************************************************************************** */
|
|
|
|
/*
|
|
* Same as Setup.c, function wWinMain(), but
|
|
* replaced unnecessary calls.
|
|
* This should be called at the beginning of each operation (install, uninstall...),
|
|
* before atexit(VC_CustomAction_Cleanup()) call.
|
|
*/
|
|
BOOL VC_CustomAction_Init(MSIHANDLE hInstaller, const wchar_t* szInstallDir)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_Init");
|
|
|
|
BOOL bOK = TRUE;
|
|
|
|
if (!InitDll(hInstaller))
|
|
{
|
|
bOK = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
// System Restore
|
|
if (IsSystemRestoreEnabled ())
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"System Restore is enabled");
|
|
|
|
wchar_t dllPath[MAX_PATH];
|
|
if (GetSystemDirectory (dllPath, MAX_PATH))
|
|
{
|
|
StringCbCatW(dllPath, sizeof(dllPath), L"\\srclient.dll");
|
|
}
|
|
else
|
|
StringCbCopyW(dllPath, sizeof(dllPath), L"C:\\Windows\\System32\\srclient.dll");
|
|
SystemRestoreDll = LoadLibrary (dllPath);
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"System Restore is not enabled");
|
|
SystemRestoreDll = 0;
|
|
}
|
|
|
|
// Set InstallationPath
|
|
wcsncpy(InstallationPath, szInstallDir, min(wcslen(szInstallDir), ARRAYSIZE(InstallationPath)));
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_Init");
|
|
return bOK;
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function localcleanup(), but
|
|
* replaced unnecessary calls.
|
|
* This should be called at the beginning of each operation (install, uninstall...),
|
|
* as an argument to atexit() before VC_CustomAction_Init() call.
|
|
*/
|
|
void VC_CustomAction_Cleanup ()
|
|
{
|
|
//MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_Cleanup");
|
|
|
|
/* 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);
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
CoUninitialize ();
|
|
|
|
CloseSysEncMutex ();
|
|
|
|
FinalizeGlobalLocks ();
|
|
|
|
//MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_Cleanup");
|
|
}
|
|
|
|
void Tokenize(const wchar_t* szInput, std::vector<std::wstring>& szTokens)
|
|
{
|
|
std::wstringstream check(szInput);
|
|
std::wstring intermediate;
|
|
while(std::getline(check, intermediate, L'?'))
|
|
{
|
|
szTokens.push_back(intermediate);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function DoInstall(), but
|
|
* without the actual installation, it only prepares the system
|
|
* before the installation (before DoFilesInstall).
|
|
* It runs as a Deferred CA.
|
|
*/
|
|
EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PreInstall(MSIHANDLE hInstaller)
|
|
{
|
|
HWND hwndDlg = NULL;
|
|
std::wstring szValueBuf = L"";
|
|
DWORD cchValueBuf = 0;
|
|
UINT uiStat = 0;
|
|
HKEY hkey = 0;
|
|
DWORD dw = 0;
|
|
BootEncryption bootEnc(NULL);
|
|
std::wstring szInstallDir = L"";
|
|
UINT uiRet = ERROR_INSTALL_FAILURE;
|
|
BOOL bOK = TRUE;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_PreInstall");
|
|
|
|
// Get UILevel to see whether we're being installed silently or not.
|
|
// Also get INSTALLDIR to see where we're being installed.
|
|
// Since this is a Deferred CA, they are to be setup in its CustomActionData.
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), (LPWSTR)TEXT(""), &cchValueBuf);
|
|
if (ERROR_MORE_DATA == uiStat)
|
|
{
|
|
++cchValueBuf; // add 1 for null termination
|
|
szValueBuf.resize(cchValueBuf);
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), &szValueBuf[0], &cchValueBuf);
|
|
if ((ERROR_SUCCESS == uiStat))
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreInstall: CustomActionData = '%s'", szValueBuf.c_str());
|
|
|
|
std::vector<std::wstring> szTokens;
|
|
Tokenize(szValueBuf.c_str(), szTokens);
|
|
|
|
for (size_t i = 0; i < szTokens.size(); i++)
|
|
{
|
|
std::wstring szToken = szTokens[i];
|
|
|
|
if (wcsncmp(szToken.c_str(), L"UILEVEL=", wcslen(L"UILEVEL=")) == 0)
|
|
{
|
|
size_t index0 = szToken.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
std::wstring uiLevel = szToken.substr(index0 + 1);
|
|
Silent = (stoi(uiLevel) <= 3);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreInstall: UILEVEL = '%s', bSilent = '%d'", uiLevel.c_str(), Silent);
|
|
}
|
|
}
|
|
else if (wcsncmp(szToken.c_str(), L"INSTALLDIR=", wcslen(L"INSTALLDIR=")) == 0)
|
|
{
|
|
size_t index0 = szToken.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
szInstallDir = szToken.substr(index0 + 1);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreInstall: INSTALLDIR = '%s'", szInstallDir.c_str());
|
|
}
|
|
}
|
|
else if (wcsncmp(szToken.c_str(), L"REINSTALL=", wcslen(L"REINSTALL=")) == 0)
|
|
{
|
|
size_t index0 = szToken.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
std::wstring szReinstall = szToken.substr(index0 + 1);
|
|
bRepairMode = (wcslen(szReinstall.c_str()) != 0);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreInstall: REINSTALL = '%s', bRepairMode = '%s'", szReinstall.c_str(), bRepairMode ? L"TRUE" : L"FALSE");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get this MSI Installer HWND.
|
|
// There cannot be 2 MSIs or more running at the same time, so we're sure we'll get ours.
|
|
// This is only possible in case of non silent install.
|
|
hwndDlg = FindWindow(L"MsiDialogCloseClass", NULL);
|
|
if (!hwndDlg && !Silent)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreInstall: MsiDialogCloseClass not found");
|
|
goto end;
|
|
}
|
|
|
|
/* Start actual work */
|
|
|
|
if (!VC_CustomAction_Init(hInstaller, szInstallDir.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreInstall: VC_CustomAction_Init() failed");
|
|
goto end;
|
|
}
|
|
atexit(VC_CustomAction_Cleanup);
|
|
|
|
bootEnc.SetParentWindow(hwndDlg);
|
|
|
|
if (DoDriverUnload_Dll (hInstaller, hwndDlg) == FALSE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreInstall: DoDriverUnload_Dll() failed");
|
|
goto end;
|
|
}
|
|
|
|
if (bSystemRestore)
|
|
{
|
|
SetSystemRestorePoint_Dll (hInstaller, FALSE);
|
|
}
|
|
|
|
if (bDisableSwapFiles && IsPagingFileActive_Dll (hInstaller, FALSE))
|
|
{
|
|
if (!DisablePagingFile())
|
|
{
|
|
handleWin32Error_Dll (hInstaller, SRC_POS);
|
|
MSILogAndShow(hInstaller, MSI_ERROR_LEVEL, GetString("FAILED_TO_DISABLE_PAGING_FILES"));
|
|
}
|
|
else
|
|
{
|
|
bRestartRequired = TRUE;
|
|
}
|
|
}
|
|
|
|
// Remove deprecated
|
|
DoServiceUninstall_Dll (hInstaller, hwndDlg, L"VeraCryptService");
|
|
|
|
if (!SystemEncryptionUpdate)
|
|
DoRegUninstall_Dll (hInstaller, TRUE);
|
|
|
|
if (UnloadDriver && DoServiceUninstall_Dll(hInstaller, hwndDlg, L"veracrypt") == FALSE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreInstall: DoServiceUninstall_Dll(veracrypt) failed");
|
|
bOK = FALSE;
|
|
}
|
|
|
|
// uiRet = MsiSetProperty(hInstaller, TEXT("ISREBOOTREQUIRED"), TEXT("1"));
|
|
// Cannot do this because this is a Deferred CA (we need Deferred so that it runs with admin privileges).
|
|
// MsiGetProperty and MsiSetProperty properties cannot be used for deferred InstallScript custom actions,
|
|
// which do not have access to the active .msi database and do not recognize any Windows Installer properties.
|
|
// They can access only the information that has been written into the execution script (CustomActionData).
|
|
// Therefore, we set the values in RegKeys that are volatile.
|
|
if (bOK)
|
|
{
|
|
if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt\\Values", 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, &dw) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx (hkey, L"Silent", 0, REG_DWORD, (const BYTE*)(&Silent), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstall", 0, REG_DWORD, (const BYTE*)(&bUninstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDowngrade", 0, REG_DWORD, (const BYTE*)(&bDowngrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstallInProgress", 0, REG_DWORD, (const BYTE*)(&bUninstallInProgress), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"PortableMode", 0, REG_DWORD, (const BYTE*)(&PortableMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"UnloadDriver", 0, REG_DWORD, (const BYTE*)(&UnloadDriver), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"Rollback", 0, REG_DWORD, (const BYTE*)(&Rollback), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bReinstallMode", 0, REG_DWORD, (const BYTE*)(&bReinstallMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpgrade", 0, REG_DWORD, (const BYTE*)(&bUpgrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPossiblyFirstTimeInstall", 0, REG_DWORD, (const BYTE*)(&bPossiblyFirstTimeInstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDevm", 0, REG_DWORD, (const BYTE*)(&bDevm), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"SystemEncryptionUpdate", 0, REG_DWORD, (const BYTE*)(&SystemEncryptionUpdate), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRestartRequired", 0, REG_DWORD, (const BYTE*)(&bRestartRequired), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDisableSwapFiles", 0, REG_DWORD, (const BYTE*)(&bDisableSwapFiles), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bSystemRestore", 0, REG_DWORD, (const BYTE*)(&bSystemRestore), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"bPromptFastStartup", 0, REG_DWORD, (const BYTE*)(&bPromptFastStartup), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptReleaseNotes", 0, REG_DWORD, (const BYTE*)(&bPromptReleaseNotes), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptTutorial", 0, REG_DWORD, (const BYTE*)(&bPromptTutorial), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpdateRescueDisk", 0, REG_DWORD, (const BYTE*)(&bUpdateRescueDisk), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRepairMode", 0, REG_DWORD, (const BYTE*)(&bRepairMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUserSetLanguage", 0, REG_DWORD, (const BYTE*)(&bUserSetLanguage), sizeof(BOOL));
|
|
|
|
RegCloseKey (hkey);
|
|
|
|
uiRet = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"End VC_CustomAction_PreInstall: Could not write to registry");
|
|
}
|
|
}
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_PreInstall");
|
|
return uiRet;
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function DoInstall(), but
|
|
* without the actual installation, it only performs
|
|
* post install operations (after DoRegInstall and last parts
|
|
* of DoFilesInstall / DoRegInstall).
|
|
* It also does the Fast Startup check, shows Release Notes and
|
|
* Beginner's Tutorial if needed and sets regkey accordingly.
|
|
* It runs as a Deferred CA.
|
|
*/
|
|
EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostInstall(MSIHANDLE hInstaller)
|
|
{
|
|
HWND hwndDlg = NULL;
|
|
std::wstring szValueBuf = L"";
|
|
DWORD cchValueBuf = 0;
|
|
UINT uiStat = 0;
|
|
HKEY hkey = 0;
|
|
DWORD dw = 0;
|
|
BootEncryption bootEnc(NULL);
|
|
std::wstring szInstallDir = L"";
|
|
UINT uiRet = ERROR_INSTALL_FAILURE;
|
|
BOOL bOK = TRUE;
|
|
WCHAR szCurrentDir[MAX_PATH];
|
|
const wchar_t* oldFileNames[] = {
|
|
L"docs\\html\\en\\AddNewSystemVar.jpg",
|
|
L"docs\\html\\en\\CertificateCannotBeVerified.jpg",
|
|
L"docs\\html\\en\\CertVerifyFails.jpg",
|
|
L"docs\\html\\en\\DistributionPackageDamaged.jpg",
|
|
L"docs\\html\\en\\DownloadVS2010.jpg",
|
|
L"docs\\html\\en\\DownloadVS2019.jpg",
|
|
L"docs\\html\\en\\DownloadVSBuildTools.jpg",
|
|
L"docs\\html\\en\\gzipCommandLine.jpg",
|
|
L"docs\\html\\en\\NasmCommandLine.jpg",
|
|
L"docs\\html\\en\\RegeditPermissions-1.jpg",
|
|
L"docs\\html\\en\\RegeditPermissions-2.jpg",
|
|
L"docs\\html\\en\\RegeditPermissions-3.jpg",
|
|
L"docs\\html\\en\\RegeditPermissions-4.jpg",
|
|
L"docs\\html\\en\\SelectAdvancedSystemSettings.jpg",
|
|
L"docs\\html\\en\\SelectEnvironmentVariables.jpg",
|
|
L"docs\\html\\en\\SelectPathVariable.jpg",
|
|
L"docs\\html\\en\\SelectThisPC.jpg",
|
|
L"docs\\html\\en\\upxCommandLine.jpg",
|
|
L"docs\\html\\en\\VS2010BuildSolution.jpg",
|
|
L"docs\\html\\en\\VS2010Win32Config.jpg",
|
|
L"docs\\html\\en\\VS2010X64Config.jpg",
|
|
L"docs\\html\\en\\VS2019ARM64Config.jpg",
|
|
L"docs\\html\\en\\VS2019BuildSolution.jpg",
|
|
L"docs\\html\\en\\YasmCommandLine.jpg",
|
|
L"docs\\html\\en\\BCH_Logo_48x30.png",
|
|
L"docs\\html\\en\\LinuxPrepAndBuild.sh",
|
|
L"docs\\html\\en\\LinuxPrepAndBuild.zip",
|
|
L"docs\\html\\en\\RIPEMD-160.html",
|
|
L"docs\\html\\en\\ru\\BCH_Logo_48x30.png",
|
|
L"Languages\\Language.ru - Copy.xml",
|
|
};
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_PostInstall");
|
|
|
|
// Get INSTALLDIR to see where we're being installed.
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), (LPWSTR)TEXT(""), &cchValueBuf);
|
|
if (ERROR_MORE_DATA == uiStat)
|
|
{
|
|
++cchValueBuf; // add 1 for null termination
|
|
szValueBuf.resize(cchValueBuf);
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), &szValueBuf[0], &cchValueBuf);
|
|
if ((ERROR_SUCCESS == uiStat))
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PostInstall: CustomActionData = '%s'", szValueBuf.c_str());
|
|
if (wcsncmp(szValueBuf.c_str(), L"INSTALLDIR=", wcslen(L"INSTALLDIR=")) == 0)
|
|
{
|
|
size_t index0 = szValueBuf.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
szInstallDir = szValueBuf.substr(index0 + 1);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PostInstall: INSTALLDIR = '%s'", szInstallDir.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read RegKeys previously setup by PreInstall
|
|
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt\\Values", 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD cbValue = sizeof(DWORD);
|
|
DWORD dwValue = 0;
|
|
|
|
RegQueryValueEx (hkey, L"Silent", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
Silent = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUninstall", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUninstall = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDowngrade", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDowngrade = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUninstallInProgress", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUninstallInProgress = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"PortableMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
PortableMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"UnloadDriver", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
UnloadDriver = (dwValue == 1);
|
|
|
|
RegQueryValueEx (hkey, L"Rollback", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
Rollback = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bReinstallMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bReinstallMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUpgrade", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUpgrade = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPossiblyFirstTimeInstall", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPossiblyFirstTimeInstall = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDevm", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDevm = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"SystemEncryptionUpdate", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
SystemEncryptionUpdate = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bRestartRequired", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bRestartRequired = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDisableSwapFiles", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDisableSwapFiles = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bSystemRestore", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bSystemRestore = (dwValue == 1);
|
|
|
|
RegQueryValueEx (hkey, L"bPromptFastStartup", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptFastStartup = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPromptReleaseNotes", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptReleaseNotes = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPromptTutorial", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptTutorial = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUpdateRescueDisk", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUpdateRescueDisk = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bRepairMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bRepairMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUserSetLanguage", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUserSetLanguage = (dwValue == 1);
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"End VC_CustomAction_PostInstall: Could not read from registry");
|
|
goto end;
|
|
}
|
|
|
|
// Get this MSI Installer HWND.
|
|
// There cannot be 2 MSIs or more running at the same time, so we're sure we'll get ours.
|
|
// This is only possible in case of non silent install.
|
|
hwndDlg = FindWindow(L"MsiDialogCloseClass", NULL);
|
|
if (!hwndDlg && !Silent)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: MsiDialogCloseClass not found");
|
|
goto end;
|
|
}
|
|
|
|
/* Start actual work */
|
|
|
|
if (!VC_CustomAction_Init(hInstaller, szInstallDir.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: VC_CustomAction_Init() failed");
|
|
goto end;
|
|
}
|
|
atexit(VC_CustomAction_Cleanup);
|
|
bootEnc.SetParentWindow(hwndDlg);
|
|
|
|
// Last part of DoFilesInstall()
|
|
{
|
|
BOOL bResult = FALSE;
|
|
WIN32_FIND_DATA f;
|
|
HANDLE h;
|
|
wchar_t szTmp[TC_MAX_PATH];
|
|
size_t i;
|
|
|
|
// delete "VeraCrypt Setup.exe" if it exists
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), L"%s%s", szInstallDir.c_str(), L"VeraCrypt Setup.exe");
|
|
if (FileExists(szTmp))
|
|
{
|
|
ForceDeleteFile(szTmp);
|
|
}
|
|
|
|
// delete files wrongly installed by previous versions in installation folder
|
|
for (i = 0; i < ARRAYSIZE(oldFileNames); i++)
|
|
{
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), L"%s%s", szInstallDir.c_str(), oldFileNames[i]);
|
|
if (FileExists(szTmp))
|
|
{
|
|
ForceDeleteFile(szTmp);
|
|
}
|
|
}
|
|
|
|
StringCbPrintfW (szTmp, sizeof(szTmp), L"%s%s", szInstallDir.c_str(), L"VeraCrypt.exe");
|
|
|
|
EnableWow64FsRedirection (FALSE);
|
|
|
|
wstring servicePath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", false);
|
|
wstring serviceLegacyPath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", true);
|
|
wstring favoritesFile = GetServiceConfigPath (TC_APPD_FILENAME_SYSTEM_FAVORITE_VOLUMES, false);
|
|
wstring favoritesLegacyFile = GetServiceConfigPath (TC_APPD_FILENAME_SYSTEM_FAVORITE_VOLUMES, true);
|
|
|
|
if (FileExists (favoritesLegacyFile.c_str())
|
|
&& !FileExists (favoritesFile.c_str()))
|
|
{
|
|
// copy the favorites XML file to the native system directory
|
|
bResult = CopyFile (favoritesLegacyFile.c_str(), favoritesFile.c_str(), FALSE);
|
|
}
|
|
else
|
|
{
|
|
bResult = TRUE;
|
|
}
|
|
|
|
if (bResult)
|
|
{
|
|
// Update the path of the service
|
|
BootEncryption BootEncObj (hwndDlg);
|
|
|
|
try
|
|
{
|
|
if (BootEncObj.GetDriverServiceStartType() == SERVICE_BOOT_START)
|
|
{
|
|
uint32 driverFlags = ReadDriverConfigurationFlags ();
|
|
uint32 serviceFlags = BootEncObj.ReadServiceConfigurationFlags ();
|
|
|
|
BootEncObj.UpdateSystemFavoritesService ();
|
|
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: INSTALLING %s", servicePath.c_str());
|
|
|
|
// Tell the service not to update loader on stop
|
|
BootEncObj.SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER, true);
|
|
|
|
if (StartStopService_Dll (hInstaller, TC_SYSTEM_FAVORITES_SERVICE_NAME, FALSE, 0, NULL))
|
|
{
|
|
// we tell the service not to load system favorites on startup and to update bootloader on startup
|
|
LPCWSTR szArgs[3] = { TC_SYSTEM_FAVORITES_SERVICE_NAME, VC_SYSTEM_FAVORITES_SERVICE_ARG_SKIP_MOUNT, VC_SYSTEM_FAVORITES_SERVICE_ARG_UPDATE_LOADER};
|
|
if (!CopyFile (szTmp, servicePath.c_str(), FALSE))
|
|
ForceCopyFile (szTmp, servicePath.c_str());
|
|
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: SystemEncryptionUpdate = %s", SystemEncryptionUpdate? L"TRUE" : L"FALSE");
|
|
|
|
StartStopService_Dll (hInstaller, TC_SYSTEM_FAVORITES_SERVICE_NAME, TRUE, SystemEncryptionUpdate? 3 : 2, szArgs);
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: failed to stop %S", servicePath.c_str());
|
|
ForceCopyFile (szTmp, servicePath.c_str());
|
|
}
|
|
|
|
BootEncObj.SetDriverConfigurationFlag (driverFlags, true);
|
|
|
|
// remove the service flag if it was set originally
|
|
if (!(serviceFlags & VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER))
|
|
BootEncObj.SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER, false);
|
|
}
|
|
}
|
|
catch (...) {}
|
|
}
|
|
|
|
// delete files from legacy path
|
|
if (FileExists (favoritesLegacyFile.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: REMOVING %s", favoritesLegacyFile.c_str());
|
|
ForceDeleteFile (favoritesLegacyFile.c_str());
|
|
}
|
|
|
|
if (FileExists (serviceLegacyPath.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: REMOVING %s", serviceLegacyPath.c_str());
|
|
ForceDeleteFile (serviceLegacyPath.c_str());
|
|
}
|
|
|
|
EnableWow64FsRedirection (TRUE);
|
|
|
|
if (bResult == FALSE)
|
|
{
|
|
LPVOID lpMsgBuf;
|
|
DWORD dwError = GetLastError ();
|
|
wchar_t szTmp2[700];
|
|
wchar_t szErrorValue[16];
|
|
wchar_t* pszDesc;
|
|
|
|
FormatMessage (
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
dwError,
|
|
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
|
(wchar_t *) &lpMsgBuf,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (lpMsgBuf)
|
|
pszDesc = (wchar_t*) lpMsgBuf;
|
|
else
|
|
{
|
|
StringCbPrintfW (szErrorValue, sizeof (szErrorValue), L"0x%.8X", dwError);
|
|
pszDesc = szErrorValue;
|
|
}
|
|
|
|
if (bUninstall == FALSE)
|
|
StringCbPrintfW (szTmp2, sizeof(szTmp2), GetString ("INSTALL_OF_FAILED"), szTmp, pszDesc);
|
|
else
|
|
StringCbPrintfW (szTmp2, sizeof(szTmp2), GetString ("UNINSTALL_OF_FAILED"), szTmp, pszDesc);
|
|
|
|
if (lpMsgBuf) LocalFree (lpMsgBuf);
|
|
|
|
if (!Silent && MessageBoxW (hwndDlg, szTmp2, lpszTitle, MB_YESNO | MB_ICONHAND) != IDYES)
|
|
goto end;
|
|
}
|
|
|
|
if (bUninstall == FALSE)
|
|
{
|
|
GetCurrentDirectory (MAX_PATH, szCurrentDir); // Save current dir since it will be changed
|
|
SetCurrentDirectory (szInstallDir.c_str());
|
|
|
|
// remove PDF from previous version if any
|
|
h = FindFirstFile (L"VeraCrypt User Guide*.pdf", &f);
|
|
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
StatDeleteFile (f.cFileName, TRUE);
|
|
}
|
|
while (FindNextFile(h, &f) != 0);
|
|
|
|
FindClose (h);
|
|
}
|
|
|
|
// remove legacy folder "docs\en\ru" if present in installation directory
|
|
{
|
|
wchar_t folder[TC_MAX_PATH];
|
|
// since we've done SetCurrentDirectory(szDestDir), a relative path will be resolved correctly
|
|
StringCbCopyW(folder, sizeof(folder), L"docs\\html\\en\\ru");
|
|
StatRemoveDirectory(folder);
|
|
}
|
|
|
|
// remove language XML files from previous version if any
|
|
h = FindFirstFile (L"Language*.xml", &f);
|
|
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
StatDeleteFile (f.cFileName, TRUE);
|
|
}
|
|
while (FindNextFile(h, &f) != 0);
|
|
|
|
FindClose (h);
|
|
}
|
|
|
|
// remvove legacy files that are not needed anymore
|
|
for (i = 0; i < sizeof (szLegacyFiles) / sizeof (szLegacyFiles[0]); i++)
|
|
{
|
|
StatDeleteFile (szLegacyFiles [i], TRUE);
|
|
}
|
|
|
|
SetCurrentDirectory(szCurrentDir);
|
|
}
|
|
}
|
|
|
|
// Last part of DoRegInstall()
|
|
{
|
|
// Register COM servers for UAC
|
|
if (!RegisterComServers ((wchar_t*)szInstallDir.c_str()))
|
|
{
|
|
MSILogAndShow (hInstaller, MSI_ERROR_LEVEL, GetString("COM_REG_FAILED"));
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (UnloadDriver && DoDriverInstall_Dll(hInstaller) == FALSE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: DoDriverInstall_Dll() failed");
|
|
bOK = FALSE;
|
|
}
|
|
else if (SystemEncryptionUpdate && UpgradeBootLoader_Dll(hInstaller, hwndDlg) == FALSE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostInstall: UpgradeBootLoader_Dll() failed");
|
|
bOK = FALSE;
|
|
}
|
|
|
|
// Shortcuts are installed by MSI, so we skip that.
|
|
|
|
if (!UnloadDriver)
|
|
bRestartRequired = TRUE;
|
|
|
|
try
|
|
{
|
|
bootEnc.RenameDeprecatedSystemLoaderBackup();
|
|
}
|
|
catch (...) { }
|
|
|
|
if (bSystemRestore)
|
|
SetSystemRestorePoint_Dll (hInstaller, TRUE);
|
|
|
|
if (bOK)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, GetString("INSTALL_COMPLETED"));
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Post install failed");
|
|
if (!SystemEncryptionUpdate)
|
|
{
|
|
bUninstall = TRUE;
|
|
Rollback = TRUE;
|
|
Silent = TRUE;
|
|
|
|
DoUninstall_Dll (hInstaller, hwndDlg);
|
|
|
|
bUninstall = FALSE;
|
|
Rollback = FALSE;
|
|
Silent = FALSE;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, GetString("ROLLBACK"));
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_WARNING_LEVEL, GetString("SYS_ENC_UPGRADE_FAILED"));
|
|
}
|
|
}
|
|
|
|
if (bOK && !bUninstall && !bDowngrade && !bRepairMode && !bDevm)
|
|
{
|
|
BOOL bHibernateEnabled = FALSE, bHiberbootEnabled = FALSE;
|
|
if (GetHibernateStatus (bHibernateEnabled, bHiberbootEnabled))
|
|
{
|
|
if (bHiberbootEnabled)
|
|
{
|
|
bPromptFastStartup = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!IsHiddenOSRunning()) // A hidden OS user should not see the post-install notes twice (on decoy OS and then on hidden OS).
|
|
{
|
|
if (bRestartRequired || SystemEncryptionUpdate)
|
|
{
|
|
// Restart required
|
|
|
|
if (bUpgrade)
|
|
{
|
|
SavePostInstallTasksSettings (TC_POST_INSTALL_CFG_RELEASE_NOTES);
|
|
if (bUpdateRescueDisk)
|
|
{
|
|
SavePostInstallTasksSettings (TC_POST_INSTALL_CFG_RESCUE_DISK);
|
|
}
|
|
}
|
|
else if (bPossiblyFirstTimeInstall)
|
|
{
|
|
SavePostInstallTasksSettings (TC_POST_INSTALL_CFG_TUTORIAL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No restart will be required
|
|
|
|
if (bUpgrade)
|
|
{
|
|
bPromptReleaseNotes = TRUE;
|
|
}
|
|
else if (bPossiblyFirstTimeInstall)
|
|
{
|
|
bPromptTutorial = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bOK)
|
|
{
|
|
// This is part of MainDialogProc, WM_CLOSE, after PostMessage (MainDlg, bOK ? TC_APPMSG_INSTALL_SUCCESS : TC_APPMSG_INSTALL_FAILURE, 0, 0);
|
|
|
|
/* if user selected a language, use for GUI in the next run */
|
|
if (bUserSetLanguage)
|
|
{
|
|
WCHAR langId[6];
|
|
MultiByteToWideChar (CP_ACP, 0, GetPreferredLangId(), -1, langId, ARRAYSIZE (langId));
|
|
WriteRegistryString (L"Software\\VeraCrypt", L"SetupUILanguage", langId);
|
|
}
|
|
|
|
if (bPromptFastStartup && AskWarnYesNo ("CONFIRM_DISABLE_FAST_STARTUP", hwndDlg) == IDYES)
|
|
{
|
|
WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power", L"HiberbootEnabled", 0);
|
|
bRestartRequired = TRUE;
|
|
}
|
|
bPromptFastStartup = FALSE;
|
|
|
|
if (bPromptReleaseNotes && AskYesNo ("AFTER_UPGRADE_RELEASE_NOTES", hwndDlg) == IDYES)
|
|
{
|
|
Applink_Dll (hInstaller, "releasenotes");
|
|
}
|
|
bPromptReleaseNotes = FALSE;
|
|
|
|
if (bPromptTutorial && AskYesNo ("AFTER_INSTALL_TUTORIAL", hwndDlg) == IDYES)
|
|
{
|
|
Applink_Dll (hInstaller, "beginnerstutorial");
|
|
}
|
|
bPromptTutorial = FALSE;
|
|
|
|
if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt\\Values", 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, &dw) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx (hkey, L"Silent", 0, REG_DWORD, (const BYTE*)(&Silent), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstall", 0, REG_DWORD, (const BYTE*)(&bUninstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDowngrade", 0, REG_DWORD, (const BYTE*)(&bDowngrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstallInProgress", 0, REG_DWORD, (const BYTE*)(&bUninstallInProgress), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"PortableMode", 0, REG_DWORD, (const BYTE*)(&PortableMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"UnloadDriver", 0, REG_DWORD, (const BYTE*)(&UnloadDriver), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"Rollback", 0, REG_DWORD, (const BYTE*)(&Rollback), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bReinstallMode", 0, REG_DWORD, (const BYTE*)(&bReinstallMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpgrade", 0, REG_DWORD, (const BYTE*)(&bUpgrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPossiblyFirstTimeInstall", 0, REG_DWORD, (const BYTE*)(&bPossiblyFirstTimeInstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDevm", 0, REG_DWORD, (const BYTE*)(&bDevm), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"SystemEncryptionUpdate", 0, REG_DWORD, (const BYTE*)(&SystemEncryptionUpdate), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRestartRequired", 0, REG_DWORD, (const BYTE*)(&bRestartRequired), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDisableSwapFiles", 0, REG_DWORD, (const BYTE*)(&bDisableSwapFiles), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bSystemRestore", 0, REG_DWORD, (const BYTE*)(&bSystemRestore), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"bPromptFastStartup", 0, REG_DWORD, (const BYTE*)(&bPromptFastStartup), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptReleaseNotes", 0, REG_DWORD, (const BYTE*)(&bPromptReleaseNotes), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptTutorial", 0, REG_DWORD, (const BYTE*)(&bPromptTutorial), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpdateRescueDisk", 0, REG_DWORD, (const BYTE*)(&bUpdateRescueDisk), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRepairMode", 0, REG_DWORD, (const BYTE*)(&bRepairMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUserSetLanguage", 0, REG_DWORD, (const BYTE*)(&bUserSetLanguage), sizeof(BOOL));
|
|
|
|
RegCloseKey (hkey);
|
|
|
|
uiRet = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"End VC_CustomAction_PostInstall: Could not write to registry");
|
|
}
|
|
|
|
// delete entry of EXE installation if it exists
|
|
RegDeleteKeyExW (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", KEY_WOW64_32KEY, 0);
|
|
}
|
|
end:
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_PostInstall");
|
|
return uiRet;
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function DoUninstall(), but
|
|
* without the actual uninstall, it only prepares the system
|
|
* before the uninstall (before DoFilesInstall).
|
|
* It runs as a Deferred CA.
|
|
*/
|
|
EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PreUninstall(MSIHANDLE hInstaller)
|
|
{
|
|
HWND hwndDlg = NULL;
|
|
std::wstring szValueBuf = L"";
|
|
DWORD cchValueBuf = 0;
|
|
UINT uiStat = 0;
|
|
HKEY hkey = 0;
|
|
DWORD dw = 0;
|
|
BootEncryption bootEnc(NULL);
|
|
std::wstring szInstallDir = L"";
|
|
UINT uiRet = ERROR_INSTALL_FAILURE;
|
|
BOOL bTempSkipSysRestore = FALSE;
|
|
BOOL bOK = TRUE;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_PreUninstall");
|
|
|
|
// Get UILevel to see whether we're being installed silently or not.
|
|
// Also get INSTALLDIR to see where we're being installed.
|
|
// Since this is a Deferred CA, they are to be setup in its CustomActionData.
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), (LPWSTR)TEXT(""), &cchValueBuf);
|
|
if (ERROR_MORE_DATA == uiStat)
|
|
{
|
|
++cchValueBuf; // add 1 for null termination
|
|
szValueBuf.resize(cchValueBuf);
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), &szValueBuf[0], &cchValueBuf);
|
|
if ((ERROR_SUCCESS == uiStat))
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreUninstall: CustomActionData = '%s'", szValueBuf.c_str());
|
|
|
|
std::vector<std::wstring> szTokens;
|
|
Tokenize(szValueBuf.c_str(), szTokens);
|
|
|
|
for (size_t i = 0; i < szTokens.size(); i++)
|
|
{
|
|
std::wstring szToken = szTokens[i];
|
|
|
|
if (wcsncmp(szToken.c_str(), L"UILEVEL=", wcslen(L"UILEVEL=")) == 0)
|
|
{
|
|
size_t index0 = szToken.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
std::wstring uiLevel = szToken.substr(index0 + 1);
|
|
Silent = (stoi(uiLevel) <= 3);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreInstall: UILEVEL = '%s', bSilent = '%d'", uiLevel.c_str(), Silent);
|
|
}
|
|
}
|
|
else if (wcsncmp(szToken.c_str(), L"INSTALLDIR=", wcslen(L"INSTALLDIR=")) == 0)
|
|
{
|
|
size_t index0 = szToken.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
szInstallDir = szToken.substr(index0 + 1);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreInstall: INSTALLDIR = '%s'", szInstallDir.c_str());
|
|
}
|
|
}
|
|
else if (wcsncmp(szToken.c_str(), L"REINSTALL=", wcslen(L"REINSTALL=")) == 0)
|
|
{
|
|
size_t index0 = szToken.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
std::wstring szReinstall = szToken.substr(index0 + 1);
|
|
bRepairMode = (wcslen(szReinstall.c_str()) != 0);
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PreInstall: REINSTALL = '%s', bRepairMode = '%s'", szReinstall.c_str(), bRepairMode ? L"TRUE" : L"FALSE");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get this MSI Installer HWND.
|
|
// There cannot be 2 MSIs or more running at the same time, so we're sure we'll get ours.
|
|
// This is only possible in case of non silent install.
|
|
hwndDlg = FindWindow(L"MsiDialogCloseClass", NULL);
|
|
if (!hwndDlg && !Silent)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreUninstall: MsiDialogCloseClass not found");
|
|
goto end;
|
|
}
|
|
|
|
/* Start actual work */
|
|
|
|
bUninstall = TRUE;
|
|
if (!VC_CustomAction_Init(hInstaller, szInstallDir.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreUninstall: VC_CustomAction_Init() failed");
|
|
goto end;
|
|
}
|
|
atexit(VC_CustomAction_Cleanup);
|
|
bootEnc.SetParentWindow(hwndDlg);
|
|
|
|
if (DoDriverUnload_Dll(hInstaller, hwndDlg) == FALSE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreUninstall: DoDriverUnload_Dll() failed");
|
|
bOK = FALSE;
|
|
bTempSkipSysRestore = TRUE; // Volumes are possibly mounted; defer System Restore point creation for this uninstall attempt.
|
|
}
|
|
else
|
|
{
|
|
if (!Rollback && bSystemRestore && !bTempSkipSysRestore)
|
|
SetSystemRestorePoint_Dll (hInstaller, FALSE);
|
|
|
|
if (DoServiceUninstall_Dll (hInstaller, hwndDlg, L"veracrypt") == FALSE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreUninstall: DoServiceUninstall_Dll(veracrypt) failed");
|
|
bOK = FALSE;
|
|
}
|
|
// DoRegUninstall_Dll removes regkeys that are not linked to MSI
|
|
// We need to do this in PreUninstall instead of in PostUninstall so that UnregisterComServers works,
|
|
// because in PostUninstall the "VeraCrypt COMReg.exe" is removed and UnregisterComServers will fail.
|
|
else if (DoRegUninstall_Dll (hInstaller, FALSE) == FALSE)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreUninstall: DoRegUninstall_Dll() failed");
|
|
bOK = FALSE;
|
|
}
|
|
}
|
|
|
|
if (bOK)
|
|
{
|
|
// uiRet = MsiSetProperty(hInstaller, TEXT("ISREBOOTREQUIRED"), TEXT("1"));
|
|
// Cannot do this because this is a Deferred CA (we need Deferred so that it runs with admin privileges).
|
|
// MsiGetProperty and MsiSetProperty properties cannot be used for deferred InstallScript custom actions,
|
|
// which do not have access to the active .msi database and do not recognize any Windows Installer properties.
|
|
// They can access only the information that has been written into the execution script (CustomActionData).
|
|
// Therefore, we set the values in RegKeys that are volatile.
|
|
if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt\\Values", 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, &dw) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx (hkey, L"Silent", 0, REG_DWORD, (const BYTE*)(&Silent), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstall", 0, REG_DWORD, (const BYTE*)(&bUninstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDowngrade", 0, REG_DWORD, (const BYTE*)(&bDowngrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstallInProgress", 0, REG_DWORD, (const BYTE*)(&bUninstallInProgress), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"PortableMode", 0, REG_DWORD, (const BYTE*)(&PortableMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"UnloadDriver", 0, REG_DWORD, (const BYTE*)(&UnloadDriver), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"Rollback", 0, REG_DWORD, (const BYTE*)(&Rollback), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bReinstallMode", 0, REG_DWORD, (const BYTE*)(&bReinstallMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpgrade", 0, REG_DWORD, (const BYTE*)(&bUpgrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPossiblyFirstTimeInstall", 0, REG_DWORD, (const BYTE*)(&bPossiblyFirstTimeInstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDevm", 0, REG_DWORD, (const BYTE*)(&bDevm), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"SystemEncryptionUpdate", 0, REG_DWORD, (const BYTE*)(&SystemEncryptionUpdate), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRestartRequired", 0, REG_DWORD, (const BYTE*)(&bRestartRequired), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDisableSwapFiles", 0, REG_DWORD, (const BYTE*)(&bDisableSwapFiles), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bSystemRestore", 0, REG_DWORD, (const BYTE*)(&bSystemRestore), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"bPromptFastStartup", 0, REG_DWORD, (const BYTE*)(&bPromptFastStartup), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptReleaseNotes", 0, REG_DWORD, (const BYTE*)(&bPromptReleaseNotes), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptTutorial", 0, REG_DWORD, (const BYTE*)(&bPromptTutorial), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpdateRescueDisk", 0, REG_DWORD, (const BYTE*)(&bUpdateRescueDisk), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRepairMode", 0, REG_DWORD, (const BYTE*)(&bRepairMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUserSetLanguage", 0, REG_DWORD, (const BYTE*)(&bUserSetLanguage), sizeof(BOOL));
|
|
|
|
RegCloseKey (hkey);
|
|
|
|
uiRet = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"End VC_CustomAction_PreUninstall: Could not write to registry");
|
|
}
|
|
}
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_PreUninstall");
|
|
return uiRet;
|
|
}
|
|
|
|
static BOOL DirectoryExists (const wchar_t *dirName)
|
|
{
|
|
DWORD attrib = GetFileAttributes (dirName);
|
|
return (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
}
|
|
|
|
static BOOL DeleteContentsOnReboot(LPCTSTR pszDir) {
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szSubPath[MAX_PATH];
|
|
WIN32_FIND_DATA FindFileData;
|
|
HANDLE hFind;
|
|
BOOL bHasBackslash = FALSE;
|
|
// check if pszDir ends with a backslash
|
|
if (pszDir[_tcslen(pszDir) - 1] == '\\')
|
|
{
|
|
bHasBackslash = TRUE;
|
|
}
|
|
|
|
// Prepare the path for FindFirstFile
|
|
if (bHasBackslash)
|
|
StringCchPrintf(szPath, MAX_PATH, TEXT("%s*"), pszDir);
|
|
else
|
|
StringCchPrintf(szPath, MAX_PATH, TEXT("%s\\*"), pszDir);
|
|
|
|
hFind = FindFirstFile(szPath, &FindFileData);
|
|
if (hFind == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL result = TRUE;
|
|
|
|
do {
|
|
if (_tcscmp(FindFileData.cFileName, TEXT(".")) != 0 &&
|
|
_tcscmp(FindFileData.cFileName, TEXT("..")) != 0) {
|
|
|
|
if (bHasBackslash)
|
|
StringCchPrintf(szSubPath, MAX_PATH, TEXT("%s%s"), pszDir, FindFileData.cFileName);
|
|
else
|
|
StringCchPrintf(szSubPath, MAX_PATH, TEXT("%s\\%s"), pszDir, FindFileData.cFileName);
|
|
|
|
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
// Recursive call to handle subdirectories
|
|
if (!DeleteContentsOnReboot(szSubPath)) {
|
|
result = FALSE; // Track failures but attempt to continue
|
|
}
|
|
} else {
|
|
// Schedule the file for deletion
|
|
if (!MoveFileEx(szSubPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)) {
|
|
result = FALSE; // Track failures
|
|
}
|
|
}
|
|
}
|
|
} while (FindNextFile(hFind, &FindFileData) != 0);
|
|
|
|
FindClose(hFind);
|
|
|
|
// Schedule the root directory for deletion, only if not done already
|
|
if (!MoveFileEx(pszDir, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)) {
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Same as Setup.c, function DoUninstall(), but
|
|
* without the actual installation, it only performs
|
|
* post install operations (after DoFilesInstall and last parts
|
|
* of DoFilesInstall / DoRegUninstall).
|
|
* It also sets regkey accordingly.
|
|
* It runs as a Deferred CA.
|
|
*/
|
|
EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostUninstall(MSIHANDLE hInstaller)
|
|
{
|
|
HWND hwndDlg = NULL;
|
|
std::wstring szValueBuf = L"";
|
|
DWORD cchValueBuf = 0;
|
|
UINT uiStat = 0;
|
|
HKEY hkey = 0;
|
|
DWORD dw = 0;
|
|
BootEncryption bootEnc(NULL);
|
|
std::wstring szInstallDir = L"";
|
|
UINT uiRet = ERROR_INSTALL_FAILURE;
|
|
BOOL bTempSkipSysRestore = FALSE;
|
|
BOOL bOK = TRUE;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_PostUninstall");
|
|
|
|
// Get INSTALLDIR to see where we're being installed.
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), (LPWSTR)TEXT(""), &cchValueBuf);
|
|
if (ERROR_MORE_DATA == uiStat)
|
|
{
|
|
++cchValueBuf; // add 1 for null termination
|
|
szValueBuf.resize(cchValueBuf);
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), &szValueBuf[0], &cchValueBuf);
|
|
if ((ERROR_SUCCESS == uiStat))
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PostUninstall: CustomActionData = '%s'", szValueBuf.c_str());
|
|
if (wcsncmp(szValueBuf.c_str(), L"INSTALLDIR=", wcslen(L"INSTALLDIR=")) == 0)
|
|
{
|
|
size_t index0 = szValueBuf.find_first_of(L"=");
|
|
if (index0 != std::wstring::npos)
|
|
{
|
|
szInstallDir = szValueBuf.substr(index0 + 1);
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PostUninstall: INSTALLDIR = '%s'", szInstallDir.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read RegKeys previously setup by PreInstall
|
|
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt\\Values", 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD cbValue = sizeof(DWORD);
|
|
DWORD dwValue = 0;
|
|
|
|
RegQueryValueEx (hkey, L"Silent", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
Silent = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUninstall", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUninstall = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDowngrade", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDowngrade = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUninstallInProgress", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUninstallInProgress = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"PortableMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
PortableMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"UnloadDriver", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
UnloadDriver = (dwValue == 1);
|
|
|
|
RegQueryValueEx (hkey, L"Rollback", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
Rollback = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bReinstallMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bReinstallMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUpgrade", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUpgrade = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPossiblyFirstTimeInstall", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPossiblyFirstTimeInstall = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDevm", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDevm = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"SystemEncryptionUpdate", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
SystemEncryptionUpdate = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bRestartRequired", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bRestartRequired = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDisableSwapFiles", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDisableSwapFiles = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bSystemRestore", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bSystemRestore = (dwValue == 1);
|
|
|
|
RegQueryValueEx (hkey, L"bPromptFastStartup", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptFastStartup = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPromptReleaseNotes", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptReleaseNotes = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPromptTutorial", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptTutorial = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUpdateRescueDisk", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUpdateRescueDisk = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bRepairMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bRepairMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUserSetLanguage", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUserSetLanguage = (dwValue == 1);
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"End VC_CustomAction_PostUninstall: Could not read from registry");
|
|
goto end;
|
|
}
|
|
|
|
// Get this MSI Installer HWND.
|
|
// There cannot be 2 MSIs or more running at the same time, so we're sure we'll get ours.
|
|
// This is only possible in case of non silent install.
|
|
hwndDlg = FindWindow(L"MsiDialogCloseClass", NULL);
|
|
if (!hwndDlg && !Silent)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: MsiDialogCloseClass not found");
|
|
goto end;
|
|
}
|
|
|
|
/* Start actual work */
|
|
|
|
bUninstall = TRUE;
|
|
if (!VC_CustomAction_Init(hInstaller, szInstallDir.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: VC_CustomAction_Init() failed");
|
|
goto end;
|
|
}
|
|
atexit(VC_CustomAction_Cleanup);
|
|
bootEnc.SetParentWindow(hwndDlg);
|
|
|
|
if (!DoApplicationDataUninstall_Dll (hInstaller))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: DoApplicationDataUninstall_Dll() failed");
|
|
bOK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Deprecated service
|
|
DoServiceUninstall_Dll (hInstaller, hwndDlg, L"VeraCryptService");
|
|
}
|
|
|
|
// Last part of DoFilesInstall()
|
|
{
|
|
EnableWow64FsRedirection (FALSE);
|
|
|
|
wstring servicePath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", false);
|
|
wstring serviceLegacyPath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", true);
|
|
wstring favoritesFile = GetServiceConfigPath (TC_APPD_FILENAME_SYSTEM_FAVORITE_VOLUMES, false);
|
|
wstring favoritesLegacyFile = GetServiceConfigPath (TC_APPD_FILENAME_SYSTEM_FAVORITE_VOLUMES, true);
|
|
|
|
// delete all files related to system favorites service
|
|
if (FileExists (favoritesFile.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: REMOVING %s", favoritesFile.c_str());
|
|
ForceDeleteFile (favoritesFile.c_str());
|
|
}
|
|
|
|
if (FileExists (servicePath.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: REMOVING %s", servicePath.c_str());
|
|
ForceDeleteFile (servicePath.c_str());
|
|
}
|
|
|
|
if (FileExists (favoritesLegacyFile.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: REMOVING %s", favoritesLegacyFile.c_str());
|
|
ForceDeleteFile (favoritesLegacyFile.c_str());
|
|
}
|
|
|
|
if (FileExists (serviceLegacyPath.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: REMOVING %s", serviceLegacyPath.c_str());
|
|
ForceDeleteFile (serviceLegacyPath.c_str());
|
|
}
|
|
|
|
EnableWow64FsRedirection (TRUE);
|
|
|
|
// remove the installation folder is case it remains after uninstall
|
|
if (DirectoryExists (szInstallDir.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: REMOVING %s", szInstallDir.c_str());
|
|
if(DeleteDirectory (szInstallDir.c_str()))
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: %s removed", szInstallDir.c_str());
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: %s could not be removed. Scheduling removal on reboot", szInstallDir.c_str());
|
|
if (DeleteContentsOnReboot(szInstallDir.c_str()))
|
|
{
|
|
bRestartRequired = TRUE;
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: %s scheduled for removal on reboot", szInstallDir.c_str());
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: %s could not be scheduled for removal on reboot", szInstallDir.c_str());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PostUninstall: %s does not exist", szInstallDir.c_str());
|
|
}
|
|
}
|
|
|
|
if (bSystemRestore && !bTempSkipSysRestore)
|
|
SetSystemRestorePoint_Dll (hInstaller, TRUE);
|
|
|
|
if (bOK)
|
|
{
|
|
// uiRet = MsiSetProperty(hInstaller, TEXT("ISREBOOTREQUIRED"), TEXT("1"));
|
|
// Cannot do this because this is a Deferred CA (we need Deferred so that it runs with admin privileges).
|
|
// MsiGetProperty and MsiSetProperty properties cannot be used for deferred InstallScript custom actions,
|
|
// which do not have access to the active .msi database and do not recognize any Windows Installer properties.
|
|
// They can access only the information that has been written into the execution script (CustomActionData).
|
|
// Therefore, we set the values in RegKeys that are volatile.
|
|
if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt\\Values", 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, &dw) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx (hkey, L"Silent", 0, REG_DWORD, (const BYTE*)(&Silent), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstall", 0, REG_DWORD, (const BYTE*)(&bUninstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDowngrade", 0, REG_DWORD, (const BYTE*)(&bDowngrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUninstallInProgress", 0, REG_DWORD, (const BYTE*)(&bUninstallInProgress), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"PortableMode", 0, REG_DWORD, (const BYTE*)(&PortableMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"UnloadDriver", 0, REG_DWORD, (const BYTE*)(&UnloadDriver), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"Rollback", 0, REG_DWORD, (const BYTE*)(&Rollback), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bReinstallMode", 0, REG_DWORD, (const BYTE*)(&bReinstallMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpgrade", 0, REG_DWORD, (const BYTE*)(&bUpgrade), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPossiblyFirstTimeInstall", 0, REG_DWORD, (const BYTE*)(&bPossiblyFirstTimeInstall), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDevm", 0, REG_DWORD, (const BYTE*)(&bDevm), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"SystemEncryptionUpdate", 0, REG_DWORD, (const BYTE*)(&SystemEncryptionUpdate), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRestartRequired", 0, REG_DWORD, (const BYTE*)(&bRestartRequired), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bDisableSwapFiles", 0, REG_DWORD, (const BYTE*)(&bDisableSwapFiles), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bSystemRestore", 0, REG_DWORD, (const BYTE*)(&bSystemRestore), sizeof(BOOL));
|
|
|
|
RegSetValueEx (hkey, L"bPromptFastStartup", 0, REG_DWORD, (const BYTE*)(&bPromptFastStartup), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptReleaseNotes", 0, REG_DWORD, (const BYTE*)(&bPromptReleaseNotes), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bPromptTutorial", 0, REG_DWORD, (const BYTE*)(&bPromptTutorial), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUpdateRescueDisk", 0, REG_DWORD, (const BYTE*)(&bUpdateRescueDisk), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bRepairMode", 0, REG_DWORD, (const BYTE*)(&bRepairMode), sizeof(BOOL));
|
|
RegSetValueEx (hkey, L"bUserSetLanguage", 0, REG_DWORD, (const BYTE*)(&bUserSetLanguage), sizeof(BOOL));
|
|
|
|
RegCloseKey (hkey);
|
|
|
|
uiRet = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"End VC_CustomAction_PostUninstall: Could not write to registry");
|
|
}
|
|
}
|
|
else
|
|
bUninstallInProgress = FALSE;
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_PostUninstall");
|
|
return uiRet;
|
|
}
|
|
|
|
/* Runs as a Commit CA : therefore, we can get / set properties that are defined in WiX.
|
|
* It sets ISREBOOTREQUIRED Wix Property accordingly and refreshes extensions list
|
|
* if REGISTERVCFILEEXT is set.
|
|
*/
|
|
EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_DoChecks(MSIHANDLE hInstaller)
|
|
{
|
|
HWND hwndDlg = NULL;
|
|
std::wstring szValueBuf = L"";
|
|
DWORD cchValueBuf = 0;
|
|
UINT uiStat = 0;
|
|
HKEY hkey = 0;
|
|
std::wstring szInstallDir = L"";
|
|
BOOL bRefreshExts = FALSE;
|
|
BOOL bDisableReboot = FALSE;
|
|
UINT uiRet = ERROR_INSTALL_FAILURE;
|
|
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_DoChecks");
|
|
|
|
// Get WIXUI_INSTALLDIR to see where we're being installed
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("APPLICATIONROOTFOLDER"), (LPWSTR)TEXT(""), &cchValueBuf);
|
|
if (ERROR_MORE_DATA == uiStat)
|
|
{
|
|
++cchValueBuf; // add 1 for null termination
|
|
szValueBuf.resize(cchValueBuf);
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("APPLICATIONROOTFOLDER"), &szValueBuf[0], &cchValueBuf);
|
|
if ((ERROR_SUCCESS == uiStat))
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_DoChecks: APPLICATIONROOTFOLDER = '%s'", szValueBuf.c_str());
|
|
szInstallDir = szValueBuf;
|
|
}
|
|
}
|
|
|
|
// Get REGISTERVCFILEEXT to see whether we should refresh extensions list.
|
|
szValueBuf.clear();
|
|
cchValueBuf = 0;
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("REGISTERVCFILEEXT"), (LPWSTR)TEXT(""), &cchValueBuf);
|
|
if (ERROR_MORE_DATA == uiStat)
|
|
{
|
|
++cchValueBuf; // add 1 for null termination
|
|
szValueBuf.resize(cchValueBuf);
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("REGISTERVCFILEEXT"), &szValueBuf[0], &cchValueBuf);
|
|
if ((ERROR_SUCCESS == uiStat))
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_DoChecks: REGISTERVCFILEEXT = '%s'", szValueBuf.c_str());
|
|
bRefreshExts = (szValueBuf[0] == L'1');
|
|
}
|
|
}
|
|
|
|
// Get REBOOT to see whether it specified "ReallySuppress" which means no automatic reboot
|
|
szValueBuf.clear();
|
|
cchValueBuf = 0;
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("REBOOT"), (LPWSTR)TEXT(""), &cchValueBuf);
|
|
if (ERROR_MORE_DATA == uiStat)
|
|
{
|
|
++cchValueBuf; // add 1 for null termination
|
|
szValueBuf.resize(cchValueBuf);
|
|
uiStat = MsiGetProperty(hInstaller, TEXT("REBOOT"), &szValueBuf[0], &cchValueBuf);
|
|
if ((ERROR_SUCCESS == uiStat))
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_DoChecks: REBOOT = '%s'", szValueBuf.c_str());
|
|
bDisableReboot = (szValueBuf[0] == L'R' || szValueBuf[0] == L'r');
|
|
}
|
|
}
|
|
|
|
// Read RegKeys previously setup by Pre/Post-Install
|
|
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt\\Values", 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD cbValue = sizeof(DWORD);
|
|
DWORD dwValue = 0;
|
|
|
|
RegQueryValueEx (hkey, L"Silent", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
Silent = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUninstall", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUninstall = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDowngrade", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDowngrade = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUninstallInProgress", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUninstallInProgress = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"PortableMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
PortableMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"UnloadDriver", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
UnloadDriver = (dwValue == 1);
|
|
|
|
RegQueryValueEx (hkey, L"Rollback", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
Rollback = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bReinstallMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bReinstallMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUpgrade", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUpgrade = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPossiblyFirstTimeInstall", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPossiblyFirstTimeInstall = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDevm", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDevm = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"SystemEncryptionUpdate", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
SystemEncryptionUpdate = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bRestartRequired", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bRestartRequired = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bDisableSwapFiles", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bDisableSwapFiles = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bSystemRestore", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bSystemRestore = (dwValue == 1);
|
|
|
|
RegQueryValueEx (hkey, L"bPromptFastStartup", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptFastStartup = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPromptReleaseNotes", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptReleaseNotes = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bPromptTutorial", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bPromptTutorial = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUpdateRescueDisk", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUpdateRescueDisk = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bRepairMode", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bRepairMode = (dwValue == 1);
|
|
RegQueryValueEx (hkey, L"bUserSetLanguage", NULL, NULL, (LPBYTE) &dwValue, &cbValue);
|
|
bUserSetLanguage = (dwValue == 1);
|
|
|
|
RegCloseKey (hkey);
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"End VC_CustomAction_DoChecks: Could not read from registry");
|
|
goto end;
|
|
}
|
|
|
|
// Get this MSI Installer HWND.
|
|
// There cannot be 2 MSIs or more running at the same time, so we're sure we'll get ours.
|
|
// This is only possible in case of non silent install.
|
|
hwndDlg = FindWindow(L"MsiDialogCloseClass", NULL);
|
|
if (!hwndDlg && !Silent)
|
|
{
|
|
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_DoChecks: MsiDialogCloseClass not found");
|
|
goto end;
|
|
}
|
|
|
|
/* Start actual work */
|
|
|
|
if (bRefreshExts)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_DoChecks: Will refresh file extensions");
|
|
SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
|
|
}
|
|
|
|
// Check if reboot was required by the pre/post-install and set Wix property ISREBOOTREQUIRED accordingly.
|
|
if (bRestartRequired)
|
|
{
|
|
if (bDisableReboot)
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_DoChecks: reboot is required but it is disabled because \"REBOOT\" specifies ReallySuppress");
|
|
uiRet = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_DoChecks: reboot is required");
|
|
uiRet = MsiSetProperty(hInstaller, L"ISREBOOTREQUIRED", L"1");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiRet = ERROR_SUCCESS;
|
|
}
|
|
|
|
// Remove volatile regkeys
|
|
SHDeleteKey(HKEY_LOCAL_MACHINE, L"Software\\.VeraCrypt");
|
|
|
|
end:
|
|
MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_DoChecks");
|
|
return uiRet;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllMain(
|
|
HMODULE hInstDLL,
|
|
DWORD dwReason,
|
|
LPVOID lpvReserved)
|
|
{
|
|
UNREFERENCED_PARAMETER(lpvReserved);
|
|
|
|
/* Save the instance handle for later,
|
|
* especially for loading embedded Language.xml file
|
|
* in Dlgcode.c, MapResource() function.
|
|
*/
|
|
hInst = hInstDLL;
|
|
|
|
return TRUE;
|
|
}
|