1.1.0
This commit is contained in:
parent
46904667b0
commit
1d29ff173e
39
CHANGELOG.md
39
CHANGELOG.md
|
@ -5,15 +5,44 @@ 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 options menu command to reset the GUI [#1589](https://github.com/sandboxie-plus/Sandboxie/issues/1589)
|
||||
|
||||
### 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
|
||||
- disabled a couple driver based workarounds for boxes in compartment mode as then thay should not be required
|
||||
|
||||
|
||||
### Fixed
|
||||
- fixed folder rename issues (this requires UseFileDeleteV2=y) [#71](https://github.com/sandboxie-plus/Sandboxie/issues/71)
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.0.10 / 5.55.10] - 2022-01-??
|
||||
|
||||
### Added
|
||||
- added option to show only boxes in hray with runnign processes [#1186](https://github.com/sandboxie-plus/Sandboxie/issues/1186)
|
||||
todo:- add reset ui ooption
|
||||
- added option to show only boxes in tray with runnign processes [#1186](https://github.com/sandboxie-plus/Sandboxie/issues/1186)
|
||||
-- additional option show only pinned bixes, in box options a bix can be set to be always shown in theay list (Pinned)
|
||||
- add reset ui option
|
||||
- added 'Run Un-Sandboxed' context menu option
|
||||
- added new trigger "OnBoxDelete" that allows to specify a command that is run UNBOXED just before the box content gets deleted
|
||||
-- note: this can be used as a replacemetn to the DeleteCommand [#591](https://github.com/sandboxie-plus/Sandboxie/issues/591)
|
||||
- sellected box operations (deletion) no longer show the progress dialog [1061](https://github.com/sandboxie-plus/Sandboxie/issues/1061)
|
||||
-- instead a box with a running operation show a blinking hour glass icon, the context menu can be used to cancel the operation
|
||||
|
||||
### Changed
|
||||
- HideHostProcess=program.exe can now be used to hide sandboxie services [#1336](https://github.com/sandboxie-plus/Sandboxie/issues/1336)
|
||||
- updater blocking is now done using a template with BlockSoftwareUpdaters
|
||||
- updater blocking is now done using a template called BlockSoftwareUpdaters
|
||||
- enchanced "StartProgram=..." making "StartCommand=..." obsolete
|
||||
-- for same functionality as "StartCommand=..." use "StartProgram=%SbieHome%\Start.exe ..."
|
||||
- merged "Auto Start" General tab with the "Auto Exec" Advanced tab into a universal"Triggers" Advanced tab
|
||||
|
||||
### Fixed
|
||||
- fixed a couple issues with the new breakout process feature and improved security (thanks Diversenok)
|
||||
|
@ -22,8 +51,8 @@ todo:- add reset ui ooption
|
|||
- fixed issue handling commandline invokation [#1133](https://github.com/sandboxie-plus/Sandboxie/issues/1133)
|
||||
- fixed ui issue with main window state when switching always on top attribute [#1169](https://github.com/sandboxie-plus/Sandboxie/issues/1169)
|
||||
- fixed issue with box context menu in tray list [1106](https://github.com/sandboxie-plus/Sandboxie/issues/1106)
|
||||
|
||||
|
||||
- fixed issue with "AutoExec=..."
|
||||
- fixed issues canceling box deletion operations didn't working [1061](https://github.com/sandboxie-plus/Sandboxie/issues/1061)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#ifndef _MY_VERSION_H
|
||||
#define _MY_VERSION_H
|
||||
|
||||
#define MY_VERSION_BINARY 5,55,10
|
||||
#define MY_VERSION_STRING "5.55.10"
|
||||
#define MY_VERSION_BINARY 5,56,0
|
||||
#define MY_VERSION_STRING "5.56.0"
|
||||
#define MY_VERSION_COMPAT "5.55.0" // this refers to the driver ABI compatibility
|
||||
|
||||
// These #defines are used by either Resource Compiler or NSIS installer
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -420,6 +420,33 @@ void DbgPrint(const char* format, ...)
|
|||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// DbgPrint
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void DbgTrace(const char* format, ...)
|
||||
{
|
||||
va_list va_args;
|
||||
va_start(va_args, format);
|
||||
|
||||
char *tmp1 = Dll_AllocTemp(510);
|
||||
|
||||
extern int(*P_vsnprintf)(char *_Buffer, size_t Count, const char * const, va_list Args);
|
||||
P_vsnprintf(tmp1, 510, format, va_args);
|
||||
|
||||
WCHAR *tmp2 = Dll_AllocTemp(510*sizeof(WCHAR));
|
||||
Sbie_snwprintf((WCHAR *)tmp2, 510, L"%S", tmp1);
|
||||
|
||||
SbieApi_MonitorPut2(MONITOR_OTHER | MONITOR_TRACE, tmp2, FALSE);
|
||||
|
||||
Dll_Free(tmp1);
|
||||
|
||||
va_end(va_args);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
int Debug_Init(void);
|
||||
|
||||
void DbgPrint(const char* format, ...);
|
||||
void DbgTrace(const char* format, ...);
|
||||
|
||||
#endif WITH_DEBUG
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ 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 MOVE_NAME_BUFFER 3
|
||||
#define NAME_BUFFER_COUNT 4
|
||||
#define NAME_BUFFER_DEPTH 24
|
||||
|
||||
|
||||
|
@ -280,6 +281,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;
|
||||
|
||||
|
@ -348,6 +350,11 @@ void Dll_FreeTlsData(void);
|
|||
WCHAR *Dll_GetTlsNameBuffer(THREAD_DATA *data, ULONG which, ULONG size);
|
||||
void Dll_PushTlsNameBuffer(THREAD_DATA *data);
|
||||
void Dll_PopTlsNameBuffer(THREAD_DATA *data);
|
||||
//void Dll_PushTlsNameBuffer_(THREAD_DATA *data, char* func);
|
||||
//void Dll_PopTlsNameBuffer_(THREAD_DATA *data, char* func);
|
||||
//#define Dll_PushTlsNameBuffer(x) Dll_PushTlsNameBuffer_(x, __FUNCTION__)
|
||||
//#define Dll_PopTlsNameBuffer(x) Dll_PopTlsNameBuffer_(x, __FUNCTION__)
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -444,7 +451,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);
|
||||
|
||||
|
@ -477,9 +484,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)
|
||||
|
@ -612,7 +617,7 @@ BOOLEAN Win32_Init(HMODULE hmodule);
|
|||
// Functions (init for DllMain)
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
BOOLEAN File_InitHandles(void);
|
||||
BOOLEAN Handle_Init(void);
|
||||
|
||||
BOOLEAN Key_Init(void);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -326,6 +327,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
|
||||
//
|
||||
|
@ -348,7 +371,7 @@ _FX void Dll_InitInjected(void)
|
|||
Dll_FixWow64Syscall();
|
||||
|
||||
if (ok)
|
||||
ok = File_InitHandles();
|
||||
ok = Handle_Init();
|
||||
|
||||
if (ok)
|
||||
ok = Obj_Init();
|
||||
|
@ -418,7 +441,7 @@ _FX void Dll_InitInjected(void)
|
|||
if (ok)
|
||||
ok = Gui_InitConsole1();
|
||||
|
||||
if (ok)
|
||||
if (ok) // Note: Ldr_Init may cause rpcss to be started early
|
||||
ok = Ldr_Init(); // last to initialize
|
||||
|
||||
//
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "dll.h"
|
||||
#include "common/pool.h"
|
||||
#include <stdio.h>
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -372,8 +373,10 @@ ALIGNED WCHAR *Dll_GetTlsNameBuffer(
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
//ALIGNED void Dll_PushTlsNameBuffer_(THREAD_DATA *data, char* func)
|
||||
ALIGNED void Dll_PushTlsNameBuffer(THREAD_DATA *data)
|
||||
{
|
||||
//DbgTrace("Dll_PushTlsNameBuffer, %s, %d\r\n", func, data->depth);
|
||||
++data->depth;
|
||||
if (data->depth > NAME_BUFFER_DEPTH - 4)
|
||||
SbieApi_Log(2310, L"%d", data->depth);
|
||||
|
@ -388,8 +391,11 @@ ALIGNED void Dll_PushTlsNameBuffer(THREAD_DATA *data)
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
//_FX void Dll_PopTlsNameBuffer_(THREAD_DATA *data, char* func)
|
||||
_FX void Dll_PopTlsNameBuffer(THREAD_DATA *data)
|
||||
{
|
||||
//DbgTrace("Dll_PopTlsNameBuffer, %s, %d\r\n", func, data->depth-1);
|
||||
|
||||
//
|
||||
// debug checks: the name buffer is allocated at least 64 bytes
|
||||
// more than needed. fill these with 0xCC, andd check that later
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -278,6 +278,7 @@ _FX NTSTATUS File_MigrateFile(
|
|||
|
||||
if (status == STATUS_SHARING_VIOLATION) {
|
||||
|
||||
if (!Dll_CompartmentMode) // NoDriverAssist
|
||||
status = SbieApi_OpenFile(&TrueHandle, TruePath);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
|
|
|
@ -0,0 +1,763 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// 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();
|
||||
static 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, BOOLEAN TrueExists);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// 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, MOVE_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_LoadPathTree_internal
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX VOID 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// File_LoadPathTree
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX BOOLEAN File_LoadPathTree()
|
||||
{
|
||||
EnterCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
File_LoadPathTree_internal(&File_PathRoot, FILE_PATH_FILE_NAME);
|
||||
|
||||
LeaveCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
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 VOID File_MarkDeleted_internal(LIST* Root, const WCHAR* Path)
|
||||
{
|
||||
EnterCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
// 1. remove deleted branche
|
||||
|
||||
LIST* Parent = NULL;
|
||||
PATH_NODE* Node = File_FindPathBranche_internal(Root, Path, &Parent, FALSE);
|
||||
if (Node) {
|
||||
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
|
||||
|
||||
LeaveCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
File_SavePathTree();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// File_MarkDeleted_v2
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX NTSTATUS File_MarkDeleted_v2(const WCHAR* TruePath)
|
||||
{
|
||||
//
|
||||
// add a file or directory to the deleted list
|
||||
//
|
||||
|
||||
EnterCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
File_MarkDeleted_internal(&File_PathRoot, TruePath);
|
||||
|
||||
LeaveCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
File_SavePathTree();
|
||||
|
||||
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, BOOLEAN TrueExists)
|
||||
{
|
||||
// 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
|
||||
|
||||
if (TrueExists || HasRelocation || (Node && Node->items.count > 0)) {
|
||||
|
||||
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(&File_PathRoot, OldTruePath, &OldOldTruePath, TRUE);
|
||||
if (OldOldTruePath) OldTruePath = OldOldTruePath;
|
||||
}
|
||||
|
||||
if (TrueExists || HasRelocation) {
|
||||
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, BOOLEAN TrueExists)
|
||||
{
|
||||
//
|
||||
// List a mapping for the new location
|
||||
//
|
||||
|
||||
EnterCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
File_SetRelocation_internal(&File_PathRoot, OldTruePath, NewTruePath, TrueExists);
|
||||
|
||||
LeaveCriticalSection(File_PathRoot_CritSec);
|
||||
|
||||
File_SavePathTree();
|
||||
|
||||
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
|
@ -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");
|
||||
|
@ -248,6 +236,16 @@ _FX BOOLEAN File_Init(void)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (File_Delete_v2)
|
||||
File_InitDelete_v2();
|
||||
|
||||
// Note: loading the file tha way its done now only works once file hooks are installed so this must eb here
|
||||
extern BOOLEAN Key_Delete_v2;
|
||||
extern BOOLEAN Key_InitDelete_v2();
|
||||
if (Key_Delete_v2)
|
||||
Key_InitDelete_v2();
|
||||
|
||||
//
|
||||
// support for Google Chrome flash plugin process
|
||||
//
|
||||
|
@ -517,6 +515,7 @@ _FX BOOLEAN File_InitDrives(ULONG DriveMask)
|
|||
status = NtOpenSymbolicLinkObject(
|
||||
&handle, SYMBOLIC_LINK_QUERY, &objattrs);
|
||||
|
||||
if (!Dll_CompartmentMode) // NoDriverAssist
|
||||
if (status == STATUS_ACCESS_DENIED) {
|
||||
|
||||
//
|
||||
|
@ -1747,6 +1746,7 @@ _FX void File_GetSetDeviceMap(WCHAR *DeviceMap96)
|
|||
|
||||
status = NtOpenDirectoryObject(&handle, DIRECTORY_QUERY, &objattrs);
|
||||
|
||||
if (!Dll_CompartmentMode) // NoDriverAssist
|
||||
if (status == STATUS_ACCESS_DENIED) {
|
||||
|
||||
//
|
||||
|
@ -1788,57 +1788,3 @@ _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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
@ -794,12 +798,13 @@ _FX WCHAR *File_TranslateTempLinks_2(WCHAR *input_str, ULONG input_len)
|
|||
|
||||
_FX NTSTATUS File_GetFileName(HANDLE FileHandle, ULONG NameLen, WCHAR* NameBuf)
|
||||
{
|
||||
//extern P_GetFinalPathNameByHandle __sys_GetFinalPathNameByHandleW;
|
||||
//if (__sys_GetFinalPathNameByHandleW(FileHandle, NameBuf, NameLen, VOLUME_NAME_NT) > 0)
|
||||
// return STATUS_SUCCESS;
|
||||
//return STATUS_UNSUCCESSFUL;
|
||||
|
||||
if (!Dll_CompartmentMode || !__sys_GetFinalPathNameByHandleW) // NoDriverAssist
|
||||
return SbieApi_GetFileName(FileHandle, NameLen, NameBuf);
|
||||
|
||||
// available in vista and later
|
||||
if (__sys_GetFinalPathNameByHandleW(FileHandle, NameBuf, NameLen, VOLUME_NAME_NT) > 0)
|
||||
return STATUS_SUCCESS;
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1164,7 +1164,7 @@ _FX NTSTATUS File_NtFsControlFile(
|
|||
InputBuffer, InputBufferLength);
|
||||
SetLastError(LastError);
|
||||
|
||||
} else if (IoControlCode == FSCTL_PIPE_IMPERSONATE) {
|
||||
} else if (IoControlCode == FSCTL_PIPE_IMPERSONATE && !Dll_CompartmentMode) {
|
||||
|
||||
SbieApi_Log(2205, L"ImpersonateNamedPipe");
|
||||
if (Proc_ImpersonateSelf(TRUE))
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
//
|
||||
// this function handles the Delete V2 as well as with snapshots
|
||||
//
|
||||
|
||||
if (File_Delete_v2) {
|
||||
|
||||
//
|
||||
// check true path relocation and deleteion for the active state
|
||||
//
|
||||
|
||||
Relocation = NULL;
|
||||
Flags = File_GetPathFlags(TruePath, &Relocation);
|
||||
if (FILE_PATH_DELETED(Flags))
|
||||
goto finish;
|
||||
|
||||
if (Relocation) {
|
||||
|
||||
if (!File_Snapshot)
|
||||
goto finish; // take a shortcut
|
||||
|
||||
TruePath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, wcslen(Relocation));
|
||||
wcscpy((WCHAR*)TruePath, Relocation);
|
||||
}
|
||||
}
|
||||
|
||||
if (File_Snapshot != NULL) {
|
||||
|
||||
NTSTATUS status;
|
||||
OBJECT_ATTRIBUTES objattrs;
|
||||
UNICODE_STRING objname;
|
||||
ULONG FileType;
|
||||
|
||||
InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
|
||||
for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != lastSnapshot; Cur_Snapshot = Cur_Snapshot->Parent)
|
||||
{
|
||||
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 finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (File_Delete_v2) {
|
||||
|
||||
//
|
||||
// check true path relocation and deleteion for the current snapshot
|
||||
//
|
||||
|
||||
Flags = File_GetPathFlags_internal(&Cur_Snapshot->PathRoot, TruePath, &Relocation, TRUE);
|
||||
if (FILE_PATH_DELETED(Flags))
|
||||
goto finish;
|
||||
|
||||
if (Relocation) {
|
||||
|
||||
if (!Cur_Snapshot->Parent)
|
||||
break; // take a shortcut
|
||||
|
||||
TruePath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, (wcslen(Relocation) + 1) * sizeof(WCHAR));
|
||||
wcscpy((WCHAR*)TruePath, Relocation);
|
||||
|
||||
if (!CopyPath)
|
||||
continue;
|
||||
|
||||
//
|
||||
// update the copy file name
|
||||
//
|
||||
|
||||
Dll_PushTlsNameBuffer(TlsData);
|
||||
|
||||
WCHAR* TruePath2, *CopyPath2;
|
||||
RtlInitUnicodeString(&objname, Relocation);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
|
||||
if (pRelocation) *pRelocation = Relocation; // can be template buffer or move buffer
|
||||
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++;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -379,6 +379,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);
|
||||
|
@ -525,6 +526,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;
|
||||
|
@ -665,6 +681,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))
|
||||
|
@ -688,11 +719,23 @@ check_sandbox_prefix:
|
|||
|
||||
*OutCopyPath = name;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
*name = L'\0';
|
||||
|
||||
//
|
||||
|
@ -883,6 +926,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
|
||||
|
@ -3730,6 +3776,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)) {
|
||||
|
||||
|
|
|
@ -23,10 +23,11 @@
|
|||
|
||||
#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
|
||||
|
@ -305,6 +306,8 @@ static const WCHAR *Key_Wow6432Node = L"\\Wow6432Node\\";
|
|||
|
||||
static BOOLEAN Key_UseObjectNames = FALSE;
|
||||
|
||||
BOOLEAN Key_Delete_v2 = FALSE;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Debug Prints
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -337,6 +340,7 @@ static BOOLEAN Key_UseObjectNames = FALSE;
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "key_del.c"
|
||||
#include "key_merge.c"
|
||||
#include "key_util.c"
|
||||
|
||||
|
@ -357,6 +361,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);
|
||||
|
||||
|
@ -450,6 +456,16 @@ _FX NTSTATUS Key_GetName(
|
|||
|
||||
if (RootDirectory) {
|
||||
|
||||
name = Handle_GetRelocationPath(RootDirectory, objname_len);
|
||||
if (name) {
|
||||
|
||||
*OutTruePath = name;
|
||||
|
||||
name = (*OutTruePath) + wcslen(*OutTruePath);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
length = 256;
|
||||
name = Dll_GetTlsNameBuffer(
|
||||
TlsData, TRUE_NAME_BUFFER, length + objname_len);
|
||||
|
@ -504,6 +520,8 @@ _FX NTSTATUS Key_GetName(
|
|||
+ ((KEY_NAME_INFORMATION *)name)->NameLength / sizeof(WCHAR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (objname_len) {
|
||||
|
||||
*name = L'\\';
|
||||
|
@ -1095,6 +1113,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,
|
||||
|
@ -1119,6 +1172,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,
|
||||
|
@ -1146,6 +1210,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
|
|||
|
||||
CopyPathCreated = FALSE;
|
||||
TruePathExists = FALSE;
|
||||
OriginalPath = NULL;
|
||||
TrueOpened = FALSE;
|
||||
|
||||
TlsData->key_NtCreateKey_lock = TRUE;
|
||||
|
||||
|
@ -1225,6 +1291,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
|
|||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) TrueOpened = TRUE;
|
||||
|
||||
__leave;
|
||||
|
||||
#undef KEY_READ_WOW64
|
||||
|
@ -1256,6 +1324,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
|
||||
|
@ -1263,8 +1333,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)) {
|
||||
|
||||
//
|
||||
|
@ -1310,6 +1379,7 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
|
|||
// requested copy key so that we can open it
|
||||
//
|
||||
|
||||
if (!Dll_CompartmentMode) // NoDriverAssist
|
||||
if (status == STATUS_ACCESS_DENIED && Secure_IsRestrictedToken(TRUE)) {
|
||||
|
||||
NTSTATUS status2 = SbieApi_SetLowLabelKey(CopyPath);
|
||||
|
@ -1350,9 +1420,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) {
|
||||
|
||||
|
@ -1417,6 +1490,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
|
||||
|
@ -1447,6 +1542,9 @@ _FX NTSTATUS Key_NtCreateKeyImpl(
|
|||
|
||||
int depth = Key_CheckDepthForIsWritePath(TruePath);
|
||||
if (depth == 0) {
|
||||
if (Dll_CompartmentMode) { // NoDriverAssist
|
||||
status = __sys_NtOpenKey(KeyHandle, Wow64KeyReadAccess, &objattrs);
|
||||
} else
|
||||
status = SbieApi_OpenKey(KeyHandle, TruePath);
|
||||
if (NT_SUCCESS(status))
|
||||
goto SkipReadOnlyCheck;
|
||||
|
@ -1464,6 +1562,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
|
||||
|
@ -1614,6 +1714,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;
|
||||
}
|
||||
|
@ -1627,6 +1729,19 @@ SkipReadOnlyCheck:
|
|||
if (CopyPathCreated)
|
||||
Key_DiscardMergeByPath(TruePath, TRUE);
|
||||
|
||||
//
|
||||
// Relocation, if we opened the true key and its relocated set the path info
|
||||
//
|
||||
|
||||
if (TrueOpened && OriginalPath) {
|
||||
|
||||
Handle_SetRelocationPath(*KeyHandle, OriginalPath);
|
||||
}
|
||||
|
||||
//
|
||||
// finish
|
||||
//
|
||||
|
||||
Dll_PopTlsNameBuffer(TlsData);
|
||||
|
||||
TlsData->key_NtCreateKey_lock = FALSE;
|
||||
|
@ -1654,6 +1769,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
|
||||
|
@ -1702,6 +1845,7 @@ _FX NTSTATUS Key_CreatePath(
|
|||
|
||||
if (NT_SUCCESS(status)) {
|
||||
|
||||
if (!Key_Delete_v2)
|
||||
if (disp == REG_OPENED_EXISTING_KEY) {
|
||||
if (Key_CheckDeletedKey(handle)) {
|
||||
|
||||
|
@ -1746,6 +1890,7 @@ _FX NTSTATUS Key_CreatePath(
|
|||
|
||||
status = Key_CreatePath_Key(&handle, objattrs, &disp);
|
||||
|
||||
if (!Dll_CompartmentMode) // NoDriverAssist
|
||||
if (status == STATUS_ACCESS_DENIED && Dll_RestrictedToken) {
|
||||
|
||||
//
|
||||
|
@ -2043,7 +2188,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;
|
||||
|
||||
|
@ -2182,6 +2327,39 @@ _FX NTSTATUS Key_MarkDeletedAndClose(HANDLE KeyHandle)
|
|||
// mark key deleted by setting its last write time information
|
||||
//
|
||||
|
||||
if (Key_Delete_v2) {
|
||||
|
||||
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
|
||||
|
||||
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(
|
||||
|
@ -2193,6 +2371,7 @@ _FX NTSTATUS Key_MarkDeletedAndClose(HANDLE KeyHandle)
|
|||
//
|
||||
|
||||
Key_DiscardMergeByHandle(TlsData, KeyHandle, TRUE);
|
||||
}
|
||||
|
||||
//
|
||||
// close key handle
|
||||
|
@ -2307,14 +2486,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 {
|
||||
|
||||
//
|
||||
|
@ -2341,6 +2524,8 @@ _FX NTSTATUS Key_NtDeleteValueKey(
|
|||
}
|
||||
}
|
||||
|
||||
Dll_PopTlsNameBuffer(TlsData);
|
||||
|
||||
SetLastError(LastError);
|
||||
return status;
|
||||
}
|
||||
|
@ -2495,6 +2680,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.
|
||||
|
@ -2509,26 +2704,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)
|
||||
{
|
||||
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
|
||||
|
@ -2601,11 +2791,17 @@ _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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__leave;
|
||||
|
@ -2789,11 +2985,17 @@ _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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__leave;
|
||||
|
@ -3188,12 +3390,17 @@ _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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__leave;
|
||||
|
@ -3544,12 +3751,27 @@ _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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__leave;
|
||||
|
@ -4068,10 +4290,155 @@ _FX HANDLE Key_GetTrueHandle(HANDLE KeyHandle, BOOLEAN *pIsOpenPath)
|
|||
_FX NTSTATUS Key_NtRenameKey(
|
||||
HANDLE KeyHandle, UNICODE_STRING *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, MOVE_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();
|
||||
}
|
||||
|
||||
//
|
||||
// rename the key ensuring we wil have a boxed copy
|
||||
//
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
|
||||
//
|
||||
// check if the target key already exists in the true path
|
||||
//
|
||||
|
||||
RtlInitUnicodeString(&objname, NewTruePath);
|
||||
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_COLLISION;
|
||||
|
||||
File_NtCloseImpl(handle);
|
||||
}
|
||||
|
||||
//
|
||||
// try renaming if it fails with access denided try again with a new handle
|
||||
//
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// set the redirection information
|
||||
//
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
|
||||
//*TruePathSlash = L'\0';
|
||||
//Key_DiscardMergeByPath(TruePath, TRUE); // fix-me: act on Key_MergeCacheList
|
||||
//*TruePathSlash = L'\\';
|
||||
|
||||
//
|
||||
// check if the true path exists and if so mark path deleted
|
||||
//
|
||||
|
||||
BOOLEAN TrueExists = FALSE;
|
||||
|
||||
RtlInitUnicodeString(&objname, TruePath);
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// setup/update the key relocation
|
||||
//
|
||||
|
||||
Key_SetRelocation(TruePath, NewTruePath, TrueExists);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Dll_PopTlsNameBuffer(TlsData);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Key_NtSaveKey
|
||||
|
@ -4081,7 +4448,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;
|
||||
}
|
||||
|
||||
|
@ -4106,6 +4473,10 @@ _FX NTSTATUS Key_NtLoadKey(
|
|||
FILE_LOAD_KEY_REQ *req;
|
||||
|
||||
status = __sys_NtLoadKey(TargetObjectAttributes, SourceObjectAttributes);
|
||||
|
||||
if (Dll_CompartmentMode) // NoDriverAssist
|
||||
return status;
|
||||
|
||||
if (status != STATUS_PRIVILEGE_NOT_HELD)
|
||||
return status;
|
||||
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
||||
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);
|
||||
VOID 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);
|
||||
VOID File_MarkDeleted_internal(LIST* Root, const WCHAR* Path);
|
||||
VOID File_SetRelocation_internal(LIST* Root, const WCHAR* OldTruePath, const WCHAR* NewTruePath, BOOLEAN TrueExists);
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// 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()
|
||||
{
|
||||
EnterCriticalSection(Key_PathRoot_CritSec);
|
||||
|
||||
File_LoadPathTree_internal(&Key_PathRoot, KEY_PATH_FILE_NAME);
|
||||
|
||||
LeaveCriticalSection(Key_PathRoot_CritSec);
|
||||
|
||||
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
|
||||
//
|
||||
|
||||
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);
|
||||
|
||||
File_MarkDeleted_internal(&Key_PathRoot, FullPath);
|
||||
|
||||
LeaveCriticalSection(Key_PathRoot_CritSec);
|
||||
|
||||
Key_SavePathTree();
|
||||
|
||||
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, BOOLEAN TrueExists)
|
||||
{
|
||||
//
|
||||
// List a mapping for the new location
|
||||
//
|
||||
|
||||
EnterCriticalSection(Key_PathRoot_CritSec);
|
||||
|
||||
File_SetRelocation_internal(&Key_PathRoot, OldTruePath, NewTruePath, TrueExists);
|
||||
|
||||
LeaveCriticalSection(Key_PathRoot_CritSec);
|
||||
|
||||
Key_SavePathTree();
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
@ -35,6 +36,7 @@ typedef struct _KEY_MERGE {
|
|||
|
||||
BOOLEAN subkeys_merged;
|
||||
LARGE_INTEGER last_write_time;
|
||||
ULONGLONG last_paths_version;
|
||||
LIST subkeys;
|
||||
|
||||
ULONG last_index;
|
||||
|
@ -200,7 +202,7 @@ _FX NTSTATUS Key_Merge(
|
|||
// 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);
|
||||
|
||||
|
@ -226,7 +228,7 @@ _FX NTSTATUS Key_Merge(
|
|||
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);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -234,6 +236,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);
|
||||
|
@ -316,6 +319,7 @@ _FX NTSTATUS Key_OpenForMerge(
|
|||
ULONG len;
|
||||
HANDLE TrueHandle;
|
||||
ULONG mp_flags;
|
||||
const WCHAR* OriginalPath = NULL;
|
||||
|
||||
*out_TrueMerge = NULL;
|
||||
*out_CopyHandle = NULL;
|
||||
|
@ -362,6 +366,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
|
||||
|
@ -379,6 +384,9 @@ _FX NTSTATUS Key_OpenForMerge(
|
|||
// if we couldn't find a copy key, indicate there is nothing to merge
|
||||
//
|
||||
|
||||
if (Key_Delete_v2 && Key_HasDeleted_v2(TruePath))
|
||||
status = STATUS_SUCCESS;
|
||||
else
|
||||
status = STATUS_BAD_INITIAL_PC;
|
||||
}
|
||||
|
||||
|
@ -387,6 +395,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
|
||||
|
@ -415,7 +435,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);
|
||||
|
@ -623,7 +643,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;
|
||||
}
|
||||
|
@ -646,6 +666,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
|
||||
|
@ -730,6 +751,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
|
||||
|
@ -828,6 +855,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
|
||||
//
|
||||
|
@ -864,7 +897,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
|
||||
|
@ -882,6 +915,7 @@ _FX NTSTATUS Key_MergeSubkeys(
|
|||
}
|
||||
|
||||
merge->last_write_time.QuadPart = info->LastWriteTime.QuadPart;
|
||||
merge->last_paths_version = Key_PathsVersion;
|
||||
|
||||
if (! TrueMerge)
|
||||
goto TrueHandleFinish;
|
||||
|
@ -962,6 +996,7 @@ TrueHandleFinish:
|
|||
info->ClassOffset != -1 ||
|
||||
info->ClassLength);
|
||||
|
||||
if (!Key_Delete_v2)
|
||||
if (IS_DELETE_MARK(&info->LastWriteTime))
|
||||
subkey_deleted = TRUE;
|
||||
else
|
||||
|
@ -988,7 +1023,8 @@ TrueHandleFinish:
|
|||
if (subkey->TitleOrClass)
|
||||
subkey2->TitleOrClass = subkey->TitleOrClass;
|
||||
}
|
||||
subkey_deleted = TRUE;
|
||||
Dll_Free(subkey);
|
||||
subkey = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1033,7 +1069,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);
|
||||
|
@ -1125,6 +1161,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
|
||||
|
@ -1379,7 +1416,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);
|
||||
}
|
||||
|
|
|
@ -1323,7 +1323,7 @@ _FX BOOL Proc_AlternateCreateProcess(
|
|||
void *lpCurrentDirectory, LPPROCESS_INFORMATION lpProcessInformation,
|
||||
BOOL *ReturnValue)
|
||||
{
|
||||
if (SbieApi_QueryConfBool(NULL, L"BlockSoftwareUpdaters", FALSE))
|
||||
//if (SbieApi_QueryConfBool(NULL, L"BlockSoftwareUpdaters", TRUE))
|
||||
if (Proc_IsSoftwareUpdateW(lpApplicationName ? lpApplicationName : lpCommandLine)) {
|
||||
|
||||
SetLastError(ERROR_ACCESS_DENIED);
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "handle.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Service Control Manager
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
//#define ErrorMessageBox(txt)
|
||||
//
|
||||
//#define HOOK_WIN32(func) { \
|
||||
|
@ -237,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;
|
||||
}
|
||||
|
||||
|
@ -258,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -422,6 +422,16 @@ _FX NTSTATUS SysInfo_GetJobName(OBJECT_ATTRIBUTES* ObjectAttributes, WCHAR** Out
|
|||
|
||||
*OutCopyPath = name;
|
||||
|
||||
//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;
|
||||
|
||||
|
@ -430,6 +440,8 @@ _FX NTSTATUS SysInfo_GetJobName(OBJECT_ATTRIBUTES* ObjectAttributes, WCHAR** Out
|
|||
|
||||
wmemcpy(name, objname_buf, objname_len);
|
||||
name += objname_len;
|
||||
}
|
||||
|
||||
*name = L'\0';
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
|
|
@ -323,6 +323,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
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#define VERSION_MJR 1
|
||||
#define VERSION_MIN 0
|
||||
#define VERSION_REV 10
|
||||
#define VERSION_MIN 1
|
||||
#define VERSION_REV 0
|
||||
#define VERSION_UPD 0
|
||||
|
||||
#ifndef STR
|
||||
|
|
Loading…
Reference in New Issue