mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-10-22 14:22:36 +00:00
Merge commit from fork
* Windows: protect system encryption support files Use protected Common Files storage and validated file handles for setup scripts, driver packages and loader backups. Remove legacy registrations and preserve recovery backups without accepting untrusted contents. Fail incomplete service replacement and keep setup configuration errors independent of boot-loader repair. * Windows: fix system encryption setup failure handling Remove PostOOBE registration after failed setup, even if loader rollback fails, while preserving the original exception. Honor service wait hints and checkpoints with a two-minute cap, and preserve failure codes in both installers. Restore saved driver flags when service replacement fails.
This commit is contained in:
@@ -45,6 +45,7 @@
|
||||
</li>
|
||||
<li><strong>Windows:</strong>
|
||||
<ul>
|
||||
<li>Security: Protect system encryption recovery backups and Windows feature update support files. Reject untrusted backup migration and driver sources, and warn when an encrypted system's original loader backup is unavailable. Retain recovery backups during uninstall and keep Windows Setup configuration failures independent of boot-loader repair.</li>
|
||||
<li>Security: Fix a local disclosure of limited disk metadata (<a href="https://github.com/veracrypt/VeraCrypt/security/advisories/GHSA-9mgv-w2fw-3m78" target="_blank">CVE-2026-77572</a>).</li>
|
||||
<li>Fix driver stability regressions reported with VeraCrypt 1.26.29 and improve cleanup during mounting and dismounting.</li>
|
||||
<li>Prevent incompatible EFI bootloader installation when Secure Boot is enabled. Refresh the Windows Boot Manager copy from compatible Windows files.</li>
|
||||
@@ -53,6 +54,7 @@
|
||||
<li>Fix windows and dialogs appearing off screen or on the wrong monitor (GH #1858, GH #1865, GH #1912).</li>
|
||||
<li>Update bundled zlib to 1.3.2 and LZMA SDK to 26.02.</li>
|
||||
</ul>
|
||||
<p><strong>Upgrade note for system encryption:</strong> Install the updated VeraCrypt before preparing a Windows feature update, and resolve any Windows update support or original loader backup warning. If Windows Setup has already staged support files, restart feature-update preparation so it stages the updated files; installing VeraCrypt does not replace a previously staged script. Preserve existing recovery backups and a known trustworthy VeraCrypt Rescue Disk. Changing an old backup's ownership or permissions does not establish that its contents are safe.</p>
|
||||
</li>
|
||||
<li><strong>Linux, macOS and BSD:</strong>
|
||||
<ul>
|
||||
|
||||
@@ -74,6 +74,11 @@ Thus, when setting or entering your password, it's crucial to type it manually u
|
||||
running). In EFI boot mode, which is the default on modern PCs, VeraCrypt can not encrypt this partition since it must remain unencrypted so that the BIOS can load the EFI bootloader from it. This in turn implies that in EFI boot mode, VeraCrypt offers only to encrypt the system partition where Windows is installed (the user can later manually encrypt other data partitions using VeraCrypt).
|
||||
In MBR legacy boot mode, VeraCrypt encrypts the partition only if you choose to encrypt the whole system drive (as opposed to choosing to encrypt only the partition where Windows is installed).</p>
|
||||
<p>In EFI boot mode with Secure Boot enabled, VeraCrypt selects a Microsoft UEFI CA-signed bootloader set allowed by the active firmware Secure Boot policy during install, repair, upgrade, or Windows PostOOBE repair: every required CA must be present in the allowed database (db) and absent from the forbidden database (dbx). The 2023 VeraCrypt loader set requires both Microsoft UEFI CA 2023 and Microsoft Option ROM UEFI CA 2023, while the 2011 loader set requires Microsoft Corporation UEFI CA 2011. If the active db/dbx policy permits neither supported set, VeraCrypt aborts instead of installing a loader that firmware will reject. If you manually change firmware Secure Boot db or dbx entries, run VeraCrypt repair or reinstall to refresh the installed bootloader set. For details, including the Microsoft 2023 certificate transition and recovery procedures, see <a href="EFISecureBoot.html" style="text-align:left; color:#0080c0; text-decoration:none">EFI Secure Boot</a>.</p>
|
||||
<h3>Windows feature updates and recovery files</h3>
|
||||
<p>Install the current VeraCrypt before preparing a Windows feature update. Resolve any warning about Windows feature update support before continuing. If Windows Setup has already staged its support files, restart feature-update preparation so that it stages the updated files. Updating VeraCrypt changes the source registration; it does not replace a script that Windows Setup has already copied. See Microsoft's <a href="https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-setup-command-line-options#postoobe" target="_blank">Windows Setup documentation</a> for details of script staging.</p>
|
||||
<p>If the installer cannot verify or remove VeraCrypt's previous Windows feature update registrations, it reports installation failure because security remediation is incomplete. Resolve the reported error and run Repair/Reinstall. An encrypted-system upgrade also reports failure if it cannot publish the replacement support files. Resolve the error before starting a Windows feature update.</p>
|
||||
<p>VeraCrypt checks the ownership and permissions of recovery backups before using or migrating them. On BIOS systems, automatic original-loader restoration requires a complete trusted backup. If that backup is unavailable, VeraCrypt asks for explicit confirmation before decryption or cleanup without automatic loader restoration; obtain trusted recovery media first. If an upgrade warns that the original loader backup is missing, damaged, unreadable, or untrusted, preserve any existing backup files and obtain a known trustworthy VeraCrypt Rescue Disk or a verified original backup before proceeding. Changing ownership or permissions alone cannot establish the safety of an old backup. Do not create a replacement backup from the current boot area of an encrypted system, or restore an unencrypted loader while the drive remains encrypted.</p>
|
||||
<p>New support files are stored in the VeraCryptSystem directory under the native Common Files folder (normally C:\Program Files\Common Files). Recovery backups are retained during application uninstall. Cleanup removes VeraCrypt's Windows Setup registrations and leaves protected support files in place; it does not depend on deleting a file that another process has open. A failure to remove a registration still requires resolution.</p>
|
||||
<p> </p>
|
||||
<p><a href="Hidden%20Operating%20System.html" style="text-align:left; color:#0080c0; text-decoration:none; font-weight:bold">Next Section >></a></p>
|
||||
</div>
|
||||
|
||||
+11
-4
@@ -352,14 +352,21 @@ DWORD BaseCom::BackupEfiSystemLoader ()
|
||||
BootEncryption bootEnc (NULL);
|
||||
bootEnc.BackupSystemLoader ();
|
||||
}
|
||||
catch (SystemException &)
|
||||
catch (SystemException &e)
|
||||
{
|
||||
return GetLastError();
|
||||
return e.ErrorCode;
|
||||
}
|
||||
catch (UserAbort&)
|
||||
{
|
||||
return ERROR_CANCELLED;
|
||||
}
|
||||
catch (ErrorException &e)
|
||||
{
|
||||
if (e.ErrLangId && strcmp (e.ErrLangId, "TC_BOOT_LOADER_ALREADY_INSTALLED") == 0)
|
||||
return TC_ERROR_BOOT_LOADER_ALREADY_INSTALLED;
|
||||
e.Show (NULL);
|
||||
return ERROR_EXCEPTION_IN_SERVICE;
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
e.Show (NULL);
|
||||
@@ -525,9 +532,9 @@ DWORD BaseCom::UpdateSetupConfigFile (BOOL bForInstall)
|
||||
BootEncryption bootEnc (NULL);
|
||||
bootEnc.UpdateSetupConfigFile (bForInstall? true : false);
|
||||
}
|
||||
catch (SystemException &)
|
||||
catch (SystemException &e)
|
||||
{
|
||||
return GetLastError();
|
||||
return e.ErrorCode;
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
|
||||
+400
-197
@@ -18,6 +18,8 @@
|
||||
#include <shlobj.h>
|
||||
#include <atlbase.h>
|
||||
#include "BootEncryption.h"
|
||||
#include "SystemEncryptionFiles.h"
|
||||
#include "SystemEncryptionSetup.h"
|
||||
#include "Boot/Windows/BootCommon.h"
|
||||
#include "Common/Resource.h"
|
||||
#include "Crc.h"
|
||||
@@ -598,11 +600,16 @@ namespace VeraCrypt
|
||||
}
|
||||
}
|
||||
|
||||
static void BackupEfiSystemLoader ()
|
||||
static void BackupEfiSystemLoader (HWND parent)
|
||||
{
|
||||
Elevate();
|
||||
|
||||
DWORD result = ElevatedComInstance->BackupEfiSystemLoader ();
|
||||
if (result == TC_ERROR_BOOT_LOADER_ALREADY_INSTALLED)
|
||||
{
|
||||
if (AskWarnNoYes ("TC_BOOT_LOADER_ALREADY_INSTALLED", parent) != IDYES) throw UserAbort (SRC_POS);
|
||||
return;
|
||||
}
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
if (result == ERROR_CANCELLED)
|
||||
@@ -796,7 +803,7 @@ namespace VeraCrypt
|
||||
static void FastFileResize (const wstring &filePath, __int64 fileSize) { throw ParameterIncorrect (SRC_POS); }
|
||||
static BOOL DeviceIoControl (BOOL readOnly, BOOL device, const wstring &filePath, DWORD dwIoControlCode, LPVOID input, DWORD inputSize, LPVOID output, DWORD outputSize) { throw ParameterIncorrect (SRC_POS); }
|
||||
static void InstallEfiBootLoader (bool preserveUserConfig, bool hiddenOSCreation, int pim, int hashAlg) { throw ParameterIncorrect (SRC_POS); }
|
||||
static void BackupEfiSystemLoader () { throw ParameterIncorrect (SRC_POS); }
|
||||
static void BackupEfiSystemLoader (HWND parent) { (void) parent; throw ParameterIncorrect (SRC_POS); }
|
||||
static void RestoreEfiSystemLoader () { throw ParameterIncorrect (SRC_POS); }
|
||||
static void GetEfiBootDeviceNumber (PSTORAGE_DEVICE_NUMBER pSdn) { throw ParameterIncorrect (SRC_POS); }
|
||||
static void WriteEfiBootSectorUserConfig (uint8 userConfig, const string &customUserMessage, int pim, int hashAlg) { throw ParameterIncorrect (SRC_POS); }
|
||||
@@ -813,11 +820,11 @@ namespace VeraCrypt
|
||||
|
||||
#endif // SETUP
|
||||
|
||||
File::File (wstring path, bool readOnly, bool create) : Elevated (false), FileOpen (false), ReadOnly (readOnly), LastError(0)
|
||||
File::File (wstring path, bool readOnly, bool create, DWORD sharing) : Elevated (false), FileOpen (false), ReadOnly (readOnly), LastError(0)
|
||||
{
|
||||
Handle = CreateFile (path.c_str(),
|
||||
readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING,
|
||||
sharing, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING,
|
||||
FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
|
||||
|
||||
if (Handle != INVALID_HANDLE_VALUE)
|
||||
@@ -828,7 +835,9 @@ namespace VeraCrypt
|
||||
{
|
||||
LastError = GetLastError();
|
||||
#ifndef SETUP
|
||||
if (LastError == ERROR_ACCESS_DENIED && IsUacSupported())
|
||||
// The COM read fallback reopens the pathname for each operation. It
|
||||
// cannot provide a stable handle when a caller excludes other writers.
|
||||
if (LastError == ERROR_ACCESS_DENIED && sharing == (FILE_SHARE_READ | FILE_SHARE_WRITE) && IsUacSupported())
|
||||
{
|
||||
Elevated = true;
|
||||
FileOpen = true;
|
||||
@@ -4552,13 +4561,14 @@ namespace VeraCrypt
|
||||
f.Close();
|
||||
}
|
||||
|
||||
bool EfiBoot::ReadFileToBuffer (const wchar_t* name, std::vector<uint8>& fileContent)
|
||||
bool EfiBoot::ReadFileToBuffer (const wchar_t* name, std::vector<uint8>& fileContent, bool requireStableRead)
|
||||
{
|
||||
fileContent.clear ();
|
||||
wstring path = EfiBootPartPath;
|
||||
path += name;
|
||||
|
||||
File f(path, true);
|
||||
File f(path, true, false, requireStableRead ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE);
|
||||
if (requireStableRead) f.CheckOpened (SRC_POS);
|
||||
if (!f.IsOpened ())
|
||||
{
|
||||
f.Close ();
|
||||
@@ -4585,6 +4595,7 @@ namespace VeraCrypt
|
||||
if (f.Read (fileContent.data (), fileSize32) != fileSize32)
|
||||
{
|
||||
f.Close ();
|
||||
fileContent.clear ();
|
||||
throw ErrorException (wstring (GetString ("EFI_BOOT_LOADER_FILE_READ_FAILED"))
|
||||
+ L"\n" + name, SRC_POS);
|
||||
}
|
||||
@@ -4748,111 +4759,205 @@ namespace VeraCrypt
|
||||
return conf.Save (path.c_str(), hwndDlg);
|
||||
}
|
||||
|
||||
static wstring GetSystemEncryptionDataDirectory (bool legacy = false)
|
||||
{
|
||||
wchar_t path[MAX_PATH];
|
||||
if (legacy)
|
||||
{
|
||||
HRESULT result = SHGetFolderPathW (NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, path);
|
||||
if (FAILED (result)) { SetLastError (HRESULT_CODE (result)); throw SystemException (SRC_POS); }
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unlike ProgramData, native Common Files does not let ordinary users
|
||||
// reserve our directory name. Use the same registry view in the x86
|
||||
// installer/COM server and the native service; keep backups independent
|
||||
// of the installation path and application uninstallation.
|
||||
DWORD size = sizeof (path);
|
||||
HKEY key;
|
||||
LSTATUS error = RegOpenKeyExW (HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
|
||||
0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
error = RegGetValueW (key, NULL, L"CommonFilesDir", RRF_RT_REG_SZ, NULL, path, &size);
|
||||
RegCloseKey (key);
|
||||
}
|
||||
if (error != ERROR_SUCCESS) { SetLastError (error); throw SystemException (SRC_POS); }
|
||||
}
|
||||
// Never change the owner of a legacy backup to make its old bytes trusted.
|
||||
return wstring (path) + (legacy ? L"\\VeraCrypt" : L"\\VeraCryptSystem");
|
||||
}
|
||||
|
||||
static void CheckSystemEncryptionFileResult (DWORD error)
|
||||
{
|
||||
if (error != ERROR_SUCCESS)
|
||||
{
|
||||
SetLastError (error);
|
||||
throw SystemException (SRC_POS);
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<unsigned char> SystemEncryptionSetupScript (wstring installation)
|
||||
{
|
||||
if (!installation.empty () && installation.back () == L'\\') installation.pop_back ();
|
||||
if (installation.size () < 3 || installation[1] != L':' || installation[2] != L'\\'
|
||||
|| installation.find_first_of (L"\"\r\n%") != wstring::npos)
|
||||
CheckSystemEncryptionFileResult (ERROR_BAD_PATHNAME);
|
||||
// cmd does not necessarily use the ANSI code page, and inherits delayed
|
||||
// expansion from its caller. Parse the ASCII preamble on separate lines
|
||||
// before reading the UTF-8 command. Never execute it if chcp fails.
|
||||
wstring command = L"@echo off\r\nsetlocal EnableExtensions DisableDelayedExpansion\r\n";
|
||||
// ASCII paths need no code-page change, including in a detached cmd
|
||||
// process with no console on which chcp could operate.
|
||||
for (size_t i = 0; i < installation.size (); ++i)
|
||||
{
|
||||
if (installation[i] > 0x7f)
|
||||
{
|
||||
command += L"\"%SystemRoot%\\System32\\chcp.com\" 65001 >nul\r\nif errorlevel 1 exit /b 1\r\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
command += L"\"" + installation + L"\\VeraCrypt.exe\" /PostOOBE\r\n";
|
||||
int length = WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, command.c_str (), (int) command.size (), NULL, 0, NULL, NULL);
|
||||
throw_sys_if (length <= 0);
|
||||
std::vector<unsigned char> script (length);
|
||||
throw_sys_if (!WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, command.c_str (), (int) command.size (),
|
||||
reinterpret_cast<char *> (&script[0]), length, NULL, NULL));
|
||||
return script;
|
||||
}
|
||||
|
||||
static void WriteSystemEncryptionSetupConfig (const wstring &directory, const SystemEncryptionSetup::Ini &config,
|
||||
std::vector<unsigned char> &snapshot, bool preserveEncoding = true)
|
||||
{
|
||||
if (config.IsEmpty ())
|
||||
{
|
||||
// Windows Setup can reject an empty configuration. Sanitizing an
|
||||
// absent file must not create one before staging has even succeeded.
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Remove (directory, L"SetupConfig.ini", &snapshot));
|
||||
snapshot.clear ();
|
||||
return;
|
||||
}
|
||||
std::vector<unsigned char> bytes;
|
||||
if (preserveEncoding) CheckSystemEncryptionFileResult (config.PreservedBytes (bytes));
|
||||
else bytes = config.Bytes ();
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Write (directory, L"SetupConfig.ini",
|
||||
bytes.data (), (DWORD) bytes.size (), &snapshot));
|
||||
snapshot.swap (bytes);
|
||||
}
|
||||
|
||||
static bool SystemEncryptionSetupPathMatches (wstring path, wstring ownedPath)
|
||||
{
|
||||
std::replace (path.begin (), path.end (), L'/', L'\\');
|
||||
std::replace (ownedPath.begin (), ownedPath.end (), L'/', L'\\');
|
||||
while (path.size () > 3 && path.back () == L'\\') path.pop_back ();
|
||||
while (ownedPath.size () > 3 && ownedPath.back () == L'\\') ownedPath.pop_back ();
|
||||
return !ownedPath.empty () && _wcsicmp (path.c_str (), ownedPath.c_str ()) == 0;
|
||||
}
|
||||
|
||||
void BootEncryption::PrepareSystemEncryptionInstallation (const wchar_t *path)
|
||||
{
|
||||
wstring installation = path;
|
||||
if (!installation.empty () && installation.back () == L'\\') installation.pop_back ();
|
||||
DWORD error = SystemEncryptionFiles::ProvisionInstallerObject (installation, true);
|
||||
if (!SystemEncryptionFiles::Missing (error)) CheckSystemEncryptionFileResult (error);
|
||||
SystemEncryptionFiles::Directory directory;
|
||||
CheckSystemEncryptionFileResult (directory.Open (installation, true));
|
||||
PrepareSystemEncryptionStorage ();
|
||||
}
|
||||
|
||||
void BootEncryption::PrepareSystemEncryptionStorage ()
|
||||
{
|
||||
SystemEncryptionFiles::Directory directory;
|
||||
CheckSystemEncryptionFileResult (directory.Open (GetSystemEncryptionDataDirectory (), true));
|
||||
}
|
||||
|
||||
void BootEncryption::UpdateSetupConfigFile (bool bForInstall)
|
||||
{
|
||||
// starting from Windows 10 1607 (Build 14393), ReflectDrivers in Setupconfig.ini is supported
|
||||
if (IsWin10BuildAtLeast(WIN_10_1607_BUILD))
|
||||
if (!IsWin10BuildAtLeast (WIN_10_1607_BUILD)) return;
|
||||
wchar_t location[TC_MAX_PATH + 20], installPath[TC_MAX_PATH] = { 0 };
|
||||
if (!GetSetupconfigLocation (location, ARRAYSIZE (location))) CheckSystemEncryptionFileResult (ERROR_PATH_NOT_FOUND);
|
||||
wstring configDirectory = location;
|
||||
while (configDirectory.size () > 3 && configDirectory.back () == L'\\') configDirectory.pop_back ();
|
||||
// Normalize only a full administrator's own objects. Never adopt an ordinary
|
||||
// user's configuration or change permissions on a legacy loader backup.
|
||||
for (bool folder : { true, false })
|
||||
{
|
||||
wchar_t szInstallPath [TC_MAX_PATH];
|
||||
wchar_t szSetupconfigLocation [TC_MAX_PATH + 20];
|
||||
|
||||
if (bForInstall)
|
||||
DWORD provision = SystemEncryptionFiles::ProvisionInstallerObject (folder ? configDirectory : configDirectory + L"\\SetupConfig.ini", folder);
|
||||
if (!SystemEncryptionFiles::Missing (provision)) CheckSystemEncryptionFileResult (provision);
|
||||
}
|
||||
SystemEncryptionFiles::Directory directory;
|
||||
DWORD error = directory.Open (configDirectory, bForInstall);
|
||||
if (!bForInstall && SystemEncryptionFiles::Missing (error)) return;
|
||||
CheckSystemEncryptionFileResult (error);
|
||||
// Serialize only configuration publication. The lock lives in the already
|
||||
// validated directory, so an ordinary user cannot reserve its name first.
|
||||
SystemEncryptionFiles::SecurityDescriptor security;
|
||||
throw_sys_if (!ConvertStringSecurityDescriptorToSecurityDescriptorW (
|
||||
L"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)", SDDL_REVISION_1, &security.Value, NULL));
|
||||
SystemEncryptionFiles::Handle lock;
|
||||
CheckSystemEncryptionFileResult (directory.OpenFile (L"VeraCrypt-SetupConfig.lock", GENERIC_WRITE | READ_CONTROL | FILE_READ_ATTRIBUTES,
|
||||
0, FILE_OPEN_IF, security.Value, lock));
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::CheckHandle (lock.Value, false));
|
||||
std::vector<unsigned char> snapshot;
|
||||
error = SystemEncryptionFiles::Read (directory, L"SetupConfig.ini", snapshot);
|
||||
if (!SystemEncryptionFiles::Missing (error)) CheckSystemEncryptionFileResult (error);
|
||||
else if (!bForInstall) return;
|
||||
SystemEncryptionSetup::Ini config;
|
||||
CheckSystemEncryptionFileResult (config.Load (snapshot));
|
||||
GetInstallationPath (NULL, installPath, ARRAYSIZE (installPath), NULL);
|
||||
wstring installation = installPath;
|
||||
if (!installation.empty () && installation.back () == L'\\') installation.pop_back ();
|
||||
const wstring storage = GetSystemEncryptionDataDirectory ();
|
||||
const wstring scriptPath = storage + L"\\SetupComplete.cmd", driversPath = storage + L"\\Drivers";
|
||||
const wstring legacyScript = GetSystemEncryptionDataDirectory (true) + L"\\SetupComplete.cmd";
|
||||
bool legacy = false, foreign = false;
|
||||
CheckSystemEncryptionFileResult (config.RemoveMatching (L"PostOOBE", [&] (const wstring &path) {
|
||||
bool old = SystemEncryptionSetupPathMatches (path, legacyScript);
|
||||
bool ours = old || SystemEncryptionSetupPathMatches (path, scriptPath);
|
||||
legacy |= old;
|
||||
foreign |= !path.empty () && !ours;
|
||||
return ours;
|
||||
}));
|
||||
CheckSystemEncryptionFileResult (config.RemoveMatching (L"ReflectDrivers", [&] (const wstring &path) {
|
||||
bool ours = SystemEncryptionSetupPathMatches (path, installation) || SystemEncryptionSetupPathMatches (path, driversPath);
|
||||
foreign |= !path.empty () && !ours;
|
||||
return ours;
|
||||
}));
|
||||
// Disarm the vulnerable script before any attempt to create new storage.
|
||||
// The installer also calls this cleanup before replacing its package.
|
||||
if (legacy || !bForInstall) WriteSystemEncryptionSetupConfig (configDirectory, config, snapshot);
|
||||
if (!bForInstall) return;
|
||||
SystemEncryptionSetup::Ini clean = config;
|
||||
try
|
||||
{
|
||||
if (foreign) throw ErrorException ("SYSENC_SETUP_CONFIG_CONFLICT", SRC_POS);
|
||||
SystemEncryptionFiles::Directory target;
|
||||
SystemEncryptionFiles::Handle executable;
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::OpenInstallerFile (installation + L"\\VeraCrypt.exe", target, executable));
|
||||
std::vector<unsigned char> script = SystemEncryptionSetupScript (installation), package[3];
|
||||
const wchar_t *names[] = { L"veracrypt.inf", L"veracrypt.sys", L"veracrypt.cat" };
|
||||
for (size_t i = 0; i < ARRAYSIZE (names); ++i)
|
||||
{
|
||||
GetInstallationPath (NULL, szInstallPath, ARRAYSIZE (szInstallPath), NULL);
|
||||
// remove ending backslash
|
||||
if (szInstallPath [wcslen (szInstallPath) - 1] == L'\\')
|
||||
{
|
||||
szInstallPath [wcslen (szInstallPath) - 1] = 0;
|
||||
}
|
||||
}
|
||||
if (GetSetupconfigLocation (szSetupconfigLocation, ARRAYSIZE (szSetupconfigLocation)))
|
||||
{
|
||||
if (bForInstall)
|
||||
::CreateDirectoryW (szSetupconfigLocation, NULL);
|
||||
|
||||
StringCchCatW (szSetupconfigLocation, ARRAYSIZE (szSetupconfigLocation), L"SetupConfig.ini");
|
||||
|
||||
if (bForInstall)
|
||||
{
|
||||
/* Before updating files, we check first if they already have the expected content. If yes, then we don't perform
|
||||
* any write operation to avoid modifying file timestamps Unnecessarily.
|
||||
*/
|
||||
bool bSkipWrite = false;
|
||||
wchar_t wszBuffer [2 * TC_MAX_PATH] = {0};
|
||||
wstring szPathParam = L"\"";
|
||||
szPathParam += szInstallPath;
|
||||
szPathParam += L"\"";
|
||||
|
||||
if ( (0 < GetPrivateProfileStringW (L"SetupConfig", L"ReflectDrivers", L"", wszBuffer, ARRAYSIZE (wszBuffer), szSetupconfigLocation))
|
||||
&& (_wcsicmp (wszBuffer, szInstallPath) == 0)
|
||||
)
|
||||
{
|
||||
bSkipWrite = true;
|
||||
}
|
||||
|
||||
if (!bSkipWrite)
|
||||
WritePrivateProfileStringW (L"SetupConfig", L"ReflectDrivers", szPathParam.c_str(), szSetupconfigLocation);
|
||||
|
||||
bSkipWrite = false;
|
||||
szPathParam = GetProgramConfigPath (L"SetupComplete.cmd");
|
||||
|
||||
wstring wszExpectedValue = L"\"";
|
||||
wszExpectedValue += szInstallPath;
|
||||
wszExpectedValue += L"\\VeraCrypt.exe\" /PostOOBE";
|
||||
|
||||
FILE* scriptFile = _wfopen (szPathParam.c_str(), L"r");
|
||||
if (scriptFile)
|
||||
{
|
||||
long fileSize = _filelength (_fileno (scriptFile));
|
||||
if (fileSize < (2 * TC_MAX_PATH))
|
||||
{
|
||||
fgetws (wszBuffer, ARRAYSIZE (wszBuffer), scriptFile);
|
||||
|
||||
if (wszBuffer[wcslen (wszBuffer) - 1] == L'\n')
|
||||
wszBuffer[wcslen (wszBuffer) - 1] = 0;
|
||||
|
||||
bSkipWrite = (0 == _wcsicmp (wszBuffer, wszExpectedValue.c_str()));
|
||||
}
|
||||
fclose (scriptFile);
|
||||
}
|
||||
|
||||
if (!bSkipWrite)
|
||||
{
|
||||
scriptFile = _wfopen (szPathParam.c_str(), L"w");
|
||||
if (scriptFile)
|
||||
{
|
||||
fwprintf (scriptFile, L"%s\n", wszExpectedValue.c_str());
|
||||
fclose (scriptFile);
|
||||
}
|
||||
}
|
||||
|
||||
bSkipWrite = false;
|
||||
|
||||
if ( (0 < GetPrivateProfileStringW (L"SetupConfig", L"PostOOBE", L"", wszBuffer, ARRAYSIZE (wszBuffer), szSetupconfigLocation))
|
||||
&& (_wcsicmp (wszBuffer, szPathParam.c_str()) == 0)
|
||||
)
|
||||
{
|
||||
bSkipWrite = true;
|
||||
}
|
||||
|
||||
if (!bSkipWrite)
|
||||
WritePrivateProfileStringW (L"SetupConfig", L"PostOOBE", szPathParam.c_str(), szSetupconfigLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FileExists (szSetupconfigLocation))
|
||||
{
|
||||
WritePrivateProfileStringW (L"SetupConfig", L"ReflectDrivers", NULL, szSetupconfigLocation);
|
||||
WritePrivateProfileStringW (L"SetupConfig", L"PostOOBE", NULL, szSetupconfigLocation);
|
||||
}
|
||||
|
||||
wstring scriptFilePath = GetProgramConfigPath (L"SetupComplete.cmd");
|
||||
if (FileExists (scriptFilePath.c_str()))
|
||||
{
|
||||
::DeleteFileW (scriptFilePath.c_str());
|
||||
}
|
||||
}
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::ProvisionInstallerObject (installation + L"\\" + names[i], false));
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Read (target, names[i], package[i]));
|
||||
if (package[i].empty ()) CheckSystemEncryptionFileResult (ERROR_INVALID_DATA);
|
||||
}
|
||||
PrepareSystemEncryptionStorage ();
|
||||
SystemEncryptionFiles::Directory drivers;
|
||||
CheckSystemEncryptionFileResult (drivers.Open (driversPath, true));
|
||||
for (size_t i = 0; i < ARRAYSIZE (names); ++i)
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Write (driversPath, names[i], package[i].data (), (DWORD) package[i].size ()));
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Write (storage, L"SetupComplete.cmd", script.data (), (DWORD) script.size ()));
|
||||
wstring scriptValue = L"\"" + scriptPath + L"\"", driversValue = L"\"" + driversPath + L"\"";
|
||||
CheckSystemEncryptionFileResult (config.Set (L"PostOOBE", &scriptValue));
|
||||
CheckSystemEncryptionFileResult (config.Set (L"ReflectDrivers", &driversValue));
|
||||
WriteSystemEncryptionSetupConfig (configDirectory, config, snapshot, false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Never leave an old registration pointing at files that failed validation.
|
||||
WriteSystemEncryptionSetupConfig (configDirectory, clean, snapshot);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5194,14 +5299,6 @@ namespace VeraCrypt
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsAdmin() && IsUacSupported())
|
||||
{
|
||||
Elevator::UpdateSetupConfigFile (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSetupConfigFile (true);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SETUP
|
||||
@@ -5249,32 +5346,69 @@ namespace VeraCrypt
|
||||
}
|
||||
#endif
|
||||
|
||||
wstring BootEncryption::GetSystemLoaderBackupPath ()
|
||||
|
||||
void BootEncryption::ReadSystemLoaderBackup (std::vector<uint8> &data)
|
||||
{
|
||||
WCHAR pathBuf[MAX_PATH];
|
||||
|
||||
throw_sys_if (!SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, pathBuf)));
|
||||
|
||||
wstring path = wstring (pathBuf) + L"\\" _T(TC_APP_NAME);
|
||||
CreateDirectory (path.c_str(), NULL);
|
||||
|
||||
return path + L'\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME;
|
||||
}
|
||||
|
||||
|
||||
void BootEncryption::RenameDeprecatedSystemLoaderBackup ()
|
||||
{
|
||||
WCHAR pathBuf[MAX_PATH];
|
||||
|
||||
if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA, NULL, 0, pathBuf)))
|
||||
SystemEncryptionFiles::Directory protectedDirectory;
|
||||
DWORD error = protectedDirectory.Open (GetSystemEncryptionDataDirectory (), false, false, false);
|
||||
if (error == ERROR_INVALID_SECURITY_DESCR || error == ERROR_REPARSE_POINT_ENCOUNTERED)
|
||||
throw ErrorException ("SYSENC_STORAGE_UNTRUSTED", SRC_POS);
|
||||
if (error == ERROR_SUCCESS) error = SystemEncryptionFiles::Read (protectedDirectory, TC_SYS_BOOT_LOADER_BACKUP_NAME, data);
|
||||
if (SystemEncryptionFiles::Missing (error))
|
||||
{
|
||||
wstring path = wstring (pathBuf) + L"\\" _T(TC_APP_NAME) + L'\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME_LEGACY;
|
||||
|
||||
if (FileExists (path.c_str()) && !FileExists (GetSystemLoaderBackupPath().c_str()))
|
||||
throw_sys_if (_wrename (path.c_str(), GetSystemLoaderBackupPath().c_str()) != 0);
|
||||
wstring legacyDirectory = GetSystemEncryptionDataDirectory (true);
|
||||
error = SystemEncryptionFiles::Read (legacyDirectory, TC_SYS_BOOT_LOADER_BACKUP_NAME, data, true);
|
||||
if (SystemEncryptionFiles::Missing (error))
|
||||
error = SystemEncryptionFiles::Read (legacyDirectory, TC_SYS_BOOT_LOADER_BACKUP_NAME_LEGACY, data, true);
|
||||
}
|
||||
if (error == ERROR_INVALID_SECURITY_DESCR)
|
||||
throw ErrorException ("SYS_LOADER_BACKUP_UNTRUSTED", SRC_POS);
|
||||
CheckSystemEncryptionFileResult (error);
|
||||
if (data.empty ())
|
||||
throw ErrorException ("SYS_LOADER_BACKUP_EMPTY", SRC_POS);
|
||||
}
|
||||
|
||||
void BootEncryption::ReadSystemLoaderBackupForRestore (std::vector<uint8> &data)
|
||||
{
|
||||
// Preserve the actual failure. Interactive callers add recovery guidance
|
||||
// after reporting the access, trust, missing-file or size error.
|
||||
ReadSystemLoaderBackup (data);
|
||||
if (data.size () != TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
|
||||
throw ErrorException ("SYS_LOADER_BACKUP_SIZE_INVALID", SRC_POS);
|
||||
}
|
||||
|
||||
void BootEncryption::RenameDeprecatedSystemLoaderBackup (bool requireBackup)
|
||||
{
|
||||
// Both installers call this during upgrades. Copy only a validated legacy
|
||||
// backup, and retain the original for recovery. Never bless old bytes by
|
||||
// taking ownership or by hashing them during migration.
|
||||
std::vector<uint8> data;
|
||||
DWORD error = SystemEncryptionFiles::Read (GetSystemEncryptionDataDirectory (), TC_SYS_BOOT_LOADER_BACKUP_NAME, data);
|
||||
bool protectedBackup = error == ERROR_SUCCESS;
|
||||
if (!protectedBackup)
|
||||
{
|
||||
if (!SystemEncryptionFiles::Missing (error)) CheckSystemEncryptionFileResult (error);
|
||||
try
|
||||
{
|
||||
ReadSystemLoaderBackup (data);
|
||||
}
|
||||
catch (SystemException &e)
|
||||
{
|
||||
if (!requireBackup && SystemEncryptionFiles::Missing (e.ErrorCode)) return;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// Migration being unnecessary does not establish recovery availability.
|
||||
// Validate existing protected bytes too, and never publish a partial BIOS
|
||||
// backup. EFI backups have a variable size and the same capture bound.
|
||||
if (data.empty () || (GetSystemDriveConfiguration ().SystemPartition.IsGPT
|
||||
? data.size () > TC_MAX_EFI_BOOT_LOADER_FILE_SIZE
|
||||
: data.size () != TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS))
|
||||
CheckSystemEncryptionFileResult (ERROR_INVALID_DATA);
|
||||
if (!protectedBackup)
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Write (GetSystemEncryptionDataDirectory (),
|
||||
TC_SYS_BOOT_LOADER_BACKUP_NAME, &data[0], (DWORD) data.size ()));
|
||||
}
|
||||
|
||||
#ifndef SETUP
|
||||
void BootEncryption::CreateRescueIsoImage (bool initialSetup, const wstring &isoImagePath)
|
||||
@@ -5355,17 +5489,12 @@ namespace VeraCrypt
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
// Original system loader
|
||||
Buffer fileBuf (0);
|
||||
std::vector<uint8> fileBuf;
|
||||
bool bLoadAdded = false;
|
||||
try
|
||||
{
|
||||
DWORD fileSize = 0;
|
||||
File sysBakFile (GetSystemLoaderBackupPath(), true);
|
||||
sysBakFile.CheckOpened (SRC_POS);
|
||||
sysBakFile.GetFileSize(fileSize);
|
||||
fileBuf.Resize ((DWORD) fileSize);
|
||||
DWORD sizeLoader = sysBakFile.Read (fileBuf.Ptr (), fileSize);
|
||||
bLoadAdded = ZipAdd (z, "EFI/Boot/original_bootx64.vc_backup", fileBuf.Ptr (), sizeLoader);
|
||||
ReadSystemLoaderBackup (fileBuf);
|
||||
bLoadAdded = ZipAdd (z, "EFI/Boot/original_bootx64.vc_backup", &fileBuf[0], (DWORD) fileBuf.size ());
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
@@ -5526,9 +5655,12 @@ namespace VeraCrypt
|
||||
// Original system loader
|
||||
try
|
||||
{
|
||||
File sysBakFile (GetSystemLoaderBackupPath(), true);
|
||||
sysBakFile.CheckOpened (SRC_POS);
|
||||
sysBakFile.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE);
|
||||
std::vector<uint8> originalLoader;
|
||||
ReadSystemLoaderBackup (originalLoader);
|
||||
if (originalLoader.size () != TC_BOOT_LOADER_AREA_SIZE)
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
memcpy (image + TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET,
|
||||
&originalLoader[0], originalLoader.size ());
|
||||
|
||||
image[TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER;
|
||||
}
|
||||
@@ -5939,25 +6071,26 @@ namespace VeraCrypt
|
||||
|
||||
void BootEncryption::BackupSystemLoader ()
|
||||
{
|
||||
// The existing COM entry point already calls this method for either disk
|
||||
// type. Elevate the whole capture/write operation, including BIOS backups.
|
||||
if (!IsAdmin ())
|
||||
{
|
||||
if (IsUacSupported ())
|
||||
{
|
||||
Elevator::BackupEfiSystemLoader (ParentWindow);
|
||||
return;
|
||||
}
|
||||
CheckSystemEncryptionFileResult (ERROR_ACCESS_DENIED);
|
||||
}
|
||||
PrepareSystemEncryptionStorage ();
|
||||
if (GetSystemDriveConfiguration().SystemPartition.IsGPT)
|
||||
{
|
||||
if (!IsAdmin()) {
|
||||
if (IsUacSupported())
|
||||
{
|
||||
Elevator::BackupEfiSystemLoader ();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning ("ADMIN_PRIVILEGES_WARN_DEVICES", ParentWindow);
|
||||
}
|
||||
}
|
||||
unsigned __int64 loaderSize = 0;
|
||||
std::vector<uint8> bootLoaderBuf;
|
||||
const wchar_t * szStdMsBootloader = L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi";
|
||||
const wchar_t * szBackupMsBootloader = L"\\EFI\\Microsoft\\Boot\\bootmgfw_ms.vc";
|
||||
const char* g_szMsBootString = "bootmgfw.pdb";
|
||||
bool bModifiedMsBoot = true;
|
||||
bool restoreStandardLoader = false;
|
||||
|
||||
EfiBootInst.PrepareBootPartition();
|
||||
|
||||
@@ -5967,20 +6100,19 @@ namespace VeraCrypt
|
||||
throw UserAbort (SRC_POS);
|
||||
}
|
||||
|
||||
EfiBootInst.GetFileSize(szStdMsBootloader, loaderSize);
|
||||
bootLoaderBuf.resize ((size_t) loaderSize);
|
||||
EfiBootInst.ReadFile(szStdMsBootloader, &bootLoaderBuf[0], (DWORD) loaderSize);
|
||||
if (!EfiBootInst.ReadFileToBuffer (szStdMsBootloader, bootLoaderBuf, true))
|
||||
throw ErrorException ("WINDOWS_EFI_BOOT_LOADER_MISSING", SRC_POS);
|
||||
|
||||
// DcsBoot.efi is always smaller than 32KB
|
||||
if (loaderSize > 32768)
|
||||
if (bootLoaderBuf.size () > 32768)
|
||||
{
|
||||
// look for bootmgfw.efi identifiant string
|
||||
if (BufferHasPattern (bootLoaderBuf.data (), (size_t) loaderSize, g_szMsBootString, strlen (g_szMsBootString)))
|
||||
if (BufferHasPattern (bootLoaderBuf.data (), bootLoaderBuf.size (), g_szMsBootString, strlen (g_szMsBootString)))
|
||||
bModifiedMsBoot = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BufferHasPattern (bootLoaderBuf.data (), (size_t) loaderSize, _T(TC_APP_NAME), wcslen (_T(TC_APP_NAME)) * 2))
|
||||
if (BufferHasPattern (bootLoaderBuf.data (), bootLoaderBuf.size (), _T(TC_APP_NAME), wcslen (_T(TC_APP_NAME)) * 2))
|
||||
{
|
||||
if (AskWarnNoYes ("TC_BOOT_LOADER_ALREADY_INSTALLED", ParentWindow) == IDNO)
|
||||
throw UserAbort (SRC_POS);
|
||||
@@ -5988,14 +6120,12 @@ namespace VeraCrypt
|
||||
// check if backup exists already and if it has bootmgfw signature
|
||||
if (EfiBootInst.FileExists (szBackupMsBootloader))
|
||||
{
|
||||
EfiBootInst.GetFileSize(szBackupMsBootloader, loaderSize);
|
||||
bootLoaderBuf.resize ((size_t) loaderSize);
|
||||
EfiBootInst.ReadFile(szBackupMsBootloader, &bootLoaderBuf[0], (DWORD) loaderSize);
|
||||
if (!EfiBootInst.ReadFileToBuffer (szBackupMsBootloader, bootLoaderBuf, true))
|
||||
throw ErrorException ("WINDOWS_EFI_BOOT_LOADER_MISSING", SRC_POS);
|
||||
|
||||
if (BufferHasPattern (bootLoaderBuf.data (), (size_t) loaderSize, g_szMsBootString, strlen (g_szMsBootString)))
|
||||
if (BufferHasPattern (bootLoaderBuf.data (), bootLoaderBuf.size (), g_szMsBootString, strlen (g_szMsBootString)))
|
||||
{
|
||||
// copy it to original location
|
||||
EfiBootInst.CopyFile (szBackupMsBootloader, szStdMsBootloader);
|
||||
restoreStandardLoader = true;
|
||||
bModifiedMsBoot = false;
|
||||
}
|
||||
}
|
||||
@@ -6011,8 +6141,13 @@ namespace VeraCrypt
|
||||
throw UserAbort (SRC_POS);
|
||||
}
|
||||
|
||||
EfiBootInst.CopyFile (szStdMsBootloader, szBackupMsBootloader);
|
||||
EfiBootInst.CopyFile (szStdMsBootloader, GetSystemLoaderBackupPath().c_str());
|
||||
// Publish only the bounded, completely read snapshot. Do not reopen
|
||||
// and copy a source that may have changed since it was inspected.
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Write (GetSystemEncryptionDataDirectory (),
|
||||
TC_SYS_BOOT_LOADER_BACKUP_NAME, &bootLoaderBuf[0], (DWORD) bootLoaderBuf.size ()));
|
||||
if (restoreStandardLoader)
|
||||
EfiBootInst.SaveFile (szStdMsBootloader, bootLoaderBuf.data (), (DWORD) bootLoaderBuf.size ());
|
||||
EfiBootInst.SaveFile (szBackupMsBootloader, bootLoaderBuf.data (), (DWORD) bootLoaderBuf.size ());
|
||||
|
||||
}
|
||||
else
|
||||
@@ -6022,26 +6157,36 @@ namespace VeraCrypt
|
||||
uint8 bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS];
|
||||
|
||||
device.SeekAt (0);
|
||||
device.Read (bootLoaderBuf, sizeof (bootLoaderBuf));
|
||||
if (device.Read (bootLoaderBuf, sizeof (bootLoaderBuf)) != sizeof (bootLoaderBuf))
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
// Prevent TrueCrypt loader from being backed up
|
||||
for (size_t i = 0; i < sizeof (bootLoaderBuf) - strlen (TC_APP_NAME); ++i)
|
||||
{
|
||||
if (memcmp (bootLoaderBuf + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
|
||||
{
|
||||
if (!ParentWindow) throw ErrorException ("TC_BOOT_LOADER_ALREADY_INSTALLED", SRC_POS);
|
||||
if (AskWarnNoYes ("TC_BOOT_LOADER_ALREADY_INSTALLED", ParentWindow) == IDNO)
|
||||
throw UserAbort (SRC_POS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
File backupFile (GetSystemLoaderBackupPath(), false, true);
|
||||
backupFile.Write (bootLoaderBuf, sizeof (bootLoaderBuf));
|
||||
CheckSystemEncryptionFileResult (SystemEncryptionFiles::Write (GetSystemEncryptionDataDirectory (),
|
||||
TC_SYS_BOOT_LOADER_BACKUP_NAME, bootLoaderBuf, sizeof (bootLoaderBuf)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BootEncryption::RestoreSystemLoader ()
|
||||
{
|
||||
std::vector<uint8> backup;
|
||||
if (!GetSystemDriveConfiguration ().SystemPartition.IsGPT)
|
||||
ReadSystemLoaderBackupForRestore (backup);
|
||||
RestoreSystemLoader (backup);
|
||||
}
|
||||
|
||||
void BootEncryption::RestoreSystemLoader (const std::vector<uint8> &validatedBiosBackup)
|
||||
{
|
||||
SystemDriveConfiguration config = GetSystemDriveConfiguration();
|
||||
if (config.SystemPartition.IsGPT) {
|
||||
@@ -6156,11 +6301,8 @@ namespace VeraCrypt
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS];
|
||||
|
||||
File backupFile (GetSystemLoaderBackupPath(), true);
|
||||
backupFile.CheckOpened(SRC_POS);
|
||||
if (backupFile.Read (bootLoaderBuf, sizeof (bootLoaderBuf)) != sizeof (bootLoaderBuf))
|
||||
std::vector<uint8> bootLoaderBuf = validatedBiosBackup;
|
||||
if (bootLoaderBuf.size () != TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
Device device (GetSystemDriveConfiguration().DevicePath);
|
||||
@@ -6169,23 +6311,15 @@ namespace VeraCrypt
|
||||
// Preserve current partition table
|
||||
uint8 mbr[TC_SECTOR_SIZE_BIOS];
|
||||
device.SeekAt (0);
|
||||
device.Read (mbr, sizeof (mbr));
|
||||
memcpy (bootLoaderBuf + TC_MAX_MBR_BOOT_CODE_SIZE, mbr + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbr) - TC_MAX_MBR_BOOT_CODE_SIZE);
|
||||
if (device.Read (mbr, sizeof (mbr)) != sizeof (mbr))
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
memcpy (&bootLoaderBuf[TC_MAX_MBR_BOOT_CODE_SIZE], mbr + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbr) - TC_MAX_MBR_BOOT_CODE_SIZE);
|
||||
|
||||
device.SeekAt (0);
|
||||
device.Write (bootLoaderBuf, sizeof (bootLoaderBuf));
|
||||
device.Write (&bootLoaderBuf[0], (DWORD) bootLoaderBuf.size ());
|
||||
}
|
||||
|
||||
ClearEfiBootLoaderDiagnosticsRegistry ();
|
||||
|
||||
if (!IsAdmin() && IsUacSupported())
|
||||
{
|
||||
Elevator::UpdateSetupConfigFile (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSetupConfigFile (false);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SETUP
|
||||
@@ -6547,6 +6681,21 @@ namespace VeraCrypt
|
||||
}
|
||||
}
|
||||
|
||||
bool BootEncryption::IsSystemFavoritesServiceInstalled ()
|
||||
{
|
||||
SC_HANDLE scm = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT);
|
||||
throw_sys_if (!scm);
|
||||
finally_do_arg (SC_HANDLE, scm, { CloseServiceHandle (finally_arg); });
|
||||
SC_HANDLE service = OpenService (scm, TC_SYSTEM_FAVORITES_SERVICE_NAME, SERVICE_QUERY_STATUS);
|
||||
if (!service)
|
||||
{
|
||||
if (GetLastError () == ERROR_SERVICE_DOES_NOT_EXIST) return false;
|
||||
throw SystemException (SRC_POS);
|
||||
}
|
||||
CloseServiceHandle (service);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BootEncryption::IsSystemFavoritesServiceRunning ()
|
||||
{
|
||||
bool bRet = false;
|
||||
@@ -6614,7 +6763,7 @@ namespace VeraCrypt
|
||||
else
|
||||
configMap &= ~flag;
|
||||
#ifdef SETUP
|
||||
WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap);
|
||||
throw_sys_if (!WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap));
|
||||
#else
|
||||
WriteLocalMachineRegistryDwordValue (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap);
|
||||
#endif
|
||||
@@ -6629,7 +6778,7 @@ namespace VeraCrypt
|
||||
else
|
||||
configMap &= ~flag;
|
||||
#ifdef SETUP
|
||||
WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, TC_SYSTEM_FAVORITES_SERVICE_NAME L"Config", configMap);
|
||||
throw_sys_if (!WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, TC_SYSTEM_FAVORITES_SERVICE_NAME L"Config", configMap));
|
||||
#else
|
||||
WriteLocalMachineRegistryDwordValue (L"SYSTEM\\CurrentControlSet\\Services\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, TC_SYSTEM_FAVORITES_SERVICE_NAME L"Config", configMap);
|
||||
#endif
|
||||
@@ -7036,10 +7185,30 @@ namespace VeraCrypt
|
||||
{
|
||||
BootEncryptionStatus encStatus = GetStatus();
|
||||
|
||||
if (encStatus.DriveEncrypted || encStatus.DriveMounted)
|
||||
if (encStatus.DriveEncrypted || encStatus.DriveMounted || encStatus.SetupInProgress)
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
SystemDriveConfiguration config = GetSystemDriveConfiguration ();
|
||||
std::vector<uint8> backup;
|
||||
// Capture the trusted bytes before changing filters or services. Use
|
||||
// this snapshot for restoration so a later file lock cannot strand us
|
||||
// after teardown with an unreadable or replaced backup.
|
||||
bool restoreLoader = true;
|
||||
if (!config.SystemPartition.IsGPT)
|
||||
{
|
||||
try { ReadSystemLoaderBackupForRestore (backup); }
|
||||
catch (Exception &e)
|
||||
{
|
||||
e.Show (ParentWindow);
|
||||
if (AskWarnNoYes ("SYS_LOADER_BACKUP_SKIP_RESTORE", ParentWindow) != IDYES) throw UserAbort (SRC_POS);
|
||||
restoreLoader = false;
|
||||
}
|
||||
}
|
||||
// A confirmation dialog must not authorize teardown of a drive whose
|
||||
// state changed while it was displayed.
|
||||
encStatus = GetStatus ();
|
||||
if (encStatus.DriveEncrypted || encStatus.DriveMounted || encStatus.SetupInProgress)
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
if (!config.SystemPartition.IsGPT) {
|
||||
if (encStatus.VolumeHeaderPresent)
|
||||
@@ -7090,7 +7259,7 @@ namespace VeraCrypt
|
||||
|
||||
finally_do_arg (bool, displayWaitDialog, { if (finally_arg) CloseStaticModelessWaitDlg(); });
|
||||
|
||||
RestoreSystemLoader ();
|
||||
if (restoreLoader) RestoreSystemLoader (backup);
|
||||
}
|
||||
catch (ErrorException &e)
|
||||
{
|
||||
@@ -7105,6 +7274,11 @@ namespace VeraCrypt
|
||||
e.Show (ParentWindow);
|
||||
throw ErrorException ("SYS_LOADER_RESTORE_FAILED", SRC_POS);
|
||||
}
|
||||
// At this point loader restoration (or explicitly acknowledged external
|
||||
// startup recovery) and driver teardown are complete. Cleanup failure
|
||||
// must not leave the wizard pretending that the drive is still encrypted.
|
||||
try { if (!IsAdmin() && IsUacSupported()) Elevator::UpdateSetupConfigFile (false); else UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (ParentWindow); Warning ("SYSENC_SETUP_CONFIG_REMOVE_FAILED", ParentWindow); }
|
||||
}
|
||||
|
||||
|
||||
@@ -7322,6 +7496,9 @@ namespace VeraCrypt
|
||||
if (encStatus.DriveMounted)
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
if (!IsAdmin() && IsUacSupported()) Elevator::UpdateSetupConfigFile (true);
|
||||
else UpdateSetupConfigFile (true);
|
||||
|
||||
try
|
||||
{
|
||||
InstallBootLoader (false, hiddenSystem, -1, hashAlgo);
|
||||
@@ -7344,6 +7521,16 @@ namespace VeraCrypt
|
||||
e.Show (ParentWindow);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!IsAdmin() && IsUacSupported()) Elevator::UpdateSetupConfigFile (false);
|
||||
else UpdateSetupConfigFile (false);
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
e.Show (ParentWindow);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -7483,6 +7670,22 @@ namespace VeraCrypt
|
||||
{
|
||||
BootEncryptionStatus encStatus = GetStatus();
|
||||
|
||||
if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress)
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
// An unavailable backup prevents automatic restoration, not decryption.
|
||||
// Require an explicit recovery decision without accepting its old bytes.
|
||||
if (!GetSystemDriveConfiguration ().SystemPartition.IsGPT)
|
||||
{
|
||||
std::vector<uint8> backup;
|
||||
try { ReadSystemLoaderBackupForRestore (backup); }
|
||||
catch (Exception &e)
|
||||
{
|
||||
e.Show (ParentWindow);
|
||||
if (AskWarnNoYes ("SYS_LOADER_BACKUP_DECRYPT_WITHOUT_RESTORE", ParentWindow) != IDYES) throw UserAbort (SRC_POS);
|
||||
}
|
||||
}
|
||||
encStatus = GetStatus ();
|
||||
if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress)
|
||||
throw ParameterIncorrect (SRC_POS);
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#ifndef TC_HEADER_Common_BootEncryption
|
||||
#define TC_HEADER_Common_BootEncryption
|
||||
|
||||
#define TC_ERROR_BOOT_LOADER_ALREADY_INSTALLED 0xe0560001UL
|
||||
|
||||
#include "Tcdefs.h"
|
||||
#include "Dlgcode.h"
|
||||
#include "Exception.h"
|
||||
@@ -31,7 +33,7 @@ namespace VeraCrypt
|
||||
{
|
||||
public:
|
||||
File () : Elevated (false), FileOpen (false), ReadOnly (false), FilePointerPosition(0), Handle(INVALID_HANDLE_VALUE), IsDevice(false), LastError(0) { }
|
||||
File (wstring path,bool readOnly = false, bool create = false);
|
||||
File (wstring path, bool readOnly = false, bool create = false, DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE);
|
||||
virtual ~File () { Close(); }
|
||||
|
||||
bool IsOpened () const { return FileOpen;}
|
||||
@@ -204,7 +206,7 @@ namespace VeraCrypt
|
||||
void SaveFile(const wchar_t* name, uint8* data, DWORD size);
|
||||
void GetFileSize(const wchar_t* name, unsigned __int64& size);
|
||||
void ReadFile(const wchar_t* name, uint8* data, DWORD size);
|
||||
bool ReadFileToBuffer (const wchar_t* name, std::vector<uint8>& fileContent);
|
||||
bool ReadFileToBuffer (const wchar_t* name, std::vector<uint8>& fileContent, bool requireStableRead = false);
|
||||
void CopyFile(const wchar_t* name, const wchar_t* targetName);
|
||||
bool FileExists(const wchar_t* name);
|
||||
static bool CompareFiles (const wchar_t* fileName1, const wchar_t* fileName2);
|
||||
@@ -310,8 +312,9 @@ namespace VeraCrypt
|
||||
void RegisterSystemFavoritesService (BOOL registerService);
|
||||
void RegisterSystemFavoritesService (BOOL registerService, BOOL noFileHandling);
|
||||
bool IsSystemFavoritesServiceRunning ();
|
||||
bool IsSystemFavoritesServiceInstalled ();
|
||||
void UpdateSystemFavoritesService ();
|
||||
void RenameDeprecatedSystemLoaderBackup ();
|
||||
void RenameDeprecatedSystemLoaderBackup (bool requireBackup);
|
||||
bool RestartComputer (BOOL bShutdown = FALSE);
|
||||
void InitialSecurityChecksForHiddenOS ();
|
||||
void RestrictPagingFilesToSystemPartition ();
|
||||
@@ -339,6 +342,8 @@ namespace VeraCrypt
|
||||
void BackupSystemLoader ();
|
||||
void RestoreSystemLoader ();
|
||||
static void UpdateSetupConfigFile (bool bForInstall);
|
||||
static void PrepareSystemEncryptionStorage ();
|
||||
static void PrepareSystemEncryptionInstallation (const wchar_t *path);
|
||||
void GetSecureBootConfig (BOOL* pSecureBootEnabled, BOOL *pVeraCryptKeysLoaded);
|
||||
void GetEfiBootLoaderSigningSupport (BOOL* pMicrosoft2023UefiCAsSupported);
|
||||
bool GetEfiBootChainTrustStatus (EfiBootChainTrustStatus& status);
|
||||
@@ -349,7 +354,9 @@ namespace VeraCrypt
|
||||
|
||||
void CreateBootLoaderInMemory (uint8 *buffer, size_t bufferSize, bool rescueDisk, bool hiddenOSCreation = false);
|
||||
void CreateVolumeHeader (uint64 volumeSize, uint64 encryptedAreaStart, Password *password, int ea, int mode, int pkcs5, int pim);
|
||||
wstring GetSystemLoaderBackupPath ();
|
||||
void ReadSystemLoaderBackup (std::vector<uint8> &data);
|
||||
void ReadSystemLoaderBackupForRestore (std::vector<uint8> &data);
|
||||
void RestoreSystemLoader (const std::vector<uint8> &validatedBiosBackup);
|
||||
uint32 GetChecksum (uint8 *data, size_t size);
|
||||
DISK_GEOMETRY_EX GetDriveGeometry (int driveNumber);
|
||||
PartitionList GetDrivePartitions (int driveNumber);
|
||||
|
||||
+39
-21
@@ -14967,12 +14967,31 @@ void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, B
|
||||
HKEY hkey;
|
||||
BOOL bInstallPathDetermined = FALSE;
|
||||
wchar_t path[MAX_PATH+20];
|
||||
ITEMIDLIST *itemList;
|
||||
ITEMIDLIST *itemList = NULL;
|
||||
if (pbInstallPathDetermined) *pbInstallPathDetermined = FALSE;
|
||||
if (!szInstallPath || !cchSize) return;
|
||||
|
||||
memset (szInstallPath, 0, cchSize * sizeof (wchar_t));
|
||||
|
||||
// Both installers record this in the driver's service key. SYSTEM has a
|
||||
// shared registry view, so the native service and 32-bit COM agree, including
|
||||
// MSI installations whose EXE uninstall entry has been removed.
|
||||
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = sizeof (path), type = 0;
|
||||
if (RegQueryValueEx (hkey, L"InstallationPath", NULL, &type, (LPBYTE) path, &size) == ERROR_SUCCESS
|
||||
&& type == REG_SZ && size >= 4 * sizeof (wchar_t) && size <= sizeof (path) && size % sizeof (wchar_t) == 0
|
||||
&& path[size / sizeof (wchar_t) - 1] == 0 && wcslen (path) == size / sizeof (wchar_t) - 1
|
||||
&& path[1] == L':' && path[2] == L'\\' && wcslen (path) + 2 <= cchSize)
|
||||
{
|
||||
StringCchCopyW (szInstallPath, cchSize, path);
|
||||
bInstallPathDetermined = TRUE;
|
||||
}
|
||||
RegCloseKey (hkey);
|
||||
}
|
||||
|
||||
// Determine if VeraCrypt is already installed and try to determine its "Program Files" location
|
||||
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", 0, KEY_READ | KEY_WOW64_32KEY, &hkey) == ERROR_SUCCESS)
|
||||
if (!bInstallPathDetermined && RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", 0, KEY_READ | KEY_WOW64_32KEY, &hkey) == ERROR_SUCCESS)
|
||||
{
|
||||
/* Default 'UninstallString' registry strings written by VeraCrypt:
|
||||
------------------------------------------------------------------------------------
|
||||
@@ -14980,23 +14999,20 @@ void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, B
|
||||
*/
|
||||
|
||||
wchar_t rv[MAX_PATH*4];
|
||||
DWORD size = sizeof (rv);
|
||||
if (RegQueryValueEx (hkey, L"UninstallString", 0, 0, (LPBYTE) &rv, &size) == ERROR_SUCCESS && wcsrchr (rv, L'/'))
|
||||
DWORD size = sizeof (rv), type = 0;
|
||||
if (RegQueryValueEx (hkey, L"UninstallString", 0, &type, (LPBYTE) &rv, &size) == ERROR_SUCCESS
|
||||
&& type == REG_SZ && size >= 2 * sizeof (wchar_t) && size <= sizeof (rv) && size % sizeof (wchar_t) == 0
|
||||
&& rv[size / sizeof (wchar_t) - 1] == 0 && wcslen (rv) == size / sizeof (wchar_t) - 1 && rv[0] == L'"')
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
// Cut and paste the location (path) where VeraCrypt is installed to InstallationPath
|
||||
if (rv[0] == L'"')
|
||||
const wchar_t *end = wcschr (rv + 1, L'"');
|
||||
if (end && wcsstr (end + 1, L"/u"))
|
||||
{
|
||||
len = wcsrchr (rv, L'/') - rv - 2;
|
||||
StringCchCopyNW (szInstallPath, cchSize, rv + 1, len);
|
||||
szInstallPath [len] = 0;
|
||||
bInstallPathDetermined = TRUE;
|
||||
|
||||
if (szInstallPath [wcslen (szInstallPath) - 1] != L'\\')
|
||||
wstring executable (rv + 1, end - rv - 1);
|
||||
size_t slash = executable.find_last_of (L'\\');
|
||||
if (slash != wstring::npos && slash >= 2 && slash + 2 <= cchSize && executable[1] == L':' && executable[2] == L'\\')
|
||||
{
|
||||
len = wcsrchr (szInstallPath, L'\\') - szInstallPath;
|
||||
szInstallPath [len] = 0;
|
||||
StringCchCopyNW (szInstallPath, cchSize, executable.c_str (), slash + 1);
|
||||
bInstallPathDetermined = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15009,8 +15025,10 @@ void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, B
|
||||
/* VeraCrypt is not installed or it wasn't possible to determine where it is installed. */
|
||||
|
||||
// Default "Program Files" path.
|
||||
SHGetSpecialFolderLocation (hwndDlg, CSIDL_PROGRAM_FILES, &itemList);
|
||||
SHGetPathFromIDList (itemList, path);
|
||||
if (FAILED (SHGetSpecialFolderLocation (hwndDlg, CSIDL_PROGRAM_FILES, &itemList))) return;
|
||||
BOOL found = SHGetPathFromIDList (itemList, path);
|
||||
CoTaskMemFree (itemList);
|
||||
if (!found) return;
|
||||
|
||||
// Use a unified default installation path (registry redirection of %ProgramFiles% does not work if the installation path is user-selectable)
|
||||
wstring s = path;
|
||||
@@ -15023,13 +15041,13 @@ void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, B
|
||||
}
|
||||
|
||||
StringCbCatW (path, sizeof(path), L"\\VeraCrypt\\");
|
||||
StringCbCopyW (szInstallPath, cchSize, path);
|
||||
StringCchCopyW (szInstallPath, cchSize, path);
|
||||
}
|
||||
|
||||
// Make sure the path ends with a backslash
|
||||
if (szInstallPath [wcslen (szInstallPath) - 1] != L'\\')
|
||||
if (szInstallPath[0] && szInstallPath [wcslen (szInstallPath) - 1] != L'\\')
|
||||
{
|
||||
StringCbCatW (szInstallPath, cchSize, L"\\");
|
||||
StringCchCatW (szInstallPath, cchSize, L"\\");
|
||||
}
|
||||
|
||||
if (pbInstallPathDetermined)
|
||||
|
||||
+10
-1
@@ -1076,7 +1076,7 @@
|
||||
<entry lang="en" key="WINDOWS_NOT_ON_BOOT_DRIVE_ERROR">WARNING: Windows does not appear to be installed on the drive from which it boots. This is not supported.\n\nYou should continue only if you are sure that Windows is installed on the drive from which it boots.\n\nDo you want to continue?</entry>
|
||||
<entry lang="en" key="TC_BOOT_LOADER_ALREADY_INSTALLED">CAUTION: The VeraCrypt Boot Loader is already installed on your system drive!\n\nIt is possible that another system on your computer is already encrypted.\n\nWARNING: PROCEEDING WITH ENCRYPTION OF THE CURRENTLY RUNNING SYSTEM MAY MAKE OTHER SYSTEM(S) IMPOSSIBLE TO START AND RELATED DATA INACCESSIBLE.\n\nAre you sure you want to continue?</entry>
|
||||
<entry lang="en" key="SYS_LOADER_RESTORE_FAILED">Failed to restore the original system loader.\n\nPlease use your VeraCrypt Rescue Disk ('Repair Options' > 'Restore original system loader') or Windows installation medium to replace the VeraCrypt Boot Loader with the Windows system loader.</entry>
|
||||
<entry lang="en" key="SYS_LOADER_UNAVAILABLE_FOR_RESCUE_DISK">The original system loader will not be stored on the Rescue Disk (probable cause: missing backup file).</entry>
|
||||
<entry lang="en" key="SYS_LOADER_UNAVAILABLE_FOR_RESCUE_DISK">The original system loader will not be stored on the Rescue Disk because its backup is missing, unreadable, or cannot be safely used.</entry>
|
||||
<entry lang="en" key="ERROR_MBR_PROTECTED">Failed to write the MBR sector.\n\nYour BIOS may be configured to protect the MBR sector. Check your BIOS settings (press F2, Delete, or Esc, after powering on your computer) for MBR/antivirus protection.</entry>
|
||||
<entry lang="en" key="BOOT_LOADER_FINGERPRINT_CHECK_FAILED">WARNING: The verification of VeraCrypt bootloader fingerprint failed!\nYour disk may have been tampered with by an attacker ("Evil Maid" attack).\n\nThis warning can also be triggered if you restored VeraCrypt boot loader using an Rescue Disk generated using a different VeraCrypt version.\n\nYou are advised to change your password immediately which will also restore the correct VeraCrypt bootloader. It is recommended to reinstall VeraCrypt and to take measures to avoid access to this machine by untrusted entities.</entry>
|
||||
<entry lang="en" key="BOOT_LOADER_VERSION_INCORRECT_PREFERENCES">The required version of the VeraCrypt Boot Loader is currently not installed. This may prevent some of the settings from being saved.</entry>
|
||||
@@ -1706,6 +1706,15 @@
|
||||
<entry lang="en" key="LINUX_ELEVATION_BLOCKED">The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run.</entry>
|
||||
<entry lang="en" key="LINUX_REQUESTER_BACKED_VOLUME">VeraCrypt could not open the volume file with administrator privileges, so it opened the file with your user account's access rights:\n{0}\n\nKeep the source share mounted and your user session active until this VeraCrypt volume is unmounted. Ejecting the share or logging out can lose data. For regular use, store the volume where VeraCrypt can open it with administrator privileges, for example on a share mounted with the kernel CIFS client.</entry>
|
||||
<entry lang="en" key="PCSC_ERROR">Smart card error</entry>
|
||||
<entry lang="en" key="SYS_LOADER_BACKUP_UNTRUSTED">VeraCrypt cannot safely use the original system loader backup because its ownership, permissions, or file path could allow modification by another user. The existing backup has been preserved.\n\nUse a known trustworthy VeraCrypt Rescue Disk for decryption and loader recovery. Windows recovery media can repair startup after the system drive has been fully decrypted. Do not replace the backup with the current boot area of an encrypted system.</entry>
|
||||
<entry lang="en" key="SYS_LOADER_BACKUP_MIGRATION_FAILED">VeraCrypt could not confirm that a trustworthy, complete original system loader backup is available in protected storage. The backup may be missing, unreadable, damaged, or unsafe to migrate. Existing backup files have been preserved. The normal unelevated wizard in older BIOS versions could create user-owned backups that can no longer be trusted automatically.\n\nBefore decrypting the system or recreating rescue media, resolve the reported error or obtain a known trustworthy VeraCrypt Rescue Disk. Changing the old backup's ownership or permissions does not establish that its contents are safe. Do not back up the current boot area of an encrypted system as a replacement.</entry>
|
||||
<entry lang="en" key="SYS_LOADER_BACKUP_SIZE_INVALID">The original BIOS system loader backup has an invalid size. A complete backup must contain exactly 32256 bytes. The existing file has been preserved.</entry>
|
||||
<entry lang="en" key="SYS_LOADER_BACKUP_EMPTY">The original system loader backup is empty. The existing file has been preserved.</entry>
|
||||
<entry lang="en" key="SYS_LOADER_BACKUP_DECRYPT_WITHOUT_RESTORE">Automatic restoration of the original BIOS system loader is unavailable because the backup could not be used.\n\nYou can decrypt the drive, but Windows may then require startup repair using trusted Windows recovery media or a verified VeraCrypt Rescue Disk. Obtain suitable recovery media before continuing. Do not restore an unencrypted boot loader while any part of the system remains encrypted.\n\nDo you want to decrypt without automatic loader restoration?</entry>
|
||||
<entry lang="en" key="SYS_LOADER_BACKUP_SKIP_RESTORE">The system drive is fully decrypted and unmounted, but its original BIOS system loader backup could not be used.\n\nYou can finish removing system encryption without restoring a loader. The current boot code will be left in place. If startup has not already been repaired, use trusted Windows recovery media or a verified VeraCrypt Rescue Disk to repair it.\n\nDo you want to finish cleanup without restoring the original system loader?</entry>
|
||||
<entry lang="en" key="SYSENC_STORAGE_UNTRUSTED">The VeraCryptSystem support directory under the native Common Files folder, one of its protected subdirectories, or an ancestor has unsafe ownership, permissions, or a redirected path. This prevents access to protected system encryption storage. Existing files have been preserved.\n\nHave an administrator investigate and relocate the obstructing object, then run VeraCrypt Repair/Reinstall. Do not approve an old loader backup merely by changing its ownership or permissions.</entry>
|
||||
<entry lang="en" key="SYSENC_SETUP_CONFIG_REMOVE_FAILED">VeraCrypt could not remove its Windows feature update registrations.\n\nResolve the preceding configuration error, then run VeraCrypt Repair/Reinstall to retry cleanup. Do not start a Windows feature update until these registrations have been removed.</entry>
|
||||
<entry lang="en" key="SYSENC_SETUP_CONFIG_CONFLICT">Windows Setup configuration contains a PostOOBE or ReflectDrivers registration that VeraCrypt cannot identify as its own. That registration has been preserved.\n\nHave an administrator resolve the configuration conflict, then run VeraCrypt Repair/Reinstall before starting a Windows feature update.</entry>
|
||||
</localization>
|
||||
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="VeraCrypt">
|
||||
|
||||
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
Copyright (c) 2026 AM Crypto. All rights reserved.
|
||||
Governed by the Apache License 2.0; see License.txt.
|
||||
*/
|
||||
|
||||
#ifndef TC_HEADER_Common_SystemEncryptionFiles
|
||||
#define TC_HEADER_Common_SystemEncryptionFiles
|
||||
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <aclapi.h>
|
||||
#include <sddl.h>
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// These files become commands or boot code. Never repair an untrusted object's
|
||||
// permissions and then accept its old contents as a trusted backup.
|
||||
namespace VeraCrypt { namespace SystemEncryptionFiles
|
||||
{
|
||||
|
||||
class Handle
|
||||
{
|
||||
public:
|
||||
explicit Handle (HANDLE value = INVALID_HANDLE_VALUE) : Value (value) { }
|
||||
~Handle () { if (Value != INVALID_HANDLE_VALUE) CloseHandle (Value); }
|
||||
HANDLE Value;
|
||||
private:
|
||||
Handle (const Handle &);
|
||||
Handle &operator= (const Handle &);
|
||||
};
|
||||
|
||||
class SecurityDescriptor
|
||||
{
|
||||
public:
|
||||
SecurityDescriptor () : Value (NULL) { }
|
||||
~SecurityDescriptor () { if (Value) LocalFree (Value); }
|
||||
PSECURITY_DESCRIPTOR Value;
|
||||
private:
|
||||
SecurityDescriptor (const SecurityDescriptor &);
|
||||
SecurityDescriptor &operator= (const SecurityDescriptor &);
|
||||
};
|
||||
|
||||
inline bool TrustedSid (PSID sid)
|
||||
{
|
||||
if (!sid || !IsValidSid (sid))
|
||||
return false;
|
||||
if (IsWellKnownSid (sid, WinLocalSystemSid) || IsWellKnownSid (sid, WinBuiltinAdministratorsSid))
|
||||
return true;
|
||||
|
||||
// Windows directories are commonly owned by TrustedInstaller.
|
||||
static const SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
|
||||
static const DWORD installer[] = { 80, 956008885, 3418522649, 1831038044, 1853292631, 2271478464 };
|
||||
if (*GetSidSubAuthorityCount (sid) != ARRAYSIZE (installer)
|
||||
|| memcmp (GetSidIdentifierAuthority (sid), &authority, sizeof (authority)) != 0)
|
||||
return false;
|
||||
for (DWORD i = 0; i < ARRAYSIZE (installer); ++i)
|
||||
if (*GetSidSubAuthority (sid, i) != installer[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool TrustedSecurity (PSECURITY_DESCRIPTOR descriptor, bool allowDirectoryCreation, bool volumeRoot = false,
|
||||
PSID installerOwner = NULL)
|
||||
{
|
||||
PSID owner = NULL;
|
||||
PACL dacl = NULL;
|
||||
BOOL present, defaulted;
|
||||
if (!GetSecurityDescriptorOwner (descriptor, &owner, &defaulted)
|
||||
|| (!TrustedSid (owner) && !(installerOwner && EqualSid (owner, installerOwner)))
|
||||
|| !GetSecurityDescriptorDacl (descriptor, &present, &dacl, &defaulted)
|
||||
|| !present || !dacl || !IsValidAcl (dacl))
|
||||
return false;
|
||||
|
||||
DWORD allowed = FILE_GENERIC_READ | FILE_GENERIC_EXECUTE;
|
||||
// Ancestors such as ProgramData can allow creation, but not removal or
|
||||
// replacement of an existing trusted child. Open children relative to
|
||||
// validated handles; sharing restrictions do not stop reparse changes.
|
||||
if (allowDirectoryCreation)
|
||||
allowed |= FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
|
||||
// The default system drive ACL grants DELETE on the volume root itself.
|
||||
// A volume root cannot be renamed or unlinked. DELETE_CHILD is still unsafe.
|
||||
if (volumeRoot) allowed |= DELETE;
|
||||
GENERIC_MAPPING mapping = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
|
||||
for (DWORD i = 0; i < dacl->AceCount; ++i)
|
||||
{
|
||||
ACE_HEADER *header;
|
||||
if (!GetAce (dacl, i, reinterpret_cast<void **> (&header)))
|
||||
return false;
|
||||
if (header->AceFlags & INHERIT_ONLY_ACE)
|
||||
continue;
|
||||
if (header->AceType == ACCESS_DENIED_ACE_TYPE)
|
||||
continue;
|
||||
// Do not try to interpret conditional or object-specific grants.
|
||||
if (header->AceType != ACCESS_ALLOWED_ACE_TYPE)
|
||||
return false;
|
||||
ACCESS_ALLOWED_ACE *ace = reinterpret_cast<ACCESS_ALLOWED_ACE *> (header);
|
||||
DWORD mask = ace->Mask;
|
||||
MapGenericMask (&mask, &mapping);
|
||||
if ((mask & ~allowed) && !TrustedSid (&ace->SidStart)
|
||||
&& !(installerOwner && EqualSid (&ace->SidStart, installerOwner)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline DWORD CheckHandle (HANDLE handle, bool directory, bool allowDirectoryCreation = false, bool volumeRoot = false)
|
||||
{
|
||||
if (volumeRoot)
|
||||
{
|
||||
// Do not apply the root exception to a substituted drive's subdirectory.
|
||||
wchar_t path[2];
|
||||
DWORD length = GetFinalPathNameByHandleW (handle, path, ARRAYSIZE (path), VOLUME_NAME_NONE);
|
||||
if (!length) return GetLastError ();
|
||||
if (length != 1 || path[0] != L'\\') return ERROR_INVALID_SECURITY_DESCR;
|
||||
}
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!GetFileInformationByHandle (handle, &info))
|
||||
return GetLastError ();
|
||||
if ((info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
|| ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) != directory
|
||||
|| (!directory && info.nNumberOfLinks != 1))
|
||||
return ERROR_INVALID_SECURITY_DESCR;
|
||||
|
||||
SecurityDescriptor descriptor;
|
||||
DWORD error = GetSecurityInfo (handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
NULL, NULL, NULL, NULL, &descriptor.Value);
|
||||
if (error != ERROR_SUCCESS)
|
||||
return error;
|
||||
return TrustedSecurity (descriptor.Value, allowDirectoryCreation, volumeRoot) ? ERROR_SUCCESS : ERROR_INVALID_SECURITY_DESCR;
|
||||
}
|
||||
|
||||
inline DWORD NewSecurity (SecurityDescriptor &descriptor, bool directory, bool executable = false)
|
||||
{
|
||||
// The explicit owner is important when a caller uses an elevated COM
|
||||
// server. Read access is needed by the unelevated rescue disk wizard.
|
||||
return ConvertStringSecurityDescriptorToSecurityDescriptorW (directory
|
||||
? L"O:BAG:BAD:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;GRGX;;;BU)"
|
||||
: executable ? L"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;GRGX;;;BU)"
|
||||
: L"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;GR;;;BU)",
|
||||
SDDL_REVISION_1, &descriptor.Value, NULL) ? ERROR_SUCCESS : GetLastError ();
|
||||
}
|
||||
|
||||
inline bool SimpleName (const std::wstring &name)
|
||||
{
|
||||
return !name.empty () && name.find_first_of (L"\\/:\0", 0, 4) == std::wstring::npos
|
||||
&& name.back () != L'.' && name.back () != L' ' && name.size () < 32768;
|
||||
}
|
||||
|
||||
inline DWORD NativeError (NTSTATUS status)
|
||||
{
|
||||
if (status >= 0) return ERROR_SUCCESS;
|
||||
typedef ULONG (NTAPI *ConvertStatus) (NTSTATUS);
|
||||
static ConvertStatus convert = reinterpret_cast<ConvertStatus> (GetProcAddress (GetModuleHandleW (L"ntdll.dll"), "RtlNtStatusToDosError"));
|
||||
return convert ? convert (status) : ERROR_GEN_FAILURE;
|
||||
}
|
||||
|
||||
inline DWORD OpenRelative (HANDLE parent, const std::wstring &name, DWORD access, DWORD sharing,
|
||||
ULONG disposition, bool directory, PSECURITY_DESCRIPTOR security, Handle &handle)
|
||||
{
|
||||
if (!SimpleName (name)) return ERROR_BAD_PATHNAME;
|
||||
// A single component is resolved against the already opened directory,
|
||||
// never against a pathname that may now lead through a different parent.
|
||||
static decltype (&NtCreateFile) createFile = reinterpret_cast<decltype (&NtCreateFile)>
|
||||
(GetProcAddress (GetModuleHandleW (L"ntdll.dll"), "NtCreateFile"));
|
||||
if (!createFile) return ERROR_PROC_NOT_FOUND;
|
||||
UNICODE_STRING objectName = {};
|
||||
objectName.Buffer = const_cast<wchar_t *> (name.c_str ());
|
||||
objectName.Length = objectName.MaximumLength = static_cast<USHORT> (name.size () * sizeof (wchar_t));
|
||||
OBJECT_ATTRIBUTES attributes = { sizeof (attributes), parent, &objectName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_DONT_REPARSE, security, NULL };
|
||||
IO_STATUS_BLOCK result = {};
|
||||
HANDLE opened = INVALID_HANDLE_VALUE;
|
||||
NTSTATUS status = createFile (&opened, access | SYNCHRONIZE, &attributes, &result, NULL,
|
||||
FILE_ATTRIBUTE_NORMAL, sharing, disposition,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE), NULL, 0);
|
||||
if (status < 0) return NativeError (status);
|
||||
handle.Value = opened;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
class Directory
|
||||
{
|
||||
public:
|
||||
Directory () : Legacy (false) { }
|
||||
~Directory ()
|
||||
{
|
||||
for (size_t i = 0; i < Handles.size (); ++i)
|
||||
CloseHandle (Handles[i]);
|
||||
}
|
||||
|
||||
DWORD Open (const std::wstring &path, bool create = false, bool legacy = false, bool pin = true)
|
||||
{
|
||||
// Only local absolute paths, with no alternate streams or ambiguous
|
||||
// components. Only the root is opened by an absolute pathname.
|
||||
if (!Handles.empty ()) return ERROR_INVALID_PARAMETER;
|
||||
if (path.size () < 3 || path[1] != L':' || path[2] != L'\\'
|
||||
|| !((path[0] >= L'A' && path[0] <= L'Z') || (path[0] >= L'a' && path[0] <= L'z'))
|
||||
|| path.find_first_of (L"/:", 2) != std::wstring::npos)
|
||||
return ERROR_BAD_PATHNAME;
|
||||
|
||||
Legacy = legacy;
|
||||
for (size_t start = 0, end = 3; ; )
|
||||
{
|
||||
bool last = end == path.size ();
|
||||
bool root = end == 3;
|
||||
std::wstring component = path.substr (start, end - start);
|
||||
SecurityDescriptor descriptor;
|
||||
if (last && create)
|
||||
{
|
||||
DWORD error = NewSecurity (descriptor, true);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
}
|
||||
|
||||
// Ancestor metadata handles neither exclude ordinary writers nor
|
||||
// conflict with their sharing modes. Pin only the final directory.
|
||||
// Metadata-only validation tolerates exclusive readers, but does
|
||||
// not pin a pathname. Pathname-based callers must keep pin enabled.
|
||||
DWORD access = last && pin ? GENERIC_READ : READ_CONTROL | FILE_READ_ATTRIBUTES;
|
||||
DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | (last ? 0 : FILE_SHARE_DELETE);
|
||||
Handle handle;
|
||||
DWORD error;
|
||||
if (root)
|
||||
{
|
||||
handle.Value = CreateFileW (component.c_str (), access, sharing, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
|
||||
error = handle.Value == INVALID_HANDLE_VALUE ? GetLastError () : ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
error = OpenRelative (Handles.back (), component, access, sharing,
|
||||
last && create ? FILE_OPEN_IF : FILE_OPEN, true, descriptor.Value, handle);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
error = CheckHandle (handle.Value, true, !last || legacy, root);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
// Recheck the parent after opening its child. A trusted child cannot
|
||||
// be removed by an ordinary user, so the parent cannot then be emptied
|
||||
// and converted into a junction. This also protects callers of the
|
||||
// pathname-only Windows profile APIs in the strict final directory.
|
||||
if (!root)
|
||||
{
|
||||
error = CheckHandle (Handles.back (), true, true, Handles.size () == 1);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
}
|
||||
Handles.push_back (handle.Value);
|
||||
handle.Value = INVALID_HANDLE_VALUE;
|
||||
if (last) return ERROR_SUCCESS;
|
||||
|
||||
start = root ? end : end + 1;
|
||||
end = path.find (L'\\', start);
|
||||
if (end == std::wstring::npos) end = path.size ();
|
||||
if (start == end || path[end - 1] == L'.' || path[end - 1] == L' ')
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD OpenFile (const std::wstring &name, DWORD access, DWORD sharing, ULONG disposition,
|
||||
PSECURITY_DESCRIPTOR security, Handle &file) const
|
||||
{
|
||||
if (Handles.empty ()) return ERROR_INVALID_HANDLE;
|
||||
DWORD error = OpenRelative (Handles.back (), name, access, sharing, disposition, false, security, file);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
// A legacy directory can allow creation and attribute writes. Do not
|
||||
// consume a file if that directory became a reparse point meanwhile.
|
||||
return CheckHandle (Handles.back (), true, Legacy, Handles.size () == 1);
|
||||
}
|
||||
|
||||
HANDLE GetHandle () const { return Handles.empty () ? INVALID_HANDLE_VALUE : Handles.back (); }
|
||||
|
||||
private:
|
||||
Directory (const Directory &);
|
||||
Directory &operator= (const Directory &);
|
||||
std::vector<HANDLE> Handles;
|
||||
bool Legacy;
|
||||
};
|
||||
|
||||
inline bool Missing (DWORD error)
|
||||
{
|
||||
return error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Provisioning of the installation package and Windows Setup settings only.
|
||||
// A full, unfiltered administrator can create individually owned objects.
|
||||
// Normalize those objects while that same principal is still privileged;
|
||||
// never apply this exception to other users or loader backups. Later reads
|
||||
// must still validate the resulting ownership and exclude existing writers.
|
||||
inline DWORD ProvisionInstallerObject (std::wstring path, bool directory, bool executable = false)
|
||||
{
|
||||
if (!path.empty () && path.back () == L'\\') path.pop_back ();
|
||||
size_t slash = path.find_last_of (L'\\');
|
||||
if (slash == std::wstring::npos || slash < 2 || slash + 1 == path.size ()) return ERROR_BAD_PATHNAME;
|
||||
Directory parent;
|
||||
// This is an ancestor, not the protected object itself. Standard roots
|
||||
// may allow child creation, but must not allow replacing an existing child.
|
||||
DWORD error = parent.Open (path.substr (0, slash == 2 ? 3 : slash), false, true, false);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
Handle object;
|
||||
error = OpenRelative (parent.GetHandle (), path.substr (slash + 1), READ_CONTROL | WRITE_DAC | WRITE_OWNER | FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ, FILE_OPEN, directory, NULL, object);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
error = CheckHandle (parent.GetHandle (), true, true, slash == 2);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
error = CheckHandle (object.Value, directory);
|
||||
if (error != ERROR_INVALID_SECURITY_DESCR) return error;
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!GetFileInformationByHandle (object.Value, &info)) return GetLastError ();
|
||||
if ((info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) || (!directory && info.nNumberOfLinks != 1)) return ERROR_INVALID_SECURITY_DESCR;
|
||||
Handle token;
|
||||
if (!OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, TRUE, &token.Value))
|
||||
{
|
||||
if (GetLastError () != ERROR_NO_TOKEN) return GetLastError ();
|
||||
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token.Value)) return GetLastError ();
|
||||
}
|
||||
TOKEN_ELEVATION_TYPE elevation; DWORD length;
|
||||
if (!GetTokenInformation (token.Value, TokenElevationType, &elevation, sizeof (elevation), &length)) return GetLastError ();
|
||||
if (elevation != TokenElevationTypeDefault) return ERROR_INVALID_SECURITY_DESCR;
|
||||
BYTE adminBuffer[SECURITY_MAX_SID_SIZE]; DWORD adminSize = sizeof (adminBuffer); BOOL administrator = FALSE;
|
||||
if (!CreateWellKnownSid (WinBuiltinAdministratorsSid, NULL, adminBuffer, &adminSize)
|
||||
|| !CheckTokenMembership (NULL, adminBuffer, &administrator)) return GetLastError ();
|
||||
if (!administrator) return ERROR_INVALID_SECURITY_DESCR;
|
||||
GetTokenInformation (token.Value, TokenUser, NULL, 0, &length);
|
||||
std::vector<unsigned char> user (length);
|
||||
if (!length || !GetTokenInformation (token.Value, TokenUser, user.data (), length, &length)) return GetLastError ();
|
||||
PSID caller = reinterpret_cast<TOKEN_USER *> (user.data ())->User.Sid;
|
||||
SecurityDescriptor oldSecurity, replacement;
|
||||
error = GetSecurityInfo (object.Value, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
NULL, NULL, NULL, NULL, &oldSecurity.Value);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
if (!TrustedSecurity (oldSecurity.Value, false, false, caller)) return ERROR_INVALID_SECURITY_DESCR;
|
||||
error = NewSecurity (replacement, directory, executable); if (error != ERROR_SUCCESS) return error;
|
||||
PSID owner; PACL acl; BOOL present, defaulted;
|
||||
if (!GetSecurityDescriptorOwner (replacement.Value, &owner, &defaulted)
|
||||
|| !GetSecurityDescriptorDacl (replacement.Value, &present, &acl, &defaulted)) return GetLastError ();
|
||||
error = SetSecurityInfo (object.Value, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
|
||||
owner, NULL, acl, NULL);
|
||||
return error == ERROR_SUCCESS ? CheckHandle (object.Value, directory) : error;
|
||||
}
|
||||
|
||||
// Keep both handles alive through any pathname-based copy of this source.
|
||||
// Provision only the same unfiltered administrator's objects, as elsewhere
|
||||
// in installer preparation; an ordinary-user owner or writer is rejected.
|
||||
inline DWORD OpenInstallerFile (const std::wstring &path, Directory &directory, Handle &file)
|
||||
{
|
||||
size_t slash = path.find_last_of (L'\\');
|
||||
if (slash == std::wstring::npos || slash < 3 || slash + 1 == path.size ()) return ERROR_BAD_PATHNAME;
|
||||
std::wstring parent = path.substr (0, slash);
|
||||
DWORD error = ProvisionInstallerObject (parent, true);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
error = directory.Open (parent);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
error = ProvisionInstallerObject (path, false, true);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
error = directory.OpenFile (path.substr (slash + 1), GENERIC_READ | READ_CONTROL,
|
||||
FILE_SHARE_READ, FILE_OPEN, NULL, file);
|
||||
return error == ERROR_SUCCESS ? CheckHandle (file.Value, false) : error;
|
||||
}
|
||||
|
||||
inline DWORD Read (HANDLE file, std::vector<unsigned char> &data)
|
||||
{
|
||||
DWORD error = CheckHandle (file, false);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
LARGE_INTEGER size;
|
||||
if (!GetFileSizeEx (file, &size)) return GetLastError ();
|
||||
if (size.QuadPart < 0 || size.QuadPart > 64 * 1024 * 1024) return ERROR_FILE_TOO_LARGE;
|
||||
data.resize (static_cast<size_t> (size.QuadPart));
|
||||
DWORD count = 0;
|
||||
if (!data.empty () && !ReadFile (file, &data[0], static_cast<DWORD> (data.size ()), &count, NULL))
|
||||
return GetLastError ();
|
||||
return count == data.size () ? ERROR_SUCCESS : ERROR_HANDLE_EOF;
|
||||
}
|
||||
|
||||
inline DWORD Read (const Directory &directory, const wchar_t *name, std::vector<unsigned char> &data)
|
||||
{
|
||||
Handle file;
|
||||
DWORD error = directory.OpenFile (name, GENERIC_READ | READ_CONTROL, FILE_SHARE_READ, FILE_OPEN, NULL, file);
|
||||
return error == ERROR_SUCCESS ? Read (file.Value, data) : error;
|
||||
}
|
||||
|
||||
inline DWORD Read (const std::wstring &directory, const wchar_t *name, std::vector<unsigned char> &data, bool legacy = false)
|
||||
{
|
||||
Directory locked;
|
||||
DWORD error = locked.Open (directory, false, legacy);
|
||||
return error == ERROR_SUCCESS ? Read (locked, name, data) : error;
|
||||
}
|
||||
|
||||
inline DWORD Publish (HANDLE file, HANDLE directory, const std::wstring &name)
|
||||
{
|
||||
if (!SimpleName (name)) return ERROR_BAD_PATHNAME;
|
||||
// The native rename accepts a directory handle, avoiding another path
|
||||
// lookup for both the temporary file and its destination. It keeps the
|
||||
// new object's security; ReplaceFile would retain the old DACL.
|
||||
struct RenameInformation
|
||||
{
|
||||
BOOLEAN ReplaceIfExists;
|
||||
HANDLE RootDirectory;
|
||||
ULONG FileNameLength;
|
||||
wchar_t FileName[1];
|
||||
};
|
||||
typedef NTSTATUS (NTAPI *SetInformation) (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, ULONG);
|
||||
static SetInformation setInformation = reinterpret_cast<SetInformation>
|
||||
(GetProcAddress (GetModuleHandleW (L"ntdll.dll"), "NtSetInformationFile"));
|
||||
if (!setInformation) return ERROR_PROC_NOT_FOUND;
|
||||
std::vector<unsigned char> buffer (sizeof (RenameInformation) + name.size () * sizeof (wchar_t));
|
||||
RenameInformation *rename = reinterpret_cast<RenameInformation *> (&buffer[0]);
|
||||
rename->ReplaceIfExists = TRUE;
|
||||
rename->RootDirectory = directory;
|
||||
rename->FileNameLength = static_cast<ULONG> (name.size () * sizeof (wchar_t));
|
||||
memcpy (rename->FileName, name.data (), rename->FileNameLength);
|
||||
IO_STATUS_BLOCK result = {};
|
||||
return NativeError (setInformation (file, &result, rename, static_cast<ULONG> (buffer.size ()), 10 /* FileRenameInformation */));
|
||||
}
|
||||
|
||||
inline DWORD Write (const std::wstring &directory, const wchar_t *name, const unsigned char *data, DWORD size,
|
||||
const std::vector<unsigned char> *expected = NULL)
|
||||
{
|
||||
if (size > 64 * 1024 * 1024) return ERROR_FILE_TOO_LARGE;
|
||||
if (size && !data) return ERROR_INVALID_PARAMETER;
|
||||
Directory locked;
|
||||
DWORD error = locked.Open (directory, true);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
if (!SimpleName (name)) return ERROR_BAD_PATHNAME;
|
||||
std::vector<unsigned char> previous;
|
||||
error = Read (locked, name, previous);
|
||||
// Detect another writer's edit since the caller read this shared file.
|
||||
// The setup lock serializes VeraCrypt callers; external writers do not
|
||||
// participate in it, so never knowingly publish a stale snapshot.
|
||||
if (expected && (error == ERROR_SUCCESS || Missing (error)) && previous != *expected)
|
||||
return ERROR_RETRY;
|
||||
if (error == ERROR_SUCCESS && previous.size () == size
|
||||
&& (size == 0 || memcmp (&previous[0], data, size) == 0))
|
||||
return ERROR_SUCCESS;
|
||||
if (error != ERROR_SUCCESS && !Missing (error)) return error;
|
||||
|
||||
SecurityDescriptor descriptor;
|
||||
error = NewSecurity (descriptor, false);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
// Only privileged callers can create files in this directory.
|
||||
// FILE_CREATE also prevents two privileged writers sharing a temporary file.
|
||||
std::wstring temporary;
|
||||
Handle file;
|
||||
for (unsigned int attempt = 0; attempt < 16; ++attempt)
|
||||
{
|
||||
wchar_t suffix[80];
|
||||
swprintf_s (suffix, ARRAYSIZE (suffix), L".%lu.%lu.%llu.%u.tmp",
|
||||
GetCurrentProcessId (), GetCurrentThreadId (), GetTickCount64 (), attempt);
|
||||
temporary = std::wstring (name) + suffix;
|
||||
error = locked.OpenFile (temporary, GENERIC_WRITE | DELETE | READ_CONTROL | FILE_READ_ATTRIBUTES, 0, FILE_CREATE, descriptor.Value, file);
|
||||
if (error == ERROR_SUCCESS) break;
|
||||
if (file.Value != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FILE_DISPOSITION_INFO disposition = { TRUE };
|
||||
SetFileInformationByHandle (file.Value, FileDispositionInfo, &disposition, sizeof (disposition));
|
||||
return error;
|
||||
}
|
||||
if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) return error;
|
||||
}
|
||||
if (file.Value == INVALID_HANDLE_VALUE) return error;
|
||||
DWORD count = 0;
|
||||
error = CheckHandle (file.Value, false);
|
||||
if (error != ERROR_SUCCESS)
|
||||
{
|
||||
FILE_DISPOSITION_INFO disposition = { TRUE };
|
||||
SetFileInformationByHandle (file.Value, FileDispositionInfo, &disposition, sizeof (disposition));
|
||||
return error;
|
||||
}
|
||||
if (!WriteFile (file.Value, data, size, &count, NULL)) error = GetLastError ();
|
||||
else if (count != size) error = ERROR_WRITE_FAULT;
|
||||
else if (!FlushFileBuffers (file.Value)) error = GetLastError ();
|
||||
else error = ERROR_SUCCESS;
|
||||
// Never publish an incomplete write. Both publication and cleanup use
|
||||
// the original handle, even if a privileged process renames an ancestor.
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
if (expected)
|
||||
{
|
||||
std::vector<unsigned char> current;
|
||||
DWORD read = Read (locked, name, current);
|
||||
if (read != ERROR_SUCCESS && !Missing (read)) return read;
|
||||
if (current != *expected) return ERROR_RETRY;
|
||||
}
|
||||
return Publish (file.Value, locked.GetHandle (), name);
|
||||
}
|
||||
// Keep a complete temporary on publication failure for recovery. Delete
|
||||
// only incomplete data; never delete a handle after an uncertain rename.
|
||||
FILE_DISPOSITION_INFO disposition = { TRUE };
|
||||
SetFileInformationByHandle (file.Value, FileDispositionInfo, &disposition, sizeof (disposition));
|
||||
return error;
|
||||
}
|
||||
|
||||
inline DWORD Remove (const std::wstring &directory, const wchar_t *name, const std::vector<unsigned char> *expected = NULL)
|
||||
{
|
||||
Directory locked;
|
||||
DWORD error = locked.Open (directory);
|
||||
if (Missing (error)) return expected && !expected->empty () ? ERROR_RETRY : ERROR_SUCCESS;
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
Handle file;
|
||||
error = locked.OpenFile (name, DELETE | READ_CONTROL | FILE_READ_ATTRIBUTES | (expected ? GENERIC_READ : 0),
|
||||
FILE_SHARE_READ, FILE_OPEN, NULL, file);
|
||||
if (Missing (error)) return expected && !expected->empty () ? ERROR_RETRY : ERROR_SUCCESS;
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
error = CheckHandle (file.Value, false);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
if (expected)
|
||||
{
|
||||
// Compare and delete through the same handle, excluding writers and
|
||||
// renames throughout. Never remove another product's intervening edit.
|
||||
std::vector<unsigned char> current;
|
||||
error = Read (file.Value, current);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
if (current != *expected) return ERROR_RETRY;
|
||||
}
|
||||
FILE_DISPOSITION_INFO disposition = { TRUE };
|
||||
return SetFileInformationByHandle (file.Value, FileDispositionInfo, &disposition, sizeof (disposition))
|
||||
? ERROR_SUCCESS : GetLastError ();
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright (c) 2026 AM Crypto. All rights reserved.
|
||||
Governed by the Apache License 2.0; see License.txt.
|
||||
*/
|
||||
#ifndef TC_HEADER_Common_SystemEncryptionSetup
|
||||
#define TC_HEADER_Common_SystemEncryptionSetup
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
namespace VeraCrypt { namespace SystemEncryptionSetup
|
||||
{
|
||||
class Ini
|
||||
{
|
||||
public:
|
||||
Ini () : Unicode (false), Utf8Bom (false) { }
|
||||
DWORD Load (const std::vector<unsigned char> &bytes)
|
||||
{
|
||||
Text.clear (); Unicode = false; Utf8Bom = false;
|
||||
if (bytes.size () >= 2 && bytes[0] == 0xff && bytes[1] == 0xfe)
|
||||
{
|
||||
if (bytes.size () % 2) return ERROR_NO_UNICODE_TRANSLATION;
|
||||
Unicode = true;
|
||||
for (size_t i = 2; i < bytes.size (); i += 2) Text += wchar_t (bytes[i] | (bytes[i + 1] << 8));
|
||||
}
|
||||
else if (bytes.size () >= 3 && bytes[0] == 0xef && bytes[1] == 0xbb && bytes[2] == 0xbf)
|
||||
{
|
||||
Unicode = true; Utf8Bom = true;
|
||||
DWORD error = Decode (std::string (bytes.begin () + 3, bytes.end ()), CP_UTF8, Text);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bytes.size () >= 2 && bytes[0] == 0xfe && bytes[1] == 0xff) return ERROR_NO_UNICODE_TRANSLATION;
|
||||
for (size_t i = 0; i < bytes.size (); ++i) Text += wchar_t (bytes[i]);
|
||||
}
|
||||
for (size_t i = 0; i < Text.size (); ++i)
|
||||
if (Text[i] < L' ' && Text[i] != L'\t' && Text[i] != L'\r' && Text[i] != L'\n') return ERROR_INVALID_DATA;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD Set (const wchar_t *key, const std::wstring *value)
|
||||
{
|
||||
std::wstring encoded;
|
||||
if (value)
|
||||
{
|
||||
if (value->find_first_of (L"\r\n") != std::wstring::npos || value->find (L'\0') != std::wstring::npos) return ERROR_INVALID_DATA;
|
||||
encoded = *value;
|
||||
if (!Unicode)
|
||||
{
|
||||
BOOL substituted = FALSE;
|
||||
UINT cp = GetACP ();
|
||||
DWORD flags = cp == CP_UTF8 ? WC_ERR_INVALID_CHARS : WC_NO_BEST_FIT_CHARS;
|
||||
BOOL *usedDefault = cp == CP_UTF8 ? NULL : &substituted;
|
||||
int size = WideCharToMultiByte (cp, flags, value->c_str (), (int) value->size (), NULL, 0, NULL, usedDefault);
|
||||
std::string bytes (size > 0 ? size : 0, '\0');
|
||||
if (size > 0 && !WideCharToMultiByte (cp, flags, value->c_str (), (int) value->size (), &bytes[0], size, NULL, usedDefault)) return GetLastError ();
|
||||
if ((size <= 0 && !value->empty ()) || substituted)
|
||||
{
|
||||
// A non-ASCII BOMless UTF-8 file is indistinguishable from
|
||||
// some ANSI files. Do not silently reinterpret its other values.
|
||||
std::string original = ByteString (Text); std::wstring utf8, decoded;
|
||||
if (cp != CP_UTF8 && Decode (original, CP_UTF8, utf8) == ERROR_SUCCESS && utf8 != Text) return ERROR_NO_UNICODE_TRANSLATION;
|
||||
DWORD error = Decode (original, cp, decoded); if (error != ERROR_SUCCESS) return error;
|
||||
Text.swap (decoded); Unicode = true;
|
||||
}
|
||||
else { encoded.clear (); for (size_t i = 0; i < bytes.size (); ++i) encoded += wchar_t ((unsigned char) bytes[i]); }
|
||||
}
|
||||
}
|
||||
std::wstring result; bool section = false, inserted = false;
|
||||
for (size_t start = 0; start < Text.size (); )
|
||||
{
|
||||
size_t end = LineEnd (Text, start);
|
||||
std::wstring original = Text.substr (start, end - start), line = Trim (original);
|
||||
if (!line.empty () && line[0] == L'[')
|
||||
{
|
||||
if (section && !inserted && value) { Append (result, key, encoded); inserted = true; }
|
||||
section = IsSection (line);
|
||||
}
|
||||
// Replace the first occurrence in place and remove duplicates.
|
||||
// Keeping its position avoids two rewrites on every maintenance run.
|
||||
if (section && IsKey (line, key))
|
||||
{
|
||||
if (value && !inserted) { Append (result, key, encoded); inserted = true; }
|
||||
}
|
||||
else result += original;
|
||||
start = end;
|
||||
}
|
||||
if (value && !inserted)
|
||||
{
|
||||
if (!section) { EndLine (result); result += L"[SetupConfig]\r\n"; }
|
||||
Append (result, key, encoded);
|
||||
}
|
||||
Text.swap (result); return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Inspect every occurrence, including duplicate sections. Cleanup must
|
||||
// remove only registrations whose ownership the caller recognizes.
|
||||
template <class Predicate> DWORD RemoveMatching (const wchar_t *key, Predicate remove)
|
||||
{
|
||||
std::wstring result; bool section = false;
|
||||
for (size_t start = 0; start < Text.size (); )
|
||||
{
|
||||
size_t end = LineEnd (Text, start);
|
||||
std::wstring original = Text.substr (start, end - start), line = Trim (original);
|
||||
bool discard = false;
|
||||
if (!line.empty () && line[0] == L'[') section = IsSection (line);
|
||||
else if (section && IsKey (line, key))
|
||||
{
|
||||
size_t equals = line.find (L'=');
|
||||
std::wstring value = equals == std::wstring::npos ? L"" : Trim (line.substr (equals + 1));
|
||||
if (value.size () >= 2 && (value[0] == L'\"' || value[0] == L'\'') && value.back () == value[0])
|
||||
value = value.substr (1, value.size () - 2);
|
||||
if (!Unicode)
|
||||
{
|
||||
DWORD error = Decode (ByteString (value), CP_ACP, value);
|
||||
if (error != ERROR_SUCCESS) return error;
|
||||
}
|
||||
discard = remove (value);
|
||||
}
|
||||
if (!discard) result += original;
|
||||
start = end;
|
||||
}
|
||||
Text.swap (result); return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool IsEmpty () const
|
||||
{
|
||||
// Empty SetupConfig headers are left by removing our last options.
|
||||
// Preserve comments, other sections and every other nonblank line.
|
||||
for (size_t start = 0; start < Text.size (); )
|
||||
{
|
||||
size_t end = LineEnd (Text, start);
|
||||
std::wstring line = Trim (Text.substr (start, end - start));
|
||||
if (!line.empty () && _wcsicmp (line.c_str (), L"[SetupConfig]") != 0) return false;
|
||||
start = end;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD PreservedBytes (std::vector<unsigned char> &bytes) const
|
||||
{
|
||||
if (!Utf8Bom) { bytes = Bytes (); return ERROR_SUCCESS; }
|
||||
// Do not activate another product's hidden UTF-8-BOM section by
|
||||
// converting its encoding while removing our own registrations.
|
||||
bytes.assign ({ 0xef, 0xbb, 0xbf });
|
||||
if (Text.empty ()) return ERROR_SUCCESS;
|
||||
int size = WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, Text.data (), (int) Text.size (), NULL, 0, NULL, NULL);
|
||||
if (!size) return GetLastError ();
|
||||
bytes.resize (3 + size);
|
||||
return WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, Text.data (), (int) Text.size (),
|
||||
reinterpret_cast<char *> (bytes.data () + 3), size, NULL, NULL) ? ERROR_SUCCESS : GetLastError ();
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Bytes () const
|
||||
{
|
||||
std::vector<unsigned char> bytes;
|
||||
if (Unicode) { bytes.push_back (0xff); bytes.push_back (0xfe); }
|
||||
for (size_t i = 0; i < Text.size (); ++i)
|
||||
{
|
||||
bytes.push_back (static_cast<unsigned char> (Text[i] & 255));
|
||||
if (Unicode) bytes.push_back (static_cast<unsigned char> (Text[i] >> 8));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
private:
|
||||
static size_t LineEnd (const std::wstring &text, size_t start)
|
||||
{
|
||||
size_t end = text.find_first_of (L"\r\n", start);
|
||||
if (end == std::wstring::npos) return text.size ();
|
||||
if (text[end] == L'\r' && end + 1 < text.size () && text[end + 1] == L'\n') ++end;
|
||||
return end + 1;
|
||||
}
|
||||
static std::string ByteString (const std::wstring &text)
|
||||
{
|
||||
std::string bytes; bytes.reserve (text.size ());
|
||||
for (size_t i = 0; i < text.size (); ++i) bytes += static_cast<char> (text[i]);
|
||||
return bytes;
|
||||
}
|
||||
static DWORD Decode (const std::string &bytes, UINT cp, std::wstring &text)
|
||||
{
|
||||
text.clear (); if (bytes.empty ()) return ERROR_SUCCESS;
|
||||
int size = MultiByteToWideChar (cp, MB_ERR_INVALID_CHARS, bytes.data (), (int) bytes.size (), NULL, 0);
|
||||
if (!size) return GetLastError ();
|
||||
text.resize (size);
|
||||
return MultiByteToWideChar (cp, MB_ERR_INVALID_CHARS, bytes.data (), (int) bytes.size (), &text[0], size) ? ERROR_SUCCESS : GetLastError ();
|
||||
}
|
||||
static std::wstring Trim (const std::wstring &text)
|
||||
{
|
||||
size_t start = text.find_first_not_of (L" \t\r\n"), end = text.find_last_not_of (L" \t\r\n");
|
||||
return start == std::wstring::npos ? L"" : text.substr (start, end - start + 1);
|
||||
}
|
||||
static bool IsSection (const std::wstring &line)
|
||||
{
|
||||
size_t end = line.find (L']');
|
||||
// Windows profile APIs also accept a section terminated by the end
|
||||
// of the line without a closing bracket. Recognize it before editing
|
||||
// so a consumer-visible value cannot survive replacement/removal.
|
||||
return _wcsicmp (Trim (line.substr (1, end == std::wstring::npos ? end : end - 1)).c_str (), L"SetupConfig") == 0;
|
||||
}
|
||||
static bool IsKey (const std::wstring &line, const wchar_t *key)
|
||||
{
|
||||
return _wcsicmp (Trim (line.substr (0, line.find (L'='))).c_str (), key) == 0;
|
||||
}
|
||||
static void EndLine (std::wstring &text) { if (!text.empty () && text.back () != L'\n' && text.back () != L'\r') text += L"\r\n"; }
|
||||
static void Append (std::wstring &text, const wchar_t *key, const std::wstring &value)
|
||||
{
|
||||
EndLine (text); text += key; text += L"="; text += value; text += L"\r\n";
|
||||
}
|
||||
std::wstring Text;
|
||||
bool Unicode, Utf8Bom;
|
||||
};
|
||||
} }
|
||||
#endif
|
||||
+12
-3
@@ -11081,6 +11081,16 @@ enum
|
||||
|
||||
static DWORD SystemFavoritesServiceLastEfiBootChainWarningMask = MAXDWORD;
|
||||
|
||||
static void SystemFavoritesServiceUpdateSetupConfigFile ()
|
||||
{
|
||||
try
|
||||
{
|
||||
BootEncryption bootEnc (NULL);
|
||||
BootEncryption::UpdateSetupConfigFile (bootEnc.GetDriverServiceStartType () == SERVICE_BOOT_START);
|
||||
}
|
||||
catch (Exception &) { SystemFavoritesServiceLogError (L"Windows feature update configuration could not be secured. Repair/Reinstall VeraCrypt before a Windows feature update."); }
|
||||
}
|
||||
|
||||
static void SystemFavoritesServiceUpdateLoaderProcessing (BOOL bForce)
|
||||
{
|
||||
SystemFavoritesServiceLogInfo (L"SystemFavoritesServiceUpdateLoaderProcessing called");
|
||||
@@ -11091,8 +11101,6 @@ static void SystemFavoritesServiceUpdateLoaderProcessing (BOOL bForce)
|
||||
SystemFavoritesServiceLogInfo (L"SystemFavoritesServiceUpdateLoaderProcessing processing");
|
||||
try
|
||||
{
|
||||
BootEncryption::UpdateSetupConfigFile (true);
|
||||
SystemFavoritesServiceLogInfo (L"SystemFavoritesServiceUpdateLoaderProcessing: UpdateSetupConfigFile called");
|
||||
if (!BootEncStatus.HiddenSystem)
|
||||
{
|
||||
// re-install our bootloader again in case the update process has removed it.
|
||||
@@ -11152,6 +11160,7 @@ static void SystemFavoritesServiceUpdateLoaderProcessing (BOOL bForce)
|
||||
SystemFavoritesServiceLogError (L"SystemFavoritesServiceUpdateLoaderProcessing failed with an unexpected exception while updating the boot loader.");
|
||||
}
|
||||
}
|
||||
SystemFavoritesServiceUpdateSetupConfigFile ();
|
||||
}
|
||||
|
||||
// Global vector containing all devices previsouly knwon to the system
|
||||
@@ -11449,7 +11458,6 @@ int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t *lpsz
|
||||
InitOSVersionInfo();
|
||||
try
|
||||
{
|
||||
BootEncryption::UpdateSetupConfigFile (true);
|
||||
SystemFavoritesServiceBootLoaderUpdateOptions updateOptions;
|
||||
uint32 serviceFlags = ReadServiceConfigurationFlags ();
|
||||
if (GetSystemFavoritesServiceBootLoaderUpdateOptions (serviceFlags, FALSE, updateOptions))
|
||||
@@ -11471,6 +11479,7 @@ int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t *lpsz
|
||||
{
|
||||
SystemFavoritesServiceLogError (L"PostOOBE boot loader update failed with an unexpected exception.");
|
||||
}
|
||||
SystemFavoritesServiceUpdateSetupConfigFile ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+90
-45
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "Apidrvr.h"
|
||||
#include "BootEncryption.h"
|
||||
#include "SystemEncryptionFiles.h"
|
||||
#include "Platform/Finally.h"
|
||||
#include "Boot/Windows/BootCommon.h"
|
||||
#include "Combo.h"
|
||||
#include "ComSetup.h"
|
||||
@@ -103,10 +105,11 @@ void localcleanup (void)
|
||||
BOOL StartStopService (HWND hwndDlg, wchar_t *lpszService, BOOL bStart, DWORD argc, LPCWSTR* argv)
|
||||
{
|
||||
SC_HANDLE hManager, hService = NULL;
|
||||
BOOL bOK = FALSE, bRet;
|
||||
BOOL bOK = FALSE;
|
||||
SERVICE_STATUS status = {0};
|
||||
int x;
|
||||
DWORD dwError, dwStartTime, dwLastProgress, dwCheckPoint = 0;
|
||||
DWORD dwExpectedState = bStart? SERVICE_RUNNING : SERVICE_STOPPED;
|
||||
DWORD dwPendingState = bStart? SERVICE_START_PENDING : SERVICE_STOP_PENDING;
|
||||
|
||||
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
if (hManager == NULL)
|
||||
@@ -129,30 +132,45 @@ BOOL StartStopService (HWND hwndDlg, wchar_t *lpszService, BOOL bStart, DWORD ar
|
||||
else
|
||||
ControlService (hService, SERVICE_CONTROL_STOP, &status);
|
||||
|
||||
for (x = 0; x < WAIT_PERIOD; x++)
|
||||
dwStartTime = dwLastProgress = GetTickCount ();
|
||||
for (;;)
|
||||
{
|
||||
bRet = QueryServiceStatus (hService, &status);
|
||||
if (bRet != TRUE)
|
||||
if (!QueryServiceStatus (hService, &status))
|
||||
goto error;
|
||||
|
||||
if (status.dwCurrentState == dwExpectedState)
|
||||
{
|
||||
bOK = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status.dwCurrentState != dwPendingState)
|
||||
{
|
||||
SetLastError (status.dwWin32ExitCode ? status.dwWin32ExitCode : ERROR_SERVICE_REQUEST_TIMEOUT);
|
||||
goto error;
|
||||
}
|
||||
|
||||
DWORD dwNow = GetTickCount ();
|
||||
if (status.dwCheckPoint > dwCheckPoint)
|
||||
{
|
||||
dwCheckPoint = status.dwCheckPoint;
|
||||
dwLastProgress = dwNow;
|
||||
}
|
||||
|
||||
// Honor pending-state progress, but cap the wait at the service's two-minute startup allowance.
|
||||
if (dwNow - dwStartTime >= 120000
|
||||
|| dwNow - dwLastProgress >= (status.dwWaitHint ? status.dwWaitHint : WAIT_PERIOD * 1000))
|
||||
{
|
||||
SetLastError (ERROR_SERVICE_REQUEST_TIMEOUT);
|
||||
goto error;
|
||||
}
|
||||
Sleep (1000);
|
||||
}
|
||||
|
||||
bRet = QueryServiceStatus (hService, &status);
|
||||
if (bRet != TRUE)
|
||||
goto error;
|
||||
|
||||
if (status.dwCurrentState != dwExpectedState)
|
||||
goto error;
|
||||
|
||||
bOK = TRUE;
|
||||
|
||||
error:
|
||||
dwError = bOK ? ERROR_SUCCESS : GetLastError ();
|
||||
|
||||
if (bOK == FALSE && GetLastError () == ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
if (bOK == FALSE && hService == NULL && dwError == ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
{
|
||||
bOK = TRUE;
|
||||
}
|
||||
@@ -163,6 +181,7 @@ error:
|
||||
if (hManager != NULL)
|
||||
CloseServiceHandle (hManager);
|
||||
|
||||
SetLastError (dwError);
|
||||
return bOK;
|
||||
}
|
||||
|
||||
@@ -991,8 +1010,12 @@ BOOL DoFilesInstall (HWND hwndDlg, wchar_t *szDestDir)
|
||||
|
||||
try
|
||||
{
|
||||
if (BootEncObj.GetDriverServiceStartType() == SERVICE_BOOT_START)
|
||||
if (SystemEncryptionUpdate || BootEncObj.IsSystemFavoritesServiceInstalled ())
|
||||
{
|
||||
SystemEncryptionFiles::Directory sourceDirectory;
|
||||
SystemEncryptionFiles::Handle sourceFile;
|
||||
DWORD sourceError = SystemEncryptionFiles::OpenInstallerFile (szTmp, sourceDirectory, sourceFile);
|
||||
if (sourceError != ERROR_SUCCESS) { SetLastError (sourceError); throw SystemException (SRC_POS); }
|
||||
uint32 driverFlags = ReadDriverConfigurationFlags ();
|
||||
uint32 serviceFlags = BootEncObj.ReadServiceConfigurationFlags ();
|
||||
|
||||
@@ -1002,27 +1025,32 @@ BOOL DoFilesInstall (HWND hwndDlg, wchar_t *szDestDir)
|
||||
|
||||
// Tell the service not to update loader on stop
|
||||
BootEncObj.SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER, true);
|
||||
finally_do_arg2 (BootEncryption *, &BootEncObj, uint32, serviceFlags, {
|
||||
try { finally_arg->SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER, (finally_arg2 & VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER) != 0); } catch (...) { }
|
||||
});
|
||||
finally_do_arg2 (BootEncryption *, &BootEncObj, uint32, driverFlags, {
|
||||
try { finally_arg->SetDriverConfigurationFlag (finally_arg2, true); } catch (...) { }
|
||||
});
|
||||
|
||||
if (StartStopService (hwndDlg, TC_SYSTEM_FAVORITES_SERVICE_NAME, FALSE, 0, NULL))
|
||||
{
|
||||
// we tell the service not to load system favorites on startup
|
||||
LPCWSTR szArgs[2] = { TC_SYSTEM_FAVORITES_SERVICE_NAME, VC_SYSTEM_FAVORITES_SERVICE_ARG_SKIP_MOUNT};
|
||||
if (!CopyFile (szTmp, servicePath.c_str(), FALSE))
|
||||
ForceCopyFile (szTmp, servicePath.c_str());
|
||||
|
||||
StartStopService (hwndDlg, TC_SYSTEM_FAVORITES_SERVICE_NAME, TRUE, 2, szArgs);
|
||||
}
|
||||
else
|
||||
ForceCopyFile (szTmp, servicePath.c_str());
|
||||
throw_sys_if (!StartStopService (hwndDlg, TC_SYSTEM_FAVORITES_SERVICE_NAME, FALSE, 0, NULL));
|
||||
throw_sys_if (!CopyFile (szTmp, servicePath.c_str(), FALSE));
|
||||
LPCWSTR szArgs[2] = { TC_SYSTEM_FAVORITES_SERVICE_NAME, VC_SYSTEM_FAVORITES_SERVICE_ARG_SKIP_MOUNT };
|
||||
throw_sys_if (!StartStopService (hwndDlg, TC_SYSTEM_FAVORITES_SERVICE_NAME, TRUE, 2, szArgs));
|
||||
|
||||
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);
|
||||
BootEncObj.SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER,
|
||||
(serviceFlags & VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER) != 0);
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
catch (Exception &e)
|
||||
{
|
||||
e.Show (hwndDlg);
|
||||
EnableWow64FsRedirection (TRUE);
|
||||
#ifndef PORTABLE
|
||||
RestorePrivilegeState (&originalPrivileges);
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// delete files from legacy path
|
||||
@@ -1090,6 +1118,16 @@ BOOL DoFilesInstall (HWND hwndDlg, wchar_t *szDestDir)
|
||||
}
|
||||
|
||||
err:
|
||||
// These executables contain the security fix. Keeping an old copy must
|
||||
// not be offered as a successful installation, including in silent mode.
|
||||
if (!bResult && !bUninstall && (wcscmp (szFiles[i], L"AVeraCrypt.exe") == 0
|
||||
|| wcscmp (szFiles[i], L"AVeraCrypt Format.exe") == 0))
|
||||
{
|
||||
#ifndef PORTABLE
|
||||
RestorePrivilegeState (&originalPrivileges);
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
if (bResult == FALSE)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
@@ -1366,6 +1404,8 @@ BOOL DoApplicationDataUninstall (HWND hwndDlg)
|
||||
wchar_t path[MAX_PATH];
|
||||
wchar_t path2[MAX_PATH];
|
||||
BOOL bOK = TRUE;
|
||||
try { BootEncryption::UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (NULL); return FALSE; }
|
||||
|
||||
StatusMessage (hwndDlg, "REMOVING_APPDATA");
|
||||
|
||||
@@ -1411,14 +1451,8 @@ BOOL DoApplicationDataUninstall (HWND hwndDlg)
|
||||
{
|
||||
StringCbCatW (path, sizeof(path), L"\\VeraCrypt");
|
||||
|
||||
// Delete original bootloader
|
||||
StringCbPrintfW (path2, sizeof(path2), L"%s\\%s", path, TC_SYS_BOOT_LOADER_BACKUP_NAME);
|
||||
RemoveMessage (hwndDlg, path2);
|
||||
StatDeleteFile (path2, FALSE);
|
||||
|
||||
// remove VeraCrypt folder
|
||||
RemoveMessage (hwndDlg, path);
|
||||
StatRemoveDirectory (path);
|
||||
// Preserve both legacy backup names for recovery.
|
||||
RemoveDirectoryW (path);
|
||||
}
|
||||
|
||||
|
||||
@@ -2191,10 +2225,13 @@ void DoUninstall (void *arg)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resolve the old installation identity before deleting its registry keys.
|
||||
try { BootEncryption::UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); bOK = FALSE; }
|
||||
if (!Rollback && bSystemRestore && !bTempSkipSysRestore)
|
||||
SetSystemRestorePoint (hwndDlg, FALSE);
|
||||
|
||||
if (DoServiceUninstall (hwndDlg, L"veracrypt") == FALSE)
|
||||
if (!bOK || DoServiceUninstall (hwndDlg, L"veracrypt") == FALSE)
|
||||
{
|
||||
bOK = FALSE;
|
||||
}
|
||||
@@ -2304,12 +2341,18 @@ void DoInstall (void *arg)
|
||||
|
||||
UpdateProgressBarProc(2);
|
||||
|
||||
try { BootEncryption::UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); PostMessage (MainDlg, TC_APPMSG_INSTALL_FAILURE, 0, 0); return; }
|
||||
|
||||
if (DoDriverUnload (hwndDlg) == FALSE)
|
||||
{
|
||||
NormalCursor ();
|
||||
PostMessage (MainDlg, TC_APPMSG_INSTALL_FAILURE, 0, 0);
|
||||
return;
|
||||
}
|
||||
try { if (SystemEncryptionUpdate) BootEncryption::PrepareSystemEncryptionInstallation (InstallationPath); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); PostMessage (MainDlg, TC_APPMSG_INSTALL_FAILURE, 0, 0); return; }
|
||||
|
||||
|
||||
if (bUpgrade
|
||||
&& (IsFileInUse (wstring (InstallationPath) + L'\\' + _T(TC_APP_NAME) L".exe")
|
||||
@@ -2399,9 +2442,11 @@ void DoInstall (void *arg)
|
||||
|
||||
try
|
||||
{
|
||||
bootEnc.RenameDeprecatedSystemLoaderBackup();
|
||||
BootEncryption::UpdateSetupConfigFile (bOK && SystemEncryptionUpdate);
|
||||
}
|
||||
catch (...) { }
|
||||
catch (Exception &e) { e.Show (hwndDlg); bOK = FALSE; }
|
||||
try { bootEnc.RenameDeprecatedSystemLoaderBackup (SystemEncryptionUpdate != FALSE); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); Warning ("SYS_LOADER_BACKUP_MIGRATION_FAILED", hwndDlg); }
|
||||
|
||||
if (bOK)
|
||||
UpdateProgressBarProc(97);
|
||||
@@ -2437,7 +2482,7 @@ void DoInstall (void *arg)
|
||||
{
|
||||
UpdateProgressBarProc(0);
|
||||
|
||||
if (!SystemEncryptionUpdate)
|
||||
if (!SystemEncryptionUpdate && !bUpgrade && !bDowngrade && !bReinstallMode && !bRepairMode)
|
||||
{
|
||||
bUninstall = TRUE;
|
||||
Rollback = TRUE;
|
||||
@@ -2451,7 +2496,7 @@ void DoInstall (void *arg)
|
||||
|
||||
StatusMessage (hwndDlg, "ROLLBACK");
|
||||
}
|
||||
else
|
||||
else if (SystemEncryptionUpdate)
|
||||
{
|
||||
Warning ("SYS_ENC_UPGRADE_FAILED", hwndDlg);
|
||||
}
|
||||
|
||||
+81
-60
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "Apidrvr.h"
|
||||
#include "BootEncryption.h"
|
||||
#include "SystemEncryptionFiles.h"
|
||||
#include "Platform/Finally.h"
|
||||
#include "Boot/Windows/BootCommon.h"
|
||||
#include "Combo.h"
|
||||
#include "ComSetup.h"
|
||||
@@ -1222,10 +1224,11 @@ end:
|
||||
BOOL StartStopService_Dll (MSIHANDLE hInstaller, wchar_t *lpszService, BOOL bStart, DWORD argc, LPCWSTR* argv)
|
||||
{
|
||||
SC_HANDLE hManager, hService = NULL;
|
||||
BOOL bOK = FALSE, bRet;
|
||||
BOOL bOK = FALSE;
|
||||
SERVICE_STATUS status = {0};
|
||||
int x;
|
||||
DWORD dwError, dwStartTime, dwLastProgress, dwCheckPoint = 0;
|
||||
DWORD dwExpectedState = bStart? SERVICE_RUNNING : SERVICE_STOPPED;
|
||||
DWORD dwPendingState = bStart? SERVICE_START_PENDING : SERVICE_STOP_PENDING;
|
||||
|
||||
hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
if (hManager == NULL)
|
||||
@@ -1243,47 +1246,55 @@ BOOL StartStopService_Dll (MSIHANDLE hInstaller, wchar_t *lpszService, BOOL bSta
|
||||
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++)
|
||||
dwStartTime = dwLastProgress = GetTickCount ();
|
||||
for (;;)
|
||||
{
|
||||
bRet = QueryServiceStatus (hService, &status);
|
||||
if (bRet != TRUE)
|
||||
if (!QueryServiceStatus (hService, &status))
|
||||
goto error;
|
||||
|
||||
if (status.dwCurrentState == dwExpectedState)
|
||||
{
|
||||
bOK = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status.dwCurrentState != dwPendingState)
|
||||
{
|
||||
SetLastError (status.dwWin32ExitCode ? status.dwWin32ExitCode : ERROR_SERVICE_REQUEST_TIMEOUT);
|
||||
goto error;
|
||||
}
|
||||
|
||||
DWORD dwNow = GetTickCount ();
|
||||
if (status.dwCheckPoint > dwCheckPoint)
|
||||
{
|
||||
dwCheckPoint = status.dwCheckPoint;
|
||||
dwLastProgress = dwNow;
|
||||
}
|
||||
|
||||
// Honor pending-state progress, but cap the wait at the service's two-minute startup allowance.
|
||||
if (dwNow - dwStartTime >= 120000
|
||||
|| dwNow - dwLastProgress >= (status.dwWaitHint ? status.dwWaitHint : WAIT_PERIOD * 1000))
|
||||
{
|
||||
SetLastError (ERROR_SERVICE_REQUEST_TIMEOUT);
|
||||
goto error;
|
||||
}
|
||||
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:
|
||||
dwError = bOK ? ERROR_SUCCESS : GetLastError ();
|
||||
|
||||
if (bOK == FALSE && GetLastError () == ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
if (bOK == FALSE && hService == NULL && dwError == ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
{
|
||||
bOK = TRUE;
|
||||
}
|
||||
else if (!bOK)
|
||||
MSILog(hInstaller, MSI_ERROR_LEVEL, L"Failed to %s service %s. Error 0x%.8X", bStart ? L"start" : L"stop", lpszService, dwError);
|
||||
|
||||
if (hService != NULL)
|
||||
CloseServiceHandle (hService);
|
||||
@@ -1291,6 +1302,7 @@ error:
|
||||
if (hManager != NULL)
|
||||
CloseServiceHandle (hManager);
|
||||
|
||||
SetLastError (dwError);
|
||||
return bOK;
|
||||
}
|
||||
|
||||
@@ -1894,6 +1906,8 @@ BOOL DoApplicationDataUninstall_Dll (MSIHANDLE hInstaller)
|
||||
wchar_t path[MAX_PATH];
|
||||
wchar_t path2[MAX_PATH];
|
||||
BOOL bOK = TRUE;
|
||||
try { BootEncryption::UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (NULL); return FALSE; }
|
||||
|
||||
MSILog(hInstaller, MSI_INFO_LEVEL, GetString("REMOVING_APPDATA"));
|
||||
|
||||
@@ -1939,14 +1953,8 @@ BOOL DoApplicationDataUninstall_Dll (MSIHANDLE hInstaller)
|
||||
{
|
||||
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);
|
||||
// Preserve both legacy backup names for recovery.
|
||||
RemoveDirectoryW (path);
|
||||
}
|
||||
|
||||
MSILog(hInstaller, MSI_INFO_LEVEL, L"End DoApplicationDataUninstall");
|
||||
@@ -1972,10 +1980,12 @@ BOOL DoUninstall_Dll (MSIHANDLE hInstaller, HWND hwndDlg)
|
||||
}
|
||||
else
|
||||
{
|
||||
try { BootEncryption::UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); bOK = FALSE; }
|
||||
if (!Rollback && bSystemRestore && !bTempSkipSysRestore)
|
||||
SetSystemRestorePoint_Dll (hInstaller, FALSE);
|
||||
|
||||
if (DoServiceUninstall_Dll (hInstaller, hwndDlg, L"veracrypt") == FALSE)
|
||||
if (!bOK || DoServiceUninstall_Dll (hInstaller, hwndDlg, L"veracrypt") == FALSE)
|
||||
{
|
||||
bOK = FALSE;
|
||||
}
|
||||
@@ -2490,11 +2500,17 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PreInstall(MSIHANDLE hInstaller)
|
||||
|
||||
bootEnc.SetParentWindow(hwndDlg);
|
||||
|
||||
try { BootEncryption::UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); goto end; }
|
||||
|
||||
if (DoDriverUnload_Dll (hInstaller, hwndDlg) == FALSE)
|
||||
{
|
||||
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreInstall: DoDriverUnload_Dll() failed");
|
||||
goto end;
|
||||
}
|
||||
try { if (SystemEncryptionUpdate) BootEncryption::PrepareSystemEncryptionInstallation (InstallationPath); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); goto end; }
|
||||
|
||||
|
||||
if (bSystemRestore)
|
||||
{
|
||||
@@ -2800,8 +2816,12 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostInstall(MSIHANDLE hInstaller)
|
||||
|
||||
try
|
||||
{
|
||||
if (BootEncObj.GetDriverServiceStartType() == SERVICE_BOOT_START)
|
||||
if (SystemEncryptionUpdate || BootEncObj.IsSystemFavoritesServiceInstalled ())
|
||||
{
|
||||
SystemEncryptionFiles::Directory sourceDirectory;
|
||||
SystemEncryptionFiles::Handle sourceFile;
|
||||
DWORD sourceError = SystemEncryptionFiles::OpenInstallerFile (szTmp, sourceDirectory, sourceFile);
|
||||
if (sourceError != ERROR_SUCCESS) { SetLastError (sourceError); throw SystemException (SRC_POS); }
|
||||
uint32 driverFlags = ReadDriverConfigurationFlags ();
|
||||
uint32 serviceFlags = BootEncObj.ReadServiceConfigurationFlags ();
|
||||
|
||||
@@ -2811,32 +2831,29 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostInstall(MSIHANDLE hInstaller)
|
||||
|
||||
// Tell the service not to update loader on stop
|
||||
BootEncObj.SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER, true);
|
||||
finally_do_arg2 (BootEncryption *, &BootEncObj, uint32, serviceFlags, {
|
||||
try { finally_arg->SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER, (finally_arg2 & VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER) != 0); } catch (...) { }
|
||||
});
|
||||
finally_do_arg2 (BootEncryption *, &BootEncObj, uint32, driverFlags, {
|
||||
try { finally_arg->SetDriverConfigurationFlag (finally_arg2, true); } catch (...) { }
|
||||
});
|
||||
|
||||
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());
|
||||
}
|
||||
throw_sys_if (!StartStopService_Dll (hInstaller, TC_SYSTEM_FAVORITES_SERVICE_NAME, FALSE, 0, NULL));
|
||||
throw_sys_if (!CopyFile (szTmp, servicePath.c_str(), FALSE));
|
||||
LPCWSTR szArgs[3] = { TC_SYSTEM_FAVORITES_SERVICE_NAME, VC_SYSTEM_FAVORITES_SERVICE_ARG_SKIP_MOUNT, VC_SYSTEM_FAVORITES_SERVICE_ARG_UPDATE_LOADER };
|
||||
throw_sys_if (!StartStopService_Dll (hInstaller, TC_SYSTEM_FAVORITES_SERVICE_NAME, TRUE, SystemEncryptionUpdate ? 3 : 2, szArgs));
|
||||
|
||||
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);
|
||||
BootEncObj.SetServiceConfigurationFlag (VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER,
|
||||
(serviceFlags & VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER) != 0);
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
catch (Exception &e)
|
||||
{
|
||||
e.Show (hwndDlg);
|
||||
EnableWow64FsRedirection (TRUE);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
// delete files from legacy path
|
||||
@@ -2970,9 +2987,11 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostInstall(MSIHANDLE hInstaller)
|
||||
|
||||
try
|
||||
{
|
||||
bootEnc.RenameDeprecatedSystemLoaderBackup();
|
||||
BootEncryption::UpdateSetupConfigFile (bOK && SystemEncryptionUpdate);
|
||||
}
|
||||
catch (...) { }
|
||||
catch (Exception &e) { e.Show (hwndDlg); bOK = FALSE; }
|
||||
try { bootEnc.RenameDeprecatedSystemLoaderBackup (SystemEncryptionUpdate != FALSE); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); Warning ("SYS_LOADER_BACKUP_MIGRATION_FAILED", hwndDlg); }
|
||||
|
||||
if (bSystemRestore)
|
||||
SetSystemRestorePoint_Dll (hInstaller, TRUE);
|
||||
@@ -2984,7 +3003,7 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostInstall(MSIHANDLE hInstaller)
|
||||
else
|
||||
{
|
||||
MSILog(hInstaller, MSI_INFO_LEVEL, L"Post install failed");
|
||||
if (!SystemEncryptionUpdate)
|
||||
if (!SystemEncryptionUpdate && !bUpgrade && !bDowngrade && !bReinstallMode && !bRepairMode)
|
||||
{
|
||||
bUninstall = TRUE;
|
||||
Rollback = TRUE;
|
||||
@@ -2998,7 +3017,7 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostInstall(MSIHANDLE hInstaller)
|
||||
|
||||
MSILog(hInstaller, MSI_INFO_LEVEL, GetString("ROLLBACK"));
|
||||
}
|
||||
else
|
||||
else if (SystemEncryptionUpdate)
|
||||
{
|
||||
MSILog(hInstaller, MSI_WARNING_LEVEL, GetString("SYS_ENC_UPGRADE_FAILED"));
|
||||
}
|
||||
@@ -3232,10 +3251,12 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PreUninstall(MSIHANDLE hInstaller)
|
||||
}
|
||||
else
|
||||
{
|
||||
try { BootEncryption::UpdateSetupConfigFile (false); }
|
||||
catch (Exception &e) { e.Show (hwndDlg); bOK = FALSE; }
|
||||
if (!Rollback && bSystemRestore && !bTempSkipSysRestore)
|
||||
SetSystemRestorePoint_Dll (hInstaller, FALSE);
|
||||
|
||||
if (DoServiceUninstall_Dll (hInstaller, hwndDlg, L"veracrypt") == FALSE)
|
||||
if (!bOK || DoServiceUninstall_Dll (hInstaller, hwndDlg, L"veracrypt") == FALSE)
|
||||
{
|
||||
MSILog(hInstaller, MSI_ERROR_LEVEL, L"VC_CustomAction_PreUninstall: DoServiceUninstall_Dll(veracrypt) failed");
|
||||
bOK = FALSE;
|
||||
|
||||
Reference in New Issue
Block a user