Merge pull request #1882 from sandboxie-plus/next

Next
This commit is contained in:
DavidXanatos 2022-05-23 20:45:31 +02:00 committed by GitHub
commit 8babe4eb14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 6196 additions and 1814 deletions

View File

@ -6,7 +6,25 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [1.1.0 / 5.56.0] - 2022-01-??
### Added
- added support for NtRenameKey (this requires UseRegDeleteV2=y) [#205](https://github.com/sandboxie-plus/Sandboxie/issues/205)
- added box size info [#1780](https://github.com/sandboxie-plus/Sandboxie/issues/1780)
### Changed
- reworked the mechanism sandboxie uses to mark host files as deleted
-- the new behavioure creates a data file in the box root FilePaths.dat instead of creating dummy files
-- it can be enabled with UseFileDeleteV2=y sane for the registry UseRegDeleteV2=y using RegPaths.dat
- reworked the TlsNameBuffer mechanism to be more versatile and less error prone
- significantly reduced the CPU usage of sandman.exe
### Fixed
- fixed folder rename issues (this requires UseFileDeleteV2=y) [#71](https://github.com/sandboxie-plus/Sandboxie/issues/71)
- fixed issue with process access [#1603](https://github.com/sandboxie-plus/Sandboxie/issues/1603)
- fixed translation issue [#1864](https://github.com/sandboxie-plus/Sandboxie/issues/1864)
- fixed ui issue with box selection window [#1867](https://github.com/sandboxie-plus/Sandboxie/issues/1867)
- fixed ui issue when switching language [#1871](https://github.com/sandboxie-plus/Sandboxie/issues/1871)
@ -92,7 +110,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
- fixed pipe impersonation in compartment mode
- fixed issue with box clean-up which was introduced in a recent build
- fixed issue with box clean-up introduced in a recent build
- fixed missing trace log clean-up command [#1773](https://github.com/sandboxie-plus/Sandboxie/issues/1773)
- fixed inability to unpin programs that have been pinned to the run menu [#1694](https://github.com/sandboxie-plus/Sandboxie/issues/1694)

View File

@ -21,9 +21,9 @@
#ifndef _MY_VERSION_H
#define _MY_VERSION_H
#define MY_VERSION_BINARY 5,55,22
#define MY_VERSION_STRING "5.55.22"
#define MY_VERSION_COMPAT "5.55.0" // this refers to the driver ABI compatibility
#define MY_VERSION_BINARY 5,56,0
#define MY_VERSION_STRING "5.56.0"
#define MY_VERSION_COMPAT "5.56.0" // this refers to the driver ABI compatibility
// These #defines are used by either Resource Compiler or NSIS installer
#define SBIE_INSTALLER_PATH "..\\Bin\\"
@ -32,8 +32,8 @@
#define MY_PRODUCT_NAME_STRING "Sandboxie"
#define MY_COMPANY_NAME_STRING "Sandboxie-Plus.com"
#define MY_COPYRIGHT_STRING "Copyright © 2020-2022 by David Xanatos (xanasoft.com)"
#define MY_COPYRIGHT_STRING_OLD "Copyright © 2004-2020 by Sandboxie Holdings, LLC"
#define MY_COPYRIGHT_STRING "Copyright © 2020-2022 by David Xanatos (xanasoft.com)"
#define MY_COPYRIGHT_STRING_OLD "Copyright © 2004-2020 by Sandboxie Holdings, LLC"
#define SANDBOXIE L"Sandboxie"
#define SBIE L"SBIE"

View File

@ -545,6 +545,9 @@ BOOLEAN NetFw_ParseRule(NETFW_RULE* rule, const WCHAR* found_value)
static int isdigit_(int c) { return (c >= '0' && c <= '9'); }
static int isxdigit_(int c) { return (isdigit_(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')); }
#undef isascii
static int isascii(int iChar) { return((iChar <= 127) && (iChar >= 0)); }
static int isalnum_(int c) { return (isdigit_(c) || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// from BSD sources: http://code.google.com/p/plan9front/source/browse/sys/src/ape/lib/bsd/?r=320990f52487ae84e28961517a4fa0d02d473bac

View File

@ -96,6 +96,7 @@
<OmitFramePointers />
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>false</TreatWarningAsError>
<PreprocessorDefinitions>WITH_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>ntdll.lib;uuid.lib;kernel32.lib</AdditionalDependencies>
@ -117,6 +118,7 @@
<CompileAs>Default</CompileAs>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>false</TreatWarningAsError>
<PreprocessorDefinitions>WITH_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>ntdll.lib;uuid.lib;kernel32.lib</AdditionalDependencies>
@ -243,6 +245,12 @@
<ClCompile Include="dump.c" />
<ClCompile Include="event.c" />
<ClCompile Include="file.c" />
<ClCompile Include="file_del.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="file_dir.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
@ -279,6 +287,18 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="file_recovery.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="file_snapshots.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="gdi.c" />
<ClCompile Include="gui.c" />
<ClCompile Include="guiclass.c" />
@ -291,6 +311,7 @@
<ClCompile Include="guimsg.c" />
<ClCompile Include="guiprop.c" />
<ClCompile Include="guititle.c" />
<ClCompile Include="handle.c" />
<ClCompile Include="hook_inst.c" />
<ClCompile Include="hook_tramp.c" />
<ClCompile Include="includes.c" />
@ -305,6 +326,12 @@
<ClCompile Include="ipstore_enum.cpp" />
<ClCompile Include="ipstore_impl.cpp" />
<ClCompile Include="key.c" />
<ClCompile Include="key_del.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="key_merge.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
@ -427,6 +454,7 @@
<ClInclude Include="dump.h" />
<ClInclude Include="guidlg.h" />
<ClInclude Include="gui_p.h" />
<ClInclude Include="handle.h" />
<ClInclude Include="hook.h" />
<ClInclude Include="ipstore_enum.h" />
<ClInclude Include="ipstore_impl.h" />

View File

@ -6,11 +6,9 @@
<ClCompile Include="custom.c" />
<ClCompile Include="dllmem.c" />
<ClCompile Include="dllpath.c" />
<ClCompile Include="event.c" />
<ClCompile Include="includes.c" />
<ClCompile Include="lsa.c" />
<ClCompile Include="mscoree.c" />
<ClCompile Include="obj.c" />
<ClCompile Include="pdh.c" />
<ClCompile Include="proc.c" />
<ClCompile Include="secure.c" />
@ -218,6 +216,25 @@
<ClCompile Include="dump.c">
<Filter>debug</Filter>
</ClCompile>
<ClCompile Include="file_del.c">
<Filter>file</Filter>
</ClCompile>
<ClCompile Include="key_del.c">
<Filter>key</Filter>
</ClCompile>
<ClCompile Include="obj.c">
<Filter>obj</Filter>
</ClCompile>
<ClCompile Include="handle.c">
<Filter>obj</Filter>
</ClCompile>
<ClCompile Include="event.c" />
<ClCompile Include="file_recovery.c">
<Filter>file</Filter>
</ClCompile>
<ClCompile Include="file_snapshots.c">
<Filter>file</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="advapi.h" />
@ -255,9 +272,6 @@
<ClInclude Include="sbiedll.h">
<Filter>api</Filter>
</ClInclude>
<ClInclude Include="obj.h">
<Filter>com</Filter>
</ClInclude>
<ClInclude Include="..\..\common\stream.h">
<Filter>common</Filter>
</ClInclude>
@ -312,6 +326,12 @@
<ClInclude Include="dump.h">
<Filter>debug</Filter>
</ClInclude>
<ClInclude Include="obj.h">
<Filter>obj</Filter>
</ClInclude>
<ClInclude Include="handle.h">
<Filter>obj</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="resource.rc" />
@ -373,6 +393,9 @@
<Filter Include="debug">
<UniqueIdentifier>{db0f9820-8908-4325-96f9-69c82fa9e268}</UniqueIdentifier>
</Filter>
<Filter Include="obj">
<UniqueIdentifier>{05955a21-494a-4624-854e-d7c9b1e33401}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Midl Include="pstore.idl">

View File

@ -132,6 +132,20 @@ _FX UCHAR GetSetCustomLevel(UCHAR SetLevel)
if (! SetLevel) {
//
// if UseRegDeleteV2 is set, check if RegPaths.dat was loaded
// if not it means the box was previusly a V1 box,
// hence return 0 and re run customization
//
// note: DeleteShellAssocKeys deletes the sandboxie shell integration keys
// so the existence of a RegPaths.dat in a customized box is a reliable indicator
//
extern BOOLEAN Key_Delete_v2;
extern BOOLEAN Key_RegPaths_Loaded;
if (Key_Delete_v2 && !Key_RegPaths_Loaded)
return 0;
//
// open the AutoExec key, also used to indicate if this sandbox
// has already been customized

View File

@ -48,8 +48,9 @@ extern __declspec(dllexport) int __CRTDECL Sbie_snprintf(char *_Buffer, size_t C
#define TRUE_NAME_BUFFER 0
#define COPY_NAME_BUFFER 1
#define TMPL_NAME_BUFFER 2
#define NAME_BUFFER_COUNT 3
#define NAME_BUFFER_DEPTH 24
#define MISC_NAME_BUFFER 3 // 4, 5, 6, 7
#define NAME_BUFFER_COUNT 8
#define NAME_BUFFER_DEPTH 16 // 12
#ifdef _WIN64
@ -152,6 +153,7 @@ typedef struct _MY_LDR_WORKER_QUEUE_STUFF {
}MY_LDR_WORKER_QUEUE_STUFF;
#endif
*/
typedef struct _THREAD_DATA {
//
@ -160,7 +162,8 @@ typedef struct _THREAD_DATA {
WCHAR *name_buffer[NAME_BUFFER_COUNT][NAME_BUFFER_DEPTH];
ULONG name_buffer_len[NAME_BUFFER_COUNT][NAME_BUFFER_DEPTH];
int depth;
int name_buffer_count[NAME_BUFFER_DEPTH];
int name_buffer_depth;
//
// locks
@ -280,6 +283,7 @@ extern BOOLEAN Dll_RestrictedToken;
extern BOOLEAN Dll_ChromeSandbox;
extern BOOLEAN Dll_FirstProcessInBox;
extern BOOLEAN Dll_CompartmentMode;
//extern BOOLEAN Dll_AlernateIpcNaming;
extern ULONG Dll_ImageType;
@ -455,7 +459,7 @@ NTSTATUS Pipe_NtCreateFile(
void *EaBuffer,
ULONG EaLength);
void File_DuplicateRecover(HANDLE OldFileHandle, HANDLE NewFileHandle);
void Handle_SetupDuplicate(HANDLE OldFileHandle, HANDLE NewFileHandle);
void File_DoAutoRecover(BOOLEAN force);
@ -488,9 +492,7 @@ BOOLEAN File_IsBlockedNetParam(const WCHAR *BoxName);
void File_GetSetDeviceMap(WCHAR *DeviceMap96);
typedef void(*P_CloseHandler)(HANDLE handle);
BOOLEAN File_RegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler);
BOOLEAN File_UnRegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler);
void File_NotifyRecover(HANDLE FileHandle);
//---------------------------------------------------------------------------
// Functions (key)
@ -623,12 +625,18 @@ BOOLEAN Win32_Init(HMODULE hmodule);
// Functions (init for DllMain)
//---------------------------------------------------------------------------
BOOLEAN File_InitHandles(void);
BOOLEAN Handle_Init(void);
BOOLEAN Key_Init(void);
extern BOOLEAN Key_Delete_v2;
BOOLEAN Key_InitDelete_v2();
BOOLEAN File_Init(void);
extern BOOLEAN File_Delete_v2;
BOOLEAN File_InitDelete_v2();
BOOLEAN Ipc_Init(void);
BOOLEAN Secure_Init(void);

View File

@ -87,6 +87,7 @@ BOOLEAN Dll_RestrictedToken = FALSE;
BOOLEAN Dll_ChromeSandbox = FALSE;
BOOLEAN Dll_FirstProcessInBox = FALSE;
BOOLEAN Dll_CompartmentMode = FALSE;
//BOOLEAN Dll_AlernateIpcNaming = FALSE;
ULONG Dll_ImageType = DLL_IMAGE_UNSPECIFIED;
@ -275,6 +276,21 @@ _FX void Dll_InitInjected(void)
Dll_SidStringLen = wcslen(Dll_SidString);
//
// break for the debugger, as soon as we have Dll_ImageName
//
if (SbieDll_CheckStringInList(Dll_ImageName, NULL, L"WaitForDebugger")) {
//if (SbieDll_GetSettingsForName_bool(NULL, Dll_ImageName, L"WaitForDebugger", FALSE)) {
//if (SbieApi_QueryConfBool(NULL, L"WaitForDebuggerAll", FALSE)) {
while (!IsDebuggerPresent()) {
OutputDebugString(L"Waiting for Debugger\n");
Sleep(500);
} __debugbreak();
}
//
// query Sandboxie home folder
//
@ -332,6 +348,28 @@ _FX void Dll_InitInjected(void)
Dll_BoxKeyPathLen = wcslen(Dll_BoxKeyPath);
Dll_BoxIpcPathLen = wcslen(Dll_BoxIpcPath);
// Dll_AlernateIpcNaming = SbieApi_QueryConfBool(NULL, L"UseAlernateIpcNaming", FALSE);
// if (Dll_AlernateIpcNaming) {
//
// //
// // instead of using a separate namespace
// // just replace all \ with _ and use it as a sufix rather then an actual path
// // similarly a its done for named pipes already
// // this approche can help to reduce teh footprint when running in portable mode
// // alternatively we could create volatile entries under AppContainerNamedObjects
// //
//
// WCHAR* ptr = (WCHAR*)Dll_BoxIpcPath;
// while (*ptr) {
// WCHAR *ptr2 = wcschr(ptr, L'\\');
// if (ptr2) {
// ptr = ptr2;
// *ptr = L'_';
// } else
// ptr += wcslen(ptr);
// }
// }
//
// check if process SID is LocalSystem
//
@ -354,7 +392,7 @@ _FX void Dll_InitInjected(void)
Dll_FixWow64Syscall();
if (ok)
ok = File_InitHandles();
ok = Handle_Init();
if (ok)
ok = Obj_Init();
@ -424,7 +462,13 @@ _FX void Dll_InitInjected(void)
if (ok)
ok = Gui_InitConsole1();
if (ok)
// we need ipc stuff to be up hance we initialize delete stuff second to last
if (ok && File_Delete_v2)
File_InitDelete_v2();
if (ok && Key_Delete_v2)
Key_InitDelete_v2();
if (ok) // Note: Ldr_Init may cause rpcss to be started early
ok = Ldr_Init(); // last to initialize
//
@ -445,32 +489,6 @@ _FX void Dll_InitInjected(void)
if (! Dll_RestrictedToken)
CustomizeSandbox();
/*while (! IsDebuggerPresent()) {
OutputDebugString(L"BREAK\n");
Sleep(500);
}
__debugbreak();*/
/*if (_wcsicmp(Dll_ImageName, L"iexplore.exe") == 0) {
WCHAR *cmd = GetCommandLine();
if (wcsstr(cmd, L"SCODEF")) {
while (! IsDebuggerPresent()) {
OutputDebugString(L"BREAK\n");
Sleep(500);
}
__debugbreak();
}
}*/
/*if (_wcsicmp(Dll_ImageName, L"dllhost.exe") == 0) {
while (! IsDebuggerPresent()) {
OutputDebugString(L"BREAK\n");
Sleep(500);
}
__debugbreak();
}*/
}
@ -825,8 +843,10 @@ _FX ULONG_PTR Dll_Ordinal1(
//
int MustRestartProcess = 0;
if(Dll_ProcessFlags & SBIE_FLAG_PROCESS_IN_PCA_JOB)
MustRestartProcess = 1;
if (Dll_ProcessFlags & SBIE_FLAG_PROCESS_IN_PCA_JOB) {
if (!SbieApi_QueryConfBool(NULL, L"NoRestartOnPAC", FALSE))
MustRestartProcess = 1;
}
else if (Dll_ProcessFlags & SBIE_FLAG_FORCED_PROCESS) {
if (SbieApi_QueryConfBool(NULL, L"ForceRestartAll", FALSE)

View File

@ -1,6 +1,6 @@
/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2020 David Xanatos, xanasoft.com
* Copyright 2020-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -24,6 +24,7 @@
#include "dll.h"
#include "common/pool.h"
#include <stdio.h>
#include "debug.h"
//---------------------------------------------------------------------------
@ -282,7 +283,7 @@ _FX THREAD_DATA *Dll_GetTlsData(ULONG *pLastError)
_FX void Dll_FreeTlsData(void)
{
THREAD_DATA *data;
ULONG depth, type;
ULONG depth, count;
if (Dll_TlsIndex == TLS_OUT_OF_INDEXES)
data = NULL;
@ -295,12 +296,12 @@ _FX void Dll_FreeTlsData(void)
for (depth = 0; depth < NAME_BUFFER_DEPTH; ++depth) {
for (type = 0; type < NAME_BUFFER_COUNT; ++type) {
for (count = 0; count < NAME_BUFFER_COUNT; ++count) {
WCHAR* buf = data->name_buffer[type][depth];
WCHAR* buf = data->name_buffer[count][depth];
if (buf)
Dll_Free(buf);
data->name_buffer[type][depth] = NULL;
data->name_buffer[count][depth] = NULL;
}
}
@ -313,16 +314,38 @@ _FX void Dll_FreeTlsData(void)
//---------------------------------------------------------------------------
ALIGNED WCHAR *Dll_GetTlsNameBuffer(
THREAD_DATA *data, ULONG which, ULONG size)
#ifdef NAME_BUFFER_DEBUG
ALIGNED WCHAR *Dll_GetTlsNameBuffer_(THREAD_DATA *data, ULONG which, ULONG size, char* func)
#else
ALIGNED WCHAR *Dll_GetTlsNameBuffer(THREAD_DATA *data, ULONG which, ULONG size)
#endif
{
WCHAR *old_name_buffer;
ULONG old_name_buffer_len;
WCHAR **name_buffer;
ULONG *name_buffer_len;
name_buffer = &data->name_buffer [which][data->depth];
name_buffer_len = &data->name_buffer_len[which][data->depth];
//
// since we have more places where we may need a name buffer now
// instead of sticking to "which" and doing our best to not reuse a particualr buffer thats still needed
// we just increment a counter and take a new buffer reach time we request one
//
if (which >= MISC_NAME_BUFFER)
which = MISC_NAME_BUFFER + data->name_buffer_count[data->name_buffer_depth]++;
#ifdef NAME_BUFFER_DEBUG
DbgTrace("Dll_GetTlsNameBuffer, %s, %d\r\n", func, which);
#endif
if (which >= NAME_BUFFER_COUNT - 4)
SbieApi_Log(2310, L"%d", which);
if (which >= NAME_BUFFER_COUNT) {
ExitProcess(-1);
}
name_buffer = &data->name_buffer [which][data->name_buffer_depth];
name_buffer_len = &data->name_buffer_len[which][data->name_buffer_depth];
//
// round up the requested size (+ extra padding of some bytes)
@ -351,7 +374,7 @@ ALIGNED WCHAR *Dll_GetTlsNameBuffer(
//
// debug checks: the name buffer is allocated at least 64 bytes
// more than needed. fill these with 0xCC, and check that later
// more than needed. fill these with 0xCC, andd check that later
//
#ifdef DEBUG_MEMORY
@ -379,13 +402,14 @@ ALIGNED void Dll_PushTlsNameBuffer(THREAD_DATA *data)
#endif
{
#ifdef NAME_BUFFER_DEBUG
DbgTrace("Dll_PushTlsNameBuffer, %s, %d\r\n", func, data->depth);
DbgTrace("Dll_PushTlsNameBuffer, %s, %d\r\n", func, data->name_buffer_depth);
#endif
++data->depth;
if (data->depth > NAME_BUFFER_DEPTH - 4)
SbieApi_Log(2310, L"%d", data->depth);
if (data->depth >= NAME_BUFFER_DEPTH) {
++data->name_buffer_depth;
data->name_buffer_count[data->name_buffer_depth] = 0; // initialize
if (data->name_buffer_depth > NAME_BUFFER_DEPTH - 4)
SbieApi_Log(2310, L"%d", data->name_buffer_depth);
if (data->name_buffer_depth >= NAME_BUFFER_DEPTH) {
ExitProcess(-1);
}
}
@ -403,12 +427,12 @@ _FX void Dll_PopTlsNameBuffer(THREAD_DATA *data)
#endif
{
#ifdef NAME_BUFFER_DEBUG
DbgTrace("Dll_PopTlsNameBuffer, %s, %d\r\n", func, data->depth-1);
DbgTrace("Dll_PopTlsNameBuffer, %s, %d\r\n", func, data->name_buffer_depth-1);
#endif
//
// debug checks: the name buffer is allocated at least 64 bytes
// more than needed. fill these with 0xCC, and check that later
// more than needed. fill these with 0xCC, andd check that later
//
#ifdef DEBUG_MEMORY
@ -446,14 +470,12 @@ _FX void Dll_PopTlsNameBuffer(THREAD_DATA *data)
__debugbreak();
}
// todo: snapshots TMPL_NAME_BUFFER
}
#endif // DEBUG_MEMORY
--data->depth;
if (data->depth < 0) {
SbieApi_Log(2310, L"%d", data->depth);
--data->name_buffer_depth;
if (data->name_buffer_depth < 0) {
SbieApi_Log(2310, L"%d", data->name_buffer_depth);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,814 @@
/*
* Copyright 2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../../common/my_version.h"
//---------------------------------------------------------------------------
// File (Delete)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Defines
//---------------------------------------------------------------------------
#define FILE_PATH_FILE_NAME L"FilePaths.dat"
// path flages, saved to file
#define FILE_DELETED_FLAG 0x0001
#define FILE_RELOCATION_FLAG 0x0002
// internal volatile status flags
#define FILE_PATH_DELETED_FLAG 0x00010000
#define FILE_PATH_RELOCATED_FLAG 0x00020000
#define FILE_CHILDREN_DELETED_FLAG 0x00040000
#define FILE_DELETED_MASK (FILE_DELETED_FLAG | FILE_PATH_DELETED_FLAG)
#define FILE_RELOCATED_MASK (FILE_RELOCATION_FLAG | FILE_PATH_RELOCATED_FLAG)
#define FILE_IS_DELETED(x) ((x & FILE_DELETED_FLAG) != 0)
#define FILE_PATH_DELETED(x) ((x & FILE_DELETED_MASK) != 0)
#define FILE_PARENT_DELETED(x) ((x & FILE_PATH_DELETED_FLAG) != 0)
#define FILE_PATH_RELOCATED(x) ((x & FILE_RELOCATED_MASK) != 0)
//---------------------------------------------------------------------------
// Structures and Types
//---------------------------------------------------------------------------
typedef struct _PATH_NODE {
LIST_ELEM list_elem;
LIST items;
ULONG flags;
WCHAR* relocation;
ULONG name_len;
WCHAR name[1];
} PATH_NODE;
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
static LIST File_PathRoot;
static CRITICAL_SECTION *File_PathRoot_CritSec = NULL;
static HANDLE File_BoxRootWatcher = NULL;
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
static ULONG File_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation);
static BOOLEAN File_SavePathTree();
static BOOLEAN File_LoadPathTree();
static VOID File_RefreshPathTree();
BOOLEAN File_InitDelete_v2();
static NTSTATUS File_MarkDeleted_v2(const WCHAR *TruePath);
static ULONG File_IsDeleted_v2(const WCHAR* TruePath);
static BOOLEAN File_HasDeleted_v2(const WCHAR* TruePath);
static WCHAR* File_GetRelocation(const WCHAR* TruePath);
static NTSTATUS File_SetRelocation(const WCHAR *OldTruePath, const WCHAR *NewTruePath);
HANDLE File_AcquireMutex(const WCHAR* MutexName);
void File_ReleaseMutex(HANDLE hMutex);
#define FILE_VFS_MUTEX SBIE L"_VFS_Mutex"
//---------------------------------------------------------------------------
// File_ClearPathBranche
//---------------------------------------------------------------------------
_FX VOID File_ClearPathBranche_internal(LIST* parent)
{
PATH_NODE* child = List_Head(parent);
while (child) {
PATH_NODE* next_child = List_Next(child);
File_ClearPathBranche_internal(&child->items);
List_Remove(parent, child);
if(child->relocation) Dll_Free(child->relocation);
Dll_Free(child);
child = next_child;
}
}
//---------------------------------------------------------------------------
// File_GetPathNode_internal
//---------------------------------------------------------------------------
_FX PATH_NODE* File_GetPathNode_internal(LIST* parent, const WCHAR* name, ULONG name_len, BOOLEAN can_add)
{
PATH_NODE* child;
child = List_Head(parent);
while (child) {
if (child->name_len == name_len && _wcsnicmp(child->name, name, name_len) == 0)
break;
child = List_Next(child);
}
if (!child && can_add) {
child = Dll_Alloc(sizeof(PATH_NODE) + name_len*sizeof(WCHAR));
memzero(child, sizeof(PATH_NODE));
//List_Init(child->items); // done by memzero
child->name_len = name_len;
wmemcpy(child->name, name, name_len);
child->name[name_len] = L'\0';
List_Insert_After(parent, NULL, child);
}
return child;
}
//---------------------------------------------------------------------------
// File_FindPathBranche_internal
//---------------------------------------------------------------------------
_FX PATH_NODE* File_FindPathBranche_internal(LIST* Root, const WCHAR* Path, LIST** pParent, BOOLEAN can_add)
{
LIST* Parent = Root;
PATH_NODE* Node;
const WCHAR* next;
for (const WCHAR* ptr = Path; *ptr; ptr = next + 1) {
next = wcschr(ptr, L'\\');
if (ptr == next) // handle initial \ as well as \\ or \\\ etc cases
continue;
if(!next) next = wcschr(ptr, L'\0'); // last
Node = File_GetPathNode_internal(Parent, ptr, (ULONG)(next - ptr), can_add);
if (!Node)
return NULL;
if (*next == L'\0') {
if (pParent) *pParent = Parent;
return Node;
}
Parent = &Node->items;
}
return NULL;
}
//---------------------------------------------------------------------------
// File_SetPathFlags_internal
//---------------------------------------------------------------------------
_FX VOID File_SetPathFlags_internal(LIST* Root, const WCHAR* Path, ULONG setFlags, ULONG clrFlags, const WCHAR* Relocation)
{
PATH_NODE* Parent = Root;
PATH_NODE* Node;
const WCHAR* next;
for (const WCHAR* ptr = Path; *ptr; ptr = next + 1) {
next = wcschr(ptr, L'\\');
if (ptr == next) // handle initial \ as well as \\ or \\\ etc cases
continue;
if(!next) next = wcschr(ptr, L'\0'); // last
Node = File_GetPathNode_internal(Parent, ptr, (ULONG)(next - ptr), TRUE);
if (*next == L'\0') { // set flag always on the last element only
Node->flags |= setFlags;
Node->flags &= ~clrFlags;
if ((clrFlags & FILE_RELOCATION_FLAG) != 0 || (setFlags & FILE_RELOCATION_FLAG) != 0) {
if (Node->relocation) {
Dll_Free(Node->relocation);
Node->relocation = NULL;
}
}
if ((setFlags & FILE_RELOCATION_FLAG) != 0 && Relocation != NULL) {
if (Relocation && wcslen(Relocation) > 0) {
Node->relocation = Dll_Alloc((wcslen(Relocation) + 1) * sizeof(WCHAR));
wcscpy(Node->relocation, Relocation);
}
}
break;
}
Parent = &Node->items;
}
}
//---------------------------------------------------------------------------
// File_GetPathFlags_internal
//---------------------------------------------------------------------------
_FX ULONG File_GetPathFlags_internal(LIST* Root, const WCHAR* Path, WCHAR** pRelocation, BOOLEAN CheckChildren)
{
ULONG Flags = 0;
const WCHAR* Relocation = NULL;
const WCHAR* SubPath = NULL;
LIST* Parent = Root;
PATH_NODE* Node;
PATH_NODE* child;
const WCHAR* next;
for (const WCHAR* ptr = Path; *ptr; ptr = next + 1) {
next = wcschr(ptr, L'\\');
if (ptr == next) // handle initial \ as well as \\ or \\\ etc cases
continue;
if(!next) next = wcschr(ptr, L'\0'); // last
Node = File_GetPathNode_internal(Parent, ptr, (ULONG)(next - ptr), FALSE);
if (!Node)
break;
//
// we return the last relocation target
//
if ((Node->flags & FILE_RELOCATION_FLAG) != 0) {
Relocation = Node->relocation;
SubPath = next;
}
if (*next == L'\0') { // last path segment
if ((Node->flags & FILE_RELOCATION_FLAG) != 0)
Flags |= FILE_RELOCATION_FLAG;
if ((Node->flags & FILE_DELETED_FLAG) != 0)
Flags |= FILE_DELETED_FLAG; // flag set for the path
if (CheckChildren) {
child = List_Head(&Node->items);
while (child) {
if ((child->flags & Flags) == Flags) {
Flags |= FILE_CHILDREN_DELETED_FLAG; // path set for children
break;
}
child = List_Next(child);
}
}
break;
}
//
// if we encounter a relocation previosue deletions on the path will be reset
// relocations are only allowed to exist for not deleted paths
//
if ((Node->flags & FILE_RELOCATION_FLAG) != 0) {
Flags = 0; // reset
Flags |= FILE_PATH_RELOCATED_FLAG;
}
else if ((Node->flags & FILE_DELETED_FLAG) != 0)
Flags |= FILE_PATH_DELETED_FLAG; // flag set for ancestor
Parent = &Node->items;
}
if (Relocation && pRelocation) {
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
*pRelocation = Dll_GetTlsNameBuffer(TlsData, MISC_NAME_BUFFER, (wcslen(Relocation) + wcslen(SubPath) + 16) * sizeof(WCHAR)); // +16 some room for changes
wcscpy(*pRelocation, Relocation);
wcscat(*pRelocation, SubPath);
}
return Flags;
}
//---------------------------------------------------------------------------
// File_GetPathFlags
//---------------------------------------------------------------------------
_FX ULONG File_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation)
{
ULONG Flags;
File_RefreshPathTree();
EnterCriticalSection(File_PathRoot_CritSec);
Flags = File_GetPathFlags_internal(&File_PathRoot, Path, pRelocation, TRUE);
LeaveCriticalSection(File_PathRoot_CritSec);
return Flags;
}
//---------------------------------------------------------------------------
// File_SavePathNode_internal
//---------------------------------------------------------------------------
_FX VOID File_SavePathNode_internal(HANDLE hPathsFile, LIST* parent, WCHAR* Path, ULONG Length, ULONG SetFlags)
{
const WCHAR CrLf[] = L"\r\n";
WCHAR FlagStr[16] = L"|";
// append L"\\"
Path[Length++] = L'\\'; //Path[Length] = L'0';
WCHAR* PathBase = Path + Length;
PATH_NODE* child;
child = List_Head(parent);
while (child) {
wmemcpy(PathBase, child->name, child->name_len + 1);
ULONG Path_Len = Length + child->name_len;
//
// don't write down flags that were already set for the parent,
// unless we have a relocation, that resets everything
//
if ((child->flags & FILE_RELOCATION_FLAG) != 0)
SetFlags = 0;
if ((child->flags & ~SetFlags) != 0 || child->relocation != NULL) {
// write the path
WriteFile(hPathsFile, Path, Path_Len * sizeof(WCHAR), NULL, NULL);
// write the flags
_ultow(child->flags, FlagStr + 1, 16);
WriteFile(hPathsFile, FlagStr, wcslen(FlagStr) * sizeof(WCHAR), NULL, NULL);
// write the relocation
if (child->relocation != NULL) {
WriteFile(hPathsFile, FlagStr, sizeof(WCHAR), NULL, NULL); // write |
WriteFile(hPathsFile, child->relocation, wcslen(child->relocation) * sizeof(WCHAR), NULL, NULL);
}
// write line ending
WriteFile(hPathsFile, CrLf, sizeof(CrLf) - sizeof(WCHAR), NULL, NULL);
}
File_SavePathNode_internal(hPathsFile, &child->items, Path, Path_Len, SetFlags | child->flags);
child = List_Next(child);
}
}
//---------------------------------------------------------------------------
// File_SavePathTree_internal
//---------------------------------------------------------------------------
_FX VOID File_SavePathTree_internal(LIST* Root, const WCHAR* name)
{
WCHAR PathsFile[MAX_PATH] = { 0 };
wcscpy(PathsFile, Dll_BoxFilePath);
wcscat(PathsFile, L"\\");
wcscat(PathsFile, name);
SbieDll_TranslateNtToDosPath(PathsFile);
HANDLE hPathsFile;
hPathsFile = CreateFile(PathsFile, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hPathsFile == INVALID_HANDLE_VALUE)
return;
WCHAR* Path = (WCHAR *)Dll_Alloc((0x7FFF + 1)*sizeof(WCHAR)); // max nt path
File_SavePathNode_internal(hPathsFile, Root, Path, 0, 0);
Dll_Free(Path);
CloseHandle(hPathsFile);
}
//---------------------------------------------------------------------------
// File_SavePathTree
//---------------------------------------------------------------------------
_FX BOOLEAN File_SavePathTree()
{
EnterCriticalSection(File_PathRoot_CritSec);
File_SavePathTree_internal(&File_PathRoot, FILE_PATH_FILE_NAME);
LeaveCriticalSection(File_PathRoot_CritSec);
return TRUE;
}
//---------------------------------------------------------------------------
// File_AcquireMutex
//---------------------------------------------------------------------------
_FX HANDLE File_AcquireMutex(const WCHAR *MutexName)
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MutexName);
if (! hMutex)
hMutex = CreateMutex(NULL, FALSE, MutexName);
if (hMutex)
WaitForSingleObject(hMutex, 5000);
return hMutex;
}
//---------------------------------------------------------------------------
// Scm_ReleaseMutex
//---------------------------------------------------------------------------
_FX void File_ReleaseMutex(HANDLE hMutex)
{
if (hMutex) {
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
}
//---------------------------------------------------------------------------
// File_LoadPathTree_internal
//---------------------------------------------------------------------------
_FX BOOLEAN File_LoadPathTree_internal(LIST* Root, const WCHAR* name)
{
WCHAR PathsFile[MAX_PATH] = { 0 };
wcscpy(PathsFile, Dll_BoxFilePath);
wcscat(PathsFile, L"\\");
wcscat(PathsFile, name);
SbieDll_TranslateNtToDosPath(PathsFile);
HANDLE hPathsFile;
hPathsFile = CreateFile(PathsFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hPathsFile == INVALID_HANDLE_VALUE)
return FALSE;
File_ClearPathBranche_internal(Root);
LARGE_INTEGER fileSize;
GetFileSizeEx(hPathsFile, &fileSize);
WCHAR* Buffer = (WCHAR *)Dll_Alloc((ULONG)fileSize.QuadPart + 128);
DWORD bytesRead;
ReadFile(hPathsFile, Buffer, (DWORD)fileSize.QuadPart, &bytesRead, NULL);
Buffer[bytesRead/sizeof(WCHAR)] = L'\0';
WCHAR* Next = Buffer;
while (*Next) {
WCHAR* Line = Next;
WCHAR* End = wcschr(Line, L'\n');
if (End == NULL) {
End = wcschr(Line, L'\0');
Next = End;
} else
Next = End + 1;
LONG LineLen = (LONG)(End - Line);
if (LineLen > 1 && Line[LineLen - 1] == L'\r')
LineLen -= 1;
WCHAR savechar = Line[LineLen];
Line[LineLen] = L'\0';
WCHAR* Sep = wcschr(Line, L'|');
if (!Sep || Sep > Next) continue; // invalid line, flags field missing
*Sep = L'\0';
WCHAR* endptr;
ULONG Flags = wcstoul(Sep + 1, &endptr, 16);
if (endptr && *endptr == L'|') endptr++;
else endptr = NULL;
File_SetPathFlags_internal(Root, Line, Flags, 0, endptr);
*Sep = L'|';
Line[LineLen] = savechar;
}
Dll_Free(Buffer);
CloseHandle(hPathsFile);
return TRUE;
}
//---------------------------------------------------------------------------
// File_LoadPathTree
//---------------------------------------------------------------------------
_FX BOOLEAN File_LoadPathTree()
{
HANDLE hMutex = File_AcquireMutex(FILE_VFS_MUTEX);
EnterCriticalSection(File_PathRoot_CritSec);
File_LoadPathTree_internal(&File_PathRoot, FILE_PATH_FILE_NAME);
LeaveCriticalSection(File_PathRoot_CritSec);
File_ReleaseMutex(hMutex);
return TRUE;
}
//---------------------------------------------------------------------------
// File_RefreshPathTree
//---------------------------------------------------------------------------
_FX VOID File_RefreshPathTree()
{
if (!File_BoxRootWatcher)
return;
if (WaitForSingleObject(File_BoxRootWatcher, 0) == WAIT_OBJECT_0) {
//
// somethign changed, reload the path tree
//
File_LoadPathTree();
}
FindNextChangeNotification(File_BoxRootWatcher); // rearm the watcher
}
//---------------------------------------------------------------------------
// File_InitDelete_v2
//---------------------------------------------------------------------------
_FX BOOLEAN File_InitDelete_v2()
{
List_Init(&File_PathRoot);
File_PathRoot_CritSec = Dll_Alloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSectionAndSpinCount(File_PathRoot_CritSec, 1000);
File_LoadPathTree();
//#ifdef WITH_DEBUG
// File_SavePathTree();
//#endif
WCHAR BoxFilePath[MAX_PATH] = { 0 };
wcscpy(BoxFilePath, Dll_BoxFilePath);
SbieDll_TranslateNtToDosPath(BoxFilePath);
File_BoxRootWatcher = FindFirstChangeNotification(BoxFilePath, FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE);
return TRUE;
}
//---------------------------------------------------------------------------
// File_MarkDeleted_internal
//---------------------------------------------------------------------------
_FX BOOLEAN File_MarkDeleted_internal(LIST* Root, const WCHAR* Path)
{
// 1. remove deleted branche
LIST* Parent = NULL;
PATH_NODE* Node = File_FindPathBranche_internal(Root, Path, &Parent, FALSE);
if (Node) {
if (Node->flags == FILE_DELETED_FLAG && Node->items.count == 0)
return FALSE; // already marked deleted
List_Remove(Parent, Node);
File_ClearPathBranche_internal(&Node->items);
if (Node->relocation) Dll_Free(Node->relocation);
Dll_Free(Node);
}
// 2. set deleted flag
File_SetPathFlags_internal(Root, Path, FILE_DELETED_FLAG, 0, NULL);
// done
return TRUE;
}
//---------------------------------------------------------------------------
// File_MarkDeleted_v2
//---------------------------------------------------------------------------
_FX NTSTATUS File_MarkDeleted_v2(const WCHAR* TruePath)
{
//
// add a file or directory to the deleted list
//
HANDLE hMutex = File_AcquireMutex(FILE_VFS_MUTEX);
EnterCriticalSection(File_PathRoot_CritSec);
BOOLEAN bSet = File_MarkDeleted_internal(&File_PathRoot, TruePath);
LeaveCriticalSection(File_PathRoot_CritSec);
if (bSet) File_SavePathTree();
File_ReleaseMutex(hMutex);
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// File_IsDeleted_v2
//---------------------------------------------------------------------------
_FX ULONG File_IsDeleted_v2(const WCHAR* TruePath)
{
//
// check if the file or one of its parent directories is listed as deleted
// use the dedicated test method to properly take into account relocations
//
ULONG Flags = File_GetPathFlags(TruePath, NULL);
return (Flags & FILE_DELETED_MASK);
}
//---------------------------------------------------------------------------
// File_HasDeleted_v2
//---------------------------------------------------------------------------
_FX BOOLEAN File_HasDeleted_v2(const WCHAR* TruePath)
{
//
// Check if this folder has deleted children
//
ULONG Flags = File_GetPathFlags(TruePath, NULL);
return (Flags & FILE_CHILDREN_DELETED_FLAG) != 0;
}
//---------------------------------------------------------------------------
// File_SetRelocation_internal
//---------------------------------------------------------------------------
_FX VOID File_SetRelocation_internal(LIST* Root, const WCHAR *OldTruePath, const WCHAR *NewTruePath)
{
// 1. separate branche from OldTruePath
LIST* Parent = NULL;
PATH_NODE* Node = File_FindPathBranche_internal(Root, OldTruePath, &Parent, FALSE);
//if(Node)
// List_Remove(Parent, Node); // leave node in it may have a delete flag
// 2. check if old path has a relocation
BOOLEAN HasRelocation = FALSE;
if (Node && (Node->flags & FILE_RELOCATION_FLAG) != 0) {
Node->flags &= ~FILE_RELOCATION_FLAG;
if (Node->relocation) {
HasRelocation = TRUE;
OldTruePath = Node->relocation; // update relocation to oritinal true target
}
}
// 3. add true delete entry OldTruePath
File_SetPathFlags_internal(Root, OldTruePath, FILE_DELETED_FLAG, 0, NULL);
// 4. set redirection NewTruePath -> OldTruePath
PATH_NODE* NewNode = File_FindPathBranche_internal(Root, NewTruePath, NULL, TRUE);
// OldTruePath may have a relocated parent, if so unwrap it
if (!HasRelocation) {
WCHAR* OldOldTruePath = NULL;
File_GetPathFlags_internal(Root, OldTruePath, &OldOldTruePath, TRUE);
if (OldOldTruePath) OldTruePath = OldOldTruePath;
}
NewNode->flags |= FILE_RELOCATION_FLAG;
NewNode->relocation = Dll_Alloc((wcslen(OldTruePath) + 1) * sizeof(WCHAR));
wcscpy(NewNode->relocation, OldTruePath);
// 5. reatach branche to NewTruePath
if (Node) {
PATH_NODE* child = List_Head(&Node->items);
while (child) {
PATH_NODE* next_child = List_Next(child);
List_Remove(&Node->items, child);
List_Insert_After(&NewNode->items, NULL, child);
child = next_child;
}
}
// 6. clean up
//if (Node) {
if (HasRelocation) {
//if (Node->relocation)
Dll_Free(Node->relocation);
Node->relocation = NULL;
//Dll_Free(Node);
}
}
//---------------------------------------------------------------------------
// File_SetRelocation
//---------------------------------------------------------------------------
_FX NTSTATUS File_SetRelocation(const WCHAR* OldTruePath, const WCHAR* NewTruePath)
{
//
// List a mapping for the new location
//
HANDLE hMutex = File_AcquireMutex(FILE_VFS_MUTEX);
EnterCriticalSection(File_PathRoot_CritSec);
File_SetRelocation_internal(&File_PathRoot, OldTruePath, NewTruePath);
LeaveCriticalSection(File_PathRoot_CritSec);
File_SavePathTree();
File_ReleaseMutex(hMutex);
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// File_GetRelocation
//---------------------------------------------------------------------------
_FX WCHAR* File_GetRelocation(const WCHAR *TruePath)
{
//
// Get redirection location, only if its the actual path and not a parent
//
WCHAR* OldTruePath = NULL;
ULONG Flags = File_GetPathFlags(TruePath, &OldTruePath);
if (FILE_PATH_RELOCATED(Flags))
return OldTruePath;
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -106,8 +106,6 @@ static WCHAR *File_AllocAndInitEnvironment_2(
static void File_AdjustDrives(
ULONG path_drive_index, BOOLEAN subst, const WCHAR *path);
static void File_InitSnapshots(void);
//---------------------------------------------------------------------------
// Variables
@ -122,20 +120,6 @@ static const WCHAR *File_DeviceMap_EnvVar = ENV_VAR_PFX L"DEVICE_MAP";
#undef ENV_VAR_PFX
//---------------------------------------------------------------------------
// File_InitHandles
//---------------------------------------------------------------------------
_FX BOOLEAN File_InitHandles(void)
{
InitializeCriticalSection(&File_HandleOnClose_CritSec);
map_init(&File_HandleOnClose, Dll_Pool);
return TRUE;
}
//---------------------------------------------------------------------------
// File_Init
//---------------------------------------------------------------------------
@ -158,6 +142,10 @@ _FX BOOLEAN File_Init(void)
File_DriveAddSN = SbieApi_QueryConfBool(NULL, L"UseVolumeSerialNumbers", FALSE);
File_Delete_v2 = SbieApi_QueryConfBool(NULL, L"UseFileDeleteV2", FALSE);
File_NoReparse = SbieApi_QueryConfBool(NULL, L"NoPathReparse", FALSE);
if (! File_InitDrives(0xFFFFFFFF))
return FALSE;
@ -166,6 +154,16 @@ _FX BOOLEAN File_Init(void)
return FALSE;
}
if (Dll_OsBuild >= 6000) { // needed for File_GetFileName used indirectly by File_InitRecoverFolders
void *GetFinalPathNameByHandleW =
GetProcAddress(Dll_KernelBase ? Dll_KernelBase : Dll_Kernel32,
"GetFinalPathNameByHandleW");
if (GetFinalPathNameByHandleW) {
SBIEDLL_HOOK(File_,GetFinalPathNameByHandleW);
}
}
File_InitSnapshots();
File_InitRecoverFolders();
@ -230,16 +228,6 @@ _FX BOOLEAN File_Init(void)
}
}
if (Dll_OsBuild >= 6000) {
void *GetFinalPathNameByHandleW =
GetProcAddress(Dll_KernelBase ? Dll_KernelBase : Dll_Kernel32,
"GetFinalPathNameByHandleW");
if (GetFinalPathNameByHandleW) {
SBIEDLL_HOOK(File_,GetFinalPathNameByHandleW);
}
}
if (Dll_OsBuild >= 8400 && Dll_IsSystemSid) {
// see File_GetTempPathW in file file_misc.c
GetTempPathW = GetProcAddress(Dll_KernelBase, "GetTempPathW");
@ -1787,58 +1775,4 @@ _FX void File_GetSetDeviceMap(WCHAR *DeviceMap96)
}
}
}
}
//---------------------------------------------------------------------------
// File_InitSnapshots
//---------------------------------------------------------------------------
// CRC
#define CRC_WITH_ADLERTZUK64
#include "common/crc.c"
_FX void File_InitSnapshots(void)
{
WCHAR ShapshotsIni[MAX_PATH] = { 0 };
wcscpy(ShapshotsIni, Dll_BoxFilePath);
wcscat(ShapshotsIni, L"\\Snapshots.ini");
SbieDll_TranslateNtToDosPath(ShapshotsIni);
WCHAR Shapshot[16] = { 0 };
GetPrivateProfileStringW(L"Current", L"Snapshot", L"", Shapshot, 16, ShapshotsIni);
if (*Shapshot == 0)
return; // not using snapshots
File_Snapshot = Dll_Alloc(sizeof(FILE_SNAPSHOT));
memzero(File_Snapshot, sizeof(FILE_SNAPSHOT));
wcscpy(File_Snapshot->ID, Shapshot);
File_Snapshot->IDlen = wcslen(Shapshot);
FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot;
File_Snapshot_Count = 1;
for (;;)
{
Cur_Snapshot->ScramKey = CRC32(Cur_Snapshot->ID, Cur_Snapshot->IDlen * sizeof(WCHAR));
WCHAR ShapshotId[26] = L"Snapshot_";
wcscat(ShapshotId, Shapshot);
//WCHAR ShapshotName[34] = { 0 };
//GetPrivateProfileStringW(ShapshotId, L"Name", L"", ShapshotName, 34, ShapshotsIni);
//wcscpy(Cur_Snapshot->Name, ShapshotName);
GetPrivateProfileStringW(ShapshotId, L"Parent", L"", Shapshot, 16, ShapshotsIni);
if (*Shapshot == 0)
break; // no more snapshots
Cur_Snapshot->Parent = Dll_Alloc(sizeof(FILE_SNAPSHOT));
memzero(Cur_Snapshot->Parent, sizeof(FILE_SNAPSHOT));
wcscpy(Cur_Snapshot->Parent->ID, Shapshot);
Cur_Snapshot->Parent->IDlen = wcslen(Shapshot);
Cur_Snapshot = Cur_Snapshot->Parent;
File_Snapshot_Count++;
}
}
}

View File

@ -1,5 +1,6 @@
/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2020-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -470,6 +471,9 @@ _FX WCHAR *File_TranslateTempLinks(
WCHAR *ret;
ULONG TruePath_len, ret_len;
if (File_NoReparse)
return NULL;
//
// entry
//

View File

@ -1,6 +1,6 @@
/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2020 David Xanatos, xanasoft.com
* Copyright 2020-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -329,8 +329,10 @@ _FX void File_ReplaceFileW_3(
(*FileFlags) &= FGN_IS_BOXED_PATH;
if (*FileFlags) {
if (File_Snapshot != NULL)
File_FindSnapshotPath(&CopyPath);
if (File_Snapshot != NULL) {
WCHAR* TmplName = File_FindSnapshotPath(CopyPath);
if (TmplName) CopyPath = TmplName;
}
len = (wcslen(CopyPath) + 1) * sizeof(WCHAR);
path = Dll_AllocTemp(len);

View File

@ -0,0 +1,726 @@
/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2020-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//
// Immediate Recovery for Files
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
static void File_InitRecoverFolders(void);
static void File_InitRecoverList(
const WCHAR *setting, LIST *list, BOOLEAN MustBeValidPath,
WCHAR *buf, ULONG buf_len);
static BOOLEAN File_IsRecoverable(const WCHAR *TruePath);
static void File_DoAutoRecover_2(BOOLEAN force, ULONG ticks);
static ULONG File_DoAutoRecover_3(
const WCHAR *PathToFind, WCHAR *PathBuf1024,
SYSTEM_HANDLE_INFORMATION *info, FILE_GET_ALL_HANDLES_RPL *rpl,
UCHAR *FileObjectTypeNumber);
static ULONG File_DoAutoRecover_4(
const WCHAR *PathToFind, WCHAR *PathBuf1024,
HANDLE FileHandle, UCHAR ObjectTypeNumber, UCHAR *FileObjectTypeNumber);
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
static LIST File_RecoverFolders;
static LIST File_RecoverIgnores;
static LIST File_RecPaths;
static CRITICAL_SECTION File_RecHandles_CritSec;
static BOOLEAN File_MsoDllLoaded = FALSE;
//---------------------------------------------------------------------------
// Structures and Types
//---------------------------------------------------------------------------
typedef struct _FILE_RECOVER_FOLDER {
LIST_ELEM list_elem;
ULONG ticks; // for File_RecPaths
ULONG path_len;
WCHAR path[1];
} FILE_RECOVER_FOLDER;
//---------------------------------------------------------------------------
// File_InitRecoverFolders
//---------------------------------------------------------------------------
_FX void File_InitRecoverFolders(void)
{
//
// init list of recoverable file handles
//
List_Init(&File_RecoverFolders);
List_Init(&File_RecoverIgnores);
InitializeCriticalSectionAndSpinCount(&File_RecHandles_CritSec, 1000);
List_Init(&File_RecPaths);
//
// init list of recover folders
//
if (SbieApi_QueryConfBool(NULL, L"AutoRecover", FALSE)) {
ULONG buf_len = 4096 * sizeof(WCHAR);
WCHAR *buf = Dll_AllocTemp(buf_len);
File_InitRecoverList(
L"RecoverFolder", &File_RecoverFolders, TRUE, buf, buf_len);
File_InitRecoverList(
L"AutoRecoverIgnore", &File_RecoverIgnores, FALSE, buf, buf_len);
Dll_Free(buf);
}
}
//---------------------------------------------------------------------------
// File_InitRecoverList
//---------------------------------------------------------------------------
_FX void File_InitRecoverList(
const WCHAR *setting, LIST *list, BOOLEAN MustBeValidPath,
WCHAR *buf, ULONG buf_len)
{
UNICODE_STRING uni;
WCHAR *TruePath, *CopyPath, *ReparsedPath;
FILE_RECOVER_FOLDER *fold;
ULONG index = 0;
while (1) {
NTSTATUS status = SbieApi_QueryConf(
NULL, setting, index, buf, buf_len - 16 * sizeof(WCHAR));
if (! NT_SUCCESS(status))
break;
++index;
RtlInitUnicodeString(&uni, buf);
status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL);
ReparsedPath = NULL;
if (NT_SUCCESS(status) && MustBeValidPath) {
ReparsedPath = File_TranslateTempLinks(TruePath, FALSE);
if (ReparsedPath)
TruePath = ReparsedPath;
} else if ((! NT_SUCCESS(status)) && (! MustBeValidPath)) {
TruePath = buf;
status = STATUS_SUCCESS;
}
if (NT_SUCCESS(status)) {
ULONG len = wcslen(TruePath);
if (len && TruePath[len - 1] == L'\\') {
TruePath[len - 1] = L'\0';
--len;
}
len = sizeof(FILE_RECOVER_FOLDER)
+ (len + 1) * sizeof(WCHAR);
fold = Dll_Alloc(len);
fold->ticks = 0; // not used
wcscpy(fold->path, TruePath);
fold->path_len = wcslen(fold->path);
List_Insert_After(list, NULL, fold);
}
if (ReparsedPath)
Dll_Free(ReparsedPath);
}
}
//---------------------------------------------------------------------------
// File_IsRecoverable
//---------------------------------------------------------------------------
_FX BOOLEAN File_IsRecoverable(
const WCHAR *TruePath)
{
const WCHAR *save_TruePath;
FILE_RECOVER_FOLDER *fold;
const WCHAR *ptr;
ULONG TruePath_len;
ULONG PrefixLen;
BOOLEAN ok;
//
// if we have a path that looks like
// \Device\LanmanRedirector\;Q:000000000000b09f\server\share\f1.txt
// \Device\Mup\;LanmanRedirector\;Q:000000000000b09f\server\share\f1.txt
// then translate to
// \Device\Mup\server\share\f1.txt
// and test again. We do this because the SbieDrv records paths
// in the \Device\Mup format. See SbieDrv::File_TranslateShares.
//
save_TruePath = TruePath;
if (_wcsnicmp(TruePath, File_Redirector, File_RedirectorLen) == 0)
PrefixLen = File_RedirectorLen;
else if (_wcsnicmp(TruePath, File_DfsClientRedir, File_DfsClientRedirLen) == 0)
PrefixLen = File_DfsClientRedirLen;
else if (_wcsnicmp(TruePath, File_HgfsRedir, File_HgfsRedirLen) == 0)
PrefixLen = File_HgfsRedirLen;
else if (_wcsnicmp(TruePath, File_MupRedir, File_MupRedirLen) == 0)
PrefixLen = File_MupRedirLen;
else
PrefixLen = 0;
if (PrefixLen && TruePath[PrefixLen] == L';') {
WCHAR *ptr = wcschr(TruePath + PrefixLen, L'\\');
if (ptr && ptr[0] && ptr[1]) {
ULONG len1 = wcslen(ptr + 1);
ULONG len2 = (File_MupLen + len1 + 8) * sizeof(WCHAR);
WCHAR *path2 = Dll_Alloc(len2);
wmemcpy(path2, File_Mup, File_MupLen);
wmemcpy(path2 + File_MupLen, ptr + 1, len1 + 1);
TruePath = (const WCHAR *)path2;
}
}
//
// look for the TruePath in the list of RecoverFolder settings
//
ok = FALSE;
fold = List_Head(&File_RecoverFolders);
while (fold) {
if (_wcsnicmp(fold->path, TruePath, fold->path_len) == 0) {
ptr = TruePath + fold->path_len;
if (*ptr == L'\\' || *ptr == L'\0') {
ok = TRUE;
break;
}
}
fold = List_Next(fold);
}
if (! ok)
goto finish;
//
// ignore files that begin with ~$ (Microsoft Office temp files)
// or that don't have a file type extension (probably temp files)
//
if (File_MsoDllLoaded) {
ptr = wcsrchr(TruePath, L'\\');
if (ptr) {
if (ptr[1] == L'~' && ptr[2] == L'$')
ok = FALSE;
else {
ptr = wcschr(ptr, L'.');
if (! ptr)
ok = FALSE;
}
if (! ok)
goto finish;
}
}
//
// look for TruePath in the list of AutoRecoverIgnore settings
//
TruePath_len = wcslen(TruePath);
fold = List_Head(&File_RecoverIgnores);
while (fold) {
if (_wcsnicmp(fold->path, TruePath, fold->path_len) == 0) {
ptr = TruePath + fold->path_len;
if (*ptr == L'\\' || *ptr == L'\0') {
ok = FALSE;
break;
}
}
if (TruePath_len >= fold->path_len) {
ptr = TruePath + TruePath_len - fold->path_len;
if (_wcsicmp(fold->path, ptr) == 0) {
ok = FALSE;
break;
}
}
fold = List_Next(fold);
}
//
// finish
//
finish:
if (TruePath != save_TruePath)
Dll_Free((WCHAR *)TruePath);
return ok;
}
//---------------------------------------------------------------------------
// File_RecordRecover
//---------------------------------------------------------------------------
_FX BOOLEAN File_RecordRecover(HANDLE FileHandle, const WCHAR *TruePath)
{
BOOLEAN IsRecoverable;
IsRecoverable = File_IsRecoverable(TruePath);
//
// in a Chrome sandbox process, handles are opened by the broker,
// so skip checking against the list of recorded file handles
//
// Note: this does not seam to be required anymore
//if ((! IsRecoverable) && Dll_ChromeSandbox) {
//
// FILE_ACCESS_INFORMATION info;
//
// status = __sys_NtQueryInformationFile(
// FileHandle, &IoStatusBlock, &info,
// sizeof(FILE_ACCESS_INFORMATION), FileAccessInformation);
//
// if (NT_SUCCESS(status) && (info.AccessFlags & FILE_WRITE_DATA))
// IsRecoverable = 2; //TRUE; // we still want to return false when called from File_NtCreateFileImpl
// else
// IsRecoverable = FALSE;
//}
if (IsRecoverable != FALSE)
Handle_RegisterCloseHandler(FileHandle, File_NotifyRecover);
return IsRecoverable == TRUE;
}
//---------------------------------------------------------------------------
// File_NotifyRecover
//---------------------------------------------------------------------------
_FX void File_NotifyRecover(HANDLE FileHandle)
{
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
NTSTATUS status;
union {
FILE_NETWORK_OPEN_INFORMATION open;
ULONG space[16];
} info;
ULONG length;
ULONG FileFlags;
UNICODE_STRING uni;
WCHAR *TruePath, *CopyPath;
IO_STATUS_BLOCK IoStatusBlock;
//
// send request to SbieCtrl (if recoverable file)
//
Dll_PushTlsNameBuffer(TlsData);
do {
RtlInitUnicodeString(&uni, L"");
status = File_GetName(
FileHandle, &uni, &TruePath, &CopyPath, &FileFlags);
if (! NT_SUCCESS(status))
break;
if (! (FileFlags & FGN_IS_BOXED_PATH))
break;
//
// Immediate Recovery
//
if (!File_IsRecoverable(TruePath))
break;
status = __sys_NtQueryInformationFile(
FileHandle, &IoStatusBlock, &info,
sizeof(FILE_NETWORK_OPEN_INFORMATION),
FileNetworkOpenInformation);
if (! NT_SUCCESS(status))
break;
if (info.open.EndOfFile.QuadPart == 0)
break;
//
// queue immediate recovery elements for later processing
//
FILE_RECOVER_FOLDER *rec;
ULONG TruePath_len;
EnterCriticalSection(&File_RecHandles_CritSec);
TruePath_len = wcslen(TruePath);
rec = List_Head(&File_RecPaths);
while (rec) {
if (rec->path_len == TruePath_len)
if (_wcsicmp(rec->path, TruePath) == 0)
break;
rec = List_Next(rec);
}
if (! rec) {
length = sizeof(FILE_RECOVER_FOLDER)
+ (TruePath_len + 1) * sizeof(WCHAR);
rec = Dll_Alloc(length);
rec->ticks = GetTickCount();
wcscpy(rec->path, TruePath);
rec->path_len = TruePath_len;
List_Insert_After(&File_RecPaths, NULL, rec);
}
LeaveCriticalSection(&File_RecHandles_CritSec);
if (rec)
File_DoAutoRecover(TRUE);
} while (0);
Dll_PopTlsNameBuffer(TlsData);
}
//---------------------------------------------------------------------------
// File_DoAutoRecover
//---------------------------------------------------------------------------
_FX void File_DoAutoRecover(BOOLEAN force)
{
static ULONG last_ticks = 0;
ULONG LastError;
THREAD_DATA *TlsData = Dll_GetTlsData(&LastError);
ULONG ticks = GetTickCount();
if (force || (ticks - last_ticks > 400)) {
last_ticks = ticks;
if (TryEnterCriticalSection(&File_RecHandles_CritSec)) {
if (List_Head(&File_RecPaths)) {
Dll_PushTlsNameBuffer(TlsData);
File_DoAutoRecover_2(force, ticks);
Dll_PopTlsNameBuffer(TlsData);
}
LeaveCriticalSection(&File_RecHandles_CritSec);
}
}
SetLastError(LastError);
}
//---------------------------------------------------------------------------
// File_DoAutoRecover_2
//---------------------------------------------------------------------------
_FX void File_DoAutoRecover_2(BOOLEAN force, ULONG ticks)
{
NTSTATUS status;
SYSTEM_HANDLE_INFORMATION *info = NULL;
FILE_GET_ALL_HANDLES_RPL *rpl = NULL;
ULONG info_len = 64, len, i;
WCHAR *pathbuf;
ULONG UseCount = 0;
FILE_RECOVER_FOLDER *rec;
UCHAR FileObjectTypeNumber = 0;
//
// get list of open handles in the system
//
for (i = 0; i < 5; ++i) {
info = Dll_AllocTemp(info_len);
status = NtQuerySystemInformation(
SystemHandleInformation, info, info_len, &len);
if (NT_SUCCESS(status))
break;
Dll_Free(info);
info_len = len + 64;
if (status == STATUS_BUFFER_OVERFLOW ||
status == STATUS_INFO_LENGTH_MISMATCH ||
status == STATUS_BUFFER_TOO_SMALL) {
continue;
}
break;
}
if (!Dll_CompartmentMode) // NoServiceAssist // don't try that in app mode, we had a proepr token
if (status == STATUS_ACCESS_DENIED) {
//
// on Windows 8.1, NtQuerySystemInformation fails, probably because
// we are running without any privileges, so go through SbieSvc
//
MSG_HEADER req;
req.length = sizeof(req);
req.msgid = MSGID_FILE_GET_ALL_HANDLES;
rpl = (FILE_GET_ALL_HANDLES_RPL *)SbieDll_CallServer(&req);
if (rpl) {
info = NULL;
status = STATUS_SUCCESS;
}
}
if (! NT_SUCCESS(status))
return;
pathbuf = Dll_AllocTemp(1024);
//
// scan list of queued recovery files
//
rec = List_Head(&File_RecPaths);
while (rec) {
FILE_RECOVER_FOLDER *rec_next = List_Next(rec);
BOOLEAN send2199 = FALSE;
if (force)
send2199 = TRUE;
else {
if (ticks - rec->ticks >= 1000) {
ULONG UseCount = File_DoAutoRecover_3(
rec->path, pathbuf, info, rpl, &FileObjectTypeNumber);
if (UseCount == 0)
send2199 = TRUE;
}
}
if (send2199) {
WCHAR *colon = wcschr(rec->path, L':');
if (!colon) {
UNICODE_STRING uni;
WCHAR *TruePath, *CopyPath;
RtlInitUnicodeString(&uni, rec->path);
status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL);
const WCHAR* strings[] = { Dll_BoxName, rec->path, CopyPath, NULL };
SbieApi_LogMsgExt(2199, strings);
}
List_Remove(&File_RecPaths, rec);
}
rec = rec_next;
}
//
// finish
//
Dll_Free(pathbuf);
if (info)
Dll_Free(info);
if (rpl)
Dll_Free(rpl);
}
//---------------------------------------------------------------------------
// File_DoAutoRecover_3
//---------------------------------------------------------------------------
_FX ULONG File_DoAutoRecover_3(
const WCHAR *PathToFind, WCHAR *PathBuf1024,
SYSTEM_HANDLE_INFORMATION *info, FILE_GET_ALL_HANDLES_RPL *rpl,
UCHAR *FileObjectTypeNumber)
{
HANDLE FileHandle;
ULONG UseCount, i;
//
// scan handles for current process
//
UseCount = 0;
if (info) {
for (i = 0; i < info->Count; ++i) {
HANDLE_INFO *hi = &info->HandleInfo[i];
if (hi->ProcessId != Dll_ProcessId)
continue;
FileHandle = (HANDLE)(ULONG_PTR)hi->Handle;
UseCount += File_DoAutoRecover_4(
PathToFind, PathBuf1024,
FileHandle, hi->ObjectTypeNumber, FileObjectTypeNumber);
}
} else if (rpl) {
for (i = 0; i < rpl->num_handles; ++i) {
UCHAR objtype = (UCHAR)(rpl->handles[i] >> 24);
FileHandle = (HANDLE)(ULONG_PTR)(rpl->handles[i] & 0x00FFFFFFU);
UseCount += File_DoAutoRecover_4(
PathToFind, PathBuf1024,
FileHandle, objtype, FileObjectTypeNumber);
}
}
return UseCount;
}
//---------------------------------------------------------------------------
// File_DoAutoRecover_4
//---------------------------------------------------------------------------
_FX ULONG File_DoAutoRecover_4(
const WCHAR *PathToFind, WCHAR *PathBuf1024,
HANDLE FileHandle, UCHAR ObjectTypeNumber, UCHAR *FileObjectTypeNumber)
{
UNICODE_STRING uni;
WCHAR *TruePath, *CopyPath;
NTSTATUS status;
//
// make sure the handle is to a file
//
if (*FileObjectTypeNumber) {
if (ObjectTypeNumber != *FileObjectTypeNumber)
return 0;
} else {
if (Obj_GetObjectType(FileHandle) == OBJ_TYPE_FILE) {
*FileObjectTypeNumber = ObjectTypeNumber;
} else
return 0;
}
//
// get file name
//
status = File_GetFileName(FileHandle, 1000, PathBuf1024);
if (! NT_SUCCESS(status))
return 0;
RtlInitUnicodeString(&uni, PathBuf1024);
status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL);
if (! NT_SUCCESS(status))
return 0;
if (_wcsicmp(PathToFind, TruePath) == 0)
return 1;
return 0;
}
//---------------------------------------------------------------------------
// File_MsoDll
//---------------------------------------------------------------------------
_FX BOOLEAN File_MsoDll(HMODULE module)
{
//
// hack for File_IsRecoverable
//
File_MsoDllLoaded = TRUE;
return TRUE;
}

View File

@ -0,0 +1,499 @@
/*
* Copyright 2020-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// File (Snapshot)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Defines
//---------------------------------------------------------------------------
#define FILE_MAX_SNAPSHOT_ID 17
#define FILE_INSNAPSHOT_FLAG 0x0004
//---------------------------------------------------------------------------
// Structures and Types
//---------------------------------------------------------------------------
typedef struct _FILE_SNAPSHOT {
WCHAR ID[FILE_MAX_SNAPSHOT_ID];
ULONG IDlen;
ULONG ScramKey;
//WCHAR Name[34];
struct _FILE_SNAPSHOT* Parent;
LIST PathRoot;
} FILE_SNAPSHOT, *PFILE_SNAPSHOT;
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
static const WCHAR* File_Snapshot_Prefix = L"snapshot-";
static const ULONG File_Snapshot_PrefixLen = 9; // wcslen(File_Snapshot_Prefix);
static FILE_SNAPSHOT *File_Snapshot = NULL;
static ULONG File_Snapshot_Count = 0;
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
static void File_ScrambleShortName(WCHAR* ShortName, CCHAR* ShortNameLength, ULONG ScramKey);
static void File_UnScrambleShortName(WCHAR* ShortName, ULONG ScramKey);
static WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, const WCHAR* CopyPath);
static WCHAR* File_FindSnapshotPath(WCHAR* CopyPath);
static WCHAR* File_ResolveTruePath(WCHAR* TruePath, WCHAR* CopyPath, ULONG* pFlags);
static ULONG File_IsDeletedEx(const WCHAR* TruePath, const WCHAR* CopyPath, FILE_SNAPSHOT* snapshot);
static void File_InitSnapshots(void);
//---------------------------------------------------------------------------
// File_Scramble_Char
//---------------------------------------------------------------------------
_FX WCHAR File_Scramble_Char(WCHAR wValue, int Key, BOOLEAN scram)
{
//
// This function allows to scramble file name charakters properly,
// i.e. no invalid cahacters can result fron this operation.
// It does not scramble invalid charakters like: " * / : < > ? \ |
// And it does not scramble ~
// The entropy of the scrambler is 25,5bit (i.e. 52 million values)
//
char reserved_ch[] = { '\"', '*', '/', ':', '<', '>', '?', '\\', '|' };
const int reserved_count = 9;
const int max_ch = 0x7E - reserved_count - 0x20;
int uValue = (wValue & 0x7F);
if (uValue < 0x20 || uValue >= 0x7E) // < space || >= ~
return wValue;
for (int i = 0; i < reserved_count; i++)
if (uValue == reserved_ch[i]) return wValue;
Key &= 0x7f;
while (Key >= max_ch)
Key -= max_ch;
if (!scram)
Key = -Key;
for (int i = 1; i <= reserved_count; i++)
if (uValue > reserved_ch[reserved_count - i]) uValue -= 1;
uValue -= 0x20;
uValue += Key;
if (uValue >= max_ch)
uValue -= max_ch;
else if (uValue < 0)
uValue += max_ch;
uValue += 0x20;
for (int i = 0; i < reserved_count; i++)
if (uValue >= reserved_ch[i]) uValue += 1;
return uValue;
}
//---------------------------------------------------------------------------
// File_ScrambleShortName
//---------------------------------------------------------------------------
_FX void File_ScrambleShortName(WCHAR* ShortName, CCHAR* ShortNameBytes, ULONG ScramKey)
{
CCHAR ShortNameLength = *ShortNameBytes / sizeof(WCHAR);
CCHAR dot_pos;
WCHAR *dot = wcsrchr(ShortName, L'.');
if (dot == NULL) {
dot_pos = ShortNameLength;
if (ShortNameLength >= 12)
return; // this should never not happen!
ShortName[ShortNameLength++] = L'.';
}
else
dot_pos = (CCHAR)(dot - ShortName);
while (ShortNameLength - dot_pos < 4)
{
if (ShortNameLength >= 12)
return; // this should never not happen!
ShortName[ShortNameLength++] = L' ';
}
*ShortNameBytes = ShortNameLength * sizeof(WCHAR);
if (dot_pos > 0)
ShortName[dot_pos - 1] = File_Scramble_Char(ShortName[dot_pos - 1], ((char*)&ScramKey)[0], TRUE);
for (int i = 1; i <= 3; i++)
ShortName[dot_pos + i] = File_Scramble_Char(ShortName[dot_pos + i], ((char*)&ScramKey)[i], TRUE);
}
//---------------------------------------------------------------------------
// File_UnScrambleShortName
//---------------------------------------------------------------------------
_FX void File_UnScrambleShortName(WCHAR* ShortName, ULONG ScramKey)
{
CCHAR ShortNameLength = (CCHAR)wcslen(ShortName);
WCHAR *dot = wcsrchr(ShortName, L'.');
if (dot == NULL)
return; // not a scrambled short name.
CCHAR dot_pos = (CCHAR)(dot - ShortName);
if (dot_pos > 0)
ShortName[dot_pos - 1] = File_Scramble_Char(ShortName[dot_pos - 1], ((char*)&ScramKey)[0], FALSE);
for (int i = 1; i <= 3; i++)
ShortName[dot_pos + i] = File_Scramble_Char(ShortName[dot_pos + i], ((char*)&ScramKey)[i], FALSE);
while (ShortName[ShortNameLength - 1] == L' ')
ShortName[ShortNameLength-- - 1] = 0;
if (ShortName[ShortNameLength - 1] == L'.')
ShortName[ShortNameLength-- - 1] = 0;
}
//---------------------------------------------------------------------------
// File_MakeSnapshotPath
//---------------------------------------------------------------------------
_FX WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, const WCHAR* CopyPath)
{
if (!Cur_Snapshot)
return NULL;
ULONG prefixLen = File_FindBoxPrefixLength(CopyPath);
if (prefixLen == 0)
return NULL;
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
WCHAR* TmplName = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER, (wcslen(CopyPath) + File_Snapshot_PrefixLen + FILE_MAX_SNAPSHOT_ID + 1) * sizeof(WCHAR));
wcsncpy(TmplName, CopyPath, prefixLen + 1);
wcscpy(TmplName + prefixLen + 1, File_Snapshot_Prefix);
wcscpy(TmplName + prefixLen + 1 + File_Snapshot_PrefixLen, Cur_Snapshot->ID);
wcscpy(TmplName + prefixLen + 1 + File_Snapshot_PrefixLen + Cur_Snapshot->IDlen, CopyPath + prefixLen);
return TmplName;
}
//---------------------------------------------------------------------------
// File_FindSnapshotPath
//---------------------------------------------------------------------------
_FX WCHAR* File_FindSnapshotPath(WCHAR* CopyPath)
{
NTSTATUS status;
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING objname;
ULONG FileType;
InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
//
// When working with snapshots the actual "CopyFile" may be located in a snapshot directory.
// To deal with that when the file is not in the active box directory we look through the snapshots,
// When we find it we update the path to point to the snapshot containing the file.
//
RtlInitUnicodeString(&objname, CopyPath);
status = File_GetFileType(&objattrs, FALSE, &FileType, NULL);
if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND))
return NULL; // file is present directly in copy path
for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != NULL; Cur_Snapshot = Cur_Snapshot->Parent)
{
WCHAR* TmplName = File_MakeSnapshotPath(Cur_Snapshot, CopyPath);
if (!TmplName)
break;
RtlInitUnicodeString(&objname, TmplName);
status = File_GetFileType(&objattrs, FALSE, &FileType, NULL);
if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND))
{
return TmplName;
}
}
return NULL; // this file is not in any snapshot
}
//---------------------------------------------------------------------------
// File_GetPathFlagsEx
//---------------------------------------------------------------------------
_FX ULONG File_GetPathFlagsEx(const WCHAR *TruePath, const WCHAR *CopyPath, WCHAR** pRelocation, FILE_SNAPSHOT* lastSnapshot)
{
ULONG Flags = 0;
WCHAR* Relocation = NULL;
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
if (File_Delete_v2)
{
File_RefreshPathTree();
if(!pRelocation)
Dll_PushTlsNameBuffer(TlsData);
EnterCriticalSection(File_PathRoot_CritSec);
//
// check true path relocation and deleteion for the active state
//
Flags = File_GetPathFlags_internal(&File_PathRoot, TruePath, &Relocation, TRUE); // this requires a name buffer
if (FILE_PATH_DELETED(Flags))
goto finish;
}
if (!File_Snapshot)
{
if (pRelocation) *pRelocation = Relocation; // return a MISC_NAME_BUFFER buffer valid at the current name buffer depth
goto finish;
}
//
// Handle snapshots
//
NTSTATUS status;
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING objname;
ULONG FileType;
InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
//
// we need a few helper buffers here, to make it efficient we will exploit
// an implementation artefact of the TlsNameBuffer mechanism, namely
// the property that after a pop the buffers remain valid untill the next push
//
// so we can pop out of the current frame request a buffer of the required size
// and still read from the buffer that was filled in the previosue frame
//
Dll_PushTlsNameBuffer(TlsData);
WCHAR* TmplRelocation = Relocation;
for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != lastSnapshot; Cur_Snapshot = Cur_Snapshot->Parent)
{
if (TmplRelocation)
{
//
// update the true file name
//
TruePath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, (wcslen(TmplRelocation) + 1) * sizeof(WCHAR));
wcscpy((WCHAR*)TruePath, TmplRelocation);
if (CopyPath)
{
//
// update the copy file name
//
Dll_PushTlsNameBuffer(TlsData);
WCHAR* TruePath2, * CopyPath2;
RtlInitUnicodeString(&objname, TmplRelocation);
File_GetName(NULL, &objname, &TruePath2, &CopyPath2, NULL);
Dll_PopTlsNameBuffer(TlsData);
// note: pop leaves TruePath2 valid we can still use it
CopyPath = Dll_GetTlsNameBuffer(TlsData, COPY_NAME_BUFFER, (wcslen(CopyPath2) + 1) * sizeof(WCHAR));
wcscpy((WCHAR*)CopyPath, CopyPath2);
}
}
if (CopyPath)
{
//
// check if the specified file is present in the current snapshot
//
WCHAR* TmplName = File_MakeSnapshotPath(Cur_Snapshot, CopyPath);
if (!TmplName)
break; // something went wrong
RtlInitUnicodeString(&objname, TmplName);
status = File_GetFileType(&objattrs, FALSE, &FileType, NULL);
if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND))
{
Flags |= FILE_INSNAPSHOT_FLAG;
Relocation = TmplName;
goto complete;
}
}
if (File_Delete_v2)
{
//
// check true path relocation and deleteion for the current snapshot
//
TmplRelocation = NULL;
Flags = File_GetPathFlags_internal(&Cur_Snapshot->PathRoot, TruePath, &TmplRelocation, TRUE);
if(TmplRelocation)
Relocation = TmplRelocation;
if (FILE_PATH_DELETED(Flags))
goto complete;
}
}
complete:
Dll_PopTlsNameBuffer(TlsData);
// note: pop leaves the buffers valid we can still use them
if (pRelocation && Relocation) // return a new TMPL_NAME_BUFFER buffer valid at the current name buffer depth
{
*pRelocation = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER, (wcslen(Relocation) + 1) * sizeof(WCHAR));
wcscpy(*pRelocation, Relocation);
}
finish:
if (File_Delete_v2)
{
LeaveCriticalSection(File_PathRoot_CritSec);
if(!pRelocation)
Dll_PopTlsNameBuffer(TlsData);
}
return Flags;
}
//---------------------------------------------------------------------------
// File_ResolveTruePath
//---------------------------------------------------------------------------
_FX WCHAR* File_ResolveTruePath(WCHAR *TruePath, WCHAR *CopyPath, ULONG* pFlags)
{
WCHAR* Relocation = NULL;
ULONG Flags = File_GetPathFlagsEx(TruePath, CopyPath, &Relocation, NULL);
if (pFlags) *pFlags = Flags;
return Relocation;
}
//---------------------------------------------------------------------------
// File_IsDeletedEx
//---------------------------------------------------------------------------
_FX ULONG File_IsDeletedEx(const WCHAR* TruePath, const WCHAR* CopyPath, FILE_SNAPSHOT* snapshot)
{
ULONG Flags = File_GetPathFlagsEx(TruePath, CopyPath, NULL, snapshot);
return (Flags & FILE_DELETED_MASK);
}
//---------------------------------------------------------------------------
// File_InitSnapshots
//---------------------------------------------------------------------------
// CRC
#define CRC_WITH_ADLERTZUK64
#include "common/crc.c"
_FX void File_InitSnapshots(void)
{
WCHAR ShapshotsIni[MAX_PATH] = { 0 };
wcscpy(ShapshotsIni, Dll_BoxFilePath);
wcscat(ShapshotsIni, L"\\Snapshots.ini");
SbieDll_TranslateNtToDosPath(ShapshotsIni);
WCHAR Shapshot[FILE_MAX_SNAPSHOT_ID] = { 0 };
GetPrivateProfileStringW(L"Current", L"Snapshot", L"", Shapshot, FILE_MAX_SNAPSHOT_ID, ShapshotsIni);
if (*Shapshot == 0)
return; // not using snapshots
File_Snapshot = Dll_Alloc(sizeof(FILE_SNAPSHOT));
memzero(File_Snapshot, sizeof(FILE_SNAPSHOT));
wcscpy(File_Snapshot->ID, Shapshot);
File_Snapshot->IDlen = wcslen(Shapshot);
FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot;
File_Snapshot_Count = 1;
for (;;)
{
Cur_Snapshot->ScramKey = CRC32(Cur_Snapshot->ID, Cur_Snapshot->IDlen * sizeof(WCHAR));
WCHAR ShapshotId[26] = L"Snapshot_";
wcscat(ShapshotId, Shapshot);
if (File_Delete_v2)
{
WCHAR PathFile[MAX_PATH];
wcscpy(PathFile, File_Snapshot_Prefix);
wcscat(PathFile, Cur_Snapshot->ID);
wcscat(PathFile, L"\\");
wcscat(PathFile, FILE_PATH_FILE_NAME);
File_LoadPathTree_internal(&Cur_Snapshot->PathRoot, PathFile);
}
//WCHAR ShapshotName[34] = { 0 };
//GetPrivateProfileStringW(ShapshotId, L"Name", L"", ShapshotName, 34, ShapshotsIni);
//wcscpy(Cur_Snapshot->Name, ShapshotName);
GetPrivateProfileStringW(ShapshotId, L"Parent", L"", Shapshot, 16, ShapshotsIni);
if (*Shapshot == 0)
break; // no more snapshots
Cur_Snapshot->Parent = Dll_Alloc(sizeof(FILE_SNAPSHOT));
memzero(Cur_Snapshot->Parent, sizeof(FILE_SNAPSHOT));
wcscpy(Cur_Snapshot->Parent->ID, Shapshot);
Cur_Snapshot->Parent->IDlen = wcslen(Shapshot);
Cur_Snapshot = Cur_Snapshot->Parent;
File_Snapshot_Count++;
}
}

View File

@ -66,7 +66,7 @@ static ULONG Gdi_CreateScalableFontResourceW(
static void Gdi_AddFontsInBox(void);
static void Gdi_AddFontsInBox_2(
HANDLE hFontsDir, void *buf8k, WCHAR *WinFonts);
HANDLE hFontsDir, WCHAR *WinFonts);
static int Gdi_EnumFontFamiliesExA(
HDC hdc, void *lpLogfont, void *lpEnumFontFamExProc,
@ -618,15 +618,13 @@ _FX void Gdi_AddFontsInBox(void)
if (hFile != INVALID_HANDLE_VALUE) {
WCHAR *path1 = Dll_AllocTemp(8192);
BOOLEAN is_copy = FALSE;
NTSTATUS status = SbieDll_GetHandlePath(hFile, path1, &is_copy);
NTSTATUS status = SbieDll_GetHandlePath(hFile, NULL, &is_copy);
if (NT_SUCCESS(status) && is_copy) {
Gdi_AddFontsInBox_2(hFile, path1, WinFonts);
Gdi_AddFontsInBox_2(hFile, WinFonts);
}
Dll_Free(path1);
CloseHandle(hFile);
}
}
@ -642,7 +640,7 @@ _FX void Gdi_AddFontsInBox(void)
//---------------------------------------------------------------------------
_FX void Gdi_AddFontsInBox_2(HANDLE hFontsDir, void *buf8k, WCHAR *WinFonts)
_FX void Gdi_AddFontsInBox_2(HANDLE hFontsDir, WCHAR *WinFonts)
{
NTSTATUS status;
FILE_DIRECTORY_INFORMATION *info;
@ -651,6 +649,8 @@ _FX void Gdi_AddFontsInBox_2(HANDLE hFontsDir, void *buf8k, WCHAR *WinFonts)
ULONG WinFonts_len = wcslen(WinFonts);
WinFonts[WinFonts_len] = L'\\';
WCHAR *buf8k = Dll_AllocTemp(8192);
while (1) {
info = (FILE_DIRECTORY_INFORMATION *)buf8k;
@ -680,6 +680,8 @@ _FX void Gdi_AddFontsInBox_2(HANDLE hFontsDir, void *buf8k, WCHAR *WinFonts)
info = (FILE_DIRECTORY_INFORMATION *)next_entry;
}
}
Dll_Free(buf8k);
}

271
Sandboxie/core/dll/handle.c Normal file
View File

@ -0,0 +1,271 @@
/*
* Copyright 2021-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// Handle
//---------------------------------------------------------------------------
#define NOGDI
#include "dll.h"
#include "handle.h"
#include <stdio.h>
#include "debug.h"
#include "common/pool.h"
#include "common/map.h"
//---------------------------------------------------------------------------
// Structures and Types
//---------------------------------------------------------------------------
typedef struct _HANDLE_STATE {
BOOLEAN DeleteOnClose;
P_CloseHandler CloseHandlers[MAX_CLOSE_HANDLERS];
WCHAR* RelocationPath;
} HANDLE_STATE;
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
extern POOL* Dll_Pool;
static HASH_MAP Handle_StatusData;
static CRITICAL_SECTION Handle_StatusData_CritSec;
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Handle_Init
//---------------------------------------------------------------------------
_FX BOOLEAN Handle_Init(void)
{
InitializeCriticalSection(&Handle_StatusData_CritSec);
map_init(&Handle_StatusData, Dll_Pool);
return TRUE;
}
//---------------------------------------------------------------------------
// Handle_SetDeleteOnClose
//---------------------------------------------------------------------------
_FX VOID Handle_SetDeleteOnClose(HANDLE FileHandle, BOOLEAN DeleteOnClose)
{
EnterCriticalSection(&Handle_StatusData_CritSec);
HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle);
if (!state) {
state = map_insert(&Handle_StatusData, FileHandle, NULL, sizeof(HANDLE_STATE));
}
state->DeleteOnClose = DeleteOnClose;
LeaveCriticalSection(&Handle_StatusData_CritSec);
}
//---------------------------------------------------------------------------
// Handle_SetRelocationPath
//---------------------------------------------------------------------------
_FX VOID Handle_SetRelocationPath(HANDLE FileHandle, WCHAR* RelocationPath)
{
EnterCriticalSection(&Handle_StatusData_CritSec);
HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle);
if (!state) { // this shoudl always be the case, as we only use Handle_SetRelocationPath when the handle is first created
state = map_insert(&Handle_StatusData, FileHandle, NULL, sizeof(HANDLE_STATE));
} else if (state->RelocationPath) Dll_Free(state->RelocationPath); // should not happen but in case
state->RelocationPath = Dll_Alloc((wcslen(RelocationPath) + 1) * sizeof(WCHAR));
wcscpy(state->RelocationPath, RelocationPath);
LeaveCriticalSection(&Handle_StatusData_CritSec);
}
//---------------------------------------------------------------------------
// Handle_GetRelocationPath
//---------------------------------------------------------------------------
_FX WCHAR* Handle_GetRelocationPath(HANDLE FileHandle, ULONG ExtraLength)
{
WCHAR* name = NULL;
EnterCriticalSection(&Handle_StatusData_CritSec);
HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle);
if (state && state->RelocationPath) {
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
ULONG length = (wcslen(state->RelocationPath) + 1) * sizeof(WCHAR);
name = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, length + ExtraLength);
wcscpy(name, state->RelocationPath);
}
LeaveCriticalSection(&Handle_StatusData_CritSec);
return name;
}
//---------------------------------------------------------------------------
// Handle_FreeCloseHandler
//---------------------------------------------------------------------------
_FX BOOLEAN Handle_FreeCloseHandler(HANDLE FileHandle, P_CloseHandler* CloseHandlers, BOOLEAN* DeleteOnClose)
{
BOOLEAN HasCloseHandlers = FALSE;
EnterCriticalSection(&Handle_StatusData_CritSec);
HANDLE_STATE* state = (HANDLE_STATE*)map_get(&Handle_StatusData, FileHandle);
if (state) {
HasCloseHandlers = TRUE;
if(CloseHandlers)
memcpy(CloseHandlers, state->CloseHandlers, MAX_CLOSE_HANDLERS * sizeof(P_CloseHandler));
if(DeleteOnClose) *DeleteOnClose = state->DeleteOnClose;
if (state->RelocationPath) Dll_Free(state->RelocationPath);
}
map_remove(&Handle_StatusData, FileHandle);
LeaveCriticalSection(&Handle_StatusData_CritSec);
return HasCloseHandlers;
}
//---------------------------------------------------------------------------
// Handle_RegisterCloseHandler
//---------------------------------------------------------------------------
_FX BOOLEAN Handle_RegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler)
{
if (!FileHandle || FileHandle == (HANDLE)-1)
return FALSE;
ULONG i;
EnterCriticalSection(&Handle_StatusData_CritSec);
HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle);
if (!state) {
state = map_insert(&Handle_StatusData, FileHandle, NULL, sizeof(HANDLE_STATE));
}
for (i = 0; i < MAX_CLOSE_HANDLERS; i++) {
if (state->CloseHandlers[i] == CloseHandler)
break; // already registered
if (state->CloseHandlers[i] == NULL) {
state->CloseHandlers[i] = CloseHandler; // set to empty slot
break;
}
}
LeaveCriticalSection(&Handle_StatusData_CritSec);
if (i == MAX_CLOSE_HANDLERS) {
SbieApi_Log(2301, L"No free CloseHandlers slot available");
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
// Handle_UnRegisterCloseHandler
//---------------------------------------------------------------------------
_FX BOOLEAN Handle_UnRegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler)
{
ULONG i = MAX_CLOSE_HANDLERS;
EnterCriticalSection(&Handle_StatusData_CritSec);
HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle);
if (state) {
for (i = 0; i < MAX_CLOSE_HANDLERS; i++) {
if (state->CloseHandlers[i] == CloseHandler) {
state->CloseHandlers[i] = NULL; // clear slot
break;
}
}
}
LeaveCriticalSection(&Handle_StatusData_CritSec);
return i != MAX_CLOSE_HANDLERS;
}
//---------------------------------------------------------------------------
// Handle_SetupDuplicate
//---------------------------------------------------------------------------
_FX void Handle_SetupDuplicate(HANDLE OldFileHandle, HANDLE NewFileHandle)
{
ULONG i;
EnterCriticalSection(&Handle_StatusData_CritSec);
HANDLE_STATE* state = map_get(&Handle_StatusData, OldFileHandle);
if (state) {
if(state->RelocationPath)
Handle_SetRelocationPath(NewFileHandle, state->RelocationPath);
// todo: add a flag to each CloseHandlers entry to indicate if it should be propagated or not
BOOLEAN found = FALSE;
for (i = 0; i < MAX_CLOSE_HANDLERS; i++) {
if (state->CloseHandlers[i] == File_NotifyRecover) {
found = TRUE;
break;
}
}
if(found)
Handle_RegisterCloseHandler(NewFileHandle, File_NotifyRecover);
}
LeaveCriticalSection(&Handle_StatusData_CritSec);
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2021-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _MY_HANDLE_H
#define _MY_HANDLE_H
//---------------------------------------------------------------------------
// Defines
//---------------------------------------------------------------------------
#define MAX_CLOSE_HANDLERS 4
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
typedef void(*P_CloseHandler)(HANDLE handle);
VOID Handle_SetDeleteOnClose(HANDLE FileHandle, BOOLEAN DeleteOnClose);
BOOLEAN Handle_RegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler);
BOOLEAN Handle_UnRegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler);
VOID Handle_SetRelocationPath(HANDLE FileHandle, WCHAR* RelocationPath);
WCHAR* Handle_GetRelocationPath(HANDLE FileHandle, ULONG ExtraLength);
BOOLEAN Handle_FreeCloseHandler(HANDLE FileHandle, P_CloseHandler* CloseHandlers, BOOLEAN* DeleteOnClose);
//---------------------------------------------------------------------------
#endif /* _MY_HANDLE_H */

View File

@ -184,7 +184,6 @@ _FX BOOLEAN Hook_Tramp_CountBytes(
void *SysProc, ULONG *ByteCount, BOOLEAN is64, BOOLEAN probe)
{
UCHAR *addr = (UCHAR *)SysProc;
//ULONG needlen = (is64 == 9 ? 13 : (is64 ? 12 : (File_TrusteerLoaded()?6:5)));
ULONG needlen = (is64 ? 12 : 5);
ULONG copylen = 0;

View File

@ -404,6 +404,7 @@ _FX BOOLEAN Ipc_Init(void)
SBIEDLL_HOOK(Ipc_, NtImpersonateThread);
}
//if (!Dll_AlernateIpcNaming) // alternate naming does not need an own namespace
Ipc_CreateObjects();
List_Init(&Ipc_DynamicPortNames);
@ -550,6 +551,21 @@ _FX NTSTATUS Ipc_GetName(
if (ObjectName) {
objname_len = ObjectName->Length & ~1;
objname_buf = ObjectName->Buffer;
//if (Dll_AlernateIpcNaming) {
//
// //
// // Since in this mode we don't call Ipc_CreateObjects we dont have a boxed namespace
// // and are using existing namespaces only with a name suffix
// // hence we can't use Global without system provileges, so we strip it
// //
//
// if (_wcsnicmp(objname_buf, L"Global\\", 7) == 0) {
// objname_len -= 7;
// objname_buf += 7;
// }
//}
} else {
objname_len = 0;
objname_buf = NULL;
@ -690,6 +706,21 @@ _FX NTSTATUS Ipc_GetName(
check_sandbox_prefix:
//if (Dll_AlernateIpcNaming)
//{
// if (length >= Dll_BoxIpcPathLen &&
// 0 == Dll_NlsStrCmp(
// &(*OutTruePath)[length - Dll_BoxIpcPathLen], Dll_BoxIpcPath, Dll_BoxIpcPathLen))
// {
// (*OutTruePath)[length - Dll_BoxIpcPathLen] = L'\0';
// length -= Dll_BoxIpcPathLen;
// if (OutIsBoxedPath)
// *OutIsBoxedPath = TRUE;
//
// goto check_sandbox_prefix;
// }
//}
//else
if (length >= Dll_BoxIpcPathLen &&
0 == Dll_NlsStrCmp(
*OutTruePath, Dll_BoxIpcPath, Dll_BoxIpcPathLen))
@ -713,11 +744,23 @@ check_sandbox_prefix:
*OutCopyPath = name;
wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen);
name += Dll_BoxIpcPathLen;
//if (Dll_AlernateIpcNaming)
//{
// wmemcpy(name, *OutTruePath, length);
// name += length;
//
// wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen);
// name += Dll_BoxIpcPathLen;
//}
//else
{
wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen);
name += Dll_BoxIpcPathLen;
wmemcpy(name, *OutTruePath, length);
name += length;
}
wmemcpy(name, *OutTruePath, length);
name += length;
*name = L'\0';
//
@ -908,6 +951,9 @@ _FX NTSTATUS Ipc_CreatePath(WCHAR *TruePath, WCHAR *CopyPath)
UNICODE_STRING objname;
WCHAR *backslash;
//if (Dll_AlernateIpcNaming)
// return STATUS_OBJECT_PATH_NOT_FOUND;
//
// open the TruePath object directory containing the object
// for which we got STATUS_OBJECT_PATH_NOT_FOUND
@ -3450,15 +3496,11 @@ _FX BOOLEAN Ipc_IsKnownDllInSandbox(
if (NT_SUCCESS(status)) {
BOOLEAN IsBoxedPath;
WCHAR *path8k = Dll_AllocTemp(8192 * sizeof(WCHAR));
status = SbieDll_GetHandlePath(handle, path8k, &IsBoxedPath);
status = SbieDll_GetHandlePath(handle, NULL, &IsBoxedPath);
if (NT_SUCCESS(status) && IsBoxedPath)
is_known_dll_in_sandbox = TRUE;
Dll_Free(path8k);
NtClose(handle);
}
@ -3984,6 +4026,20 @@ _FX ULONG Ipc_NtQueryObjectName(UNICODE_STRING *ObjectName, ULONG MaxLen)
ULONG Len = ObjectName->Length;
WCHAR *Buf = ObjectName->Buffer;
//if (Dll_AlernateIpcNaming)
//{
// if (Len >= Dll_BoxIpcPathLen * sizeof(WCHAR) &&
// 0 == Dll_NlsStrCmp(&Buf[Len - Dll_BoxIpcPathLen], Dll_BoxIpcPath, Dll_BoxIpcPathLen)) {
//
// Buf[Len - Dll_BoxIpcPathLen] = L'\0';
//
// ObjectName->Length -= (USHORT)Dll_BoxIpcPathLen;
// ObjectName->MaximumLength = ObjectName->Length + sizeof(WCHAR);
//
// return ObjectName->MaximumLength;
// }
//}
//else
if (Len >= Dll_BoxIpcPathLen * sizeof(WCHAR) &&
0 == Dll_NlsStrCmp(Buf, Dll_BoxIpcPath, Dll_BoxIpcPathLen)) {

View File

@ -24,10 +24,11 @@
#define NOGDI
#include "dll.h"
#include "obj.h"
#include "handle.h"
#include "core/svc/FileWire.h"
#include "core/drv/api_defs.h"
#include <stdio.h>
#include "debug.h"
//---------------------------------------------------------------------------
// Defines
@ -306,6 +307,8 @@ static const WCHAR *Key_Wow6432Node = L"\\Wow6432Node\\";
static BOOLEAN Key_UseObjectNames = FALSE;
BOOLEAN Key_Delete_v2 = FALSE;
//---------------------------------------------------------------------------
// Debug Prints
//---------------------------------------------------------------------------
@ -338,6 +341,7 @@ static BOOLEAN Key_UseObjectNames = FALSE;
//---------------------------------------------------------------------------
#include "key_del.c"
#include "key_merge.c"
#include "key_util.c"
@ -358,6 +362,8 @@ _FX BOOLEAN Key_Init(void)
Key_UseObjectNames = SbieApi_QueryConfBool(NULL, L"UseObjectNameForKeys", FALSE);
Key_Delete_v2 = SbieApi_QueryConfBool(NULL, L"UseRegDeleteV2", FALSE);
List_Init(&Key_Handles);
List_Init(&Key_MergeCacheList);
@ -433,6 +439,7 @@ _FX NTSTATUS Key_GetName(
ULONG length;
WCHAR *name;
ULONG objname_len;
BOOLEAN is_boxed_path;
*OutTruePath = NULL;
*OutCopyPath = NULL;
@ -587,6 +594,8 @@ _FX NTSTATUS Key_GetName(
// and restore the "\REGISTRY" prefix that would have been lost.
//
is_boxed_path = FALSE;
check_sandbox_prefix:
if (length >= Dll_BoxKeyPathLen &&
@ -598,6 +607,7 @@ check_sandbox_prefix:
length -= Dll_BoxKeyPathLen - Key_RegistryLen;
if (OutIsBoxedPath)
*OutIsBoxedPath = TRUE;
is_boxed_path = TRUE;
goto check_sandbox_prefix;
}
@ -651,6 +661,33 @@ check_sandbox_prefix:
return STATUS_OBJECT_NAME_NOT_FOUND;
}
//
// if this is a unboxed path, and we opened it by object,
// check path relocation and update true path accordingly.
//
if (!is_boxed_path && RootDirectory) {
name = Handle_GetRelocationPath(RootDirectory, objname_len);
if (name) {
*OutTruePath = name;
name = (*OutTruePath) + wcslen(*OutTruePath);
if (objname_len) {
*name = L'\\';
++name;
memcpy(name, ObjectName->Buffer, objname_len);
name += objname_len / sizeof(WCHAR);
}
*name = L'\0';
}
}
//
// now create the copy path, which is the box prefix prepended
// to the true path that we have. note that the copy path will
@ -1096,6 +1133,41 @@ _FX NTSTATUS Key_NtCreateKey(
//---------------------------------------------------------------------------
#ifdef WITH_DEBUG_
static P_NtCreateKey __sys_NtCreateKey_ = NULL;
_FX NTSTATUS Key_MyCreateKey(
HANDLE *KeyHandle,
ACCESS_MASK DesiredAccess,
OBJECT_ATTRIBUTES *ObjectAttributes,
ULONG TitleIndex,
UNICODE_STRING *Class,
ULONG CreateOptions,
ULONG *Disposition)
{
ULONG Disposition_ = 0;
if (!Disposition)
Disposition = &Disposition_;
NTSTATUS status = __sys_NtCreateKey_(
KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex,
Class, CreateOptions, Disposition);
if (*Disposition == REG_CREATED_NEW_KEY) {
while (! IsDebuggerPresent()) { OutputDebugString(L"BREAK\n"); Sleep(500); }
__debugbreak();
}
//if (NT_SUCCESS(status)) DbgPrint("%p: %p\r\n", _ReturnAddress(), *KeyHandle);
status = StopTailCallOptimization(status);
return status;
}
#endif
_FX NTSTATUS Key_NtCreateKeyImpl(
HANDLE *KeyHandle,
ACCESS_MASK DesiredAccess,
@ -1120,6 +1192,17 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
BOOLEAN CopyPathCreated;
BOOLEAN TruePathExists;
PSECURITY_DESCRIPTOR *OverrideSecurityDescriptor;
ULONG TruePathFlags;
WCHAR* OriginalPath;
BOOLEAN TrueOpened;
#ifdef WITH_DEBUG_
if (__sys_NtCreateKey_ == NULL)
{
__sys_NtCreateKey_ = __sys_NtCreateKey;
__sys_NtCreateKey = Key_MyCreateKey;
}
#endif
//
// if this is a recursive invocation of NtCreateKey,
@ -1147,6 +1230,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
CopyPathCreated = FALSE;
TruePathExists = FALSE;
OriginalPath = NULL;
TrueOpened = FALSE;
TlsData->key_NtCreateKey_lock = TRUE;
@ -1226,6 +1311,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
}
}
if (NT_SUCCESS(status)) TrueOpened = TRUE;
__leave;
#undef KEY_READ_WOW64
@ -1257,6 +1344,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
Wow64KeyReadAccess = Key_GetWow64Flag(TruePath, KEY_READ);
RtlInitUnicodeString(&objname, CopyPath);
//
// first we try to create or open CopyPath with whatever DesiredAccess
// the caller specified. if this succeeds, then CopyPath must exist
@ -1264,8 +1353,7 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
// we also check that the parent of the key is not marked deleted.
//
RtlInitUnicodeString(&objname, CopyPath);
if (!Key_Delete_v2)
if (Key_CheckDeletedParent(CopyPath)) {
//
@ -1351,9 +1439,12 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
if (NT_SUCCESS(status)) {
BOOLEAN KeyDeleted = Key_CheckDeletedKey(*KeyHandle);
BOOLEAN KeyDeleted = FALSE;
if (KeyDeleted) {
if (!Key_Delete_v2)
if (Key_CheckDeletedKey(*KeyHandle)) {
KeyDeleted = TRUE;
if (CreateOptions == tzuk) {
@ -1418,6 +1509,28 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
__leave;
}
//
// Check true path relocation
//
TruePathFlags = 0;
if (Key_Delete_v2) {
WCHAR* OldTruePath = Key_ResolveTruePath(TruePath, &TruePathFlags);
if (OldTruePath) {
OriginalPath = TruePath;
TruePath = OldTruePath;
}
// if key marked as deleted dont even try opening true path
if (KEY_PATH_DELETED(TruePathFlags) && CreateOptions == tzuk) {
status = STATUS_OBJECT_NAME_NOT_FOUND;
__leave;
}
}
//
// if we're successful, or we got any of the three status codes
// that we don't handle, then stop here
@ -1465,6 +1578,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
if (NT_SUCCESS(status)) {
TrueOpened = TRUE;
//
// if the TruePath key exists, and caller is asking for
// read-only (*) access to this key, then return the handle
@ -1476,9 +1591,13 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
// the reason is that if NtSetValueKey has to re-open this key
// for write access, it would not be able to pass the WOW64 flag
//
// this special case makes IMHO no sense, wow registry redirection
// acts only on specific paths, and our sanboxed paths do not fall
// into that category, hence thay dont need KEY_WOW64_xxKEY flags!
//
if (OriginalDesiredAccess & (KEY_WOW64_32KEY | KEY_WOW64_64KEY))
goto SkipReadOnlyCheck;
//if (OriginalDesiredAccess & (KEY_WOW64_32KEY | KEY_WOW64_64KEY))
// goto SkipReadOnlyCheck;
if (((DesiredAccess & ~MAXIMUM_ALLOWED) & KEY_DENIED_ACCESS) == 0) {
@ -1615,6 +1734,8 @@ SkipReadOnlyCheck:
status = __sys_NtOpenKey(
KeyHandle, DesiredAccess, ObjectAttributes);
if (NT_SUCCESS(status)) TrueOpened = TRUE; // is that right?
if (NT_SUCCESS(status) && Disposition)
*Disposition = REG_OPENED_EXISTING_KEY;
}
@ -1628,6 +1749,20 @@ SkipReadOnlyCheck:
if (CopyPathCreated)
Key_DiscardMergeByPath(TruePath, TRUE);
//
// Relocation, if we opened a relocated location we need to
// store the original true path for the Key_GetName function
//
if (TrueOpened && OriginalPath) {
Handle_SetRelocationPath(*KeyHandle, OriginalPath);
}
//
// finish
//
Dll_PopTlsNameBuffer(TlsData);
TlsData->key_NtCreateKey_lock = FALSE;
@ -1655,6 +1790,34 @@ _FX NTSTATUS Key_CreatePath(
USHORT savemaximumlength;
ULONG disp;
if (Key_Delete_v2) {
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
BOOLEAN ParentDeleted = FALSE;
WCHAR *TruePath;
WCHAR *CopyPath;
Dll_PushTlsNameBuffer(TlsData);
__try {
status = Key_GetName(NULL, objattrs->ObjectName, &TruePath, &CopyPath, NULL);
} __except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
if (NT_SUCCESS(status)) {
ParentDeleted = KEY_PARENT_DELETED(Key_IsDeleted_v2(TruePath));
}
Dll_PopTlsNameBuffer(TlsData);
if(ParentDeleted)
return STATUS_OBJECT_NAME_NOT_FOUND;
}
//
// first we traverse backward along the path, removing the last
// path component each time, and trying to create the path that
@ -1703,6 +1866,7 @@ _FX NTSTATUS Key_CreatePath(
if (NT_SUCCESS(status)) {
if (!Key_Delete_v2)
if (disp == REG_OPENED_EXISTING_KEY) {
if (Key_CheckDeletedKey(handle)) {
@ -2044,7 +2208,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, &objattrs);
status = Key_NtOpenKeyImpl(&handle, GENERIC_WRITE | KEY_READ | DELETE, &objattrs);
if (! NT_SUCCESS(status))
__leave;
@ -2183,17 +2347,51 @@ _FX NTSTATUS Key_MarkDeletedAndClose(HANDLE KeyHandle)
// mark key deleted by setting its last write time information
//
kwti.LastWriteTime.HighPart = DELETE_MARK_HIGH;
kwti.LastWriteTime.LowPart = DELETE_MARK_LOW;
status = NtSetInformationKey(
KeyHandle, KeyWriteTimeInformation,
&kwti, sizeof(KEY_WRITE_TIME_INFORMATION));
if (Key_Delete_v2) {
//
// refresh all merges
//
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
Key_DiscardMergeByHandle(TlsData, KeyHandle, TRUE);
UNICODE_STRING objname;
WCHAR *TruePath;
WCHAR *CopyPath;
Dll_PushTlsNameBuffer(TlsData);
RtlInitUnicodeString(&objname, L"");
__try {
status = Key_GetName(KeyHandle, &objname, &TruePath, &CopyPath, NULL);
} __except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
if (NT_SUCCESS(status)) {
Key_MarkDeletedEx_v2(TruePath, NULL);
Key_DiscardMergeByPath(TruePath, TRUE);
}
Dll_PopTlsNameBuffer(TlsData);
__sys_NtDeleteKey(KeyHandle);
}
else {
kwti.LastWriteTime.HighPart = DELETE_MARK_HIGH;
kwti.LastWriteTime.LowPart = DELETE_MARK_LOW;
status = NtSetInformationKey(
KeyHandle, KeyWriteTimeInformation,
&kwti, sizeof(KEY_WRITE_TIME_INFORMATION));
//
// refresh all merges
//
Key_DiscardMergeByHandle(TlsData, KeyHandle, TRUE);
}
//
// close key handle
@ -2308,14 +2506,18 @@ _FX NTSTATUS Key_NtDeleteValueKey(
status = GetExceptionCode();
}
Dll_PopTlsNameBuffer(TlsData);
if (NT_SUCCESS(status)) {
if (PATH_IS_OPEN(mp_flags)) {
status = __sys_NtDeleteValueKey(KeyHandle, ValueName);
} if (Key_Delete_v2){
Key_MarkDeletedEx_v2(TruePath, ValueName->Buffer);
__sys_NtDeleteValueKey(KeyHandle, ValueName);
} else {
//
@ -2342,6 +2544,8 @@ _FX NTSTATUS Key_NtDeleteValueKey(
}
}
Dll_PopTlsNameBuffer(TlsData);
SetLastError(LastError);
return status;
}
@ -2496,6 +2700,16 @@ _FX NTSTATUS Key_NtQueryKeyImpl(
__try {
//
// get the full paths for the true and copy keys
//
RtlInitUnicodeString(&objname, L"");
status = Key_GetName(KeyHandle, &objname, &TruePath, &CopyPath, NULL);
if (! NT_SUCCESS(status))
__leave;
//
// for KeyBasicInformation, KeyNodeInformation, KeyFlagsInformation,
// we let the system handle the call, then check for the delete mark.
@ -2510,26 +2724,21 @@ _FX NTSTATUS Key_NtQueryKeyImpl(
KeyHandle, KeyInformationClass, KeyInformation,
Length, ResultLength);
if (KeyInformationClass != KeyFlagsInformation &&
(NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
IS_DELETE_MARK((LARGE_INTEGER *)KeyInformation))
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW)
{
status = STATUS_KEY_DELETED;
if (Key_Delete_v2) {
if (Key_IsDeleted_v2(TruePath))
status = STATUS_KEY_DELETED;
}
else if(KeyInformationClass != KeyFlagsInformation) {
if (IS_DELETE_MARK((LARGE_INTEGER*)KeyInformation))
status = STATUS_KEY_DELETED;
}
}
__leave;
}
//
// get the full paths for the true and copy keys
//
RtlInitUnicodeString(&objname, L"");
status = Key_GetName(KeyHandle, &objname, &TruePath, &CopyPath, NULL);
if (! NT_SUCCESS(status))
__leave;
//
// for KeyNameInformation, we want to place TruePath in the
// output buffer, even if KeyHandle is a boxed key. this is
@ -2602,10 +2811,16 @@ _FX NTSTATUS Key_NtQueryKeyImpl(
KeyHandle, KeyInformationClass, KeyInformation,
Length, ResultLength);
if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
IS_DELETE_MARK((LARGE_INTEGER *)KeyInformation))
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW)
{
status = STATUS_KEY_DELETED;
if (Key_Delete_v2) {
if (Key_IsDeleted_v2(TruePath))
status = STATUS_KEY_DELETED;
}
else {
if (IS_DELETE_MARK((LARGE_INTEGER*)KeyInformation))
status = STATUS_KEY_DELETED;
}
}
}
@ -2790,10 +3005,16 @@ _FX NTSTATUS Key_NtEnumerateKey(
KeyHandle, Index, KeyInformationClass, KeyInformation,
Length, ResultLength);
if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
IS_DELETE_MARK((LARGE_INTEGER *)KeyInformation))
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW)
{
status = STATUS_KEY_DELETED;
if (Key_Delete_v2) {
if (Key_IsDeleted_v2(TruePath))
status = STATUS_KEY_DELETED;
}
else {
if (IS_DELETE_MARK((LARGE_INTEGER*)KeyInformation))
status = STATUS_KEY_DELETED;
}
}
}
@ -3189,11 +3410,16 @@ _FX NTSTATUS Key_NtQueryValueKey(
KeyValueInformationClass, KeyValueInformation,
Length, ResultLength);
if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
Key_CheckDeletedValue(
KeyValueInformationClass, KeyValueInformation))
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW)
{
status = STATUS_OBJECT_NAME_NOT_FOUND;
if (Key_Delete_v2) {
if(Key_IsDeletedEx_v2(TruePath, ValueNameBuf, TRUE))
status = STATUS_OBJECT_NAME_NOT_FOUND;
}
else {
if (Key_CheckDeletedValue(KeyValueInformationClass, KeyValueInformation))
status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
}
@ -3545,11 +3771,26 @@ _FX NTSTATUS Key_NtEnumerateValueKey(
KeyValueInformationClass, KeyValueInformation,
Length, ResultLength);
if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
Key_CheckDeletedValue(
KeyValueInformationClass, KeyValueInformation))
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW)
{
status = STATUS_OBJECT_NAME_NOT_FOUND;
if (Key_Delete_v2) {
WCHAR* ValueName;
if (KeyValueInformationClass == KeyValueBasicInformation)
ValueName = ((KEY_VALUE_BASIC_INFORMATION *)KeyValueInformation)->Name;
else if (KeyValueInformationClass == KeyValueFullInformation)
ValueName = ((KEY_VALUE_FULL_INFORMATION *)KeyValueInformation)->Name;
else
ValueName = 0;
if(ValueName && Key_IsDeletedEx_v2(TruePath, ValueName, TRUE))
status = STATUS_OBJECT_NAME_NOT_FOUND;
}
else {
if (Key_CheckDeletedValue(KeyValueInformationClass, KeyValueInformation))
status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
}
@ -4069,8 +4310,161 @@ _FX HANDLE Key_GetTrueHandle(HANDLE KeyHandle, BOOLEAN *pIsOpenPath)
_FX NTSTATUS Key_NtRenameKey(
HANDLE KeyHandle, UNICODE_STRING *ReplacementName)
{
SbieApi_Log(2205, L"NtRenameKey");
return __sys_NtRenameKey(KeyHandle, ReplacementName);
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
if (!Key_Delete_v2) {
SbieApi_Log(2205, L"NtRenameKey");
return __sys_NtRenameKey(KeyHandle, ReplacementName);
}
NTSTATUS status;
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING objname;
HANDLE handle;
WCHAR* TruePath;
WCHAR* CopyPath;
WCHAR* NewTruePath;
Dll_PushTlsNameBuffer(TlsData);
//
// get the full new name of the key to be renamed
//
__try {
status = Key_GetName(KeyHandle, NULL, &TruePath, &CopyPath, NULL);
WCHAR* TruePathSlash = wcsrchr(TruePath, L'\\');
if (!TruePathSlash){
status = STATUS_INVALID_PARAMETER;
__leave;
}
ULONG len = (ULONG)(TruePathSlash - TruePath + 1);
NewTruePath = Dll_GetTlsNameBuffer(TlsData, MISC_NAME_BUFFER,
len * sizeof(WCHAR) + ReplacementName->Length + sizeof(WCHAR));
wmemcpy(NewTruePath, TruePath, len);
wmemcpy(NewTruePath + len, ReplacementName->Buffer, ReplacementName->Length / sizeof(WCHAR));
NewTruePath[len + ReplacementName->Length / sizeof(WCHAR)] = L'\0';
} __except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
if (!NT_SUCCESS(status))
goto finish;
//
// check if the target key already exists in the true path
//
WCHAR* NewTruePath2 = NewTruePath;
WCHAR* OldTruePath = Key_GetRelocation(NewTruePath);
if (OldTruePath)
NewTruePath2 = OldTruePath;
RtlInitUnicodeString(&objname, NewTruePath2);
InitializeObjectAttributes(
&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = __sys_NtOpenKey(&handle, KEY_READ, &objattrs);
if (NT_SUCCESS(status)) {
if(Key_IsDeleted_v2(NewTruePath))
status = STATUS_OBJECT_NAME_NOT_FOUND;
File_NtCloseImpl(handle);
}
if (status != STATUS_OBJECT_NAME_NOT_FOUND)
goto finish;
//
// rename the key ensuring we wil have a boxed copy
// try renaming if it fails with access denided try again with a new handle
//
status = __sys_NtRenameKey(KeyHandle, ReplacementName);
if (status == STATUS_ACCESS_DENIED) {
//
// if we get STATUS_ACCESS_DENIED, the caller may be using a
// TruePath handle that was opened with MAXIMUM_ALLOWED, but
// reduced to read-only access in our NtCreateKey
//
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING objname;
HANDLE handle;
RtlInitUnicodeString(&objname, L"");
InitializeObjectAttributes(
&objattrs, &objname, OBJ_CASE_INSENSITIVE, KeyHandle, NULL);
status = NtOpenKey(&handle, KEY_WRITE, &objattrs);
if (NT_SUCCESS(status)) {
status = __sys_NtRenameKey(handle, ReplacementName);
NtClose(handle);
}
}
//
// check if the true path exists and if so mark path deleted
//
BOOLEAN TrueExists = FALSE;
WCHAR* TruePath2 = TruePath;
OldTruePath = Key_GetRelocation(TruePath);
if (OldTruePath)
TruePath2 = OldTruePath;
RtlInitUnicodeString(&objname, TruePath2);
InitializeObjectAttributes(
&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = __sys_NtOpenKey(&handle, KEY_READ, &objattrs);
if (NT_SUCCESS(status)) {
//
// if the true key exists mark it deleted
//
TrueExists = TRUE;
File_NtCloseImpl(handle);
}
//
// set the redirection information
//
if (TrueExists) {
Key_SetRelocation(TruePath, NewTruePath);
}
//*TruePathSlash = L'\0';
//Key_DiscardMergeByPath(TruePath, TRUE); // fix-me: act on Key_MergeCacheList
//*TruePathSlash = L'\\';
status = STATUS_SUCCESS;
finish:
Dll_PopTlsNameBuffer(TlsData);
return status;
}
@ -4082,7 +4476,7 @@ _FX NTSTATUS Key_NtRenameKey(
_FX NTSTATUS Key_NtSaveKey(
HANDLE KeyHandle, HANDLE FileHandle)
{
//SbieApi_Log(2205, L"NtSaveKey");
SbieApi_Log(2205, L"NtSaveKey");
return STATUS_SUCCESS;
}

View File

@ -0,0 +1,371 @@
/*
* Copyright 2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../../common/my_version.h"
//---------------------------------------------------------------------------
// Key (Delete)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Defines
//---------------------------------------------------------------------------
#define KEY_PATH_FILE_NAME L"RegPaths.dat"
// Keep in sync with the FILE_..._FLAG's in file_del.c
//
// path flages, saved to file
#define KEY_DELETED_FLAG 0x0001
#define KEY_RELOCATION_FLAG 0x0002
// internal volatile status flags
#define KEY_PATH_DELETED_FLAG 0x00010000
#define KEY_PATH_RELOCATED_FLAG 0x00020000
#define KEY_CHILDREN_DELETED_FLAG 0x00040000
#define KEY_DELETED_MASK (KEY_DELETED_FLAG | KEY_PATH_DELETED_FLAG)
#define KEY_RELOCATED_MASK (KEY_RELOCATION_FLAG | KEY_PATH_RELOCATED_FLAG)
#define KEY_IS_DELETED(x) ((x & KEY_DELETED_FLAG) != 0)
#define KEY_PATH_DELETED(x) ((x & KEY_DELETED_MASK) != 0)
#define KEY_PARENT_DELETED(x) ((x & KEY_PATH_DELETED_FLAG) != 0)
#define KEY_PATH_RELOCATED(x) ((x & KEY_RELOCATED_MASK) != 0)
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
static LIST Key_PathRoot;
static CRITICAL_SECTION *Key_PathRoot_CritSec = NULL;
BOOLEAN Key_RegPaths_Loaded = FALSE;
static HANDLE Key_BoxRootWatcher = NULL;
static volatile ULONGLONG Key_PathsVersion = 0; // count reloads
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
static ULONG Key_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation);
static BOOLEAN Key_SavePathTree();
static BOOLEAN Key_LoadPathTree();
static VOID Key_RefreshPathTree();
BOOLEAN Key_InitDelete_v2();
static NTSTATUS Key_MarkDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName);
static ULONG Key_IsDeleted_v2(const WCHAR* TruePath);
static ULONG Key_IsDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName, BOOLEAN IsValue);
//
// we re use the _internal functions of the file implementation as thay all are generic enough
//
VOID File_ClearPathBranche_internal(LIST* parent);
VOID File_SavePathTree_internal(LIST* Root, const WCHAR* name);
BOOLEAN File_LoadPathTree_internal(LIST* Root, const WCHAR* name);
VOID File_SetPathFlags_internal(LIST* Root, const WCHAR* Path, ULONG setFlags, ULONG clrFlags, const WCHAR* Relocation);
ULONG File_GetPathFlags_internal(LIST* Root, const WCHAR* Path, WCHAR** pRelocation, BOOLEAN CheckChildren);
VOID File_SavePathNode_internal(HANDLE hPathsFile, LIST* parent, WCHAR* Path, ULONG Length, ULONG SetFlags);
BOOLEAN File_MarkDeleted_internal(LIST* Root, const WCHAR* Path);
VOID File_SetRelocation_internal(LIST* Root, const WCHAR* OldTruePath, const WCHAR* NewTruePath);
HANDLE File_AcquireMutex(const WCHAR* MutexName);
void File_ReleaseMutex(HANDLE hMutex);
#define KEY_VCM_MUTEX SBIE L"_VCM_Mutex"
//---------------------------------------------------------------------------
// Key_GetPathFlags
//---------------------------------------------------------------------------
_FX ULONG Key_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation)
{
ULONG Flags;
Key_RefreshPathTree();
EnterCriticalSection(Key_PathRoot_CritSec);
Flags = File_GetPathFlags_internal(&Key_PathRoot, Path, pRelocation, TRUE);
LeaveCriticalSection(Key_PathRoot_CritSec);
return Flags;
}
//---------------------------------------------------------------------------
// Key_SavePathTree
//---------------------------------------------------------------------------
_FX BOOLEAN Key_SavePathTree()
{
EnterCriticalSection(Key_PathRoot_CritSec);
File_SavePathTree_internal(&Key_PathRoot, KEY_PATH_FILE_NAME);
LeaveCriticalSection(Key_PathRoot_CritSec);
Key_PathsVersion++;
return TRUE;
}
//---------------------------------------------------------------------------
// Key_LoadPathTree
//---------------------------------------------------------------------------
_FX BOOLEAN Key_LoadPathTree()
{
HANDLE hMutex = File_AcquireMutex(KEY_VCM_MUTEX);
EnterCriticalSection(Key_PathRoot_CritSec);
Key_RegPaths_Loaded = File_LoadPathTree_internal(&Key_PathRoot, KEY_PATH_FILE_NAME);
LeaveCriticalSection(Key_PathRoot_CritSec);
File_ReleaseMutex(hMutex);
Key_PathsVersion++;
return TRUE;
}
//---------------------------------------------------------------------------
// Key_RefreshPathTree
//---------------------------------------------------------------------------
_FX VOID Key_RefreshPathTree()
{
if (!Key_BoxRootWatcher)
return;
if (WaitForSingleObject(Key_BoxRootWatcher, 0) == WAIT_OBJECT_0) {
//
// somethign changed, reload the path tree
//
Key_LoadPathTree();
}
FindNextChangeNotification(Key_BoxRootWatcher); // rearm the watcher
}
//---------------------------------------------------------------------------
// Key_InitDelete_v2
//---------------------------------------------------------------------------
_FX BOOLEAN Key_InitDelete_v2()
{
List_Init(&Key_PathRoot);
Key_PathRoot_CritSec = Dll_Alloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSectionAndSpinCount(Key_PathRoot_CritSec, 1000);
Key_LoadPathTree();
//#ifdef WITH_DEBUG
// Key_SavePathTree();
//#endif
WCHAR BoxFilePath[MAX_PATH] = { 0 };
wcscpy(BoxFilePath, Dll_BoxFilePath);
SbieDll_TranslateNtToDosPath(BoxFilePath);
Key_BoxRootWatcher = FindFirstChangeNotification(BoxFilePath, FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE);
return TRUE;
}
//---------------------------------------------------------------------------
// Key_MarkDeletedEx_v2
//---------------------------------------------------------------------------
_FX NTSTATUS Key_MarkDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName)
{
//
// add a key/value or directory to the deleted list
//
HANDLE hMutex = File_AcquireMutex(KEY_VCM_MUTEX);
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
WCHAR* FullPath = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER,
(wcslen(TruePath) + (ValueName ? wcslen(ValueName) : 0) + 16) * sizeof(WCHAR)); // template buffer is not used for reg reputpose it here
wcscpy(FullPath, TruePath);
if (ValueName) {
wcscat(FullPath, L"\\$");
wcscat(FullPath, ValueName);
}
EnterCriticalSection(Key_PathRoot_CritSec);
BOOLEAN bSet = File_MarkDeleted_internal(&Key_PathRoot, FullPath);
LeaveCriticalSection(Key_PathRoot_CritSec);
if (bSet) Key_SavePathTree();
File_ReleaseMutex(hMutex);
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// Key_IsDeleted_v2
//---------------------------------------------------------------------------
_FX ULONG Key_IsDeleted_v2(const WCHAR* TruePath)
{
//
// check if the key/value or one of its parent directories is listed as deleted
//
ULONG Flags = Key_GetPathFlags(TruePath, NULL);
return (Flags & KEY_DELETED_MASK);
}
//---------------------------------------------------------------------------
// Key_IsDeletedEx_v2
//---------------------------------------------------------------------------
_FX ULONG Key_IsDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName, BOOLEAN IsValue)
{
//
// check if the key/value or one of its parent directories is listed as deleted
//
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
WCHAR* FullPath = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER,
(wcslen(TruePath) + (ValueName ? wcslen(ValueName) : 0) + 16) * sizeof(WCHAR)); // template buffer is not used for reg reputpose it here
wcscpy(FullPath, TruePath);
if (ValueName) {
wcscat(FullPath, IsValue ? L"\\$" : L"\\");
wcscat(FullPath, ValueName);
}
return Key_IsDeleted_v2(FullPath);
}
//---------------------------------------------------------------------------
// Key_HasDeleted_v2
//---------------------------------------------------------------------------
_FX BOOLEAN Key_HasDeleted_v2(const WCHAR* TruePath)
{
//
// Check if this folder has deleted children
//
ULONG Flags = Key_GetPathFlags(TruePath, NULL);
return (Flags & KEY_CHILDREN_DELETED_FLAG) != 0;
}
//---------------------------------------------------------------------------
// Key_SetRelocation
//---------------------------------------------------------------------------
_FX NTSTATUS Key_SetRelocation(const WCHAR *OldTruePath, const WCHAR *NewTruePath)
{
//
// List a mapping for the new location
//
HANDLE hMutex = File_AcquireMutex(KEY_VCM_MUTEX);
EnterCriticalSection(Key_PathRoot_CritSec);
File_SetRelocation_internal(&Key_PathRoot, OldTruePath, NewTruePath);
LeaveCriticalSection(Key_PathRoot_CritSec);
Key_SavePathTree();
File_ReleaseMutex(hMutex);
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// Key_GetRelocation
//---------------------------------------------------------------------------
_FX WCHAR* Key_GetRelocation(const WCHAR *TruePath)
{
//
// Get redirection location, only if its the actual path and not a parent
//
WCHAR* OldTruePath = NULL;
ULONG Flags = Key_GetPathFlags(TruePath, &OldTruePath);
if (KEY_PATH_RELOCATED(Flags))
return OldTruePath;
return NULL;
}
//---------------------------------------------------------------------------
// Key_ResolveTruePath
//---------------------------------------------------------------------------
_FX WCHAR* Key_ResolveTruePath(const WCHAR *TruePath, ULONG* PathFlags)
{
//
// Resolve the true path, taking into account redirection locations of parent folder
//
WCHAR* OldTruePath = NULL;
ULONG Flags = Key_GetPathFlags(TruePath, &OldTruePath);
if (PathFlags) *PathFlags = Flags;
return OldTruePath;
}

View File

@ -1,5 +1,6 @@
/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2021-2022 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -36,6 +37,7 @@ typedef struct _KEY_MERGE {
BOOLEAN subkeys_merged;
LARGE_INTEGER last_write_time;
ULONGLONG last_paths_version;
LIST subkeys;
ULONG last_index;
@ -196,14 +198,15 @@ _FX NTSTATUS Key_Merge(
// the same key path, so we are going to use it.
//
break;
if(Key_PathsVersion == merge->last_paths_version)
break;
}
//
// if we got here, we need to discard the stale entry
//
File_UnRegisterCloseHandler(merge->handle, Key_NtClose);
Handle_UnRegisterCloseHandler(merge->handle, Key_NtClose);
List_Remove(&Key_Handles, merge);
Key_MergeFree(merge, TRUE);
@ -225,11 +228,13 @@ _FX NTSTATUS Key_Merge(
merge->ticks = ticks_now;
// merge->cant_merge = FALSE; // memzero takes care of this
merge->last_paths_version = Key_PathsVersion;
merge->name_len = TruePath_len;
memcpy(merge->name, TruePath, TruePath_len + sizeof(WCHAR));
List_Insert_Before(&Key_Handles, NULL, merge);
File_RegisterCloseHandler(merge->handle, Key_NtClose);
Handle_RegisterCloseHandler(merge->handle, Key_NtClose);
}
//
@ -237,6 +242,7 @@ _FX NTSTATUS Key_Merge(
// or CopyPath exist, but not both, so return special status
//
if(!Key_Delete_v2 || !Key_HasDeleted_v2(TruePath))
if (merge->cant_merge) {
LeaveCriticalSection(&Key_Handles_CritSec);
@ -319,6 +325,7 @@ _FX NTSTATUS Key_OpenForMerge(
ULONG len;
HANDLE TrueHandle;
ULONG mp_flags;
const WCHAR* OriginalPath = NULL;
*out_TrueMerge = NULL;
*out_CopyHandle = NULL;
@ -365,6 +372,7 @@ _FX NTSTATUS Key_OpenForMerge(
&info, sizeof(KEY_BASIC_INFORMATION), &len);
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
// if (!Key_Delete_v2 &&
if (IS_DELETE_MARK(&info.LastWriteTime))
status = STATUS_KEY_DELETED;
else
@ -382,7 +390,10 @@ _FX NTSTATUS Key_OpenForMerge(
// if we couldn't find a copy key, indicate there is nothing to merge
//
status = STATUS_BAD_INITIAL_PC;
if (Key_Delete_v2 && Key_HasDeleted_v2(TruePath))
status = STATUS_SUCCESS;
else
status = STATUS_BAD_INITIAL_PC;
}
if (! NT_SUCCESS(status)) {
@ -390,6 +401,18 @@ _FX NTSTATUS Key_OpenForMerge(
return status;
}
//
// get the redirection location for this key if there is one
//
if (Key_Delete_v2) {
WCHAR* OldTruePath = Key_GetRelocation(TruePath);
if (OldTruePath) {
OriginalPath = TruePath;
TruePath = OldTruePath;
}
}
//
// open TruePath for KEY_READ access. we use __sys_NtOpenKey
// because we really want the TruePath key, even if there is
@ -418,7 +441,7 @@ _FX NTSTATUS Key_OpenForMerge(
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
status = Key_MergeCache(
TrueHandle, &info.LastWriteTime, TruePath, out_TrueMerge);
TrueHandle, &info.LastWriteTime, OriginalPath ? OriginalPath : TruePath, out_TrueMerge);
}
File_NtCloseImpl(TrueHandle);
@ -442,7 +465,7 @@ _FX NTSTATUS Key_OpenForMerge(
//
if (use_rule_specificity)
Key_MergeCache(NULL, &info.LastWriteTime, TruePath, out_TrueMerge);
Key_MergeCache(NULL, &info.LastWriteTime, OriginalPath ? OriginalPath : TruePath, out_TrueMerge);
}
if (! NT_SUCCESS(status)) {
@ -637,7 +660,7 @@ _FX NTSTATUS Key_MergeCache(
if (merge) {
if (LastWriteTime->QuadPart == merge->last_write_time.QuadPart) {
if (LastWriteTime->QuadPart == merge->last_write_time.QuadPart && Key_PathsVersion == merge->last_paths_version) {
*out_TrueMerge = merge;
return STATUS_SUCCESS;
}
@ -660,6 +683,7 @@ _FX NTSTATUS Key_MergeCache(
}
merge->last_write_time.QuadPart = LastWriteTime->QuadPart;
merge->last_paths_version = Key_PathsVersion;
//
// build the subkeys and values in the true merge
@ -837,6 +861,12 @@ _FX NTSTATUS Key_MergeCacheSubkeys(KEY_MERGE *merge, HANDLE TrueHandle)
info->ClassOffset != -1 ||
info->ClassLength);
if (Key_Delete_v2 && Key_IsDeletedEx_v2(merge->name, subkey->name, FALSE)) {
Dll_Free(subkey);
++index;
continue;
}
//
// find where to insert it. if the new key is already larger than
// our last key in the sorted list, instead directly at the end
@ -936,6 +966,12 @@ _FX NTSTATUS Key_MergeCacheValues(KEY_MERGE *merge, HANDLE TrueHandle)
memcpy(value->data_ptr,
(UCHAR *)info + info->DataOffset, info->DataLength);
if (Key_Delete_v2 && Key_IsDeletedEx_v2(merge->name, value->name, TRUE)) {
Dll_Free(value);
++index;
continue;
}
//
// find where to insert it
//
@ -973,7 +1009,7 @@ _FX NTSTATUS Key_MergeSubkeys(
KEY_NODE_INFORMATION *info;
ULONG index;
KEY_MERGE_SUBKEY *subkey, *subkey2;
BOOLEAN subkey_deleted;
BOOLEAN subkey_deleted = FALSE;
//
// get the latest of the two LastWriteTime fields
@ -991,6 +1027,7 @@ _FX NTSTATUS Key_MergeSubkeys(
}
merge->last_write_time.QuadPart = info->LastWriteTime.QuadPart;
merge->last_paths_version = Key_PathsVersion;
if (! TrueMerge)
goto TrueHandleFinish;
@ -1071,6 +1108,7 @@ TrueHandleFinish:
info->ClassOffset != -1 ||
info->ClassLength);
if (!Key_Delete_v2)
if (IS_DELETE_MARK(&info->LastWriteTime))
subkey_deleted = TRUE;
else
@ -1097,7 +1135,8 @@ TrueHandleFinish:
if (subkey->TitleOrClass)
subkey2->TitleOrClass = subkey->TitleOrClass;
}
subkey_deleted = TRUE;
Dll_Free(subkey);
subkey = NULL;
break;
}
@ -1142,7 +1181,7 @@ _FX NTSTATUS Key_MergeValues(
KEY_VALUE_FULL_INFORMATION *info;
ULONG index;
KEY_MERGE_VALUE *value, *value2;
BOOLEAN value_deleted;
BOOLEAN value_deleted = FALSE;
info_len = 128; // at least sizeof(KEY_VALUE_FULL_INFORMATION)
info = Dll_Alloc(info_len);
@ -1234,6 +1273,7 @@ TrueHandleFinish:
memcpy(value->data_ptr,
(UCHAR *)info + info->DataOffset, value->data_len);
if (!Key_Delete_v2)
if (info->Type == tzuk)
value_deleted = TRUE;
else
@ -1488,7 +1528,7 @@ _FX void Key_DiscardMergeByPath(const WCHAR *TruePath, BOOLEAN Recurse)
}
}
File_UnRegisterCloseHandler(merge->handle, Key_NtClose);
Handle_UnRegisterCloseHandler(merge->handle, Key_NtClose);
List_Remove(&Key_Handles, merge);
Key_MergeFree(merge, TRUE);
}

View File

@ -45,12 +45,6 @@ static NTSTATUS Obj_NtQueryVirtualMemory(
SIZE_T Length,
SIZE_T *ResultLength);
static NTSTATUS Obj_NtQueryInformationProcess(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength);
//---------------------------------------------------------------------------
// Variables
@ -61,8 +55,6 @@ static P_NtQueryObject __sys_NtQueryObject = NULL;
P_NtQueryVirtualMemory __sys_NtQueryVirtualMemory = NULL;
P_NtQueryInformationProcess __sys_NtQueryInformationProcess = NULL;
//---------------------------------------------------------------------------
// Obj_Init
@ -76,7 +68,6 @@ _FX BOOLEAN Obj_Init(void)
#else
SBIEDLL_HOOK(Obj_,NtQueryObject);
SBIEDLL_HOOK(Obj_,NtQueryVirtualMemory);
SBIEDLL_HOOK(Obj_,NtQueryInformationProcess);
#endif
return TRUE;
}
@ -411,42 +402,3 @@ finish:
SetLastError(LastError);
return status;
}
//---------------------------------------------------------------------------
// Obj_NtQueryVirtualMemory
//---------------------------------------------------------------------------
_FX NTSTATUS Obj_NtQueryInformationProcess(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength)
{
NTSTATUS status;
ULONG outlen;
status = __sys_NtQueryInformationProcess(
ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, &outlen);
if (ProcessInformationClass == ProcessImageFileName && ProcessInformation != NULL)
{
//
// since file paths are always shorter without the sandbox prefix we can keep this simple
//
ULONG tmplen;
PUNICODE_STRING fileName = (PUNICODE_STRING)ProcessInformation;
tmplen = File_NtQueryObjectName(fileName, fileName->MaximumLength);
if (tmplen)
outlen = sizeof(UNICODE_STRING) + tmplen;
}
if (ReturnLength)
*ReturnLength = outlen;
return status;
}

View File

@ -291,7 +291,7 @@ static P_WinExec __sys_WinExec = NULL;
static P_RunSetupCommandW __sys_RunSetupCommandW = NULL;
static P_NtSetInformationProcess __sys_NtSetInformationProcess = NULL;
static P_NtQueryInformationProcess __sys_NtQueryInformationProcess = NULL;
P_NtQueryInformationProcess __sys_NtQueryInformationProcess = NULL;
static P_NtCreateProcessEx __sys_NtCreateProcessEx = NULL;
@ -2766,6 +2766,17 @@ _FX NTSTATUS Proc_NtQueryInformationProcess(
}
}
/*if (ProcessInformationClass == ProcessImageFileName && ProcessInformation != NULL) {
ULONG tmplen;
PUNICODE_STRING fileName = (PUNICODE_STRING)ProcessInformation;
tmplen = File_NtQueryObjectName(fileName, fileName->MaximumLength);
if (tmplen)
outlen = sizeof(UNICODE_STRING) + tmplen;
}*/
return status;
}

View File

@ -28,7 +28,10 @@
#include "core/drv/api_defs.h"
#include "core/svc/msgids.h"
#include "common/my_version.h"
//#include "core/low/lowdata.h"
//
//extern SBIELOW_DATA* SbieApi_data;
//#define SBIELOW_CALL(x) ((P_##x)&SbieApi_data->x##_code)
#pragma optimize("",off)
@ -141,9 +144,28 @@ _FX NTSTATUS SbieApi_Ioctl(ULONG64 *parms)
// processing a request before sending the next request
//
status = NtDeviceIoControlFile(
SbieApi_DeviceHandle, NULL, NULL, NULL, &MyIoStatusBlock,
API_SBIEDRV_CTLCODE, parms, sizeof(ULONG64) * 8, NULL, 0);
extern P_NtDeviceIoControlFile __sys_NtDeviceIoControlFile;
if (__sys_NtDeviceIoControlFile) {
//
// once NtDeviceIoControlFile is hooked, bypass it
//
status = __sys_NtDeviceIoControlFile(
SbieApi_DeviceHandle, NULL, NULL, NULL, &MyIoStatusBlock,
API_SBIEDRV_CTLCODE, parms, sizeof(ULONG64) * 8, NULL, 0);
} else {
status = NtDeviceIoControlFile(
SbieApi_DeviceHandle, NULL, NULL, NULL, &MyIoStatusBlock,
API_SBIEDRV_CTLCODE, parms, sizeof(ULONG64) * 8, NULL, 0);
}
// that would be even better but would only work in the native case
//status = SBIELOW_CALL(NtDeviceIoControlFile)(
// SbieApi_DeviceHandle, NULL, NULL, NULL, &MyIoStatusBlock,
// API_SBIEDRV_CTLCODE, parms, sizeof(ULONG64) * 8, NULL, 0);
}
return status;

View File

@ -16,6 +16,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "handle.h"
//---------------------------------------------------------------------------
// Service Control Manager
//---------------------------------------------------------------------------
@ -238,7 +240,7 @@ _FX BOOL Scm_OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE
if (NT_SUCCESS(status) && ProcessHandle == GetCurrentProcess()) {
File_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler);
Handle_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler);
TlsData->scm_last_own_token = *phTokenOut;
}
@ -259,7 +261,7 @@ _FX BOOL Scm_OpenThreadToken(HANDLE ThreadHandle, DWORD DesiredAccess, BOOL Open
if (NT_SUCCESS(status) && ThreadHandle == GetCurrentThread()) {
File_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler);
Handle_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler);
TlsData->scm_last_own_token = *phTokenOut;
}

View File

@ -722,8 +722,17 @@ _FX NTSTATUS Secure_NtDuplicateObject(
if (SourceProcessHandle == NtCurrentProcess()) {
if (TargetProcessHandle == NtCurrentProcess() && TargetHandle)
File_DuplicateRecover(SourceHandle, *TargetHandle);
if (TargetProcessHandle == NtCurrentProcess() && TargetHandle) {
//
// this also duplicates the "recoverability"
// of the old handle to the new handle. needed in particular for
// SHFileOperation to recover correctly on Windows Vista
//
if(SourceHandle && *TargetHandle)
Handle_SetupDuplicate(SourceHandle, *TargetHandle);
}
if (SourceHandle)
Key_NtClose(SourceHandle);

View File

@ -422,14 +422,26 @@ _FX NTSTATUS SysInfo_GetJobName(OBJECT_ATTRIBUTES* ObjectAttributes, WCHAR** Out
*OutCopyPath = name;
wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen);
name += Dll_BoxIpcPathLen;
//if (Dll_AlernateIpcNaming)
//{
// wmemcpy(name, objname_buf, objname_len);
// name += objname_len;
//
// wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen);
// name += Dll_BoxIpcPathLen;
//}
//else
{
wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen);
name += Dll_BoxIpcPathLen;
*name = L'\\';
name++;
*name = L'\\';
name++;
wmemcpy(name, objname_buf, objname_len);
name += objname_len;
}
wmemcpy(name, objname_buf, objname_len);
name += objname_len;
*name = L'\0';
return STATUS_SUCCESS;

View File

@ -1458,8 +1458,7 @@ _FX NTSTATUS Conf_Api_Reload(PROCESS *proc, ULONG64 *parms)
}
}
BOOLEAN obj_filter_enabled = Conf_Get_Boolean(NULL, L"EnableObjectFiltering", 0, FALSE);
extern BOOLEAN Obj_CallbackInstalled;
BOOLEAN obj_filter_enabled = Conf_Get_Boolean(NULL, L"EnableObjectFiltering", 0, TRUE);
if (Obj_CallbackInstalled != obj_filter_enabled && Driver_OsVersion > DRIVER_WINDOWS_VISTA) {
if (obj_filter_enabled) {
Obj_Load_Filter();

View File

@ -615,6 +615,11 @@ void* Driver_FindMissingService(const char* ProcName, int prmcnt)
}
//---------------------------------------------------------------------------
// Driver_FindMissingServices
//---------------------------------------------------------------------------
_FX BOOLEAN Driver_FindMissingServices(void)
{
#ifdef OLD_DDK

View File

@ -1785,4 +1785,4 @@ _FX void Ipc_Unload(void)
{
if (Ipc_Dynamic_Ports.pPortLock)
Mem_FreeLockResource(&Ipc_Dynamic_Ports.pPortLock);
}
}

View File

@ -267,6 +267,8 @@ _FX void Log_Msg_Process(
ULONG session_id,
HANDLE process_id)
{
DbgPrint("Sbie MSG_%d: %S; %S\r\n", (error_code & 0xFFFF), string1, string2);
ULONG facility = (error_code >> 16) & 0x0F;
if (facility & MSG_FACILITY_EVENT)
Log_Event_Msg(error_code, string1, string2);

View File

@ -644,7 +644,6 @@ _FX POBJECT_TYPE Obj_GetTypeObjectType(void)
(POBJECT_TYPE *)(ptr + i + 7 + offset);
}
}
DbgPrint("pObTypeIndexTable = %p\n", pObTypeIndexTable);
}
#else ! _WIN64
UCHAR k = 0;
@ -661,9 +660,8 @@ _FX POBJECT_TYPE Obj_GetTypeObjectType(void)
pObTypeIndexTable = (POBJECT_TYPE *)*ptr2;
}
}
#endif _WIN64
//DbgPrint("pObTypeIndexTable = %p\n", pObTypeIndexTable);
}
if (! pObTypeIndexTable) {
@ -778,4 +776,4 @@ _FX BOOLEAN Obj_AddObjectType(const WCHAR *TypeName)
Obj_ObjectTypes[i] = object;
return TRUE;
}
}

View File

@ -323,4 +323,4 @@ Exit:
//_FX VOID Obj_PostOperationCallback(
// _In_ PVOID RegistrationContext, _In_ POB_POST_OPERATION_INFORMATION PostInfo)
//{
//}
//}

View File

@ -1547,4 +1547,4 @@ _FX BOOLEAN Process_ScheduleKill(PROCESS *proc, LONG delay_ms)
return TRUE;
}
return FALSE;
}
}

View File

@ -82,7 +82,6 @@ const ULONG tzuk = 'xobs';
// WinMain
//---------------------------------------------------------------------------
ULONG Dll_Windows = 0;
int WinMain(
HINSTANCE hInstance,
@ -97,9 +96,6 @@ int WinMain(
_Ntdll = GetModuleHandle(L"ntdll.dll");
_Kernel32 = GetModuleHandle(L"kernel32.dll");
GetSystemInfo(&_SystemInfo);
if (GetProcAddress(_Ntdll, "LdrFastFailInLoaderCallout")) {
Dll_Windows = 10;
}
WCHAR *cmdline = GetCommandLine();
if (cmdline) {

View File

@ -69,7 +69,7 @@ void CSimpleListModel::Sync(QList<QVariantMap> List)
Changed = true;
ColValue.Raw = Value;
//ColValue.Formated =
//ColValue.Formatted =
}
if(State != Changed)
@ -195,7 +195,7 @@ QVariant CListItemModel::Data(const QModelIndex &index, int role, int section) c
case Qt::DisplayRole:
{
SListNode::SValue& Value = pNode->Values[section];
return Value.Formated.isValid() ? Value.Formated : Value.Raw;
return Value.Formatted.isValid() ? Value.Formatted : Value.Raw;
}
case Qt::EditRole: // sort role
{

View File

@ -56,7 +56,7 @@ protected:
struct SValue
{
QVariant Raw;
QVariant Formated;
QVariant Formatted;
};
QVector<SValue> Values;
};

View File

@ -110,7 +110,7 @@ void CSimpleTreeModel::Sync(const QMap<QVariant, QVariantMap>& List)
Changed = true;
ColValue.Raw = Value;
//ColValue.Formated =
//ColValue.Formatted =
}
if(State != Changed)
@ -385,7 +385,7 @@ QVariant CTreeItemModel::NodeData(STreeNode* pNode, int role, int section) const
case Qt::DisplayRole:
{
STreeNode::SValue& Value = pNode->Values[section];
return Value.Formated.isValid() ? Value.Formated : Value.Raw;
return Value.Formatted.isValid() ? Value.Formatted : Value.Raw;
}
case Qt::EditRole: // sort role
{

View File

@ -80,7 +80,7 @@ protected:
{
QVariant Raw;
QVariant SortKey;
QVariant Formated;
QVariant Formatted;
};
QVector<SValue> Values;
};

View File

@ -106,7 +106,7 @@ CBoxBorder::CBoxBorder(CSbieAPI* pApi, QObject* parent) : QObject(parent)
SetLayeredWindowAttributes(m->BorderWnd, 0, 192, LWA_ALPHA);
::ShowWindow(m->BorderWnd, SW_HIDE);
m_uTimerID = startTimer(10);
m_uTimerID = startTimer(100);
}
CBoxBorder::~CBoxBorder()

View File

@ -119,6 +119,13 @@ void CSandBox::UpdateDetails()
{
}
void CSandBox::SetBoxPaths(const QString& FilePath, const QString& RegPath, const QString& IpcPath)
{
m_FilePath = FilePath;
m_RegPath = RegPath;
m_IpcPath = IpcPath;
}
SB_STATUS CSandBox::RunStart(const QString& Command, bool Elevated)
{
#ifdef _DEBUG
@ -140,7 +147,7 @@ SB_STATUS CSandBox::TerminateAll()
bool CSandBox::IsEmpty() const
{
return !QDir(m_FilePath).exists();
return !QFile::exists(m_FilePath);
}
SB_PROGRESS CSandBox::CleanBox()
@ -327,6 +334,8 @@ struct SBoxDataFile
QList<SBoxDataFile> CSandBox__BoxDataFiles = QList<SBoxDataFile>()
<< SBoxDataFile("RegHive", true, false)
<< SBoxDataFile("RegPaths.dat", false, false)
<< SBoxDataFile("FilePaths.dat", false, true)
;
bool CSandBox::IsInitialized() const

View File

@ -42,6 +42,7 @@ public:
virtual void UpdateDetails();
virtual void SetBoxPaths(const QString& FilePath, const QString& RegPath, const QString& IpcPath);
virtual QString GetFileRoot() const { return m_FilePath; }
virtual QString GetRegRoot() const { return m_RegPath; }
virtual QString GetIpcRoot() const { return m_IpcPath; }
@ -54,6 +55,7 @@ public:
virtual SB_STATUS RunSandboxed(const QString& Command);
virtual SB_STATUS TerminateAll();
virtual void OpenBox() {}
virtual void CloseBox() {}
virtual bool IsEnabled() const { return m_IsEnabled; }

View File

@ -129,7 +129,9 @@ CSbieAPI::CSbieAPI(QObject* parent) : QThread(parent)
m_pGlobalSection = new CSbieIni("GlobalSettings", this, this);
m_pUserSection = new CSbieIni("UserSettings", this, this); // dummy
m_IniReLoad = false;
m_bReloadPending = false;
m_bBoxesDirty = false;
m_LastTraceEntry = 0;
@ -289,7 +291,7 @@ SB_STATUS CSbieAPI::Connect(bool takeOver, bool withQueue)
//m->lastRecordNum = 0;
// Note: this lib is not using all functions hence it can be compatible with multiple driver ABI revisions
QStringList CompatVersions = QStringList () << "5.55.0";
QStringList CompatVersions = QStringList () << "5.56.0";
QString CurVersion = GetVersion();
if (!CompatVersions.contains(CurVersion))
{
@ -357,6 +359,7 @@ SB_STATUS CSbieAPI::Disconnect()
m_SandBoxes.clear();
m_BoxedProxesses.clear();
m_bBoxesDirty = true;
emit StatusChanged();
return SB_OK;
@ -786,10 +789,12 @@ SB_STATUS CSbieAPI::TakeOver()
return SB_OK;
}
SB_STATUS CSbieAPI::WatchIni(bool bEnable)
SB_STATUS CSbieAPI::WatchIni(bool bEnable, bool bReLoad)
{
if (bEnable)
if (bEnable) {
m_IniWatcher.addPath(m_IniPath);
m_IniReLoad = bReLoad;
}
else
m_IniWatcher.removePath(m_IniPath);
return SB_OK;
@ -807,7 +812,9 @@ void CSbieAPI::OnIniChanged(const QString &path)
void CSbieAPI::OnReloadConfig()
{
m_bReloadPending = false;
ReloadConfig();
m_bBoxesDirty = true;
if (m_IniReLoad)
ReloadConfig();
}
typedef struct _FILE_FS_VOLUME_INFORMATION {
@ -1115,13 +1122,17 @@ quint32 CSbieAPI::GetSessionID() const
return m->sessionId;
}
SB_STATUS CSbieAPI::ReloadBoxes(bool bFullUpdate)
SB_STATUS CSbieAPI::ReloadBoxes(bool bForceUpdate)
{
if (bForceUpdate || (!m_bBoxesDirty && !m_IniWatcher.files().isEmpty()))
return SB_OK;
m_bBoxesDirty = false;
QMap<QString, CSandBoxPtr> OldSandBoxes = m_SandBoxes;
for (int i = 0;;i++)
{
QString BoxName = SbieIniGet(QString(), QString(), (i | CONF_GET_NO_EXPAND));
QString BoxName = SbieIniGet(QString(), QString(), (i | CONF_GET_NO_EXPAND | CONF_GET_NO_TEMPLS));
if (BoxName.isNull())
break;
@ -1134,10 +1145,8 @@ SB_STATUS CSbieAPI::ReloadBoxes(bool bFullUpdate)
{
pBox = CSandBoxPtr(NewSandBox(BoxName, this));
m_SandBoxes.insert(BoxName.toLower(), pBox);
UpdateBoxPaths(pBox);
}
else if(bFullUpdate)
UpdateBoxPaths(pBox);
UpdateBoxPaths(pBox);
pBox->m_IsEnabled = bIsEnabled;
@ -1238,6 +1247,8 @@ void CSbieAPI::CommitIniChanges()
SbieIniSet("", "", ""); // commit and refresh
if (bRemoved) m_IniWatcher.addPath(m_IniPath);
m_bBoxesDirty = true;
}
QString CSbieAPI::SbieIniGetEx(const QString& Section, const QString& Setting)
@ -1405,6 +1416,12 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions)
if (pBox.isNull())
continue;
if (pBox->m_ActiveProcessCount == 0) {
pBox->m_ActiveProcessCount = 1;
pBox->OpenBox();
emit BoxOpened(pBox->GetName());
}
pProcess->m_pBox = pBox.data();
pBox->m_ProcessList.insert(ProcessId, pProcess);
m_BoxedProxesses.insert(ProcessId, pProcess);
@ -1569,9 +1586,11 @@ SB_STATUS CSbieAPI::UpdateBoxPaths(const CSandBoxPtr& pSandBox)
if (!Status)
return Status;
pSandBox->m_FilePath = Nt2DosPath(QString::fromWCharArray(FileRoot.c_str(), wcslen(FileRoot.c_str())));
pSandBox->m_RegPath = QString::fromWCharArray(KeyRoot.c_str(), wcslen(KeyRoot.c_str()));
pSandBox->m_IpcPath = QString::fromWCharArray(IpcRoot.c_str(), wcslen(IpcRoot.c_str()));
QString FilePath = Nt2DosPath(QString::fromWCharArray(FileRoot.c_str(), wcslen(FileRoot.c_str())));
QString RegPath = QString::fromWCharArray(KeyRoot.c_str(), wcslen(KeyRoot.c_str()));
QString IpcPath = QString::fromWCharArray(IpcRoot.c_str(), wcslen(IpcRoot.c_str()));
pSandBox->SetBoxPaths(FilePath, RegPath, IpcPath);
return SB_OK;
}
@ -1909,12 +1928,12 @@ QString CSbieAPI::GetBoxedPath(const QString& BoxName, const QString& Path)
CSandBoxPtr pBox = GetBoxByName(BoxName);
if (!pBox)
return QString();
return GetBoxedPath(pBox, Path);
return GetBoxedPath(pBox.data(), Path);
}
//#pragma comment(lib, "mpr.lib")
QString CSbieAPI::GetBoxedPath(const CSandBoxPtr& pBox, const QString& Path)
QString CSbieAPI::GetBoxedPath(CSandBox* pBox, const QString& Path)
{
QString BoxRoot = pBox->m_FilePath;
@ -1974,7 +1993,7 @@ QString CSbieAPI::GetBoxedPath(const CSandBoxPtr& pBox, const QString& Path)
return Paths;*/
}
QString CSbieAPI::GetRealPath(const CSandBoxPtr& pBox, const QString& Path)
QString CSbieAPI::GetRealPath(CSandBox* pBox, const QString& Path)
{
QString RealPath;
QString BoxRoot = pBox->m_FilePath;
@ -2045,10 +2064,7 @@ SB_STATUS CSbieAPI::ReloadConf(quint32 flags, quint32 SessionId)
emit ConfigReloaded();
//emit LogMessage("Sandboxie config has been reloaded.", false);
emit LogSbieMessage(0, QStringList() << "Sandboxie config has been reloaded" << "" << "", 4);
ReloadBoxes(true);
m_bBoxesDirty = true;
return SB_OK;
}
@ -2318,6 +2334,12 @@ CBoxedProcessPtr CSbieAPI::OnProcessBoxed(quint32 ProcessId, const QString& Path
if (!pBox)
return CBoxedProcessPtr();
if (pBox->m_ActiveProcessCount == 0) {
pBox->m_ActiveProcessCount = 1;
pBox->OpenBox();
emit BoxOpened(pBox->GetName());
}
pProcess = CBoxedProcessPtr(NewBoxedProcess(ProcessId, pBox.data()));
pBox->m_ProcessList.insert(ProcessId, pProcess);
m_BoxedProxesses.insert(ProcessId, pProcess);

View File

@ -47,7 +47,7 @@ public:
virtual QString GetVersion();
virtual SB_STATUS TakeOver();
virtual SB_STATUS WatchIni(bool bEnable = true);
virtual SB_STATUS WatchIni(bool bEnable = true, bool bReLoad = true);
virtual QString GetSbiePath() const { return m_SbiePath; }
virtual QString GetIniPath() const { return m_IniPath; }
@ -57,7 +57,7 @@ public:
virtual void UpdateDriveLetters();
virtual QString Nt2DosPath(QString NtPath, bool* pOk = NULL) const;
virtual SB_STATUS ReloadBoxes(bool bFullUpdate = false);
virtual SB_STATUS ReloadBoxes(bool bForceUpdate = false);
static SB_STATUS ValidateName(const QString& BoxName);
virtual SB_STATUS CreateBox(const QString& BoxName, bool bReLoad = true);
@ -77,8 +77,8 @@ public:
virtual bool GetProcessExemption(quint32 process_id, quint32 action_id);
virtual QString GetBoxedPath(const QString& BoxName, const QString& Path);
virtual QString GetBoxedPath(const CSandBoxPtr& pBox, const QString& Path);
virtual QString GetRealPath(const CSandBoxPtr& pBox, const QString& Path);
virtual QString GetBoxedPath(CSandBox* pBox, const QString& Path);
virtual QString GetRealPath(CSandBox* pBox, const QString& Path);
enum ESetMode
{
@ -158,6 +158,7 @@ signals:
void LogSbieMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId);
void ProcessBoxed(quint32 ProcessId, const QString& Path, const QString& Box, quint32 ParentId);
void FileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId);
void BoxOpened(const QString& BoxName);
void BoxClosed(const QString& BoxName);
void NotAuthorized(bool bLoginRequired, bool &bRetry);
void QueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data);
@ -228,8 +229,9 @@ protected:
QString m_SbiePath;
QString m_IniPath;
QFileSystemWatcher m_IniWatcher;
bool m_IniReLoad;
bool m_bReloadPending;
bool m_bBoxesDirty;
bool m_bWithQueue;
bool m_bTerminate;

View File

@ -0,0 +1,129 @@
#include "stdafx.h"
#include "BoxMonitor.h"
#include "../MiscHelpers/Common/Common.h"
CBoxMonitor::CBoxMonitor()
{
m_bTerminate = false;
start();
}
CBoxMonitor::~CBoxMonitor()
{
m_bTerminate = true;
if (!wait(10 * 1000))
terminate();
}
void CBoxMonitor::Notify(const wstring& strDirectory)
{
m_Mutex.lock();
m_Boxes[QString::fromStdWString(strDirectory)].Changed = true;
m_Mutex.unlock();
}
quint64 CBoxMonitor::CounDirSize(const QString& Directory, SBox* Box)
{
quint64 TotalSize = 0;
if (Box->pBox.isNull() || m_bTerminate)
return TotalSize;
QDir Dir(Directory);
foreach(const QFileInfo & Info, Dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot))
{
if (Info.isDir())
TotalSize += CounDirSize(Info.filePath(), Box);
else
TotalSize += QFile(Info.filePath()).size();
}
return TotalSize;
}
void CBoxMonitor::run()
{
while (!m_bTerminate)
{
m_Mutex.lock();
QList<QString> Keys = m_Boxes.keys();
m_Mutex.unlock();
quint64 CurTick = GetCurTick();
foreach(const QString& Key, Keys) {
m_Mutex.lock();
SBox* Box = &m_Boxes[Key];
m_Mutex.unlock();
quint64 MinScanInterval = Box->ScanDuration * 100;
if (MinScanInterval < 30 * 1000)
MinScanInterval = 30 * 1000;
if (MinScanInterval > 30 * 60 * 1000)
MinScanInterval = 30 * 60 * 1000;
if (Box->Changed && (Box->Closed || Box->LastScan == 0 || (CurTick - Box->LastScan) > MinScanInterval)) {
qDebug() << "Rescanning:" << Key << "(" + QDateTime::currentDateTime().toString() + ")";
quint64 ScanStart = GetCurTick();
Box->TotalSize = CounDirSize(Key, Box);
Box->ScanDuration = GetCurTick() - ScanStart;
Box->LastScan = GetCurTick();
QMetaObject::invokeMethod(this, "UpdateBox", Qt::QueuedConnection,
//Q_RETURN_ARG(int, retVal),
Q_ARG(QString, Key)
);
Box->Changed = false;
}
m_Mutex.lock();
if (Box->pBox.isNull())
m_Boxes.remove(Key);
m_Mutex.unlock();
}
Sleep(1000);
}
}
void CBoxMonitor::UpdateBox(const QString& Path)
{
// Note: this functin runs in the main thread
m_Mutex.lock();
SBox Box = m_Boxes.value(Path);
m_Mutex.unlock();
if (Box.pBox)
Box.pBox->SetSize(Box.TotalSize);
}
void CBoxMonitor::AddBox(CSandBoxPlus* pBox, bool AndWatch)
{
QMutexLocker Lock(&m_Mutex);
m_Boxes[pBox->GetFileRoot()].pBox = pBox;
if (AndWatch) {
m_Boxes[pBox->GetFileRoot()].Closed = false;
AddDirectory(pBox->GetFileRoot().toStdWString().c_str(), true, FILE_NOTIFY_CHANGE_SIZE);
}
else
m_Boxes[pBox->GetFileRoot()].Changed = true;
}
void CBoxMonitor::CloseBox(CSandBoxPlus* pBox, bool AndClear)
{
QMutexLocker Lock(&m_Mutex);
if(AndClear)
m_Boxes[pBox->GetFileRoot()].pBox.clear();
m_Boxes[pBox->GetFileRoot()].Closed = true;
DetachDirectory(pBox->GetFileRoot().toStdWString().c_str());
}

View File

@ -0,0 +1,49 @@
#pragma once
#include "Helpers/ReadDirectoryChanges.h"
#include "SbiePlusAPI.h"
class CBoxMonitor : public QThread, public CReadDirectoryChanges
{
Q_OBJECT
public:
CBoxMonitor();
~CBoxMonitor();
virtual void Notify(const wstring& strDirectory);
virtual void run();
void AddBox(CSandBoxPlus* pBox, bool AndWatch = false);
void CloseBox(CSandBoxPlus* pBox, bool AndClear = false);
private slots:
void UpdateBox(const QString& Path);
protected:
struct SBox
{
SBox() {
Changed = false;
Closed = false;
LastScan = 0;
ScanDuration = 0;
TotalSize = 0;
}
QPointer<CSandBoxPlus> pBox;
bool Changed;
bool Closed;
quint64 LastScan;
quint64 ScanDuration;
quint64 TotalSize;
};
quint64 CounDirSize(const QString& Dir, SBox* Box);
QMutex m_Mutex;
QMap<QString, SBox> m_Boxes;
bool m_bTerminate;
};

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>

View File

@ -54,6 +54,42 @@
<layout class="QGridLayout" name="gridLayout_9">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_8">
<item row="11" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1" colspan="2">
<widget class="QCheckBox" name="chkNotifications">
<property name="text">
<string>Show Notifications for relevant log Messages</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="11" column="2">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="1" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
@ -68,83 +104,6 @@
</item>
</layout>
</item>
<item row="7" column="1" colspan="2">
<widget class="QCheckBox" name="chkAsyncBoxOps">
<property name="text">
<string>Run box operations asynchronously whenever possible (like content deletion)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="uiLang"/>
</item>
<item row="10" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="1" colspan="2">
<widget class="QCheckBox" name="chkShowRecovery">
<property name="text">
<string>Show first recovery window when emptying sandboxes</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QCheckBox" name="chkDarkTheme">
<property name="text">
<string>Use Dark Theme (fully applied after a restart)</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QCheckBox" name="chkWatchConfig">
<property name="text">
<string>Watch Sandboxie.ini for changes</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QCheckBox" name="chkNotifications">
<property name="text">
<string>Show Notifications for relevant log Messages</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="10" column="2">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="1" colspan="2">
<widget class="QCheckBox" name="chkNotifyRecovery">
<property name="text">
<string>Show recoverable files as notifications</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
@ -155,6 +114,13 @@
</property>
</widget>
</item>
<item row="7" column="1" colspan="2">
<widget class="QCheckBox" name="chkAsyncBoxOps">
<property name="text">
<string>Run box operations asynchronously whenever possible (like content deletion)</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QCheckBox" name="chkSandboxUrls">
<property name="text">
@ -165,6 +131,16 @@
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
<widget class="QCheckBox" name="chkShowRecovery">
<property name="text">
<string>Show first recovery window when emptying sandboxes</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="uiLang"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="font">
@ -179,6 +155,37 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QCheckBox" name="chkDarkTheme">
<property name="text">
<string>Use Dark Theme (fully applied after a restart)</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="1" colspan="2">
<widget class="QCheckBox" name="chkWatchConfig">
<property name="text">
<string>Watch Sandboxie.ini for changes</string>
</property>
</widget>
</item>
<item row="6" column="1" colspan="2">
<widget class="QCheckBox" name="chkNotifyRecovery">
<property name="text">
<string>Show recoverable files as notifications</string>
</property>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QCheckBox" name="chkMonitorSize">
<property name="text">
<string>Count and display the disk space ocupied by each sandbox</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -0,0 +1,120 @@
//
// The MIT License
//
// Copyright (c) 2010 James E Beveridge
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This sample code is for my blog entry titled, "Understanding ReadDirectoryChangesW"
// http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
// See ReadMe.txt for overview information.
#include "stdafx.h"
#include "ReadDirectoryChanges.h"
#include "ReadDirectoryChangesPrivate.h"
using namespace ReadDirectoryChangesPrivate;
///////////////////////////////////////////////////////////////////////////
// CReadDirectoryChanges
CReadDirectoryChanges::CReadDirectoryChanges()// int nMaxCount) : m_Notifications(nMaxCount)
{
m_hThread = NULL;
m_dwThreadId= 0;
m_pServer = new CReadChangesServer(this);
}
CReadDirectoryChanges::~CReadDirectoryChanges()
{
Terminate();
delete m_pServer;
}
void CReadDirectoryChanges::Init()
{
//
// Kick off the worker thread, which will be
// managed by CReadChangesServer.
//
m_hThread = (HANDLE)_beginthreadex(NULL,
0,
CReadChangesServer::ThreadStartProc,
m_pServer,
0,
&m_dwThreadId
);
}
void CReadDirectoryChanges::Terminate()
{
if (m_hThread)
{
::QueueUserAPC(CReadChangesServer::TerminateProc, m_hThread, (ULONG_PTR)m_pServer);
::WaitForSingleObjectEx(m_hThread, 10000, true);
::CloseHandle(m_hThread);
m_hThread = NULL;
m_dwThreadId = 0;
}
}
void CReadDirectoryChanges::AddDirectory( LPCTSTR szDirectory, BOOL bWatchSubtree, DWORD dwNotifyFilter, DWORD dwBufferSize )
{
if (!m_hThread)
Init();
CReadChangesRequest* pRequest = new CReadChangesRequest(m_pServer, szDirectory, bWatchSubtree, dwNotifyFilter, dwBufferSize);
QueueUserAPC(CReadChangesServer::AddDirectoryProc, m_hThread, (ULONG_PTR)pRequest);
}
void CReadDirectoryChanges::DetachDirectory( LPCTSTR szDirectory )
{
if (!m_hThread)
Init();
pair<ReadDirectoryChangesPrivate::CReadChangesServer*, wstring>* pRequest = new pair<ReadDirectoryChangesPrivate::CReadChangesServer*, wstring>(m_pServer, szDirectory);
QueueUserAPC(CReadChangesServer::DetachDirectoryProc, m_hThread, (ULONG_PTR)pRequest);
}
//void CReadDirectoryChanges::Push(DWORD dwAction, wstring& wstrFilename)
//{
// m_Notifications.push( TDirectoryChangeNotification(dwAction, wstrFilename) );
//}
//
//bool CReadDirectoryChanges::Pop(DWORD& dwAction, wstring& wstrFilename)
//{
// TDirectoryChangeNotification pair;
// if (!m_Notifications.pop(pair))
// return false;
//
// dwAction = pair.first;
// wstrFilename = pair.second;
//
// return true;
//}
//
//bool CReadDirectoryChanges::CheckOverflow()
//{
// bool b = m_Notifications.overflow();
// if (b)
// m_Notifications.clear();
// return b;
//}

View File

@ -0,0 +1,148 @@
//
// The MIT License
//
// Copyright (c) 2010 James E Beveridge
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This sample code is for my blog entry titled, "Understanding ReadDirectoryChangesW"
// http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
// See ReadMe.txt for overview information.
#pragma once
#include <windows.h>
#include "ThreadSafeQueue.h"
typedef pair<DWORD,wstring> TDirectoryChangeNotification;
namespace ReadDirectoryChangesPrivate
{
class CReadChangesServer;
}
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Track changes to filesystem directories and report them
/// to the caller via a thread-safe queue.
/// </summary>
/// <remarks>
/// <para>
/// This sample code is based on my blog entry titled, "Understanding ReadDirectoryChangesW"
/// http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
/// </para><para>
/// All functions in CReadDirectoryChangesServer run in
/// the context of the calling thread.
/// </para>
/// <example><code>
/// CReadDirectoryChanges changes;
/// changes.AddDirectory(_T("C:\\"), false, dwNotificationFlags);
///
/// const HANDLE handles[] = { hStopEvent, changes.GetWaitHandle() };
///
/// while (!bTerminate)
/// {
/// ::MsgWaitForMultipleObjectsEx(
/// _countof(handles),
/// handles,
/// INFINITE,
/// QS_ALLINPUT,
/// MWMO_INPUTAVAILABLE | MWMO_ALERTABLE);
/// switch (rc)
/// {
/// case WAIT_OBJECT_0 + 0:
/// bTerminate = true;
/// break;
/// case WAIT_OBJECT_0 + 1:
/// // We've received a notification in the queue.
/// {
/// DWORD dwAction;
/// wstring wstrFilename;
/// changes.Pop(dwAction, wstrFilename);
/// wprintf(L"%s %s\n", ExplainAction(dwAction), wstrFilename);
/// }
/// break;
/// case WAIT_OBJECT_0 + _countof(handles):
/// // Get and dispatch message
/// break;
/// case WAIT_IO_COMPLETION:
/// // APC complete.No action needed.
/// break;
/// }
/// }
/// </code></example>
/// </remarks>
class CReadDirectoryChanges
{
public:
CReadDirectoryChanges();// int nMaxChanges = 1000);
~CReadDirectoryChanges();
void Init();
void Terminate();
/// <summary>
/// Add a new directory to be monitored.
/// </summary>
/// <param name="wszDirectory">Directory to monitor.</param>
/// <param name="bWatchSubtree">True to also monitor subdirectories.</param>
/// <param name="dwNotifyFilter">The types of file system events to monitor, such as FILE_NOTIFY_CHANGE_ATTRIBUTES.</param>
/// <param name="dwBufferSize">The size of the buffer used for overlapped I/O.</param>
/// <remarks>
/// <para>
/// This function will make an APC call to the worker thread to issue a new
/// ReadDirectoryChangesW call for the given directory with the given flags.
/// </para>
/// </remarks>
void AddDirectory( LPCTSTR wszDirectory, BOOL bWatchSubtree, DWORD dwNotifyFilter, DWORD dwBufferSize=16384 );
void DetachDirectory( LPCTSTR wszDirectory );
virtual void Notify( const wstring& strDirectory ) {}
/// <summary>
/// Return a handle for the Win32 Wait... functions that will be
/// signaled when there is a queue entry.
/// </summary>
//HANDLE GetWaitHandle() { return m_Notifications.GetWaitHandle(); }
//
//bool Pop(DWORD& dwAction, wstring& wstrFilename);
//
//// "Push" is for usage by ReadChangesRequest. Not intended for external usage.
//void Push(DWORD dwAction, wstring& wstrFilename);
//
//// Check if the queue overflowed. If so, clear it and return true.
//bool CheckOverflow();
unsigned int GetThreadId() { return m_dwThreadId; }
protected:
ReadDirectoryChangesPrivate::CReadChangesServer* m_pServer;
HANDLE m_hThread;
unsigned int m_dwThreadId;
//CThreadSafeQueue<TDirectoryChangeNotification> m_Notifications;
};

View File

@ -0,0 +1,183 @@
//
// The MIT License
//
// Copyright (c) 2010 James E Beveridge
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This sample code is for my blog entry titled, "Understanding ReadDirectoryChangesW"
// http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
// See ReadMe.txt for overview information.
#include "stdafx.h"
#include "ReadDirectoryChanges.h"
#include "ReadDirectoryChangesPrivate.h"
#include <shlwapi.h>
// The namespace is a convenience to emphasize that these are internals
// interfaces. The namespace can be safely removed if you need to.
namespace ReadDirectoryChangesPrivate
{
///////////////////////////////////////////////////////////////////////////
// CReadChangesRequest
CReadChangesRequest::CReadChangesRequest(CReadChangesServer* pServer, LPCTSTR sz, BOOL b, DWORD dw, DWORD size)
{
m_pServer = pServer;
m_dwFilterFlags = dw;
m_bIncludeChildren = b;
m_wstrDirectory = sz;
m_hDirectory = 0;
::ZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
// The hEvent member is not used when there is a completion
// function, so it's ok to use it to point to the object.
m_Overlapped.hEvent = this;
m_Buffer.resize(size);
m_BackupBuffer.resize(size);
}
CReadChangesRequest::~CReadChangesRequest()
{
// RequestTermination() must have been called successfully.
_ASSERTE(m_hDirectory == NULL || m_hDirectory == INVALID_HANDLE_VALUE);
}
bool CReadChangesRequest::OpenDirectory()
{
// Allow this routine to be called redundantly.
if (m_hDirectory)
return true;
m_hDirectory = ::CreateFileW(
m_wstrDirectory.c_str(), // pointer to the file name
FILE_LIST_DIRECTORY, // access (read/write) mode
FILE_SHARE_READ // share mode
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE,
NULL, // security descriptor
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS // file attributes
| FILE_FLAG_OVERLAPPED,
NULL); // file with attributes to copy
if (m_hDirectory == INVALID_HANDLE_VALUE)
{
return false;
}
return true;
}
void CReadChangesRequest::BeginRead()
{
DWORD dwBytes=0;
// This call needs to be reissued after every APC.
BOOL success = ::ReadDirectoryChangesW(
m_hDirectory, // handle to directory
&m_Buffer[0], // read results buffer
m_Buffer.size(), // length of buffer
m_bIncludeChildren, // monitoring option
m_dwFilterFlags, // filter conditions
&dwBytes, // bytes returned
&m_Overlapped, // overlapped buffer
&NotificationCompletion); // completion routine
}
//static
VOID CALLBACK CReadChangesRequest::NotificationCompletion(
DWORD dwErrorCode, // completion code
DWORD dwNumberOfBytesTransfered, // number of bytes transferred
LPOVERLAPPED lpOverlapped) // I/O information buffer
{
CReadChangesRequest* pBlock = (CReadChangesRequest*)lpOverlapped->hEvent;
if (dwErrorCode == ERROR_OPERATION_ABORTED)
{
::InterlockedDecrement(&pBlock->m_pServer->m_nOutstandingRequests);
delete pBlock;
return;
}
// This might mean overflow? Not sure.
if(!dwNumberOfBytesTransfered)
return;
// Can't use sizeof(FILE_NOTIFY_INFORMATION) because
// the structure is padded to 16 bytes.
_ASSERTE(dwNumberOfBytesTransfered >= offsetof(FILE_NOTIFY_INFORMATION, FileName) + sizeof(WCHAR));
pBlock->BackupBuffer(dwNumberOfBytesTransfered);
// Get the new read issued as fast as possible. The documentation
// says that the original OVERLAPPED structure will not be used
// again once the completion routine is called.
pBlock->BeginRead();
//pBlock->ProcessNotification();
pBlock->m_pServer->m_pBase->Notify(pBlock->GetDirectory());
}
void CReadChangesRequest::ProcessNotification()
{
BYTE* pBase = m_BackupBuffer.data();
for (;;)
{
FILE_NOTIFY_INFORMATION& fni = (FILE_NOTIFY_INFORMATION&)*pBase;
wstring wstrFilename(fni.FileName, fni.FileNameLength/sizeof(wchar_t));
// Handle a trailing backslash, such as for a root directory.
if (m_wstrDirectory.back() != L'\\')
wstrFilename = m_wstrDirectory + L"\\" + wstrFilename;
else
wstrFilename = m_wstrDirectory + wstrFilename;
// If it could be a short filename, expand it.
LPCWSTR wszFilename = PathFindFileNameW(wstrFilename.c_str());
int len = lstrlenW(wszFilename);
// The maximum length of an 8.3 filename is twelve, including the dot.
if (len <= 12 && wcschr(wszFilename, L'~'))
{
// Convert to the long filename form. Unfortunately, this
// does not work for deletions, so it's an imperfect fix.
wchar_t wbuf[MAX_PATH];
if (::GetLongPathNameW(wstrFilename.c_str(), wbuf, _countof(wbuf)) > 0)
wstrFilename = wbuf;
}
//m_pServer->m_pBase->Push(fni.Action, wstrFilename);
if (!fni.NextEntryOffset)
break;
pBase += fni.NextEntryOffset;
};
}
}

View File

@ -0,0 +1,212 @@
//
// The MIT License
//
// Copyright (c) 2010 James E Beveridge
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This sample code is for my blog entry titled, "Understanding ReadDirectoryChangesW"
// http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
// See ReadMe.txt for overview information.
class CReadDirectoryChanges;
namespace ReadDirectoryChangesPrivate
{
class CReadChangesServer;
///////////////////////////////////////////////////////////////////////////
// All functions in CReadChangesRequest run in the context of the worker thread.
// One instance of this object is created for each call to AddDirectory().
class CReadChangesRequest
{
public:
CReadChangesRequest(CReadChangesServer* pServer, LPCTSTR sz, BOOL b, DWORD dw, DWORD size);
~CReadChangesRequest();
bool OpenDirectory();
void BeginRead();
// The dwSize is the actual number of bytes sent to the APC.
void BackupBuffer(DWORD dwSize)
{
// We could just swap back and forth between the two
// buffers, but this code is easier to understand and debug.
memcpy(&m_BackupBuffer[0], &m_Buffer[0], dwSize);
}
void ProcessNotification();
void RequestTermination()
{
// ::CancelIoEx(m_hDirectory, &m_Overlapped);
::CancelIo(m_hDirectory);
::CloseHandle(m_hDirectory);
m_hDirectory = nullptr;
}
const wstring& GetDirectory() { return m_wstrDirectory; }
CReadChangesServer* m_pServer;
protected:
static VOID CALLBACK NotificationCompletion(
DWORD dwErrorCode, // completion code
DWORD dwNumberOfBytesTransfered, // number of bytes transferred
LPOVERLAPPED lpOverlapped); // I/O information buffer
// Parameters from the caller for ReadDirectoryChangesW().
DWORD m_dwFilterFlags;
BOOL m_bIncludeChildren;
wstring m_wstrDirectory;
// Result of calling CreateFile().
HANDLE m_hDirectory;
// Required parameter for ReadDirectoryChangesW().
OVERLAPPED m_Overlapped;
// Data buffer for the request.
// Since the memory is allocated by malloc, it will always
// be aligned as required by ReadDirectoryChangesW().
vector<BYTE> m_Buffer;
// Double buffer strategy so that we can issue a new read
// request before we process the current buffer.
vector<BYTE> m_BackupBuffer;
};
///////////////////////////////////////////////////////////////////////////
// All functions in CReadChangesServer run in the context of the worker thread.
// One instance of this object is allocated for each instance of CReadDirectoryChanges.
// This class is responsible for thread startup, orderly thread shutdown, and shimming
// the various C++ member functions with C-style Win32 functions.
class CReadChangesServer
{
public:
CReadChangesServer(CReadDirectoryChanges* pParent)
{
m_bTerminate=false; m_nOutstandingRequests=0;m_pBase=pParent;
}
static unsigned int WINAPI ThreadStartProc(LPVOID arg)
{
CReadChangesServer* pServer = (CReadChangesServer*)arg;
pServer->Run();
return 0;
}
// Called by QueueUserAPC to start orderly shutdown.
static void CALLBACK TerminateProc(__in ULONG_PTR arg)
{
CReadChangesServer* pServer = (CReadChangesServer*)arg;
pServer->RequestTermination();
}
// Called by QueueUserAPC to add another directory.
static void CALLBACK AddDirectoryProc(__in ULONG_PTR arg)
{
CReadChangesRequest* pRequest = (CReadChangesRequest*)arg;
pRequest->m_pServer->AddDirectory(pRequest);
}
static void CALLBACK DetachDirectoryProc(__in ULONG_PTR arg)
{
pair<ReadDirectoryChangesPrivate::CReadChangesServer*, wstring>* pRequest = (pair<ReadDirectoryChangesPrivate::CReadChangesServer*, wstring>*)arg;
pRequest->first->DetachDirectory(pRequest);
}
CReadDirectoryChanges* m_pBase;
volatile DWORD m_nOutstandingRequests;
protected:
void Run()
{
while (m_nOutstandingRequests || !m_bTerminate)
{
DWORD rc = ::SleepEx(INFINITE, true);
}
}
void AddDirectory( CReadChangesRequest* pBlock )
{
for (auto I = m_pBlocks.begin(); I != m_pBlocks.end(); ++I)
{
if ((*I)->GetDirectory() == pBlock->GetDirectory())
{
delete pBlock;
return;
}
}
if (pBlock->OpenDirectory())
{
::InterlockedIncrement(&pBlock->m_pServer->m_nOutstandingRequests);
m_pBlocks.push_back(pBlock);
pBlock->BeginRead();
}
else
delete pBlock;
}
void DetachDirectory(pair<ReadDirectoryChangesPrivate::CReadChangesServer*, wstring>* pRequest)
{
for (auto I = m_pBlocks.begin(); I != m_pBlocks.end(); )
{
if ((*I)->GetDirectory() == pRequest->second)
{
::InterlockedDecrement(&pRequest->first->m_nOutstandingRequests);
(*I)->RequestTermination();
delete (*I);
I = m_pBlocks.erase(I);
}
else
++I;
}
delete pRequest;
}
void RequestTermination()
{
m_bTerminate = true;
for (DWORD i=0; i<m_pBlocks.size(); ++i)
{
// Each Request object will delete itself.
m_pBlocks[i]->RequestTermination();
}
m_pBlocks.clear();
}
vector<CReadChangesRequest*> m_pBlocks;
bool m_bTerminate;
};
}

View File

@ -0,0 +1,122 @@
//
// The MIT License
//
// Copyright (c) 2010 James E Beveridge
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This sample code is for my blog entry titled, "Understanding ReadDirectoryChangesW"
// http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
// See ReadMe.txt for overview information.
#include <list>
template <typename C>
class CThreadSafeQueue : protected std::list<C>
{
public:
CThreadSafeQueue(int nMaxCount)
{
m_bOverflow = false;
m_hSemaphore = ::CreateSemaphore(
NULL, // no security attributes
0, // initial count
nMaxCount, // max count
NULL); // anonymous
}
~CThreadSafeQueue()
{
::CloseHandle(m_hSemaphore);
m_hSemaphore = NULL;
}
void push(C& c)
{
//CComCritSecLock<CComAutoCriticalSection> lock( m_Crit, true );
QMutexLocker lock(&m_Mutex);
push_back( c );
//lock.Unlock();
lock.unlock();
if (!::ReleaseSemaphore(m_hSemaphore, 1, NULL))
{
// If the semaphore is full, then take back the entry.
//lock.Lock();
lock.relock();
pop_back();
if (GetLastError() == ERROR_TOO_MANY_POSTS)
{
m_bOverflow = true;
}
}
}
bool pop(C& c)
{
//CComCritSecLock<CComAutoCriticalSection> lock( m_Crit, true );
QMutexLocker lock(&m_Mutex);
// If the user calls pop() more than once after the
// semaphore is signaled, then the semaphore count will
// get out of sync. We fix that when the queue empties.
if (empty())
{
while (::WaitForSingleObject(m_hSemaphore, 0) != WAIT_TIMEOUT)
1;
return false;
}
c = front();
pop_front();
return true;
}
// If overflow, use this to clear the queue.
void clear()
{
//CComCritSecLock<CComAutoCriticalSection> lock( m_Crit, true );
QMutexLocker lock(&m_Mutex);
for (DWORD i=0; i<size(); i++)
WaitForSingleObject(m_hSemaphore, 0);
__super::clear();
m_bOverflow = false;
}
bool overflow()
{
return m_bOverflow;
}
HANDLE GetWaitHandle() { return m_hSemaphore; }
protected:
HANDLE m_hSemaphore;
//CComAutoCriticalSection m_Crit;
QMutex m_Mutex;
bool m_bOverflow;
};

View File

@ -71,8 +71,8 @@ QList<QVariant> CMonitorModel::Sync(const QMap<QString, CMonitorEntryPtr>& Entry
/*switch (section)
{
//case eType: ColValue.Formated = ; break;
//case eValue: ColValue.Formated = ; break;
//case eType: ColValue.Formatted = ; break;
//case eValue: ColValue.Formatted = ; break;
}*/
}

View File

@ -2,7 +2,6 @@
#include "SbieModel.h"
#include "../../MiscHelpers/Common/Common.h"
#include "../../MiscHelpers/Common/IconExtreactor.h"
#include <QFileIconProvider>
#include "../SandMan.h"
CSbieModel::CSbieModel(QObject *parent)
@ -114,6 +113,8 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
QMap<QList<QVariant>, QList<STreeNode*> > New;
QHash<QVariant, STreeNode*> Old = m_Map;
bool bWatchSize = theConf->GetBool("Options/WatchBoxSize", false);
foreach(const QString& Group, Groups.keys())
{
if (Group.isEmpty())
@ -232,6 +233,7 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
{
case eName: Value = pBox->GetName(); break;
case eStatus: Value = pBox.objectCast<CSandBoxPlus>()->GetStatusStr(); break;
case eInfo: Value = bWatchSize ? pBox.objectCast<CSandBoxPlus>()->GetSize() : 0; break;
case ePath: Value = pBox->GetFileRoot(); break;
}
@ -245,7 +247,8 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
switch (section)
{
case eName: ColValue.Formated = Value.toString().replace("_", " "); break;
case eName: ColValue.Formatted = Value.toString().replace("_", " "); break;
case eInfo: ColValue.Formatted = Value.toULongLong() > 0 ? FormatSize(Value.toULongLong()) : ""; break;
}
}
@ -273,8 +276,6 @@ bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QList<QVariant>& Path, cons
int ActiveCount = 0;
QFileIconProvider IconProvider;
foreach(const CBoxedProcessPtr& pProc, ProcessList)
{
QSharedPointer<CSbieProcess> pProcess = pProc.objectCast<CSbieProcess>();
@ -326,7 +327,7 @@ bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QList<QVariant>& Path, cons
//else
// pNode->Icon = icons.first().pixmap;
pNode->Icon = IconProvider.icon(QFileInfo(pProcess->GetFileName()));
pNode->Icon = m_IconProvider.icon(QFileInfo(pProcess->GetFileName()));
if (pNode->Icon.isNull() || !pNode->Icon.isValid())
pNode->Icon = m_ExeIcon;
Changed = 1;
@ -345,7 +346,7 @@ bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QList<QVariant>& Path, cons
case eStatus: Value = pProcess->GetStatusStr(); break;
case eTitle: Value = theAPI->GetProcessTitle(pProcess->GetProcessId()); break;
//case eLogCount: break; // todo Value = pProcess->GetResourceLog().count(); break;
case eTimeStamp: Value = pProcess->GetTimeStamp(); break;
case eInfo: Value = pProcess->GetTimeStamp(); break;
//case ePath: Value = pProcess->GetFileName(); break;
case ePath: {
QString CmdLine = pProcess->GetCommandLine();
@ -364,9 +365,9 @@ bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QList<QVariant>& Path, cons
switch (section)
{
case eProcessId: ColValue.Formated = QString::number(pProcess->GetProcessId()); break;
//case eLogCount: ColValue.Formated = QString::number(Value.toInt()); break;
case eTimeStamp: ColValue.Formated = pProcess->GetTimeStamp().toString("hh:mm:ss"); break;
case eProcessId: ColValue.Formatted = QString::number(pProcess->GetProcessId()); break;
//case eLogCount: ColValue.Formatted = QString::number(Value.toInt()); break;
case eInfo: ColValue.Formatted = pProcess->GetTimeStamp().toString("hh:mm:ss"); break;
}
}
@ -475,8 +476,10 @@ QVariant CSbieModel::headerData(int section, Qt::Orientation orientation, int ro
case eProcessId: return tr("Process ID");
case eStatus: return tr("Status");
case eTitle: return tr("Title");
case eInfo: return tr("Info");
//case eSize: return tr("Size");
//case eLogCount: return tr("Log Count");
case eTimeStamp: return tr("Start Time");
//case eTimeStamp: return tr("Start Time");
case ePath: return tr("Path / Command Line");
}
}

View File

@ -4,7 +4,7 @@
#include "../SbieProcess.h"
#include "../../MiscHelpers/Common/TreeItemModel.h"
#include <QMimeData>
#include <QFileIconProvider>
class CSbieModel : public CTreeItemModel
{
@ -45,8 +45,10 @@ public:
eProcessId,
eTitle,
eStatus,
eInfo,
//eSize,
//eLogCount,
eTimeStamp,
//eTimeStamp,
ePath,
eCount
};
@ -92,4 +94,5 @@ private:
QIcon m_ExeIcon;
QString m_SbieModelMimeType;
QFileIconProvider m_IconProvider;
};

View File

@ -155,20 +155,20 @@ QList<QVariant> CTraceModel::Sync(const QVector<CTraceEntryPtr>& EntryList, int
/*case eProcess:
{
CBoxedProcessPtr pProcess = theAPI->GetProcessById(pEntry->GetProcessId());
ColValue.Formated = QString("%1 (%2, %3)").arg(pProcess.isNull() ? tr("Unknown") : pProcess->GetProcessName()).arg(pEntry->GetProcessId()).arg(pEntry->GetThreadId());
ColValue.Formatted = QString("%1 (%2, %3)").arg(pProcess.isNull() ? tr("Unknown") : pProcess->GetProcessName()).arg(pEntry->GetProcessId()).arg(pEntry->GetThreadId());
break;
}
case eTimeStamp: ColValue.Formated = pEntry->GetTimeStamp().toString("hh:mm:ss.zzz"); break;*/
case eTimeStamp: ColValue.Formatted = pEntry->GetTimeStamp().toString("hh:mm:ss.zzz"); break;*/
case eProcess:
if(!m_bTree) {
QString Name = pEntry->GetProcessName();
ColValue.Formated = QString("%1 (%2, %3) - %4").arg(Name.isEmpty() ? tr("Unknown") : Name)
ColValue.Formatted = QString("%1 (%2, %3) - %4").arg(Name.isEmpty() ? tr("Unknown") : Name)
.arg(pEntry->GetProcessId()).arg(pEntry->GetThreadId()).arg(pEntry->GetTimeStamp().toString("hh:mm:ss.zzz"));
} else
ColValue.Formated = pEntry->GetTimeStamp().toString("hh:mm:ss.zzz");
ColValue.Formatted = pEntry->GetTimeStamp().toString("hh:mm:ss.zzz");
break;
//case eType: ColValue.Formated = ; break;
//case eValue: ColValue.Formated = ; break;
//case eType: ColValue.Formatted = ; break;
//case eValue: ColValue.Formatted = ; break;
}
}
@ -252,9 +252,9 @@ CTraceModel::STreeNode* CTraceModel::MkVirtualNode(const QVariant& Id, STreeNode
QString Name = GetProcessName(pid);
pNode->Values[0].Raw = pid;
if(!Name.isEmpty())
pNode->Values[0].Formated = tr("%1 (%2)").arg(Name).arg(pid);
pNode->Values[0].Formatted = tr("%1 (%2)").arg(Name).arg(pid);
else
pNode->Values[0].Formated = tr("Process %1").arg(pid);
pNode->Values[0].Formatted = tr("Process %1").arg(pid);
}
else if (typeId.first == "tid")
{
@ -262,10 +262,10 @@ CTraceModel::STreeNode* CTraceModel::MkVirtualNode(const QVariant& Id, STreeNode
quint32 pid = Split2(pParent->ID.toString(), "_").second.toUInt();
LogThreadId(pid, tid);
pNode->Values[0].Raw = tid;
pNode->Values[0].Formated = tr("Thread %1").arg(tid);
pNode->Values[0].Formatted = tr("Thread %1").arg(tid);
}
else*/
pNode->Values[0].Raw = pNode->Values[0].Formated = Id;
pNode->Values[0].Raw = pNode->Values[0].Formatted = Id;
return pNode;
}

View File

@ -68,6 +68,7 @@
<file>IconOffC.png</file>
<file>IconOffCx.png</file>
<file>Actions/Monitor.png</file>
<file>SideLogo.png</file>
</qresource>
<qresource prefix="/Boxes">
<file alias="Empty3">Boxes/sandbox-b-empty.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -21,6 +21,7 @@
#include "Views/TraceView.h"
#include "Windows/SelectBoxWindow.h"
#include "../UGlobalHotkey/uglobalhotkeys.h"
#include "Wizards/SetupWizard.h"
#include "Helpers/WinAdmin.h"
CSbiePlusAPI* theAPI = NULL;
@ -203,25 +204,6 @@ CSandMan::CSandMan(QWidget *parent)
CreateTrayMenu();
/*QWidgetAction* pBoxWidget = new QWidgetAction(m_pTrayMenu);
QWidget* pWidget = new QWidget();
pWidget->setMaximumHeight(200);
QGridLayout* pLayout = new QGridLayout();
pLayout->addWidget(pBar, 0, 0);
pWidget->setLayout(pLayout);
pBoxWidget->setDefaultWidget(pWidget);*/
/*QLabel* pLabel = new QLabel("test");
pLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
pLabel->setAlignment(Qt::AlignCenter);
pBoxWidget->setDefaultWidget(pLabel);*/
//m_pTrayMenu->addAction(pBoxWidget);
//m_pTrayMenu->addSeparator();
m_pTrayMenu->addAction(m_pExit);
bool bAutoRun = QApplication::arguments().contains("-autorun");
if(g_PendingMessage.isEmpty()){
@ -355,6 +337,7 @@ void CSandMan::CreateMenus()
m_pStopSvc = m_pMaintenanceItems->addAction(tr("Stop Service"), this, SLOT(OnMaintenance()));
m_pUninstallSvc = m_pMaintenanceItems->addAction(tr("Uninstall Service"), this, SLOT(OnMaintenance()));
m_pMaintenance->addSeparator();
m_pSetupWizard = m_pMaintenance->addAction(CSandMan::GetIcon("Software"), tr("Setup Wizard"), this, SLOT(OnMaintenance()));
if(IsFullyPortable())
m_pUninstallAll = m_pMaintenance->addAction(CSandMan::GetIcon("Uninstall"), tr("Uninstall All"), this, SLOT(OnMaintenance()));
@ -384,6 +367,8 @@ void CSandMan::CreateMenus()
m_pMenuView->addSeparator();
m_pRefreshAll = m_pMenuView->addAction(CSandMan::GetIcon("Recover"), tr("Refresh View"), this, SLOT(OnRefresh()));
m_pCleanUpMenu = m_pMenuView->addMenu(CSandMan::GetIcon("Clean"), tr("Clean Up"));
m_pCleanUpProcesses = m_pCleanUpMenu->addAction(tr("Cleanup Processes"), this, SLOT(OnCleanUp()));
m_pCleanUpMenu->addSeparator();
@ -594,6 +579,25 @@ void CSandMan::CreateTrayMenu()
m_pDisableForce2 = m_pTrayMenu->addAction(tr("Pause Forcing Programs"), this, SLOT(OnDisableForce2()));
m_pDisableForce2->setCheckable(true);
m_pTrayMenu->addSeparator();
/*QWidgetAction* pBoxWidget = new QWidgetAction(m_pTrayMenu);
QWidget* pWidget = new QWidget();
pWidget->setMaximumHeight(200);
QGridLayout* pLayout = new QGridLayout();
pLayout->addWidget(pBar, 0, 0);
pWidget->setLayout(pLayout);
pBoxWidget->setDefaultWidget(pWidget);*/
/*QLabel* pLabel = new QLabel("test");
pLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
pLabel->setAlignment(Qt::AlignCenter);
pBoxWidget->setDefaultWidget(pLabel);*/
//m_pTrayMenu->addAction(pBoxWidget);
//m_pTrayMenu->addSeparator();
m_pTrayMenu->addAction(m_pExit);
}
void CSandMan::OnExit()
@ -1027,8 +1031,10 @@ SB_STATUS CSandMan::DeleteBoxContent(const CSandBoxPtr& pBox, EDelMode Mode, boo
Status = pBox->CleanBox();
Ret = Status;
if (Status.GetStatus() == OP_ASYNC)
if (Status.GetStatus() == OP_ASYNC) {
Ret = AddAsyncOp(Status.GetValue(), true, tr("Auto Deleting %1 Content").arg(pBox->GetName()));
pBox.objectCast<CSandBoxPlus>()->UpdateSize();
}
}
finish:
@ -1142,8 +1148,7 @@ void CSandMan::OnStatusChanged()
OnIniReloaded();
if (theConf->GetBool("Options/WatchIni", true))
theAPI->WatchIni(true);
theAPI->WatchIni(true, theConf->GetBool("Options/WatchIni", true));
if (!theAPI->ReloadCert().IsError()) {
CSettingsWindow::LoadCertificate();
@ -1173,6 +1178,18 @@ void CSandMan::OnStatusChanged()
OnLogMessage(tr("Default sandbox not found; creating: %1").arg("DefaultBox"));
theAPI->CreateBox("DefaultBox");
}
int BusinessUse = theConf->GetInt("Options/BusinessUse", 2);
if (g_CertInfo.business && BusinessUse == 0) // if we have a Business cert switch to that use case
theConf->SetValue("Options/BusinessUse", 1);
int WizardLevel = theConf->GetBool("Options/WizardLevel", 0);
if (WizardLevel == 0) {
if (CSetupWizard::ShowWizard())
UpdateSettings();
else // if user canceled mark that and not show again
theConf->SetValue("Options/WizardLevel", -1);
}
}
else
{
@ -1726,7 +1743,13 @@ void CSandMan::OnMaintenance()
CSettingsWindow__RemoveContextMenu();
CSbieUtils::RemoveContextMenu2();
}
else if (sender() == m_pSetupWizard) {
if (CSetupWizard::ShowWizard())
UpdateSettings();
return;
}
HandleMaintenance(Status);
}
@ -1838,6 +1861,20 @@ void CSandMan::SetViewMode(bool bAdvanced)
}
}
void CSandMan::OnRefresh()
{
if (!theAPI->IsConnected())
return;
theAPI->ReloadBoxes(true);
if (theConf->GetBool("Options/WatchBoxSize", false)) {
QMap<QString, CSandBoxPtr> Boxes = theAPI->GetAllBoxes();
foreach(const CSandBoxPtr & pBox, Boxes)
pBox.objectCast<CSandBoxPlus>()->UpdateSize();
}
}
void CSandMan::OnCleanUp()
{
if (sender() == m_pCleanUpMsgLog || sender() == m_pCleanUpButton)
@ -2031,6 +2068,8 @@ void CSandMan::OnReloadIni()
void CSandMan::OnIniReloaded()
{
OnLogSbieMessage(0, QStringList() << "Sandboxie config has been reloaded" << "" << "", 4);
m_pBoxView->ReloadUserConfig();
m_pPopUpWindow->ReloadHiddenMessages();
}

View File

@ -179,6 +179,7 @@ private slots:
void OnViewMode(QAction* action);
void OnAlwaysTop();
void OnRefresh();
void OnCleanUp();
void OnProcView();
@ -258,6 +259,7 @@ private:
QAction* m_pUninstallSvc;
QAction* m_pStopAll;
QAction* m_pUninstallAll;
QAction* m_pSetupWizard;
QAction* m_pExit;
QMenu* m_pMenuView;
@ -265,6 +267,7 @@ private:
QAction* m_pShowHidden;
QAction* m_pWndTopMost;
int m_iMenuViewPos;
QAction* m_pRefreshAll;
QMenu* m_pCleanUpMenu;
QAction* m_pCleanUpProcesses;
QAction* m_pCleanUpMsgLog;

View File

@ -8,6 +8,7 @@ HEADERS += ./stdafx.h \
./SbiePlusAPI.h \
./SbieProcess.h \
./BoxJob.h \
./BoxMonitor.h \
./Models/SbieModel.h \
./Models/TraceModel.h \
./Models/MonitorModel.h \
@ -16,6 +17,8 @@ HEADERS += ./stdafx.h \
./Dialogs/MultiErrorDialog.h \
./Helpers/FindTool.h \
./Helpers/WinAdmin.h \
./Helpers/ReadDirectoryChanges.h \
./Helpers/ReadDirectoryChangesPrivate.h \
./Windows/NewBoxWindow.h \
./Windows/RecoveryWindow.h \
./Windows/PopUpWindow.h \
@ -23,7 +26,8 @@ HEADERS += ./stdafx.h \
./Windows/SettingsWindow.h \
./Windows/OptionsWindow.h \
./Windows/SelectBoxWindow.h \
./Windows/FileBrowserWindow.h
./Windows/FileBrowserWindow.h\
./Wizards/SetupWizard.h
SOURCES += ./main.cpp \
./stdafx.cpp \
@ -31,6 +35,7 @@ SOURCES += ./main.cpp \
./SbiePlusAPI.cpp \
./SbieProcess.cpp \
./BoxJob.cpp \
./BoxMonitor.cpp \
./Models/TraceModel.cpp \
./Models/MonitorModel.cpp \
./Models/SbieModel.cpp \
@ -39,6 +44,8 @@ SOURCES += ./main.cpp \
./Dialogs/MultiErrorDialog.cpp \
./Helpers/FindTool.cpp \
./Helpers/WinAdmin.cpp \
./Helpers/ReadDirectoryChanges.cpp \
./Helpers/ReadDirectoryChangesPrivate.cpp \
./Helpers/WindowFromPointEx.cpp \
./Windows/NewBoxWindow.cpp \
./Windows/OptionsWindow.cpp \
@ -57,7 +64,8 @@ SOURCES += ./main.cpp \
./Windows/SettingsWindow.cpp \
./Windows/SnapshotsWindow.cpp \
./Windows/SelectBoxWindow.cpp \
./Windows/FileBrowserWindow.cpp
./Windows/FileBrowserWindow.cpp\
./Wizards/SetupWizard.cpp
FORMS += ./Forms/NewBoxWindow.ui \
./Forms/OptionsWindow.ui \

View File

@ -196,8 +196,11 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="BoxJob.cpp" />
<ClCompile Include="BoxMonitor.cpp" />
<ClCompile Include="Dialogs\MultiErrorDialog.cpp" />
<ClCompile Include="Helpers\FindTool.cpp" />
<ClCompile Include="Helpers\ReadDirectoryChanges.cpp" />
<ClCompile Include="Helpers\ReadDirectoryChangesPrivate.cpp" />
<ClCompile Include="Helpers\WinAdmin.cpp" />
<ClCompile Include="Helpers\WindowFromPointEx.cpp" />
<ClCompile Include="main.cpp" />
@ -233,8 +236,10 @@
<ClCompile Include="Windows\SelectBoxWindow.cpp" />
<ClCompile Include="Windows\SettingsWindow.cpp" />
<ClCompile Include="Windows\SnapshotsWindow.cpp" />
<ClCompile Include="Wizards\SetupWizard.cpp" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="Wizards\SetupWizard.h" />
<QtMoc Include="Windows\FileBrowserWindow.h" />
<QtMoc Include="Windows\SelectBoxWindow.h" />
<QtMoc Include="Views\TraceView.h" />
@ -250,7 +255,12 @@
<QtMoc Include="Models\TraceModel.h" />
<QtMoc Include="Dialogs\MultiErrorDialog.h" />
<QtMoc Include="BoxJob.h" />
<ClInclude Include="..\version.h" />
<QtMoc Include="BoxMonitor.h" />
<ClInclude Include="Helpers\FindTool.h" />
<ClInclude Include="Helpers\ReadDirectoryChanges.h" />
<ClInclude Include="Helpers\ReadDirectoryChangesPrivate.h" />
<ClInclude Include="Helpers\ThreadSafeQueue.h" />
<ClInclude Include="Helpers\WinAdmin.h" />
<QtMoc Include="Models\MonitorModel.h" />
<ClInclude Include="resource.h" />

View File

@ -46,6 +46,9 @@
<Extensions>ts</Extensions>
<ParseFiles>false</ParseFiles>
</Filter>
<Filter Include="Wizards">
<UniqueIdentifier>{4bf40c7e-2ce4-4528-813c-3b48b8c56155}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
@ -147,6 +150,18 @@
<ClCompile Include="Models\MonitorModel.cpp">
<Filter>Models</Filter>
</ClCompile>
<ClCompile Include="Wizards\SetupWizard.cpp">
<Filter>Wizards</Filter>
</ClCompile>
<ClCompile Include="Helpers\ReadDirectoryChanges.cpp">
<Filter>Helpers</Filter>
</ClCompile>
<ClCompile Include="Helpers\ReadDirectoryChangesPrivate.cpp">
<Filter>Helpers</Filter>
</ClCompile>
<ClCompile Include="BoxMonitor.cpp">
<Filter>SandMan</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@ -161,6 +176,18 @@
<ClInclude Include="resource.h">
<Filter>Resource Files</Filter>
</ClInclude>
<ClInclude Include="..\version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Helpers\ReadDirectoryChanges.h">
<Filter>Helpers</Filter>
</ClInclude>
<ClInclude Include="Helpers\ReadDirectoryChangesPrivate.h">
<Filter>Helpers</Filter>
</ClInclude>
<ClInclude Include="Helpers\ThreadSafeQueue.h">
<Filter>Helpers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<QtMoc Include="SandMan.h">
@ -217,6 +244,12 @@
<QtMoc Include="Models\MonitorModel.h">
<Filter>Models</Filter>
</QtMoc>
<QtMoc Include="Wizards\SetupWizard.h">
<Filter>Wizards</Filter>
</QtMoc>
<QtMoc Include="BoxMonitor.h">
<Filter>SandMan</Filter>
</QtMoc>
</ItemGroup>
<ItemGroup>
<QtRcc Include="Resources\SandMan.qrc">

View File

@ -4,14 +4,18 @@
#include "SandMan.h"
#include "..\MiscHelpers\Common\Common.h"
#include <windows.h>
#include "BoxMonitor.h"
CSbiePlusAPI::CSbiePlusAPI(QObject* parent) : CSbieAPI(parent)
{
m_BoxMonitor = new CBoxMonitor();
m_JobCount = 0;
}
CSbiePlusAPI::~CSbiePlusAPI()
{
delete m_BoxMonitor;
}
CSandBox* CSbiePlusAPI::NewSandBox(const QString& BoxName, class CSbieAPI* pAPI)
@ -94,7 +98,10 @@ CSandBoxPlus::CSandBoxPlus(const QString& BoxName, class CSbieAPI* pAPI) : CSand
m_bApplicationCompartment = false;
m_iUnsecureDebugging = 0;
m_TotalSize = theConf->GetValue("SizeCache/" + m_Name, -1).toLongLong();
m_SuspendRecovery = false;
m_IsEmpty = false;
m_pOptionsWnd = NULL;
m_pRecoveryWnd = NULL;
@ -154,11 +161,56 @@ void CSandBoxPlus::UpdateDetails()
CSandBox::UpdateDetails();
}
void CSandBoxPlus::SetBoxPaths(const QString& FilePath, const QString& RegPath, const QString& IpcPath)
{
CSandBox::SetBoxPaths(FilePath, RegPath, IpcPath);
m_IsEmpty = IsEmpty();
if (theConf->GetBool("Options/WatchBoxSize", false) && m_TotalSize == -1)
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->AddBox(this);
}
void CSandBoxPlus::UpdateSize()
{
m_TotalSize = -1;
if(theConf->GetBool("Options/WatchBoxSize", false))
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->AddBox(this);
m_IsEmpty = IsEmpty();
}
void CSandBoxPlus::SetSize(quint64 Size)
{
m_TotalSize = Size;
theConf->SetValue("SizeCache/" + m_Name, Size);
}
void CSandBoxPlus::OpenBox()
{
CSandBox::OpenBox();
m_IsEmpty = false;
if (theConf->GetBool("Options/WatchBoxSize", false))
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->AddBox(this, true);
}
void CSandBoxPlus::CloseBox()
{
CSandBox::CloseBox();
m_SuspendRecovery = false;
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->CloseBox(this);
}
SB_PROGRESS CSandBoxPlus::CleanBox()
{
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->CloseBox(this, true);
SB_PROGRESS Status = CSandBox::CleanBox();
return Status;
}
bool CSandBoxPlus::CheckUnsecureConfig() const
@ -190,7 +242,7 @@ QString CSandBoxPlus::GetStatusStr() const
QStringList Status;
if (IsEmpty())
if (m_IsEmpty)
Status.append(tr("Empty"));
if (m_bApplicationCompartment)
@ -513,6 +565,8 @@ void CSandBoxPlus::OnAsyncFinished()
if (!m_JobQueue.isEmpty())
StartNextJob();
else
UpdateSize();
}
void CSandBoxPlus::OnAsyncMessage(const QString& Text)

View File

@ -29,6 +29,9 @@ protected:
int m_JobCount;
QMultiMap<quint32, QString> m_WindowMap;
friend class CSandBoxPlus;
class CBoxMonitor* m_BoxMonitor;
};
///////////////////////////////////////////////////////////////////////////////
@ -44,8 +47,13 @@ public:
virtual void UpdateDetails();
virtual void SetBoxPaths(const QString& FilePath, const QString& RegPath, const QString& IpcPath);
virtual void OpenBox();
virtual void CloseBox();
virtual SB_PROGRESS CleanBox();
virtual QString GetStatusStr() const;
virtual void SetLogApi(bool bEnable);
@ -72,6 +80,10 @@ public:
virtual void SetLeaderProgram(const QString& ProgName, bool bSet);
virtual int IsLeaderProgram(const QString& ProgName);
virtual void UpdateSize();
virtual quint64 GetSize() const { if(m_TotalSize == -1) return 0; return m_TotalSize; }
virtual void SetSize(quint64 Size); //{ m_TotalSize = Size; }
virtual bool IsRecoverySuspended() const { return m_SuspendRecovery; }
virtual void SetSuspendRecovery(bool bSet = true) { m_SuspendRecovery = bSet; }
@ -126,7 +138,10 @@ protected:
bool m_bApplicationCompartment;
int m_iUnsecureDebugging;
quint64 m_TotalSize;
bool m_SuspendRecovery;
bool m_IsEmpty;
QString m_StatusStr;
QSet<QString> m_RecentPrograms;

View File

@ -8,7 +8,6 @@
#include "../../MiscHelpers/Common/Common.h"
#include "../Windows/OptionsWindow.h"
#include "../Windows/SnapshotsWindow.h"
#include <QFileIconProvider>
#include "../../MiscHelpers/Common/CheckableMessageBox.h"
#include "../Windows/RecoveryWindow.h"
#include "../Windows/NewBoxWindow.h"
@ -1351,8 +1350,6 @@ void CSbieView::UpdateRunMenu(const CSandBoxPtr& pBox)
while (m_iMenuRun < m_pMenuRun->actions().count())
m_pMenuRun->removeAction(m_pMenuRun->actions().at(m_iMenuRun));
QFileIconProvider IconProvider;
QStringList RunOptions = pBox->GetTextList("RunCommand", true);
foreach(const QString& RunOption, RunOptions)
{
@ -1372,7 +1369,7 @@ void CSbieView::UpdateRunMenu(const CSandBoxPtr& pBox)
if (Path.left(1) == "\\")
Path.prepend(pBox->GetFileRoot());
pAction->setIcon(IconProvider.icon(QFileInfo(Path)));
pAction->setIcon(m_IconProvider.icon(QFileInfo(Path)));
pAction->setData(NameCmd.second);
}

View File

@ -3,6 +3,7 @@
#include "../../MiscHelpers/Common/PanelView.h"
#include "../../MiscHelpers/Common/TreeviewEx.h"
#include "../Models/SbieModel.h"
#include <QFileIconProvider>
class CSbieView : public CPanelView
{
@ -152,4 +153,6 @@ private:
QAction* m_pRemove;
int m_iMenuRun;
QFileIconProvider m_IconProvider;
};

View File

@ -218,7 +218,7 @@ void CFileBrowserWindow::OnFileMenu(const QPoint&)
FileList.append(qMakePair(BoxedPath, RecoveryFolder + "\\" + FileName));
}
else {
QString RealPath = theAPI->GetRealPath(m_pBox, BoxedPath);
QString RealPath = theAPI->GetRealPath(m_pBox.data(), BoxedPath);
FileList.append(qMakePair(BoxedPath, RealPath));
}
}

View File

@ -312,12 +312,12 @@ int CRecoveryWindow::FindFiles(const QString& Folder)
//foreach(const QString & Path, theAPI->GetBoxedPath(m_pBox, Folder))
// Count += FindFiles(Folder, Path, Folder);
//return Count;
return FindFiles(theAPI->GetBoxedPath(m_pBox, Folder), Folder, Folder).first;
return FindFiles(theAPI->GetBoxedPath(m_pBox.data(), Folder), Folder, Folder).first;
}
int CRecoveryWindow::FindBoxFiles(const QString& Folder)
{
QString RealFolder = theAPI->GetRealPath(m_pBox, m_pBox->GetFileRoot() + Folder);
QString RealFolder = theAPI->GetRealPath(m_pBox.data(), m_pBox->GetFileRoot() + Folder);
if (RealFolder.isEmpty())
return 0;
return FindFiles(m_pBox->GetFileRoot() + Folder, RealFolder, RealFolder).first;

View File

@ -301,6 +301,8 @@ void CSettingsWindow::LoadSettings()
ui.chkPanic->setChecked(theConf->GetBool("Options/EnablePanicKey", false));
ui.keyPanic->setKeySequence(QKeySequence(theConf->GetString("Options/PanicKeySequence", "Shift+Pause")));
ui.chkMonitorSize->setChecked(theConf->GetBool("Options/WatchBoxSize", false));
ui.chkWatchConfig->setChecked(theConf->GetBool("Options/WatchIni", true));
@ -458,6 +460,8 @@ void CSettingsWindow::SaveSettings()
theConf->SetValue("Options/EnablePanicKey", ui.chkPanic->isChecked());
theConf->SetValue("Options/PanicKeySequence", ui.keyPanic->keySequence().toString());
theConf->SetValue("Options/WatchBoxSize", ui.chkMonitorSize->isChecked());
theConf->SetValue("Options/WatchIni", ui.chkWatchConfig->isChecked());
theConf->SetValue("Options/SysTrayIcon", ui.cmbSysTray->currentIndex());
@ -570,80 +574,26 @@ void CSettingsWindow::SaveSettings()
{
QByteArray Certificate = ui.txtCertificate->toPlainText().toUtf8();
if (g_Certificate != Certificate) {
QPalette palette = QApplication::palette();
QString CertPath = theAPI->GetSbiePath() + "\\Certificate.dat";
if (!Certificate.isEmpty()) {
auto Args = GetArguments(Certificate, L'\n', L':');
bool bLooksOk = true;
if (Args.value("NAME").isEmpty()) // mandatory
bLooksOk = false;
//if (Args.value("UPDATEKEY").isEmpty())
// bLooksOk = false;
if (Args.value("SIGNATURE").isEmpty()) // absolutely mandatory
bLooksOk = false;
if (bLooksOk) {
QString TempPath = QDir::tempPath() + "/Sbie+Certificate.dat";
QFile CertFile(TempPath);
if (CertFile.open(QFile::WriteOnly)) {
CertFile.write(Certificate);
CertFile.close();
}
WindowsMoveFile(TempPath.replace("/", "\\"), CertPath.replace("/", "\\"));
}
else {
Certificate.clear();
QMessageBox::critical(this, "Sandboxie-Plus", tr("This does not look like a certificate, please enter the entire certificate, not just a portion of it."));
}
}
else if(!g_Certificate.isEmpty()){
WindowsMoveFile(CertPath.replace("/", "\\"), "");
}
if (theGUI->m_DarkTheme)
palette.setColor(QPalette::Text, Qt::black);
ui.lblCertExp->setVisible(false);
bool bRet = ApplyCertificate(Certificate, this);
if (Certificate.isEmpty())
{
palette.setColor(QPalette::Base, Qt::white);
}
else if (!theAPI->ReloadCert().IsError())
{
g_FeatureFlags = theAPI->GetFeatureFlags();
theGUI->UpdateCertState();
if (g_CertInfo.expired || g_CertInfo.outdated) {
if(g_CertInfo.expired)
QMessageBox::information(this, "Sandboxie-Plus", tr("This certificate is unfortunately expired."));
else
QMessageBox::information(this, "Sandboxie-Plus", tr("This certificate is unfortunately outdated."));
palette.setColor(QPalette::Base, QColor(255, 255, 192));
ui.lblCertExp->setVisible(true);
}
else {
QMessageBox::information(this, "Sandboxie-Plus", tr("Thank you for supporting the development of Sandboxie-Plus."));
palette.setColor(QPalette::Base, QColor(192, 255, 192));
}
else if (!bRet)
palette.setColor(QPalette::Base, QColor(255, 192, 192));
else if (g_CertInfo.expired || g_CertInfo.outdated) {
palette.setColor(QPalette::Base, QColor(255, 255, 192));
ui.lblCertExp->setVisible(true);
}
else
{
QMessageBox::critical(this, "Sandboxie-Plus", tr("This support certificate is not valid."));
palette.setColor(QPalette::Base, QColor(255, 192, 192));
Certificate.clear();
g_CertInfo.State = 0;
}
g_Certificate = Certificate;
palette.setColor(QPalette::Base, QColor(192, 255, 192));
ui.txtCertificate->setPalette(palette);
}
@ -660,6 +610,71 @@ void CSettingsWindow::SaveSettings()
emit OptionsChanged();
}
bool CSettingsWindow::ApplyCertificate(const QByteArray &Certificate, QWidget* widget)
{
QString CertPath = theAPI->GetSbiePath() + "\\Certificate.dat";
if (!Certificate.isEmpty()) {
auto Args = GetArguments(Certificate, L'\n', L':');
bool bLooksOk = true;
if (Args.value("NAME").isEmpty()) // mandatory
bLooksOk = false;
//if (Args.value("UPDATEKEY").isEmpty())
// bLooksOk = false;
if (Args.value("SIGNATURE").isEmpty()) // absolutely mandatory
bLooksOk = false;
if (bLooksOk) {
QString TempPath = QDir::tempPath() + "/Sbie+Certificate.dat";
QFile CertFile(TempPath);
if (CertFile.open(QFile::WriteOnly)) {
CertFile.write(Certificate);
CertFile.close();
}
WindowsMoveFile(TempPath.replace("/", "\\"), CertPath.replace("/", "\\"));
}
else {
QMessageBox::critical(widget, "Sandboxie-Plus", tr("This does not look like a certificate, please enter the entire certificate not just a portion of it."));
return false;
}
}
else if(!g_Certificate.isEmpty()){
WindowsMoveFile(CertPath.replace("/", "\\"), "");
}
if (Certificate.isEmpty())
return false;
if (!theAPI->ReloadCert().IsError())
{
g_FeatureFlags = theAPI->GetFeatureFlags();
theGUI->UpdateCertState();
if (g_CertInfo.expired || g_CertInfo.outdated) {
if(g_CertInfo.expired)
QMessageBox::information(widget, "Sandboxie-Plus", tr("This certificate is unfortunately expired."));
else
QMessageBox::information(widget, "Sandboxie-Plus", tr("This certificate is unfortunately outdated."));
}
else {
QMessageBox::information(widget, "Sandboxie-Plus", tr("Thank you for supporting the development of Sandboxie-Plus."));
}
g_Certificate = Certificate;
return true;
}
else
{
QMessageBox::critical(widget, "Sandboxie-Plus", tr("This support certificate is not valid."));
g_CertInfo.State = 0;
g_Certificate.clear();
return false;
}
}
void CSettingsWindow::apply()
{
if (!ui.btnEditIni->isEnabled())

View File

@ -24,6 +24,8 @@ public:
virtual void accept() {}
virtual void reject();
static bool ApplyCertificate(const QByteArray &Certificate, QWidget* widget);
static void LoadCertificate();
signals:

View File

@ -0,0 +1,327 @@
#include "stdafx.h"
#include "SetupWizard.h"
#include "../MiscHelpers/Common/Common.h"
#include "../Windows/SettingsWindow.h"
#include "../SandMan.h"
#include "Helpers/WinAdmin.h"
QString emailRegExp = QStringLiteral(".+@.+");
CSetupWizard::CSetupWizard(QWidget *parent)
: QWizard(parent)
{
setPage(Page_Intro, new CIntroPage);
setPage(Page_Certificate, new CCertificatePage);
setPage(Page_Shell, new CShellPage);
setPage(Page_Finish, new CFinishPage);
setWizardStyle(ModernStyle);
//setOption(HaveHelpButton, true);
setPixmap(QWizard::LogoPixmap, QPixmap(":/SandMan.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
connect(this, &QWizard::helpRequested, this, &CSetupWizard::showHelp);
setWindowTitle(tr("Setup Wizard"));
}
void CSetupWizard::showHelp()
{
static QString lastHelpMessage;
QString message;
switch (currentId()) {
case Page_Intro:
message = tr("The decision you make here will affect which page you get to see next.");
break;
default:
message = tr("This help is likely not to be of any help.");
}
if (lastHelpMessage == message)
message = tr("Sorry, I already gave what help I could.");
QMessageBox::information(this, tr("Setup Wizard Help"), message);
lastHelpMessage = message;
}
bool CSetupWizard::ShowWizard()
{
CSetupWizard wizard;
if (!wizard.exec())
return false;
//bool useBusiness = wizard.field("useBusiness").toBool();
//QString Certificate = wizard.field("useCertificate").toString();
//bool isEvaluate = wizard.field("isEvaluate").toBool();
AutorunEnable(wizard.field("isAutoStart").toBool());
if (wizard.field("useContecxtMenu").toBool())
CSettingsWindow__AddContextMenu();
if (wizard.field("useBrowserIcon").toBool())
CSettingsWindow__AddBrowserIcon();
if (wizard.field("isUpdate").toBool()) {
theConf->SetValue("Options/CheckForUpdates", 1);
theConf->SetValue("Options/DownloadUpdates", 1);
theConf->SetValue("Options/InstallUpdates", 1);
}
theConf->SetValue("Options/WizardLevel", 1);
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// CIntroPage
//
CIntroPage::CIntroPage(QWidget *parent)
: QWizardPage(parent)
{
setTitle(tr("Introduction"));
setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png"));
QVBoxLayout *layout = new QVBoxLayout;
QLabel* pTopLabel = new QLabel(tr("Welcome to the Setup Wizard. This wizard will help you to configure your copy of <b>Sandboxie-Plus</b>. "
"You can start this wizard at any time from the Box->Maintenance if you do not wish to complete it now."));
pTopLabel->setWordWrap(true);
layout->addWidget(pTopLabel);
QWidget* pSpace = new QWidget();
pSpace->setMinimumHeight(16);
layout->addWidget(pSpace);
int BusinessUse = theConf->GetInt("Options/BusinessUse", 2);
m_pLabel = new QLabel(tr("Select how you would like to use Sandboxie-Plus"));
layout->addWidget(m_pLabel);
m_pPersonalRadio = new QRadioButton(tr("&Personally for private non comertial use"));
layout->addWidget(m_pPersonalRadio);
connect(m_pPersonalRadio, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged()));
registerField("usePersonal", m_pPersonalRadio);
m_pBusinessRadio = new QRadioButton(tr("&Commercially for business or enterprise use"));
layout->addWidget(m_pBusinessRadio);
connect(m_pBusinessRadio, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged()));
registerField("useBusiness", m_pBusinessRadio);
if (BusinessUse != 2) {
m_pLabel->setEnabled(false);
m_pPersonalRadio->setChecked(BusinessUse == 0);
m_pPersonalRadio->setEnabled(false);
m_pBusinessRadio->setChecked(BusinessUse == 1);
m_pBusinessRadio->setEnabled(false);
}
setLayout(layout);
}
int CIntroPage::nextId() const
{
if(g_Certificate.isEmpty())
return CSetupWizard::Page_Certificate;
return CSetupWizard::Page_Shell;
}
bool CIntroPage::isComplete() const
{
if (m_pLabel->isEnabled() && !m_pPersonalRadio->isChecked() && !m_pBusinessRadio->isChecked())
return false;
return QWizardPage::isComplete();
}
//////////////////////////////////////////////////////////////////////////////////////////
// CCertificatePage
//
CCertificatePage::CCertificatePage(QWidget *parent)
: QWizardPage(parent)
{
setTitle(tr("Install your <b>Sandboxie-Plus</b> support certificate"));
setSubTitle(tr("If you have a supporter certificate, please fill it into the field below."));
QGridLayout *layout = new QGridLayout;
m_pTopLabel = new QLabel();
m_pTopLabel->setWordWrap(true);
layout->addWidget(m_pTopLabel);
m_pCertificate = new QPlainTextEdit();
m_pCertificate->setMaximumSize(QSize(16777215, 73));
m_pCertificate->setPlaceholderText(
"NAME: User Name\n"
"LEVEL: ULTIMATE\n"
"DATE: dd.mm.yyyy\n"
"UPDATEKEY: 00000000000000000000000000000000\n"
"SIGNATURE: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
);
//layout->addWidget(m_pCertificate); // we dont show this page when there already is a certificat present
connect(m_pCertificate, SIGNAL(textChanged()), this, SIGNAL(completeChanged()));
registerField("useCertificate", m_pCertificate, "plainText");
m_pEvaluate = new QCheckBox(tr("Start evaluation without a certificate for a limited periode of time."));
layout->addWidget(m_pEvaluate);
connect(m_pEvaluate, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged()));
registerField("isEvaluate", m_pEvaluate);
layout->addWidget(new QWidget());
setLayout(layout);
}
void CCertificatePage::initializePage()
{
m_pCertificate->setPlainText(g_Certificate);
if (field("useBusiness").toBool())
{
theConf->SetValue("Options/BusinessUse", 1);
m_pTopLabel->setText(
tr("To use <b>Sandboxie-Plus</b> in a business setting an apropriate business use <a href=\"https://sandboxie-plus.com/go.php?to=sbie-get-cert\">support certificate</a> is required. "
"If you do not yet have the required certificate(s) you can get those from the <a href=\"https://xanasoft.com/shop/\">xanasoft.com web shop</a>.")
);
m_pEvaluate->setVisible(true);
}
else
{
theConf->SetValue("Options/BusinessUse", 0);
m_pTopLabel->setText(
tr("<b>Sandboxie-Plus</b> provides additional features and box types exclusively to <u>project supporters</u>. "
"Boxes like the Privacy Enhanced boxes <b><font color='red'>protect user data from illicit access</font></b> by the sandboxed programs. "
"If you are not yet a supporter then please consider <a href=\"https://sandboxie-plus.com/go.php?to=sbie-get-cert\">supporting the project</a> "
"to to ensure furtehr developement of sandboxie and to receive a <a href=\"https://sandboxie-plus.com/go.php?to=sbie-cert\">supporter certificate</a>.")
);
m_pEvaluate->setVisible(false);
}
}
int CCertificatePage::nextId() const
{
return CSetupWizard::Page_Shell;
}
bool CCertificatePage::isComplete() const
{
if (field("useBusiness").toBool())
{
m_pCertificate->setEnabled(!m_pEvaluate->isChecked());
if (m_pCertificate->toPlainText().isEmpty() && !m_pEvaluate->isChecked())
return false;
}
return QWizardPage::isComplete();
}
bool CCertificatePage::validatePage()
{
QByteArray Certificate = m_pCertificate->toPlainText().toLatin1();
if (!m_pEvaluate->isChecked() && !Certificate.isEmpty() && g_Certificate != Certificate) {
return CSettingsWindow::ApplyCertificate(Certificate, this);
}
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// CShellPage
//
CShellPage::CShellPage(QWidget *parent)
: QWizardPage(parent)
{
setTitle(tr("Configure <b>Sandboxie-Plus</b> shell integration"));
setSubTitle(tr("Configure how Sandboxie-Plus should integrate with your system."));
QVBoxLayout *layout = new QVBoxLayout;
m_pAutoStart = new QCheckBox(tr("Start UI with Windows"));
m_pAutoStart->setChecked(true);
layout->addWidget(m_pAutoStart);
registerField("isAutoStart", m_pAutoStart);
m_pContecxtMenu = new QCheckBox(tr("Add 'Run Sandboxed' to the explorer context menu"));
m_pContecxtMenu->setChecked(true);
layout->addWidget(m_pContecxtMenu);
registerField("useContecxtMenu", m_pContecxtMenu);
m_pBrowserIcon = new QCheckBox(tr("Add desktop shortcut for starting Web browser under Sandboxie"));
m_pBrowserIcon->setChecked(true);
layout->addWidget(m_pBrowserIcon);
registerField("useBrowserIcon", m_pBrowserIcon);
setLayout(layout);
}
int CShellPage::nextId() const
{
return CSetupWizard::Page_Finish;
}
//////////////////////////////////////////////////////////////////////////////////////////
// CFinishPage
//
CFinishPage::CFinishPage(QWidget *parent)
: QWizardPage(parent)
{
setTitle(tr("Complete Your Configuration"));
setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png"));
QVBoxLayout *layout = new QVBoxLayout;
m_pLabel = new QLabel;
m_pLabel->setWordWrap(true);
m_pLabel->setText(tr("Almost complete, click Finish to apply all selected options and finisch the wizard."));
layout->addWidget(m_pLabel);
QWidget* pSpacer = new QWidget();
pSpacer->setMinimumHeight(16);
layout->addWidget(pSpacer);
//QLabel* pLabel = new QLabel;
//pLabel->setWordWrap(true);
//pLabel->setText(tr("Like with any other security product it's important to keep your Sandboxie-Plus up to date."));
//layout->addWidget(pLabel);
m_pUpdate = new QCheckBox(tr("Keep Sandboxie-Plus up to date."));
m_pUpdate->setChecked(true);
layout->addWidget(m_pUpdate);
registerField("isUpdate", m_pUpdate);
setLayout(layout);
}
int CFinishPage::nextId() const
{
return -1;
}
void CFinishPage::initializePage()
{
}
//void ConclusionPage::setVisible(bool visible)
//{
// QWizardPage::setVisible(visible);
//
// if (visible) {
// wizard()->setButtonText(QWizard::CustomButton1, tr("&Print"));
// wizard()->setOption(QWizard::HaveCustomButton1, true);
// connect(wizard(), &QWizard::customButtonClicked,
// this, &ConclusionPage::printButtonClicked);
// } else {
// wizard()->setOption(QWizard::HaveCustomButton1, false);
// disconnect(wizard(), &QWizard::customButtonClicked,
// this, &ConclusionPage::printButtonClicked);
// }
//}

View File

@ -0,0 +1,107 @@
#pragma once
#include <QWizard>
QT_BEGIN_NAMESPACE
class QCheckBox;
class QLabel;
class QLineEdit;
class QRadioButton;
QT_END_NAMESPACE
class CSetupWizard : public QWizard
{
Q_OBJECT
public:
enum { Page_Intro, Page_Certificate, Page_Shell, Page_Finish };
CSetupWizard(QWidget *parent = nullptr);
static bool ShowWizard();
private slots:
void showHelp();
};
//////////////////////////////////////////////////////////////////////////////////////////
// CIntroPage
//
class CIntroPage : public QWizardPage
{
Q_OBJECT
public:
CIntroPage(QWidget *parent = nullptr);
int nextId() const override;
bool isComplete() const override;
private:
QLabel* m_pLabel;
QRadioButton *m_pPersonalRadio;
QRadioButton *m_pBusinessRadio;
};
//////////////////////////////////////////////////////////////////////////////////////////
// CCertificatePage
//
class CCertificatePage : public QWizardPage
{
Q_OBJECT
public:
CCertificatePage(QWidget *parent = nullptr);
void initializePage() override;
int nextId() const override;
bool isComplete() const override;
bool validatePage() override;
private:
QLabel* m_pTopLabel;
QPlainTextEdit* m_pCertificate;
QCheckBox* m_pEvaluate;
};
//////////////////////////////////////////////////////////////////////////////////////////
// CShellPage
//
class CShellPage : public QWizardPage
{
Q_OBJECT
public:
CShellPage(QWidget *parent = nullptr);
int nextId() const override;
private:
QCheckBox *m_pAutoStart;
QCheckBox *m_pContecxtMenu;
QCheckBox *m_pBrowserIcon;
};
//////////////////////////////////////////////////////////////////////////////////////////
// CFinishPage
//
class CFinishPage : public QWizardPage
{
Q_OBJECT
public:
CFinishPage(QWidget *parent = nullptr);
void initializePage() override;
int nextId() const override;
//void setVisible(bool visible) override;
private:
QLabel *m_pLabel;
QCheckBox *m_pUpdate;
};

View File

@ -106,6 +106,7 @@ using namespace std;
#include <QColorDialog>
#include <QToolButton>
#include <QScreen>
#include <QRadioButton>
// other includes

View File

@ -1,8 +1,8 @@
#pragma once
#define VERSION_MJR 1
#define VERSION_MIN 0
#define VERSION_REV 22
#define VERSION_MIN 1
#define VERSION_REV 0
#define VERSION_UPD 0
#ifndef STR