From 50029ee077770bc1032075d7318cf1defa9507f2 Mon Sep 17 00:00:00 2001 From: DavidXanatos <3890945+DavidXanatos@users.noreply.github.com> Date: Wed, 25 Jan 2023 12:54:41 +0100 Subject: [PATCH] 1.7.0 --- CHANGELOG.md | 23 +- Sandboxie/apps/control/Updater.cpp | 9 +- Sandboxie/common/my_version.h | 4 +- Sandboxie/core/dll/SboxDll.vcxproj | 2 + Sandboxie/core/dll/debug.c | 2 +- Sandboxie/core/dll/dllmain.c | 8 + Sandboxie/core/dll/dump.c | 8 +- Sandboxie/core/dll/file_copy.c | 61 +++- Sandboxie/core/dll/key.c | 187 ++++++++-- Sandboxie/core/dll/ldr.c | 46 ++- Sandboxie/core/dll/ldr_init.c | 31 +- Sandboxie/core/dll/util_64.asm | 17 +- Sandboxie/core/dll/util_arm.asm | 3 +- Sandboxie/core/low/init.c | 29 +- Sandboxie/core/low/inject.c | 59 ++- .../MiscHelpers/Common/DebugHelpers.cpp | 6 + SandboxiePlus/QSbieAPI/SbieUtils.cpp | 87 +++++ SandboxiePlus/QSbieAPI/SbieUtils.h | 3 + SandboxiePlus/SandMan/Forms/OptionsWindow.ui | 339 +++++++++++++----- SandboxiePlus/SandMan/Forms/SettingsWindow.ui | 270 +++++++------- SandboxiePlus/SandMan/OnlineUpdater.cpp | 10 +- SandboxiePlus/SandMan/OnlineUpdater.h | 2 +- SandboxiePlus/SandMan/SandManRecovery.cpp | 108 +++++- SandboxiePlus/SandMan/Views/SbieView.cpp | 9 +- .../SandMan/Windows/OptionsAdvanced.cpp | 2 - .../SandMan/Windows/OptionsGeneral.cpp | 338 ++++++++++++++++- .../SandMan/Windows/OptionsNetwork.cpp | 1 + .../SandMan/Windows/OptionsWindow.cpp | 49 ++- SandboxiePlus/SandMan/Windows/OptionsWindow.h | 24 ++ .../SandMan/Windows/SettingsWindow.cpp | 6 +- SandboxiePlus/SandMan/Wizards/SetupWizard.cpp | 1 - SandboxiePlus/version.h | 4 +- 32 files changed, 1393 insertions(+), 355 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bd9509d..29f97867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,30 @@ This project adheres to [Semantic Versioning](http://semver.org/). +## [1.7.0 / 5.62.0] - 2023-01-25 -## [1.6.7 / 5.61.7] - 2023-01-? +### Added +- added OnFileRecovery trigger allowing to check files before recovering them [#2202](https://github.com/sandboxie-plus/Sandboxie/issues/2202) + +- added more box structure presets to sandbox options +-- Note: these can only be changed when the box is empty + +- added new File Migration option page with additional settings +- added SBIE2113/SBIE2114/SBIE2115 message to indicate files not being migrated due to presets + +### changed +- moved SeparateUserFolders checlbox from global settings to per box options + +### fixed +- resolved SbieDll.dll incompatybility with shadow stack and enabled /CETCOMPAT for SbieDll.dll [#2559](https://github.com/sandboxie-plus/Sandboxie/issues/2559) +- added missing registry hooks to improve compatybility with newer appliations +- fixed permission isue with registry entries in privacy mode boxes + + + + +## [1.6.7 / 5.61.7] - 2023-01-24 ### Added - added option to the classic ui to apply a supporter certificate diff --git a/Sandboxie/apps/control/Updater.cpp b/Sandboxie/apps/control/Updater.cpp index e5aaee2d..5c5c8cc3 100644 --- a/Sandboxie/apps/control/Updater.cpp +++ b/Sandboxie/apps/control/Updater.cpp @@ -237,13 +237,14 @@ BOOLEAN CUpdater::QueryUpdateData(UPDATER_DATA* Context) JSONValue* jsonObject = NULL; JSONObject jsonRoot; - Path.Format(L"/update.php?software=sandboxie&version=%S&system=windows-%d.%d.%d-%s&language=%d&auto=%s", MY_VERSION_STRING, + Path.Format(L"/update.php?software=sandboxie&version=%S&system=windows-%d.%d.%d-%s&language=%d&auto=%s", + MY_VERSION_STRING, m_osvi.dwMajorVersion, m_osvi.dwMinorVersion, m_osvi.dwBuildNumber, #ifdef _M_ARM64 - m_osvi.dwMajorVersion, m_osvi.dwMinorVersion, m_osvi.dwBuildNumber, L"ARM64", + L"ARM64", #elif _WIN64 - m_osvi.dwMajorVersion, m_osvi.dwMinorVersion, m_osvi.dwBuildNumber, L"x86_64", + L"x86_64", #else - m_osvi.dwMajorVersion, m_osvi.dwMinorVersion, m_osvi.dwBuildNumber, L"i386", + L"i386", #endif SbieDll_GetLanguage(NULL), Context->Manual ? L"0" : L"1"); diff --git a/Sandboxie/common/my_version.h b/Sandboxie/common/my_version.h index 55d2bf84..65ef71af 100644 --- a/Sandboxie/common/my_version.h +++ b/Sandboxie/common/my_version.h @@ -21,8 +21,8 @@ #ifndef _MY_VERSION_H #define _MY_VERSION_H -#define MY_VERSION_BINARY 5,61,7 -#define MY_VERSION_STRING "5.61.7" +#define MY_VERSION_BINARY 5,62,0 +#define MY_VERSION_STRING "5.62.0" #define MY_ABI_VERSION 0x56000 // These #defines are used by either Resource Compiler or NSIS installer diff --git a/Sandboxie/core/dll/SboxDll.vcxproj b/Sandboxie/core/dll/SboxDll.vcxproj index ccf7d433..cf4092c9 100644 --- a/Sandboxie/core/dll/SboxDll.vcxproj +++ b/Sandboxie/core/dll/SboxDll.vcxproj @@ -204,6 +204,7 @@ true false false + true /ignore:4281 %(AdditionalOptions) @@ -294,6 +295,7 @@ true false false + true /ignore:4281 %(AdditionalOptions) diff --git a/Sandboxie/core/dll/debug.c b/Sandboxie/core/dll/debug.c index 2d37bb13..a27cebdc 100644 --- a/Sandboxie/core/dll/debug.c +++ b/Sandboxie/core/dll/debug.c @@ -46,7 +46,7 @@ //#define BREAK_PROC "ExecSecureObjects" //#define BREAK_PROC "SoftwareDirectorMsiErrorCheck" //#define BREAK_PROC "InstallDriverPackages" -#define BREAK_PROC "MSIunzipcore" +//#define BREAK_PROC "MSIunzipcore" #undef HIDE_SBIEDLL diff --git a/Sandboxie/core/dll/dllmain.c b/Sandboxie/core/dll/dllmain.c index 9925011d..87782c0c 100644 --- a/Sandboxie/core/dll/dllmain.c +++ b/Sandboxie/core/dll/dllmain.c @@ -383,6 +383,14 @@ _FX void Dll_InitInjected(void) // } // } + +#ifdef WITH_DEBUG + if (SbieApi_QueryConfBool(NULL, L"DisableSbieDll", FALSE)) { + Dll_InitComplete = TRUE; + return; + } +#endif + // // check if process SID is LocalSystem // diff --git a/Sandboxie/core/dll/dump.c b/Sandboxie/core/dll/dump.c index 708833c9..d4f59ebd 100644 --- a/Sandboxie/core/dll/dump.c +++ b/Sandboxie/core/dll/dump.c @@ -106,7 +106,10 @@ static LONG __stdcall Dump_CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pEx) } #endif - SbieApi_Log(2224, L"%S [%S]", Dll_ImageName, Dll_BoxName); + if (pEx->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C || pEx->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) + return EXCEPTION_CONTINUE_SEARCH; + + SbieApi_Log(2224, L"%S (0x%08X) [%S]", Dll_ImageName, pEx->ExceptionRecord->ExceptionCode, Dll_BoxName); BOOLEAN bSuccess = FALSE; HANDLE hFile; @@ -242,6 +245,9 @@ _FX int Dump_Init(void) SBIEDLL_HOOK(Dump_, SetUnhandledExceptionFilter); + // Register Vectored Exception Handler + //AddVectoredExceptionHandler(0, Dump_CrashHandlerExceptionFilter); + //SbieApi_MonitorPutMsg(MONITOR_OTHER | MONITOR_TRACE, L"Minidump enabled", FALSE); return 1; } \ No newline at end of file diff --git a/Sandboxie/core/dll/file_copy.c b/Sandboxie/core/dll/file_copy.c index f7b90da1..c726db94 100644 --- a/Sandboxie/core/dll/file_copy.c +++ b/Sandboxie/core/dll/file_copy.c @@ -51,6 +51,7 @@ static BOOLEAN File_MigrationDenyWrite = FALSE; static ULONGLONG File_CopyLimitKb = (80 * 1024); // 80 MB static BOOLEAN File_CopyLimitSilent = FALSE; +static BOOLEAN File_NotifyNoCopy = FALSE; //--------------------------------------------------------------------------- // File_InitFileMigration @@ -76,10 +77,37 @@ _FX BOOLEAN File_InitFileMigration(void) File_InitCopyLimit(); + File_NotifyNoCopy = SbieApi_QueryConfBool(NULL, L"NotifyNoCopy", FALSE); + return TRUE; } +//--------------------------------------------------------------------------- +// File_MigrateFile_Message +//--------------------------------------------------------------------------- + + +_FX VOID File_MigrateFile_Message(const WCHAR* TruePath, ULONGLONG file_size, int MsgID) +{ + const WCHAR* name = wcsrchr(TruePath, L'\\'); + if (name) + ++name; + else + name = TruePath; + + ULONG TruePathNameLen = wcslen(name); + WCHAR* text = Dll_AllocTemp( + (TruePathNameLen + 64) * sizeof(WCHAR)); + Sbie_snwprintf(text, (TruePathNameLen + 64), L"%s [%s / %I64u]", + name, Dll_BoxName, file_size); + + SbieApi_Log(MsgID, text); + + Dll_Free(text); +} + + //--------------------------------------------------------------------------- // File_MigrateFile_GetMode //--------------------------------------------------------------------------- @@ -121,8 +149,21 @@ found_match: Dll_Free(path_lwr); - if (mode != NUM_COPY_MODES) + if (mode != NUM_COPY_MODES) { + + if (File_NotifyNoCopy) { + if (mode == FILE_DONT_COPY) { + if(File_MigrationDenyWrite) + File_MigrateFile_Message(TruePath, file_size, 2114); + else // else open read only + File_MigrateFile_Message(TruePath, file_size, 2115); + } + else if (mode == FILE_COPY_EMPTY) + File_MigrateFile_Message(TruePath, file_size, 2113); + } + return mode; + } // // if tere is no configuration for this file type/path decide based on the file size @@ -162,23 +203,7 @@ found_match: // else if (!File_CopyLimitSilent) - { - const WCHAR* name = wcsrchr(TruePath, L'\\'); - if (name) - ++name; - else - name = TruePath; - - ULONG TruePathNameLen = wcslen(name); - WCHAR* text = Dll_AllocTemp( - (TruePathNameLen + 64) * sizeof(WCHAR)); - Sbie_snwprintf(text, (TruePathNameLen + 64), L"%s [%s / %I64u]", - name, Dll_BoxName, file_size); - - SbieApi_Log(2102, text); - - Dll_Free(text); - } + File_MigrateFile_Message(TruePath, file_size, 2102); return FILE_DONT_COPY; } diff --git a/Sandboxie/core/dll/key.c b/Sandboxie/core/dll/key.c index d2a26e1b..c2988a85 100644 --- a/Sandboxie/core/dll/key.c +++ b/Sandboxie/core/dll/key.c @@ -81,10 +81,17 @@ static NTSTATUS Key_NtOpenKey( ACCESS_MASK DesiredAccess, OBJECT_ATTRIBUTES *ObjectAttributes); +static NTSTATUS Key_NtOpenKeyTransacted( + HANDLE *KeyHandle, + ACCESS_MASK DesiredAccess, + OBJECT_ATTRIBUTES *ObjectAttributes, + HANDLE TransactionHandle); + static NTSTATUS Key_NtOpenKeyImpl( HANDLE *KeyHandle, ACCESS_MASK DesiredAccess, - OBJECT_ATTRIBUTES *ObjectAttributes); + OBJECT_ATTRIBUTES *ObjectAttributes, + HANDLE TransactionHandle); static NTSTATUS Key_NtOpenKeyEx( HANDLE *KeyHandle, @@ -92,6 +99,13 @@ static NTSTATUS Key_NtOpenKeyEx( OBJECT_ATTRIBUTES *ObjectAttributes, ULONG OpenOptions); +static NTSTATUS Key_NtOpenKeyTransactedEx( + HANDLE *KeyHandle, + ACCESS_MASK DesiredAccess, + OBJECT_ATTRIBUTES *ObjectAttributes, + ULONG OpenOptions, + HANDLE TransactionHandle); + static NTSTATUS Key_NtCreateKey( HANDLE *KeyHandle, ACCESS_MASK DesiredAccess, @@ -101,6 +115,16 @@ static NTSTATUS Key_NtCreateKey( ULONG CreateOptions, ULONG *Disposition); +static NTSTATUS Key_NtCreateKeyTransacted( + PHANDLE KeyHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG TitleIndex, + PUNICODE_STRING Class, + ULONG CreateOptions, + HANDLE TransactionHandle, + PULONG Disposition); + static NTSTATUS Key_NtCreateKeyImpl( HANDLE *KeyHandle, ACCESS_MASK DesiredAccess, @@ -108,7 +132,8 @@ static NTSTATUS Key_NtCreateKeyImpl( ULONG TitleIndex, UNICODE_STRING *Class, ULONG CreateOptions, - ULONG *Disposition); + ULONG *Disposition, + HANDLE TransactionHandle); static NTSTATUS Key_CreatePath( OBJECT_ATTRIBUTES *objattrs, PSECURITY_DESCRIPTOR *sd); @@ -280,8 +305,11 @@ NTSTATUS File_NtCloseImpl(HANDLE FileHandle); P_NtOpenKey __sys_NtOpenKey = NULL; +static P_NtOpenKeyTransacted __sys_NtOpenKeyTransacted = NULL; static P_NtOpenKeyEx __sys_NtOpenKeyEx = NULL; +static P_NtOpenKeyTransactedEx __sys_NtOpenKeyTransactedEx = NULL; static P_NtCreateKey __sys_NtCreateKey = NULL; +static P_NtCreateKeyTransacted __sys_NtCreateKeyTransacted = NULL; static P_NtDeleteKey __sys_NtDeleteKey = NULL; static P_NtDeleteValueKey __sys_NtDeleteValueKey = NULL; static P_NtSetValueKey __sys_NtSetValueKey = NULL; @@ -428,6 +456,20 @@ _FX BOOLEAN Key_Init(void) SBIEDLL_HOOK(Key_, NtOpenKeyEx); } + void* NtOpenKeyTransacted = GetProcAddress(Dll_Ntdll, "NtOpenKeyTransacted"); + if (NtOpenKeyTransacted) { // Windows vista + SBIEDLL_HOOK(Key_, NtOpenKeyTransacted); + } + + void* NtOpenKeyTransactedEx = GetProcAddress(Dll_Ntdll, "NtOpenKeyTransactedEx"); + if (NtOpenKeyTransactedEx) { // windows server 2008 R2 + SBIEDLL_HOOK(Key_, NtOpenKeyTransactedEx); + } + + void* NtCreateKeyTransacted = GetProcAddress(Dll_Ntdll, "NtCreateKeyTransacted"); + if (NtCreateKeyTransacted) { // Windows vista + SBIEDLL_HOOK(Key_, NtCreateKeyTransacted); + } SBIEDLL_HOOK(Key_, NtSaveKey); @@ -1086,7 +1128,26 @@ _FX NTSTATUS Key_NtOpenKey( ACCESS_MASK DesiredAccess, OBJECT_ATTRIBUTES *ObjectAttributes) { - NTSTATUS status = Key_NtOpenKeyImpl(KeyHandle, DesiredAccess, ObjectAttributes); + NTSTATUS status = Key_NtOpenKeyImpl(KeyHandle, DesiredAccess, ObjectAttributes, NULL); + + status = StopTailCallOptimization(status); + + return status; +} + + +//--------------------------------------------------------------------------- +// Key_NtOpenKeyTransacted +//--------------------------------------------------------------------------- + + +_FX NTSTATUS Key_NtOpenKeyTransacted( + HANDLE *KeyHandle, + ACCESS_MASK DesiredAccess, + OBJECT_ATTRIBUTES *ObjectAttributes, + HANDLE TransactionHandle) +{ + NTSTATUS status = Key_NtOpenKeyImpl(KeyHandle, DesiredAccess, ObjectAttributes, TransactionHandle); status = StopTailCallOptimization(status); @@ -1101,7 +1162,8 @@ _FX NTSTATUS Key_NtOpenKey( _FX NTSTATUS Key_NtOpenKeyImpl( HANDLE *KeyHandle, ACCESS_MASK DesiredAccess, - OBJECT_ATTRIBUTES *ObjectAttributes) + OBJECT_ATTRIBUTES *ObjectAttributes, + HANDLE TransactionHandle) { // // use Key_NtCreateKey here so if anybody else intercepts @@ -1109,7 +1171,7 @@ _FX NTSTATUS Key_NtOpenKeyImpl( // NTSTATUS status = Key_NtCreateKeyImpl( - KeyHandle, DesiredAccess, ObjectAttributes, 0, NULL, tzuk, NULL); + KeyHandle, DesiredAccess, ObjectAttributes, 0, NULL, tzuk, NULL, TransactionHandle); return status; } @@ -1134,7 +1196,36 @@ _FX NTSTATUS Key_NtOpenKeyEx( }*/ status = Key_NtCreateKeyImpl( - KeyHandle, DesiredAccess, ObjectAttributes, 0, NULL, tzuk, NULL); + KeyHandle, DesiredAccess, ObjectAttributes, 0, NULL, tzuk, NULL, NULL); + + status = StopTailCallOptimization(status); + + return status; +} + + +//--------------------------------------------------------------------------- +// Key_NtOpenKeyTransactedEx +//--------------------------------------------------------------------------- + + +_FX NTSTATUS Key_NtOpenKeyTransactedEx( + HANDLE *KeyHandle, + ACCESS_MASK DesiredAccess, + OBJECT_ATTRIBUTES *ObjectAttributes, + ULONG OpenOptions, + HANDLE TransactionHandle) +{ + NTSTATUS status; + + OpenOptions &= ~REG_OPTION_BACKUP_RESTORE; + /*if (OpenOptions) { + // probably REG_OPTION_OPEN_LINK + SbieApi_Log(2205, L"NtOpenKeyEx (%08X)", OpenOptions); + }*/ + + status = Key_NtCreateKeyImpl( + KeyHandle, DesiredAccess, ObjectAttributes, 0, NULL, tzuk, NULL, TransactionHandle); status = StopTailCallOptimization(status); @@ -1162,7 +1253,38 @@ _FX NTSTATUS Key_NtCreateKey( TitleIndex, Class, CreateOptions, - Disposition); + Disposition, + NULL); + + status = StopTailCallOptimization(status); + + return status; +} + + +//--------------------------------------------------------------------------- +// Key_NtCreateKeyTransacted +//--------------------------------------------------------------------------- + + +NTSTATUS Key_NtCreateKeyTransacted( + PHANDLE KeyHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG TitleIndex, + PUNICODE_STRING Class, + ULONG CreateOptions, + HANDLE TransactionHandle, + PULONG Disposition) +{ + NTSTATUS status = Key_NtCreateKeyImpl( KeyHandle, + DesiredAccess, + ObjectAttributes, + TitleIndex, + Class, + CreateOptions, + Disposition, + TransactionHandle); status = StopTailCallOptimization(status); @@ -1217,7 +1339,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl( ULONG TitleIndex, UNICODE_STRING *Class, ULONG CreateOptions, - ULONG *Disposition) + ULONG *Disposition, + HANDLE TransactionHandle) { ULONG LastError; THREAD_DATA *TlsData = Dll_GetTlsData(&LastError); @@ -1246,6 +1369,9 @@ _FX NTSTATUS Key_NtCreateKeyImpl( } #endif +#define __sys_NtCreateKeyX(kh, da, oa, ti, c, co, d) (TransactionHandle ? __sys_NtCreateKeyTransacted(kh, da, oa, ti, c, co, TransactionHandle, d) : __sys_NtCreateKey(kh, da, oa, ti, c, co, d)) +#define __sys_NtOpenKeyX(kh, da, oa) (TransactionHandle ? __sys_NtOpenKeyTransacted(kh, da, oa, TransactionHandle) : __sys_NtOpenKey(kh, da, oa)) + // // if this is a recursive invocation of NtCreateKey, // then pass it as-is down the chain @@ -1255,12 +1381,12 @@ _FX NTSTATUS Key_NtCreateKeyImpl( if (CreateOptions == tzuk) { - return __sys_NtOpenKey( + return __sys_NtOpenKeyX( KeyHandle, DesiredAccess, ObjectAttributes); } else { - return __sys_NtCreateKey( + return __sys_NtCreateKeyX( KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex, Class, CreateOptions, Disposition); } @@ -1338,32 +1464,32 @@ _FX NTSTATUS Key_NtCreateKeyImpl( if (CreateOptions == tzuk) { if(IsAKey) - status = __sys_NtOpenKey(KeyHandle, DesiredAccess, ObjectAttributes); + status = __sys_NtOpenKeyX(KeyHandle, DesiredAccess, ObjectAttributes); else - status = __sys_NtOpenKey(KeyHandle, DesiredAccess, &objattrs); + status = __sys_NtOpenKeyX(KeyHandle, DesiredAccess, &objattrs); if (status == STATUS_ACCESS_DENIED && DesiredAccess == MAXIMUM_ALLOWED) { - status = __sys_NtOpenKey( + status = __sys_NtOpenKeyX( KeyHandle, KEY_READ_WOW64, &objattrs); } } else { if(IsAKey) - status = __sys_NtCreateKey( + status = __sys_NtCreateKeyX( KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex, Class, CreateOptions, Disposition); else - status = __sys_NtCreateKey( + status = __sys_NtCreateKeyX( KeyHandle, DesiredAccess, &objattrs, TitleIndex, Class, CreateOptions, Disposition); if (status == STATUS_ACCESS_DENIED && DesiredAccess == MAXIMUM_ALLOWED) { - status = __sys_NtCreateKey( + status = __sys_NtCreateKeyX( KeyHandle, KEY_READ_WOW64, &objattrs, TitleIndex, Class, CreateOptions, Disposition); } @@ -1434,14 +1560,14 @@ _FX NTSTATUS Key_NtCreateKeyImpl( if (CreateOptions == tzuk) { - status = __sys_NtOpenKey( + status = __sys_NtOpenKeyX( KeyHandle, DesiredAccess | KEY_READ, &objattrs); } else { CreateOptions &= ~REG_OPTION_BACKUP_RESTORE; - status = __sys_NtCreateKey( + status = __sys_NtCreateKeyX( KeyHandle, DesiredAccess | KEY_READ, &objattrs, TitleIndex, Class, CreateOptions, Disposition); @@ -1466,12 +1592,12 @@ _FX NTSTATUS Key_NtCreateKeyImpl( if (CreateOptions == tzuk) { - status2 = __sys_NtOpenKey( + status2 = __sys_NtOpenKeyX( KeyHandle, DesiredAccess | KEY_READ, &objattrs); } else { - status2 = __sys_NtCreateKey( + status2 = __sys_NtCreateKeyX( KeyHandle, DesiredAccess | KEY_READ, &objattrs, TitleIndex, Class, CreateOptions, Disposition); @@ -1542,7 +1668,7 @@ _FX NTSTATUS Key_NtCreateKeyImpl( HANDLE handle; RtlInitUnicodeString(&objname, TruePath); - status = __sys_NtOpenKey( + status = __sys_NtOpenKeyX( &handle, Wow64KeyReadAccess, &objattrs); if (NT_SUCCESS(status)) { @@ -1633,7 +1759,7 @@ _FX NTSTATUS Key_NtCreateKeyImpl( // otherwise not write-only, so do normal NtOpenKey // - status = __sys_NtOpenKey(KeyHandle, Wow64KeyReadAccess, &objattrs); + status = __sys_NtOpenKeyX(KeyHandle, Wow64KeyReadAccess, &objattrs); } if (NT_SUCCESS(status)) { @@ -1747,7 +1873,7 @@ SkipReadOnlyCheck: // as described above in more detail // - status = __sys_NtOpenKey(KeyHandle, DesiredAccess, &objattrs); + status = __sys_NtOpenKeyX(KeyHandle, DesiredAccess, &objattrs); if (NT_SUCCESS(status) && Disposition) { @@ -1782,7 +1908,7 @@ SkipReadOnlyCheck: status = Key_NtCreateKeyImpl( KeyHandle, DesiredAccess, ObjectAttributes, - TitleIndex, Class, CreateOptions, Disposition); + TitleIndex, Class, CreateOptions, Disposition, TransactionHandle); if (status == STATUS_ACCESS_DENIED && CreateOptions != tzuk) { @@ -1791,7 +1917,7 @@ SkipReadOnlyCheck: // so try one more time using NtOpenKey // - status = __sys_NtOpenKey( + status = __sys_NtOpenKeyX( KeyHandle, DesiredAccess, ObjectAttributes); if (NT_SUCCESS(status)) TrueOpened = TRUE; // is that right? @@ -1819,6 +1945,9 @@ SkipReadOnlyCheck: Handle_SetRelocationPath(*KeyHandle, OriginalPath); } +#undef __sys_NtCreateKeyX +#undef __sys_NtOpenKeyX + // // finish // @@ -2268,7 +2397,7 @@ _FX NTSTATUS Key_NtDeleteKeyTreeImpl(HANDLE KeyHandle, BOOLEAN DeleteTree) // open the key. this will create a copy key, if necessary // - status = Key_NtOpenKeyImpl(&handle, GENERIC_WRITE | KEY_READ | DELETE, &objattrs); + status = Key_NtOpenKeyImpl(&handle, GENERIC_WRITE | KEY_READ | DELETE, &objattrs, NULL); if (! NT_SUCCESS(status)) __leave; @@ -3241,7 +3370,7 @@ _FX NTSTATUS Key_NtEnumerateKey( status = Key_NtOpenKeyImpl(&SubkeyHandle, Key_GetWow64Flag(SubkeyPath, KEY_READ), - &objattrs); + &objattrs, NULL); } } @@ -4955,7 +5084,7 @@ _FX void Key_CreateBaseKeys() // InitializeObjectAttributes( - &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); + &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, Secure_NormalSD); for (WCHAR** base_key = base_keys; *base_key; base_key++) { @@ -4964,6 +5093,6 @@ _FX void Key_CreateBaseKeys() RtlInitUnicodeString(&objname, buff); - Key_CreatePath(&objattrs, NULL); + Key_CreatePath(&objattrs, Secure_EveryoWneSD); } } diff --git a/Sandboxie/core/dll/ldr.c b/Sandboxie/core/dll/ldr.c index fd22a240..2fa46b27 100644 --- a/Sandboxie/core/dll/ldr.c +++ b/Sandboxie/core/dll/ldr.c @@ -493,6 +493,16 @@ _FX BOOLEAN Ldr_Init() LdrCheckImmersive(); } + + // + // set PEB.ProcessParameters->LoaderThreads = 0 + // + + if (SbieApi_QueryConfBool(NULL, L"NoParallelLoading", FALSE)) { + RTL_USER_PROCESS_PARAMETERS* ProcessParms = Proc_GetRtlUserProcessParameters(); + ProcessParms->LoaderThreads = 0; + } + // // do some more initializations based on the executable image, // and inject code at the program entrypoint @@ -782,6 +792,38 @@ _FX void Ldr_CallDllCallbacks_WithLock(void) } +//--------------------------------------------------------------------------- +// Ldr_LdrLoadDllImpl +//--------------------------------------------------------------------------- + + +_FX NTSTATUS Ldr_LdrLoadDllImpl( + WCHAR* PathString, + ULONG* DllFlags, + UNICODE_STRING* ModuleName, + HANDLE* ModuleHandle) +{ + NTSTATUS status = 0; + + //WCHAR text[4096]; + //Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (loading...)", (ModuleName && ModuleName->Buffer) ? ModuleName->Buffer : PathString); + //SbieApi_MonitorPutMsg(MONITOR_IMAGE, text); + + status = __sys_LdrLoadDll(PathString, DllFlags, ModuleName, ModuleHandle); + + if (!NT_SUCCESS(status)) { + WCHAR text[4096]; + Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (load failed 0x%08X)", (ModuleName && ModuleName->Buffer) ? ModuleName->Buffer : PathString, status); + SbieApi_MonitorPutMsg(MONITOR_IMAGE, text); + } + + //Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (... 0x%08X)", (ModuleName && ModuleName->Buffer) ? ModuleName->Buffer : PathString, status); + //SbieApi_MonitorPutMsg(MONITOR_IMAGE, text); + + return status; +} + + //--------------------------------------------------------------------------- // Ldr_LdrLoadDll //--------------------------------------------------------------------------- @@ -804,7 +846,7 @@ _FX NTSTATUS Ldr_LdrLoadDll( status = __sys_LdrLockLoaderLock(0, &state, &LdrCookie); if (NT_SUCCESS(status)) { - status = __sys_LdrLoadDll(PathString, DllFlags, ModuleName, ModuleHandle); + status = Ldr_LdrLoadDllImpl(PathString, DllFlags, ModuleName, ModuleHandle); if (NT_SUCCESS(status)) { Ldr_CallDllCallbacks(); @@ -833,7 +875,7 @@ _FX NTSTATUS Ldr_Win10_LdrLoadDll( // NTSTATUS status = 0; - status = __sys_LdrLoadDll(PathString, DllFlags, ModuleName, ModuleHandle); + status = Ldr_LdrLoadDllImpl(PathString, DllFlags, ModuleName, ModuleHandle); Scm_SecHostDll_W8(); return status; } diff --git a/Sandboxie/core/dll/ldr_init.c b/Sandboxie/core/dll/ldr_init.c index 74e91f1d..03350976 100644 --- a/Sandboxie/core/dll/ldr_init.c +++ b/Sandboxie/core/dll/ldr_init.c @@ -35,7 +35,8 @@ #define LDR_INJECT_SETTING_NAME L"InjectDllARM64" #define LDR_HOST_INJECT_SETTING_NAME L"HostInjectDllARM64" -#define LDR_INJECT_NUM_SAVE_BYTES 16 +//#define LDR_INJECT_NUM_SAVE_BYTES 16 +#define LDR_INJECT_NUM_SAVE_BYTES 20 #elif _WIN64 @@ -43,7 +44,8 @@ #define LDR_INJECT_SETTING_NAME L"InjectDll64" #define LDR_HOST_INJECT_SETTING_NAME L"HostInjectDll64" -#define LDR_INJECT_NUM_SAVE_BYTES 12 +//#define LDR_INJECT_NUM_SAVE_BYTES 12 +#define LDR_INJECT_NUM_SAVE_BYTES 19 #else ! _WIN64 @@ -757,8 +759,9 @@ _FX void Ldr_Inject_Init(BOOLEAN bHostInject) #ifdef _M_ARM64 ULONG* aCode = (ULONG*)entrypoint; + *aCode++ = 0x10000000; // adr x0, 0 - copy pc to x0 *aCode++ = 0x58000048; // ldr x8, 8 - *aCode++ = 0xD63F0100; // blr x8 + *aCode++ = 0xD61F0100; // br x8 *(ULONG_PTR*)aCode = (ULONG_PTR)Ldr_Inject_Entry64; NtFlushInstructionCache(GetCurrentProcess(), entrypoint, LDR_INJECT_NUM_SAVE_BYTES); @@ -768,8 +771,14 @@ _FX void Ldr_Inject_Init(BOOLEAN bHostInject) entrypoint[0] = 0x48; // mov rax, Ldr_Inject_Entry64 entrypoint[1] = 0xB8; *(ULONG_PTR *)(entrypoint + 2) = (ULONG_PTR)Ldr_Inject_Entry64; - entrypoint[10] = 0xFF; // call rax - entrypoint[11] = 0xD0; + + entrypoint[10] = 0x48; // lea rcx, [rip - 0x11] + entrypoint[11] = 0x8d; + entrypoint[12] = 0x0d; + *(ULONG*)(entrypoint + 13) = -0x11; + + entrypoint[17] = 0xFF; // jmp rax + entrypoint[18] = 0xE0; #else ! _WIN64 @@ -788,7 +797,7 @@ _FX void Ldr_Inject_Init(BOOLEAN bHostInject) //--------------------------------------------------------------------------- -_FX void Ldr_Inject_Entry(ULONG_PTR *pRetAddr) +_FX void* Ldr_Inject_Entry(ULONG_PTR *pPtr) { UCHAR *entrypoint; ULONG dummy_prot; @@ -797,12 +806,12 @@ _FX void Ldr_Inject_Entry(ULONG_PTR *pRetAddr) // restore correct code sequence at the entrypoint // -#ifdef _M_ARM64 - entrypoint = ((UCHAR *)*pRetAddr) - (LDR_INJECT_NUM_SAVE_BYTES - sizeof(ULONG_PTR)); // after blr comes the 64bit address +#ifdef _WIN64 + entrypoint = (UCHAR*)pPtr; #else - entrypoint = ((UCHAR *)*pRetAddr) - LDR_INJECT_NUM_SAVE_BYTES; + entrypoint = ((UCHAR *)*pPtr) - LDR_INJECT_NUM_SAVE_BYTES; + *pPtr = (ULONG_PTR)entrypoint; #endif - *pRetAddr = (ULONG_PTR)entrypoint; // If entrypoint hook is different, need to adjust offset. Copying the original byets won't have the correct offset. // MS UEV also hooks exe entry. @@ -853,4 +862,6 @@ _FX void Ldr_Inject_Entry(ULONG_PTR *pRetAddr) { Ldr_LoadInjectDlls(g_bHostInject); } + + return entrypoint; } diff --git a/Sandboxie/core/dll/util_64.asm b/Sandboxie/core/dll/util_64.asm index 4e801b12..ac85143f 100644 --- a/Sandboxie/core/dll/util_64.asm +++ b/Sandboxie/core/dll/util_64.asm @@ -139,15 +139,10 @@ EXTERN Ldr_Inject_Entry : PROC Ldr_Inject_Entry64 PROC - ; - ; Normally we would start with sub rsp,8+(4*8) but in this case - ; we know the caller has not aligned the stack correctly - ; - - sub rsp,8+8+(4*8) - lea rcx,[rsp+8+8+(4*8)] ; setup pRetAddr parameter + sub rsp,8+(4*8) call Ldr_Inject_Entry - add rsp,8+8+(4*8) + mov rdx, rax + add rsp,8+(4*8) ; ; clear the stack of any leftovers from Ldr_Inject_Entry. @@ -162,7 +157,7 @@ Ldr_Inject_Entry64 PROC cld rep stosq - ret + jmp rdx Ldr_Inject_Entry64 ENDP @@ -171,9 +166,7 @@ Ldr_Inject_Entry64 ENDP ; Gui_FixupCallbackPointers ;---------------------------------------------------------------------------- - nop - nop - nop + Gui_FixupCallbackPointers PROC ; diff --git a/Sandboxie/core/dll/util_arm.asm b/Sandboxie/core/dll/util_arm.asm index a83fe853..2860c53d 100644 --- a/Sandboxie/core/dll/util_arm.asm +++ b/Sandboxie/core/dll/util_arm.asm @@ -149,11 +149,10 @@ l02 Ldr_Inject_Entry64 PROC stp fp, lr, [sp, #-0x10]! ; push - add x0, sp, 0x8 ; pRetAddr parameter ldr x8, =Ldr_Inject_Entry blr x8 ldp fp, lr, [sp], #0x10 ; pop - ret + br x0 ENDP diff --git a/Sandboxie/core/low/init.c b/Sandboxie/core/low/init.c index 6385d681..09711ec2 100644 --- a/Sandboxie/core/low/init.c +++ b/Sandboxie/core/low/init.c @@ -152,7 +152,6 @@ _FX NTSTATUS SbieApi_Ioctl(SBIELOW_DATA *data, void *parms) //--------------------------------------------------------------------------- -#if 1 _FX NTSTATUS SbieApi_DebugPrint(SBIELOW_DATA *data, const WCHAR *text) { NTSTATUS status = 0; @@ -171,13 +170,34 @@ _FX NTSTATUS SbieApi_DebugPrint(SBIELOW_DATA *data, const WCHAR *text) memzero(parms, sizeof(parms)); args->func_code = API_LOG_MESSAGE; args->session_id.val = -1; - args->msgid.val = 2101; + args->msgid.val = 1122; args->msgtext.val = &msgtext; status = SbieApi_Ioctl(data, parms); return status; } -#endif + + +//--------------------------------------------------------------------------- +// SbieApi_DebugError +//--------------------------------------------------------------------------- + + +_FX NTSTATUS SbieApi_DebugError(SBIELOW_DATA* data, ULONG error) +{ + // Note: A normal string like L"text" would not resultin position independent code !!! + // hence we create a string array and fill it byte by byte + + wchar_t text[] = { 'L','o','w','L','e','v','e','l',' ','E','r','r','o','r',':',' ','0','x',0,0,0,0,0,0,0,0,0,0}; + + // covert ulong to hex string and copy it into the message array + wchar_t* ptr = &text[18]; // point after L"...0x" + wchar_t table[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + for(int i=28; i >= 0; i-=4) + *ptr++ = table[(error >> i) & 0xF]; + + return SbieApi_DebugPrint(data, text); +} //--------------------------------------------------------------------------- @@ -724,6 +744,9 @@ ULONG_PTR EntrypointC(SBIELOW_DATA *data, void *DetourCode, void *SystemService) // WaitForDebugger(data); + //wchar_t text[] = { 't','e','s','t',0 }; + //SbieApi_DebugPrint(data, text); + PrepSyscalls(data, SystemService); if (!data->flags.bHostInject && !data->flags.bNoSysHooks) InitSyscalls(data, SystemService); diff --git a/Sandboxie/core/low/inject.c b/Sandboxie/core/low/inject.c index 69ee9ccd..d5d1bb93 100644 --- a/Sandboxie/core/low/inject.c +++ b/Sandboxie/core/low/inject.c @@ -34,11 +34,12 @@ typedef long NTSTATUS; // Functions //--------------------------------------------------------------------------- +_FX NTSTATUS SbieApi_DebugError(SBIELOW_DATA* data, ULONG error); -UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName); +UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName, ULONG *pErr); static UCHAR *FindDllExport2( - void *DllBase, IMAGE_DATA_DIRECTORY *dir0, const UCHAR *ProcName); + void *DllBase, IMAGE_DATA_DIRECTORY *dir0, const UCHAR *ProcName, ULONG *pErr); #ifdef _M_ARM64 void* Hook_GetFFSTarget(UCHAR* SourceFunc); @@ -57,7 +58,7 @@ static void InitInjectWow64(SBIELOW_DATA *data); //--------------------------------------------------------------------------- -_FX UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName) +_FX UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName, ULONG* pErr) { IMAGE_DOS_HEADER *dos_hdr; IMAGE_NT_HEADERS *nt_hdrs; @@ -68,11 +69,15 @@ _FX UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName) // dos_hdr = (void *)DllBase; - if (dos_hdr->e_magic != 'MZ' && dos_hdr->e_magic != 'ZM') + if (dos_hdr->e_magic != 'MZ' && dos_hdr->e_magic != 'ZM') { + *pErr = 0xa; return NULL; + } nt_hdrs = (IMAGE_NT_HEADERS *)((UCHAR *)dos_hdr + dos_hdr->e_lfanew); - if (nt_hdrs->Signature != IMAGE_NT_SIGNATURE) // 'PE\0\0' + if (nt_hdrs->Signature != IMAGE_NT_SIGNATURE) { // 'PE\0\0' + *pErr = 0xb; return NULL; + } if (nt_hdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { @@ -83,7 +88,7 @@ _FX UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName) if (opt_hdr_32->NumberOfRvaAndSizes) { IMAGE_DATA_DIRECTORY *dir0 = &opt_hdr_32->DataDirectory[0]; - func_ptr = FindDllExport2(DllBase, dir0, ProcName); + func_ptr = FindDllExport2(DllBase, dir0, ProcName, pErr); } } @@ -99,7 +104,7 @@ _FX UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName) if (opt_hdr_64->NumberOfRvaAndSizes) { IMAGE_DATA_DIRECTORY *dir0 = &opt_hdr_64->DataDirectory[0]; - func_ptr = FindDllExport2(DllBase, dir0, ProcName); + func_ptr = FindDllExport2(DllBase, dir0, ProcName, pErr); } } @@ -115,7 +120,7 @@ _FX UCHAR *FindDllExport(void *DllBase, const UCHAR *ProcName) _FX UCHAR *FindDllExport2( - void *DllBase, IMAGE_DATA_DIRECTORY *dir0, const UCHAR *ProcName) + void *DllBase, IMAGE_DATA_DIRECTORY *dir0, const UCHAR *ProcName, ULONG* pErr) { void *proc = NULL; ULONG i, j, n; @@ -163,6 +168,7 @@ _FX UCHAR *FindDllExport2( // might have to scan LDR tables to find the target dll // + *pErr = 0xc; proc = NULL; } } @@ -214,6 +220,7 @@ _FX void InitInject(SBIELOW_DATA *data, void *DetourCode) void *RegionBase; SIZE_T RegionSize; ULONG OldProtect; + ULONG uError = 0; // // now that syscalls were intercepted, we can use the top of the syscall @@ -278,23 +285,35 @@ _FX void InitInject(SBIELOW_DATA *data, void *DetourCode) // LdrCode = FindDllExport(ntdll_base, - (UCHAR *)extra + extra->LdrLoadDll_offset); + (UCHAR *)extra + extra->LdrLoadDll_offset, &uError); + if (!LdrCode) { + SbieApi_DebugError(data, (0x01 << 4) | uError); + return; + } #ifdef _M_ARM64 - if (data->flags.is_arm64ec && LdrCode) + if (data->flags.is_arm64ec) LdrCode = Hook_GetFFSTarget(LdrCode); #endif - if (! LdrCode) + if (!LdrCode) { + SbieApi_DebugError(data, 0x01d); return; + } inject->LdrLoadDll = (ULONG_PTR)LdrCode; LdrCode = FindDllExport(ntdll_base, - (UCHAR *)extra + extra->LdrGetProcAddr_offset); + (UCHAR *)extra + extra->LdrGetProcAddr_offset, &uError); + if (!LdrCode) { + SbieApi_DebugError(data, (0x02 << 4) | uError); + return; + } #ifdef _M_ARM64 - if (data->flags.is_arm64ec && LdrCode) + if (data->flags.is_arm64ec) LdrCode = Hook_GetFFSTarget(LdrCode); #endif - if (! LdrCode) + if (!LdrCode) { + SbieApi_DebugError(data, 0x02d); return; + } inject->LdrGetProcAddr = (ULONG_PTR)LdrCode; #ifdef _M_ARM64 @@ -311,9 +330,11 @@ _FX void InitInject(SBIELOW_DATA *data, void *DetourCode) #ifdef _WIN64 if (data->flags.is_wow64) { LdrCode = FindDllExport(ntdll_base, - (UCHAR*)extra + extra->NtRaiseHardError_offset); - if (!LdrCode) + (UCHAR*)extra + extra->NtRaiseHardError_offset, &uError); + if (!LdrCode) { + SbieApi_DebugError(data, (0x03 << 4) | uError); return; + } inject->NtRaiseHardError = (ULONG_PTR)LdrCode; } else @@ -339,9 +360,11 @@ _FX void InitInject(SBIELOW_DATA *data, void *DetourCode) #endif { LdrCode = FindDllExport(ntdll_base, - (UCHAR *)extra + extra->RtlFindActCtx_offset); - if (! LdrCode) + (UCHAR *)extra + extra->RtlFindActCtx_offset, &uError); + if (!LdrCode) { + SbieApi_DebugError(data, (0x04 << 4) | uError); return; + } } inject->RtlFindActCtx = (ULONG_PTR)LdrCode; diff --git a/SandboxiePlus/MiscHelpers/Common/DebugHelpers.cpp b/SandboxiePlus/MiscHelpers/Common/DebugHelpers.cpp index 25b9e441..a2bc207f 100644 --- a/SandboxiePlus/MiscHelpers/Common/DebugHelpers.cpp +++ b/SandboxiePlus/MiscHelpers/Common/DebugHelpers.cpp @@ -212,6 +212,9 @@ static LONG __stdcall MyCrashHandlerExceptionFilter(EXCEPTION_POINTERS* pEx) #endif bool bSuccess = false; + if (pEx->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C || pEx->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) + return EXCEPTION_CONTINUE_SEARCH; + wchar_t szMiniDumpFileName[128]; wsprintf(szMiniDumpFileName, L"%s %s.dmp", s_szMiniDumpName, QDateTime::currentDateTime().toString("dd.MM.yyyy hh-mm-ss,zzz").replace(QRegularExpression("[:*?<>|\"\\/]"), "_").toStdWString().c_str()); @@ -286,6 +289,9 @@ void InitMiniDumpWriter(const wchar_t* Name, const wchar_t* Path) // Additional call "PreventSetUnhandledExceptionFilter"... // See also: "SetUnhandledExceptionFilter" and VC8 (and later) // http://blog.kalmbachnet.de/?postid=75 + + // Register Vectored Exception Handler + AddVectoredExceptionHandler(0, MyCrashHandlerExceptionFilter); } diff --git a/SandboxiePlus/QSbieAPI/SbieUtils.cpp b/SandboxiePlus/QSbieAPI/SbieUtils.cpp index 935ffff6..1dc41263 100644 --- a/SandboxiePlus/QSbieAPI/SbieUtils.cpp +++ b/SandboxiePlus/QSbieAPI/SbieUtils.cpp @@ -242,6 +242,93 @@ CSbieProgressPtr CSbieUtils::RunCommand(const QString& Command, bool noGui) return pProgress; } +int CSbieUtils::ExecCommand(const QString& Command, bool noGui, quint32 Timeout) +{ + STARTUPINFOW si = { 0 }; + si.cb = sizeof(si); + if (noGui) { + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.wShowWindow = SW_HIDE; + } + + PROCESS_INFORMATION pi = { 0 }; + if (!CreateProcessW(NULL, (LPWSTR)Command.toStdWString().c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) + return -1; + + int iRet = -2; + if (WaitForSingleObject(pi.hProcess, (DWORD)Timeout) == WAIT_OBJECT_0) + { + DWORD dwRet; + if (GetExitCodeProcess(pi.hProcess, &dwRet)) + iRet = (int)dwRet; + } + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + return iRet; +} + +int CSbieUtils::ExecCommandEx(const QString& Command, QString* pOutput, quint32 Timeout) +{ + HANDLE stdoutReadHandle; + HANDLE stdoutWriteHandle; + SECURITY_ATTRIBUTES saAttr; + // Set the bInheritHandle flag so pipe handles are inherited. + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = nullptr; + // Create a pipe for the child process's STDOUT. + if (!CreatePipe(&stdoutReadHandle, &stdoutWriteHandle, &saAttr, 0)) + return -4; + if (!SetHandleInformation(stdoutReadHandle, HANDLE_FLAG_INHERIT, 0)) + return -4; + + STARTUPINFOW si = { 0 }; + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = stdoutWriteHandle; + si.hStdError = stdoutWriteHandle; + si.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION pi = { 0 }; + if (!CreateProcessW(NULL, (LPWSTR)Command.toStdWString().c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) + return -1; + + DWORD exitCode, dataSize; + do + { + // Check if the process is alive. + GetExitCodeProcess(pi.hProcess, &exitCode); + + // Check if there is anything in the pipe. + if (!PeekNamedPipe(stdoutReadHandle, nullptr, 0, nullptr, &dataSize, nullptr)) + return -3; + if (dataSize == 0) + Sleep(10); + else { + // Read the data out of the pipe. + CHAR buffer[4096] = { 0 }; + if (!ReadFile(stdoutReadHandle, buffer, sizeof(buffer) - 1, &dataSize, nullptr)) + return -3; + + pOutput->append(QString(buffer)); + } + } while (exitCode == STILL_ACTIVE || dataSize != 0); + + CloseHandle(stdoutReadHandle); + CloseHandle(stdoutWriteHandle); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + return (int)exitCode; +} + ////////////////////////////////////////////////////////////////////////////// // Shell integration diff --git a/SandboxiePlus/QSbieAPI/SbieUtils.h b/SandboxiePlus/QSbieAPI/SbieUtils.h index b33a18e7..01dfca88 100644 --- a/SandboxiePlus/QSbieAPI/SbieUtils.h +++ b/SandboxiePlus/QSbieAPI/SbieUtils.h @@ -39,6 +39,9 @@ public: static CSbieProgressPtr RunCommand(const QString& Command, bool noGui = false); + static int ExecCommand(const QString& Command, bool noGui = false, quint32 Timeout = -1); + static int ExecCommandEx(const QString& Command, QString* pOutput, quint32 Timeout = -1); + private: static SB_RESULT(void*) ElevateOps(const QStringList& Ops); static SB_STATUS ExecOps(const QStringList& Ops); diff --git a/SandboxiePlus/SandMan/Forms/OptionsWindow.ui b/SandboxiePlus/SandMan/Forms/OptionsWindow.ui index ec0c8f77..e93ef0d0 100644 --- a/SandboxiePlus/SandMan/Forms/OptionsWindow.ui +++ b/SandboxiePlus/SandMan/Forms/OptionsWindow.ui @@ -281,41 +281,48 @@ + + + + Warn when an application opens a harddrive handle + + + - + - Auto delete content when last sandboxed process terminates + Protect this sandbox from deletion or emptying - - - - - 75 - true - true - - + + - File Migration + Allow elevated sandboxed applications to read the harddrive - - - - Qt::Vertical - - + + + 20 - 40 + 16777215 - + + + + - + + + + Use volume serial numbers for drives, like: \drive\C~1234-ABCD + + + + @@ -342,31 +349,21 @@ - - + + - kilobytes + The box structure can only be changed when the sandbox is empty - - + + - Prompt user for large file migration + Allow sandboxed processes to open files protected by EFS - - - - Separate user folders - - - false - - - - + @@ -376,65 +373,21 @@ - Raw Disk access + Disk/File access - - - - - 75 - 16777215 - - - - - - + + - Issue message 2102 when a file is too large + Virtualization scheme - - - - - 20 - 16777215 - - + + - - - - - - - - Allow elevated sandboxed applications to read the harddrive - - - - - - - Warn when an application opens a harddrive handle - - - - - - - Copy file size limit: - - - - - - - Protect this sandbox from deletion or emptying + Auto delete content when last sandboxed process terminates @@ -452,6 +405,212 @@ + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Separate user folders + + + false + + + + + + + + + + File Migration + + + + 3 + + + 3 + + + 6 + + + 3 + + + + + + + Copy file size limit: + + + + + + + Prompt user for large file migration + + + + + + + + 75 + true + true + + + + File Migration + + + + + + + 2113: Content of migrated file was discarded +2114: File was not migrated, write access to file was denied +2115: File was not migrated, file will be opened read only + + + Issue message 2113/2114/2115 when a file is not fully migrated + + + + + + + + 100 + 16777215 + + + + + + + + kilobytes + + + + + + + Add Pattern + + + + + + + Remove Pattern + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Show Templates + + + + + + + true + + + + Action + + + + + Program + + + + + Pattern + + + + + + + + Sandboxie does not allow writing to host files, unless permitted by the user. When a sandboxed application attempts to modify a file, the entire file must be copied into the sandbox, for large files this can take a significate amount of time. Sandboxie offers options for handling these cases, which can be configured on this page. + + + true + + + + + + + Using wildcard patterns file specific behavior can be configured in the list below: + + + + + + + Issue message 2102 when a file is too large + + + + + + + When a file cannot be migrated, open it in read-only mode instead + + + @@ -4375,8 +4534,6 @@ Please note that this values are currently user specific and saved globally for treeRun btnAddCmd btnDelCmd - chkCopyLimit - chkNoCopyWarn chkAutoEmpty chkProtectBox treeTriggers diff --git a/SandboxiePlus/SandMan/Forms/SettingsWindow.ui b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui index 8a5578c4..d9d6f4a7 100644 --- a/SandboxiePlus/SandMan/Forms/SettingsWindow.ui +++ b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui @@ -115,6 +115,7 @@ + 75 true true @@ -151,6 +152,7 @@ + 75 true true @@ -213,6 +215,7 @@ + 75 true true @@ -305,6 +308,7 @@ + 75 true true @@ -328,6 +332,7 @@ + 75 true true @@ -354,6 +359,7 @@ + 75 true true @@ -541,6 +547,7 @@ + 75 true true @@ -738,14 +745,20 @@ - - - - Portable root folder + + + + Qt::Horizontal - + + + 40 + 20 + + + - + Qt::Horizontal @@ -758,52 +771,13 @@ - - - - - true - true - - - - Sandboxing features - - - - + - Use Windows Filtering Platform to restrict network access + Activate Kernel Mode Object Filtering - - - - Sandbox <a href="sbie://docs/ipcrootpath">ipc root</a>: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - - - - - - - - Separate user folders - - - - - - @@ -817,18 +791,25 @@ - - - - Qt::Vertical + + + + Use a Sandboxie login instead of an anonymous token (experimental) - - - 20 - 40 - + + + + + + Use Windows Filtering Platform to restrict network access - + + + + + + + @@ -843,10 +824,24 @@ - - + + + + + 75 + true + true + + - Sandbox <a href="sbie://docs/keyrootpath">registry root</a>: + Sandboxing features + + + + + + + Sandbox <a href="sbie://docs/ipcrootpath">ipc root</a>: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -856,69 +851,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Hook selected Win32k system calls to enable GPU acceleration (experimental) - - - - - - - Use a Sandboxie login instead of an anonymous token (experimental) - - - - - - - - true - true - - - - Sandbox default - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Activate Kernel Mode Object Filtering - - - @@ -929,8 +861,91 @@ - - + + + + Sandbox <a href="sbie://docs/keyrootpath">registry root</a>: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + + + + Hook selected Win32k system calls to enable GPU acceleration (experimental) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 75 + true + true + + + + Sandbox default + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Portable root folder + + @@ -974,6 +989,7 @@ + 75 true true @@ -1244,6 +1260,7 @@ + 75 true true @@ -1336,6 +1353,7 @@ + 75 true true @@ -1488,8 +1506,6 @@ chkSandboxUrls fileRoot btnBrowse - chkSeparateUserFolders - chkAutoRoot regRoot ipcRoot chkStartBlock diff --git a/SandboxiePlus/SandMan/OnlineUpdater.cpp b/SandboxiePlus/SandMan/OnlineUpdater.cpp index c07be493..87c9fb80 100644 --- a/SandboxiePlus/SandMan/OnlineUpdater.cpp +++ b/SandboxiePlus/SandMan/OnlineUpdater.cpp @@ -937,11 +937,11 @@ bool COnlineUpdater::IsVersionNewer(const QString& VersionStr) ///////////////////////////////////////////////////////////////////////////////////////////////// // cert stuf -void COnlineUpdater::UpdateCert() +void COnlineUpdater::UpdateCert(bool bWait) { QString UpdateKey; // for now only patreons can update the cert automatically TArguments args = GetArguments(g_Certificate, L'\n', L':'); - if(args.value("TYPE").indexOf("PATREON") == 0) + if(args.value("TYPE").contains("PATREON")) UpdateKey = args.value("UPDATEKEY"); if (UpdateKey.isEmpty()) { theGUI->OpenUrl("https://sandboxie-plus.com/go.php?to=sbie-get-cert"); @@ -971,6 +971,12 @@ void COnlineUpdater::UpdateCert() //Request.setRawHeader("Accept-Encoding", "gzip"); QNetworkReply* pReply = m_RequestManager->get(Request); connect(pReply, SIGNAL(finished()), this, SLOT(OnCertCheck())); + + if (bWait) { + while (!pReply->isFinished()) { + QCoreApplication::processEvents(); // keep UI responsive + } + } } void COnlineUpdater::OnCertCheck() diff --git a/SandboxiePlus/SandMan/OnlineUpdater.h b/SandboxiePlus/SandMan/OnlineUpdater.h index cd87183a..6161833a 100644 --- a/SandboxiePlus/SandMan/OnlineUpdater.h +++ b/SandboxiePlus/SandMan/OnlineUpdater.h @@ -32,7 +32,7 @@ public: void GetUpdates(QObject* receiver, const char* member, const QVariantMap& Params = QVariantMap()); - void UpdateCert(); + void UpdateCert(bool bWait = false); void CheckForUpdates(bool bManual = false); diff --git a/SandboxiePlus/SandMan/SandManRecovery.cpp b/SandboxiePlus/SandMan/SandManRecovery.cpp index 5f22ef2a..783d46f3 100644 --- a/SandboxiePlus/SandMan/SandManRecovery.cpp +++ b/SandboxiePlus/SandMan/SandManRecovery.cpp @@ -70,27 +70,129 @@ CRecoveryWindow* CSandMan::ShowRecovery(const CSandBoxPtr& pBox, bool bFind) return pBoxEx->m_pRecoveryWnd; } -SB_PROGRESS CSandMan::RecoverFiles(const QString& BoxName, const QList>& FileList, int Action) +SB_PROGRESS CSandMan::CheckFiles(const QString& BoxName, const QStringList& Files) { CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress()); - QtConcurrent::run(CSandMan::RecoverFilesAsync, pProgress, BoxName, FileList, Action); + CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); + QStringList Checkers; + if (!pBox.isNull()) { + foreach(const QString & Value, pBox->GetTextList("OnFileRecovery", true, false, true)) { + Checkers.append(pBox->Expand(Value)); + } + } + QtConcurrent::run(CSandMan::CheckFilesAsync, pProgress, BoxName, Files, Checkers); return SB_PROGRESS(OP_ASYNC, pProgress); } -void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QList>& FileList, int Action) +void CSandMan::CheckFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QStringList& Files, const QStringList& Checkers) +{ + int FailCount = 0; + for (QStringList::const_iterator I = Files.begin(); I != Files.end(); ++I) + { + if (pProgress->IsCanceled()) break; + + QString BoxPath = *I; + QString FileName = BoxPath.mid(BoxPath.lastIndexOf("\\") + 1); + + pProgress->ShowMessage(tr("Checking file %1").arg(FileName)); + + foreach(const QString & Value, Checkers) { + QString Output; + int ret = CSbieUtils::ExecCommandEx(Value + " \"" + BoxPath + "\"", &Output, 15000); // 15 sec timeout + if (ret != 0) { + FailCount++; + QMetaObject::invokeMethod(theGUI, "ShowMessage", Qt::BlockingQueuedConnection, // show this message using the GUI thread + Q_ARG(QString, tr("The file %1 failed a security check!\r\n\r\n%2").arg(BoxPath).arg(Output)), + Q_ARG(int, QMessageBox::Warning) + ); + } + } + } + if (FailCount == 0) { + QMetaObject::invokeMethod(theGUI, "ShowMessage", Qt::BlockingQueuedConnection, // show this message using the GUI thread + Q_ARG(QString, tr("All files passed the checks")), + Q_ARG(int, QMessageBox::Information) + ); + } + + pProgress->Finish(SB_OK); +} + +SB_PROGRESS CSandMan::RecoverFiles(const QString& BoxName, const QList>& FileList, int Action) +{ + CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress()); + CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); + QStringList Checkers; + if (!pBox.isNull()) { + foreach(const QString & Value, pBox->GetTextList("OnFileRecovery", true, false, true)) { + Checkers.append(pBox->Expand(Value)); + } + } + QtConcurrent::run(CSandMan::RecoverFilesAsync, pProgress, BoxName, FileList, Checkers, Action); + return SB_PROGRESS(OP_ASYNC, pProgress); +} + +void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QList>& FileList, const QStringList& Checkers, int Action) { SB_STATUS Status = SB_OK; int OverwriteOnExist = -1; + int RecoverCheckFailed = -1; QStringList Unrecovered; for (QList>::const_iterator I = FileList.begin(); I != FileList.end(); ++I) { + if (pProgress->IsCanceled()) break; + QString BoxPath = I->first; QString RecoveryPath = I->second; QString FileName = BoxPath.mid(BoxPath.lastIndexOf("\\") + 1); QString RecoveryFolder = RecoveryPath.left(RecoveryPath.lastIndexOf("\\") + 1); + if (!Checkers.isEmpty()) { + + pProgress->ShowMessage(tr("Checking file %1").arg(FileName)); + + //bool bNoGui = true; + //if (GetKeyState(VK_CONTROL) & 0x8000) + // bNoGui = false; + + int ret = 0; + foreach(const QString & Value, Checkers) { + QString Output; + ret = CSbieUtils::ExecCommandEx(Value + " \"" + BoxPath + "\"", &Output, 15000); // 15 sec timeout + if (ret != 0) { + + int Recover = RecoverCheckFailed; + if (Recover == -1) + { + bool forAll = false; + int retVal = 0; + QMetaObject::invokeMethod(theGUI, "ShowQuestion", Qt::BlockingQueuedConnection, // show this question using the GUI thread + Q_RETURN_ARG(int, retVal), + Q_ARG(QString, tr("The file %1 failed a security check, do you want to recover it anyways?\r\n\r\n%2").arg(BoxPath).arg(Output)), + Q_ARG(QString, tr("Do this for all files!")), + Q_ARG(bool*, &forAll), + Q_ARG(int, QDialogButtonBox::Yes | QDialogButtonBox::No), + Q_ARG(int, QDialogButtonBox::No), + Q_ARG(int, QMessageBox::Warning) + ); + + Recover = retVal == QDialogButtonBox::Yes ? 1 : 0; + if (forAll) + RecoverCheckFailed = Recover; + } + + if (Recover == 1) + ret = 0; + else + break; + } + } + if (ret != 0) + continue; // Do not recover this file + } + pProgress->ShowMessage(tr("Recovering file %1 to %2").arg(FileName).arg(RecoveryFolder)); QDir().mkpath(RecoveryFolder); diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp index fa414955..433fa095 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.cpp +++ b/SandboxiePlus/SandMan/Views/SbieView.cpp @@ -161,6 +161,8 @@ void CSbieView::CreateMenu() } else m_pMenuRunStart = NULL; + //m_pMenuRunTools->addSeparator(); + m_pMenuAutoRun = m_pMenuRun->addAction(CSandMan::GetIcon("ReloadIni"), tr("Execute Autorun Entries"), this, SLOT(OnSandBoxAction())); m_pMenuRunTools = m_pMenuRun->addMenu(CSandMan::GetIcon("Maintenance"), tr("More Tools")); m_pMenuRunBrowser = m_pMenuRunTools->addAction(CSandMan::GetIcon("Internet"), tr("Default Web Browser"), this, SLOT(OnSandBoxAction())); m_pMenuRunMailer = m_pMenuRunTools->addAction(CSandMan::GetIcon("Email"), tr("Default eMail Client"), this, SLOT(OnSandBoxAction())); @@ -172,13 +174,10 @@ void CSbieView::CreateMenu() m_pMenuRunTools->addSeparator(); m_pMenuRunCmd = m_pMenuRunTools->addAction(CSandMan::GetIcon("Cmd"), tr("Command Prompt"), this, SLOT(OnSandBoxAction())); m_pMenuRunCmdAdmin = m_pMenuRunTools->addAction(CSandMan::GetIcon("Cmd"), tr("Command Prompt (as Admin)"), this, SLOT(OnSandBoxAction())); -#ifdef _WIN64 +#ifndef _WIN64 if(CSbieAPI::IsWow64()) - m_pMenuRunCmd32 = m_pMenuRunTools->addAction(CSandMan::GetIcon("Cmd"), tr("Command Prompt (32-bit)"), this, SLOT(OnSandBoxAction())); #endif - m_pMenuRunTools->addSeparator(); - m_pMenuAutoRun = m_pMenuRunTools->addAction(CSandMan::GetIcon("ReloadIni"), tr("Execute Autorun Entries"), this, SLOT(OnSandBoxAction())); - + m_pMenuRunCmd32 = m_pMenuRunTools->addAction(CSandMan::GetIcon("Cmd"), tr("Command Prompt (32-bit)"), this, SLOT(OnSandBoxAction())); m_pMenuRun->addSeparator(); m_iMenuRun = m_pMenuRun->actions().count(); m_pMenuEmptyBox = m_pMenuBox->addAction(CSandMan::GetIcon("EmptyAll"), tr("Terminate All Programs"), this, SLOT(OnSandBoxAction())); diff --git a/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp b/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp index e8f9f82a..ee400243 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp @@ -49,8 +49,6 @@ void COptionsWindow::CreateAdvanced() m_AdvOptions.insert("FakeAdminRights", SAdvOption{eOnlySpec, QStringList() << "y" << "n", tr("Make specified processes think they have admin permissions.")}); m_AdvOptions.insert("WaitForDebugger", SAdvOption{eOnlySpec, QStringList() << "y" << "n", tr("Force specified processes to wait for a debugger to attach.")}); m_AdvOptions.insert("BoxNameTitle", SAdvOption{eOnlySpec, QStringList() << "y" << "n" << "-", tr("")}); - m_AdvOptions.insert("UseFileDeleteV2", SAdvOption{eNoSpec, QStringList() << "y" << "n", tr("")}); - m_AdvOptions.insert("UseRegDeleteV2", SAdvOption{eNoSpec, QStringList() << "y" << "n", tr("")}); m_AdvOptions.insert("FileRootPath", SAdvOption{eNoSpec, QStringList(), tr("Sandbox file system root")}); m_AdvOptions.insert("KeyRootPath", SAdvOption{eNoSpec, QStringList(), tr("Sandbox registry root")}); m_AdvOptions.insert("IpcRootPath", SAdvOption{eNoSpec, QStringList(), tr("Sandbox ipc root")}); diff --git a/SandboxiePlus/SandMan/Windows/OptionsGeneral.cpp b/SandboxiePlus/SandMan/Windows/OptionsGeneral.cpp index 8a1ef207..cdce9ff7 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsGeneral.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsGeneral.cpp @@ -156,12 +156,33 @@ void COptionsWindow::CreateGeneral() //connect(ui.chkOpenSmartCard, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); //connect(ui.chkOpenBluetooth, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); + ui.cmbVersion->addItem(tr("Version 1")); + ui.cmbVersion->addItem(tr("Version 2")); + + bool bEmpty = ((CSandBoxPlus*)m_pBox.data())->IsEmpty(); + ui.lblWhenEmpty->setVisible(!bEmpty); + ui.lblScheme->setEnabled(bEmpty); + ui.cmbVersion->setEnabled(bEmpty); + ui.chkSeparateUserFolders->setEnabled(bEmpty); + ui.chkUseVolumeSerialNumbers->setEnabled(bEmpty); + + connect(ui.cmbVersion, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged())); connect(ui.chkSeparateUserFolders, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); + connect(ui.chkUseVolumeSerialNumbers, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); connect(ui.txtCopyLimit, SIGNAL(textChanged(const QString&)), this, SLOT(OnGeneralChanged())); connect(ui.chkCopyLimit, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); connect(ui.chkCopyPrompt, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); connect(ui.chkNoCopyWarn, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); + connect(ui.chkDenyWrite, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); + connect(ui.chkNoCopyMsg, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); + + connect(ui.btnAddCopy, SIGNAL(clicked(bool)), this, SLOT(OnAddCopyRule())); + connect(ui.btnDelCopy, SIGNAL(clicked(bool)), this, SLOT(OnDelCopyRule())); + connect(ui.treeCopy, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnCopyItemDoubleClicked(QTreeWidgetItem*, int))); + connect(ui.treeCopy, SIGNAL(itemSelectionChanged()), this, SLOT(OnCopySelectionChanged())); + connect(ui.treeCopy, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnCopyChanged(QTreeWidgetItem*, int))); + connect(ui.chkShowCopyTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowCopyTmpl())); connect(ui.chkProtectBox, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); connect(ui.chkAutoEmpty, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); @@ -254,14 +275,30 @@ void COptionsWindow::LoadGeneral() ui.cmbDblClick->setCurrentIndex(pos); if (pos == -1) ui.cmbDblClick->setCurrentText(Action); + + if (m_pBox->GetBool("UseFileDeleteV2", false) && m_pBox->GetBool("UseRegDeleteV2", false)) + ui.cmbVersion->setCurrentIndex(1); + else if (!m_pBox->GetBool("UseFileDeleteV2", false) && !m_pBox->GetBool("UseRegDeleteV2", false)) + ui.cmbVersion->setCurrentIndex(0); + else { + ui.cmbVersion->setEditable(true); + ui.cmbVersion->lineEdit()->setReadOnly(true); + ui.cmbVersion->setCurrentText(tr("Indeterminate")); + } + ReadGlobalCheck(ui.chkSeparateUserFolders, "SeparateUserFolders", true); + ReadGlobalCheck(ui.chkUseVolumeSerialNumbers, "UseVolumeSerialNumbers", false); int iLimit = m_pBox->GetNum("CopyLimitKb", 80 * 1024); ui.chkCopyLimit->setChecked(iLimit != -1); ui.txtCopyLimit->setText(QString::number(iLimit > 0 ? iLimit : 80 * 1024)); ui.chkCopyPrompt->setChecked(m_pBox->GetBool("PromptForFileMigration", true)); ui.chkNoCopyWarn->setChecked(!m_pBox->GetBool("CopyLimitSilent", false)); + ui.chkDenyWrite->setChecked(m_pBox->GetBool("CopyBlockDenyWrite", false)); + ui.chkNoCopyMsg->setChecked(m_pBox->GetBool("NotifyNoCopy", false)); + LoadCopyRules(); + ui.chkProtectBox->setChecked(m_pBox->GetBool("NeverDelete", false)); ui.chkAutoEmpty->setChecked(m_pBox->GetBool("AutoDelete", false)); @@ -328,11 +365,29 @@ void COptionsWindow::SaveGeneral() } WriteTextList("RunCommand", RunCommands); - WriteGlobalCheck(ui.chkSeparateUserFolders, "SeparateUserFolders", true); + if (ui.cmbVersion->isEnabled()) + { + if (ui.cmbVersion->currentIndex() == 1) { // V2 + m_pBox->SetBool("UseFileDeleteV2", true); + m_pBox->SetBool("UseRegDeleteV2", true); + } + else if (ui.cmbVersion->currentIndex() == 0) { // V1 + m_pBox->DelValue("UseFileDeleteV2"); + m_pBox->DelValue("UseRegDeleteV2"); + } + + WriteGlobalCheck(ui.chkSeparateUserFolders, "SeparateUserFolders", true); + WriteGlobalCheck(ui.chkUseVolumeSerialNumbers, "UseVolumeSerialNumbers", false); + } WriteText("CopyLimitKb", ui.chkCopyLimit->isChecked() ? ui.txtCopyLimit->text() : "-1"); WriteAdvancedCheck(ui.chkCopyPrompt, "PromptForFileMigration", "", "n"); WriteAdvancedCheck(ui.chkNoCopyWarn, "CopyLimitSilent", "", "y"); + WriteAdvancedCheck(ui.chkDenyWrite, "CopyBlockDenyWrite", "y", ""); + WriteAdvancedCheck(ui.chkNoCopyMsg, "NotifyNoCopy", "y", ""); + + if (m_CopyRulesChanged) + SaveCopyRules(); WriteAdvancedCheck(ui.chkProtectBox, "NeverDelete", "y", ""); WriteAdvancedCheck(ui.chkAutoEmpty, "AutoDelete", "y", ""); @@ -343,6 +398,287 @@ void COptionsWindow::SaveGeneral() m_GeneralChanged = false; } +// copy +void COptionsWindow::LoadCopyRules() +{ + ui.treeCopy->clear(); + + foreach(const QString & Value, m_pBox->GetTextList("CopyAlways", m_Template)) + ParseAndAddCopyRule(Value, eCopyAlways); + foreach(const QString & Value, m_pBox->GetTextList("DontCopy", m_Template)) + ParseAndAddCopyRule(Value, eDontCopy); + foreach(const QString & Value, m_pBox->GetTextList("CopyEmpty", m_Template)) + ParseAndAddCopyRule(Value, eCopyEmpty); + + foreach(const QString & Value, m_pBox->GetTextList("CopyAlwaysDisabled", m_Template)) + ParseAndAddCopyRule(Value, eCopyAlways, true); + foreach(const QString & Value, m_pBox->GetTextList("DontCopyDisabled", m_Template)) + ParseAndAddCopyRule(Value, eDontCopy, true); + foreach(const QString & Value, m_pBox->GetTextList("CopyEmptyDisabled", m_Template)) + ParseAndAddCopyRule(Value, eCopyEmpty, true); + + LoadCopyRulesTmpl(); + + m_CopyRulesChanged = false; +} + +void COptionsWindow::LoadCopyRulesTmpl(bool bUpdate) +{ + if (ui.chkShowCopyTmpl->isChecked()) + { + foreach(const QString & Template, m_pBox->GetTemplates()) + { + foreach(const QString & Value, m_pBox->GetTextListTmpl("CopyAlways", Template)) + ParseAndAddCopyRule(Value, eCopyAlways, false, Template); + foreach(const QString & Value, m_pBox->GetTextListTmpl("DontCopy", Template)) + ParseAndAddCopyRule(Value, eDontCopy, false, Template); + foreach(const QString & Value, m_pBox->GetTextListTmpl("CopyEmpty", Template)) + ParseAndAddCopyRule(Value, eCopyEmpty, false, Template); + } + } + else if (bUpdate) + { + for (int i = 0; i < ui.treeCopy->topLevelItemCount(); ) + { + QTreeWidgetItem* pItem = ui.treeCopy->topLevelItem(i); + int Type = pItem->data(0, Qt::UserRole).toInt(); + if (Type == -1) { + delete pItem; + continue; // entry from template + } + i++; + } + } +} + +QString COptionsWindow::GetCopyActionStr(ECopyAction Action) +{ + switch (Action) + { + case eCopyAlways: return tr("Always copy"); + case eDontCopy: return tr("Don't copy"); + case eCopyEmpty: return tr("Copy empty"); + } + return ""; +} + +void COptionsWindow::ParseAndAddCopyRule(const QString& Value, ECopyAction Action, bool disabled, const QString& Template) +{ + QTreeWidgetItem* pItem = new QTreeWidgetItem(); + + pItem->setText(0, GetCopyActionStr(Action)); + pItem->setData(0, Qt::UserRole, Template.isEmpty() ? (int)Action : -1); + + QString Program; + QString Pattern; + QStringList Values = Value.split(","); + if (Values.size() >= 2) { + Program = Values[0]; + Pattern = Values[1]; + } + else + Pattern = Values[0]; + + // todo this block is also used by access move this to an own function + pItem->setData(1, Qt::UserRole, Program); + bool bAll = Program.isEmpty(); + if (bAll) + Program = tr("All Programs"); + bool Not = Program.left(1) == "!"; + if (Not) + Program.remove(0, 1); + if (Program.left(1) == "<") + Program = tr("Group: %1").arg(Program.mid(1, Program.length() - 2)); + else if (!bAll) + m_Programs.insert(Program); + pItem->setText(1, (Not ? "NOT " : "") + Program); + + pItem->setText(2, Pattern); + + if (Template.isEmpty()) + pItem->setCheckState(0, disabled ? Qt::Unchecked : Qt::Checked); + ui.treeCopy->addTopLevelItem(pItem); +} + +void COptionsWindow::SaveCopyRules() +{ + QList CopyAlways; + QList CopyAlwaysDisabled; + QList DontCopy; + QList DontCopyDisabled; + QList CopyEmpty; + QList CopyEmptyDisabled; + for (int i = 0; i < ui.treeCopy->topLevelItemCount(); i++) + { + QTreeWidgetItem* pItem = ui.treeCopy->topLevelItem(i); + int Type = pItem->data(0, Qt::UserRole).toInt(); + if (Type == -1) + continue; // entry from template + ECopyAction Action = (ECopyAction)pItem->data(0, Qt::UserRole).toInt(); + QString Program = pItem->data(1, Qt::UserRole).toString(); + QString Pattern = pItem->text(2); + + if (!Program.isEmpty()) + Pattern.prepend(Program + ","); + + if (pItem->checkState(0) == Qt::Checked) { + switch (Action) { + case eCopyAlways: CopyAlways.append(Pattern); break; + case eDontCopy: DontCopy.append(Pattern); break; + case eCopyEmpty: CopyEmpty.append(Pattern); break; + } + } + else { + switch (Action) { + case eCopyAlways: CopyAlwaysDisabled.append(Pattern); break; + case eDontCopy: DontCopyDisabled.append(Pattern); break; + case eCopyEmpty: CopyEmptyDisabled.append(Pattern); break; + } + } + } + WriteTextList("CopyAlways", CopyAlways); + WriteTextList("CopyAlwaysDisabled", CopyAlwaysDisabled); + WriteTextList("DontCopy", DontCopy); + WriteTextList("DontCopyDisabled", DontCopyDisabled); + WriteTextList("CopyEmpty", CopyEmpty); + WriteTextList("CopyEmptyDisabled", CopyEmptyDisabled); + + m_CopyRulesChanged = false; +} + +void COptionsWindow::OnCopyItemDoubleClicked(QTreeWidgetItem* pItem, int Column) +{ + int Action = pItem->data(0, Qt::UserRole).toInt(); + if (Action == -1) { + QMessageBox::warning(this, "SandboxiePlus", tr("Template values can not be edited.")); + return; + } + + QComboBox* pMode = new QComboBox(); + pMode->addItem(tr("Always copy"), (int)eCopyAlways); + pMode->addItem(tr("Don't copy"), (int)eDontCopy); + pMode->addItem(tr("Copy empty"), (int)eCopyEmpty); + pMode->setCurrentIndex(pMode->findData(pItem->data(0, Qt::UserRole))); + ui.treeCopy->setItemWidget(pItem, 0, pMode); + + QString Program = pItem->data(1, Qt::UserRole).toString(); + + // todo: + QWidget* pProgram = new QWidget(); + pProgram->setAutoFillBackground(true); + QHBoxLayout* pLayout = new QHBoxLayout(); + pLayout->setContentsMargins(0, 0, 0, 0); + pLayout->setSpacing(0); + pProgram->setLayout(pLayout); + QToolButton* pNot = new QToolButton(pProgram); + pNot->setText("!"); + pNot->setCheckable(true); + if (Program.left(1) == "!") { + pNot->setChecked(true); + Program.remove(0, 1); + } + pLayout->addWidget(pNot); + QComboBox* pCombo = new QComboBox(pProgram); + pCombo->addItem(tr("All Programs"), ""); + + for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++) { + QTreeWidgetItem* pItem = ui.treeGroups->topLevelItem(i); + pCombo->addItem(tr("Group: %1").arg(pItem->text(0)), pItem->data(0, Qt::UserRole).toString()); + } + + foreach(const QString & Name, m_Programs) + pCombo->addItem(Name, Name); + + pCombo->setEditable(true); + int Index = pCombo->findData(Program); + pCombo->setCurrentIndex(Index); + if (Index == -1) + pCombo->setCurrentText(Program); + pLayout->addWidget(pCombo); + + ui.treeCopy->setItemWidget(pItem, 1, pProgram); + + QLineEdit* pPattern = new QLineEdit(); + pPattern->setText(pItem->text(2)); + ui.treeCopy->setItemWidget(pItem, 2, pPattern); +} + +void COptionsWindow::OnCopyChanged(QTreeWidgetItem* pItem, int Column) +{ + if (Column != 0) + return; + + m_CopyRulesChanged = true; + OnOptChanged(); +} + +void COptionsWindow::CloseCopyEdit(bool bSave) +{ + for (int i = 0; i < ui.treeCopy->topLevelItemCount(); i++) + { + QTreeWidgetItem* pItem = ui.treeCopy->topLevelItem(i); + CloseCopyEdit(pItem, bSave); + } +} + +void COptionsWindow::CloseCopyEdit(QTreeWidgetItem* pItem, bool bSave) +{ + QWidget* pProgram = ui.treeCopy->itemWidget(pItem, 1); + if (!pProgram) + return; + + if (bSave) + { + QComboBox* pAction = (QComboBox*)ui.treeCopy->itemWidget(pItem, 0); + + QHBoxLayout* pLayout = (QHBoxLayout*)pProgram->layout(); + QToolButton* pNot = (QToolButton*)pLayout->itemAt(0)->widget(); + QComboBox* pCombo = (QComboBox*)pLayout->itemAt(1)->widget(); + + QLineEdit* pPattern = (QLineEdit*)ui.treeCopy->itemWidget(pItem, 2); + + QString Program = pCombo->currentText(); + int Index = pCombo->findText(Program); + if (Index != -1) + Program = pCombo->itemData(Index, Qt::UserRole).toString(); + + pItem->setText(0, pAction->currentText()); + pItem->setData(0, Qt::UserRole, pAction->currentData()); + + pItem->setText(1, (pNot->isChecked() ? "NOT " : "") + pCombo->currentText()); + pItem->setData(1, Qt::UserRole, (pNot->isChecked() ? "!" : "") + Program); + + pItem->setText(2, pPattern->text()); + + m_CopyRulesChanged = true; + OnOptChanged(); + } + + for (int i = 0; i < 3; i++) + ui.treeCopy->setItemWidget(pItem, i, NULL); +} + +void COptionsWindow::OnAddCopyRule() +{ + ParseAndAddCopyRule("", eCopyAlways); + + m_CopyRulesChanged = true; + OnOptChanged(); +} + +void COptionsWindow::OnDelCopyRule() +{ + QTreeWidgetItem* pItem = ui.treeCopy->currentItem(); + if (!pItem) + return; + + delete pItem; + + m_CopyRulesChanged = true; + OnOptChanged(); +} +// + void COptionsWindow::OnGeneralChanged() { ui.lblCopyLimit->setEnabled(ui.chkCopyLimit->isChecked()); diff --git a/SandboxiePlus/SandMan/Windows/OptionsNetwork.cpp b/SandboxiePlus/SandMan/Windows/OptionsNetwork.cpp index 079198f5..e01b5645 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsNetwork.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsNetwork.cpp @@ -347,6 +347,7 @@ void COptionsWindow::CheckINetBlock() void COptionsWindow::LoadNetFwRules() { ui.treeNetFw->clear(); + foreach(const QString & Value, m_pBox->GetTextList("NetworkAccess", m_Template)) ParseAndAddFwRule(Value); diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp index 87b53199..ed10c1fe 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp @@ -161,6 +161,7 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri ui.tabs->tabBar()->setProperty("isSidebar", true); + ui.tabs->setCurrentIndex(0); ui.tabs->setTabIcon(0, CSandMan::GetIcon("Config")); ui.tabs->setTabIcon(1, CSandMan::GetIcon("Security")); ui.tabs->setTabIcon(2, CSandMan::GetIcon("Group")); @@ -175,26 +176,33 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri ui.tabs->setTabIcon(11, CSandMan::GetIcon("Template")); ui.tabs->setTabIcon(12, CSandMan::GetIcon("Editor")); + ui.tabsGeneral->setCurrentIndex(0); ui.tabsGeneral->setTabIcon(0, CSandMan::GetIcon("Box")); - ui.tabsGeneral->setTabIcon(1, CSandMan::GetIcon("File")); - ui.tabsGeneral->setTabIcon(2, CSandMan::GetIcon("NoAccess")); - ui.tabsGeneral->setTabIcon(3, CSandMan::GetIcon("Run")); + ui.tabsGeneral->setTabIcon(1, CSandMan::GetIcon("Folder")); + ui.tabsGeneral->setTabIcon(2, CSandMan::GetIcon("Move")); + ui.tabsGeneral->setTabIcon(3, CSandMan::GetIcon("NoAccess")); + ui.tabsGeneral->setTabIcon(4, CSandMan::GetIcon("Run")); + ui.tabsSecurity->setCurrentIndex(0); ui.tabsSecurity->setTabIcon(0, CSandMan::GetIcon("Shield7")); ui.tabsSecurity->setTabIcon(1, CSandMan::GetIcon("Fence")); ui.tabsSecurity->setTabIcon(2, CSandMan::GetIcon("Shield12")); + ui.tabsForce->setCurrentIndex(0); ui.tabsForce->setTabIcon(0, CSandMan::GetIcon("Force")); ui.tabsForce->setTabIcon(1, CSandMan::GetIcon("Breakout")); + ui.tabsStop->setCurrentIndex(0); ui.tabsStop->setTabIcon(0, CSandMan::GetIcon("Fail")); ui.tabsStop->setTabIcon(1, CSandMan::GetIcon("Pass")); + ui.tabsInternet->setCurrentIndex(0); ui.tabsInternet->setTabIcon(0, CSandMan::GetIcon("Program")); ui.tabsInternet->setTabIcon(1, CSandMan::GetIcon("Wall")); ui.tabsInternet->setTabIcon(2, CSandMan::GetIcon("DNS")); ui.tabsInternet->setTabIcon(3, CSandMan::GetIcon("Proxy")); + ui.tabsAccess->setCurrentIndex(0); ui.tabsAccess->setTabIcon(0, CSandMan::GetIcon("Folder")); ui.tabsAccess->setTabIcon(1, CSandMan::GetIcon("RegEdit")); ui.tabsAccess->setTabIcon(2, CSandMan::GetIcon("Port")); @@ -203,9 +211,11 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri //ui.tabsAccess->setTabIcon(0, CSandMan::GetIcon("Rules")); ui.tabsAccess->setTabIcon(5, CSandMan::GetIcon("Policy")); + ui.tabsRecovery->setCurrentIndex(0); ui.tabsRecovery->setTabIcon(0, CSandMan::GetIcon("QuickRecovery")); ui.tabsRecovery->setTabIcon(1, CSandMan::GetIcon("ImmidiateRecovery")); + ui.tabsAdvanced->setCurrentIndex(0); ui.tabsAdvanced->setTabIcon(0, CSandMan::GetIcon("Compatibility")); ui.tabsAdvanced->setTabIcon(1, CSandMan::GetIcon("Trigger")); ui.tabsAdvanced->setTabIcon(2, CSandMan::GetIcon("Anon")); @@ -214,6 +224,7 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri ui.tabsAdvanced->setTabIcon(5, CSandMan::GetIcon("SetLogging")); ui.tabsAdvanced->setTabIcon(6, CSandMan::GetIcon("Bug")); + ui.tabsTemplates->setCurrentIndex(0); ui.tabsTemplates->setTabIcon(0, CSandMan::GetIcon("Compatibility")); ui.tabsTemplates->setTabIcon(1, CSandMan::GetIcon("Explore")); ui.tabsTemplates->setTabIcon(2, CSandMan::GetIcon("Accessibility")); @@ -506,7 +517,8 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri UpdateCurrentTab(); ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); - + + ui.treeCopy->viewport()->installEventFilter(this); ui.treeINet->viewport()->installEventFilter(this); ui.treeNetFw->viewport()->installEventFilter(this); ui.treeFiles->viewport()->installEventFilter(this); @@ -601,11 +613,13 @@ bool COptionsWindow::eventFilter(QObject *source, QEvent *event) { if (event->type() == QEvent::KeyPress && ((QKeyEvent*)event)->key() == Qt::Key_Escape && ((QKeyEvent*)event)->modifiers() == Qt::NoModifier - && (source == ui.treeINet->viewport() || source == ui.treeNetFw->viewport() + && (source == ui.treeCopy->viewport() + || source == ui.treeINet->viewport() || source == ui.treeNetFw->viewport() // || source == ui.treeAccess->viewport() || source == ui.treeFiles->viewport() || source == ui.treeKeys->viewport() || source == ui.treeIPC->viewport() || source == ui.treeWnd->viewport() || source == ui.treeCOM->viewport() || (ui.treeOptions && source == ui.treeOptions->viewport()))) { + CloseCopyEdit(false); CloseINetEdit(false); CloseNetFwEdit(false); CloseAccessEdit(false); @@ -616,6 +630,7 @@ bool COptionsWindow::eventFilter(QObject *source, QEvent *event) if (event->type() == QEvent::KeyPress && (((QKeyEvent*)event)->key() == Qt::Key_Enter || ((QKeyEvent*)event)->key() == Qt::Key_Return) && (((QKeyEvent*)event)->modifiers() == Qt::NoModifier || ((QKeyEvent*)event)->modifiers() == Qt::KeypadModifier)) { + CloseCopyEdit(true); CloseINetEdit(true); CloseNetFwEdit(true); CloseAccessEdit(true); @@ -623,6 +638,21 @@ bool COptionsWindow::eventFilter(QObject *source, QEvent *event) return true; // cancel event } + if (source == ui.treeCopy->viewport() && event->type() == QEvent::MouseButtonPress) + { + CloseCopyEdit(); + } + + if (source == ui.treeINet->viewport() && event->type() == QEvent::MouseButtonPress) + { + CloseINetEdit(); + } + + if (source == ui.treeNetFw->viewport() && event->type() == QEvent::MouseButtonPress) + { + CloseNetFwEdit(); + } + if (//source == ui.treeAccess->viewport() (source == ui.treeFiles->viewport() || source == ui.treeKeys->viewport() || source == ui.treeIPC->viewport() || source == ui.treeWnd->viewport() || source == ui.treeCOM->viewport()) && event->type() == QEvent::MouseButtonPress) @@ -630,15 +660,6 @@ bool COptionsWindow::eventFilter(QObject *source, QEvent *event) CloseAccessEdit(); } - if (source == ui.treeINet->viewport() && event->type() == QEvent::MouseButtonPress) - { - CloseINetEdit(); - } - - if (source == ui.treeNetFw->viewport() && event->type() == QEvent::MouseButtonPress) - { - CloseNetFwEdit(); - } if ((ui.treeOptions && source == ui.treeOptions->viewport()) && event->type() == QEvent::MouseButtonPress) { diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.h b/SandboxiePlus/SandMan/Windows/OptionsWindow.h index e0ff0bf4..ef226faa 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsWindow.h +++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.h @@ -54,6 +54,13 @@ private slots: void OnBoxTypChanged(); void UpdateBoxType(); + void OnCopyItemDoubleClicked(QTreeWidgetItem* pItem, int Column); + void OnCopySelectionChanged() { CloseCopyEdit(); OnOptChanged(); } + void OnCopyChanged(QTreeWidgetItem* pItem, int Column); + void OnShowCopyTmpl() { LoadCopyRulesTmpl(true); } + void OnAddCopyRule(); + void OnDelCopyRule(); + void OnBrowsePath(); void OnAddCommand(); void OnDelCommand(); @@ -224,6 +231,13 @@ protected: void OnTab(QWidget* pTab); + enum ECopyAction + { + eCopyAlways, + eDontCopy, + eCopyEmpty, + }; + enum ENetWfAction { eAllow, @@ -306,6 +320,11 @@ protected: QString GetActionFile(); + QString GetCopyActionStr(ECopyAction Action); + void ParseAndAddCopyRule(const QString& Value, ECopyAction Action, bool disabled = false, const QString& Template = QString()); + void CloseCopyEdit(bool bSave = true); + void CloseCopyEdit(QTreeWidgetItem* pItem, bool bSave = true); + void SetProgramItem(QString Program, QTreeWidgetItem* pItem, int Column, const QString& Sufix = QString()); QString SelectProgram(bool bOrGroup = true); @@ -328,6 +347,10 @@ protected: void LoadGeneral(); void SaveGeneral(); + void LoadCopyRules(); + void LoadCopyRulesTmpl(bool bUpdate = false); + void SaveCopyRules(); + void UpdateBoxSecurity(); void LoadGroups(); @@ -461,6 +484,7 @@ protected: bool m_HoldBoxType; bool m_GeneralChanged; + bool m_CopyRulesChanged; bool m_GroupsChanged; bool m_ForcedChanged; bool m_StopChanged; diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp index 85d93e95..e77be852 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp @@ -649,7 +649,7 @@ void CSettingsWindow::LoadSettings() QString IpcRootPath_Default = "\\Sandbox\\%USER%\\%SANDBOX%\\Session_%SESSION%"; ui.fileRoot->setText(theAPI->GetGlobalSettings()->GetText("FileRootPath", FileRootPath_Default)); - ui.chkSeparateUserFolders->setChecked(theAPI->GetGlobalSettings()->GetBool("SeparateUserFolders", true)); + //ui.chkSeparateUserFolders->setChecked(theAPI->GetGlobalSettings()->GetBool("SeparateUserFolders", true)); ui.regRoot->setText(theAPI->GetGlobalSettings()->GetText("KeyRootPath", KeyRootPath_Default)); ui.ipcRoot->setText(theAPI->GetGlobalSettings()->GetText("IpcRootPath", IpcRootPath_Default)); @@ -682,7 +682,7 @@ void CSettingsWindow::LoadSettings() { ui.cmbDefault->setEnabled(false); ui.fileRoot->setEnabled(false); - ui.chkSeparateUserFolders->setEnabled(false); + //ui.chkSeparateUserFolders->setEnabled(false); ui.chkAutoRoot->setEnabled(false); ui.chkWFP->setEnabled(false); ui.chkObjCb->setEnabled(false); @@ -950,7 +950,7 @@ void CSettingsWindow::SaveSettings() WriteText("DefaultBox", ui.cmbDefault->currentData().toString()); WriteText("FileRootPath", ui.fileRoot->text()); //ui.fileRoot->setText("\\??\\%SystemDrive%\\Sandbox\\%USER%\\%SANDBOX%"); - WriteAdvancedCheck(ui.chkSeparateUserFolders, "SeparateUserFolders", "", "n"); + //WriteAdvancedCheck(ui.chkSeparateUserFolders, "SeparateUserFolders", "", "n"); WriteText("KeyRootPath", ui.regRoot->text()); //ui.regRoot->setText("\\REGISTRY\\USER\\Sandbox_%USER%_%SANDBOX%"); WriteText("IpcRootPath", ui.ipcRoot->text()); //ui.ipcRoot->setText("\\Sandbox\\%USER%\\%SANDBOX%\\Session_%SESSION%"); diff --git a/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp b/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp index 98cd69c2..c3d0474f 100644 --- a/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp +++ b/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp @@ -92,7 +92,6 @@ bool CSetupWizard::ShowWizard() theGUI->UpdateSettings(true); - return true; } diff --git a/SandboxiePlus/version.h b/SandboxiePlus/version.h index 74f8ca38..e4ef851b 100644 --- a/SandboxiePlus/version.h +++ b/SandboxiePlus/version.h @@ -1,8 +1,8 @@ #pragma once #define VERSION_MJR 1 -#define VERSION_MIN 6 -#define VERSION_REV 7 +#define VERSION_MIN 7 +#define VERSION_REV 0 #define VERSION_UPD 0 #ifndef STR