Build 0.4.0 / 5.43

This commit is contained in:
DavidXanatos 2020-09-05 17:45:39 +02:00
parent de57cdedc5
commit 4a35c9f695
50 changed files with 3071 additions and 704 deletions

View File

@ -3,6 +3,35 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## [0.4.0 / 5.43] - 2020-09-05
### Added
- added a proper custom installer to the the Plus release
- added sandbox snapshot functionality to sbie core
-- filesystem is saved incrementally, the snapshots built upon each other
-- each snapshot gets a full copy of the box registry for now
-- each snapshot can have multiple children snapshots
- added access status to resource monitor
- added setting to change border width
- added snapshot manager UI to SandMan
- added template to enable authentication with an Yubikey or comparable 2FA device
- added ui for program allert
- added software compatybility options to teh UI
### Changed
- SandMan UI now handles deletion of sandboxe content on its own
- no longer adding redundnat resource accesses as new events
### Fixed
- fixed issues when hooking functions from delay loaded libraries
- fixed issues when hooking an already hooked function
- fixed issues with the new box settings editor
### Removed
- removes deprecated workaround in the hooking mechanism for an obsolete antimalware product
## [0.3.5 / 5.42.1] - 2020-07-19 ## [0.3.5 / 5.42.1] - 2020-07-19
### Added ### Added

View File

@ -160,6 +160,44 @@ _FX ULONG64 CRC_AdlerTzuk64(const UCHAR *data, int len)
#endif CRC_WITH_ADLERTZUK64 #endif CRC_WITH_ADLERTZUK64
ULONG CRC32(const char *buf, size_t len)
{
ULONG crc = 0;
static ULONG table[256];
static int have_table = 0;
ULONG rem;
ULONG octet;
int i, j;
const char *p, *q;
/* This check is not thread safe; there is no mutex. */
if (have_table == 0) {
/* Calculate CRC table. */
for (i = 0; i < 256; i++) {
rem = i; /* remainder from polynomial division */
for (j = 0; j < 8; j++) {
if (rem & 1) {
rem >>= 1;
rem ^= 0xedb88320;
}
else
rem >>= 1;
}
table[i] = rem;
}
have_table = 1;
}
crc = ~crc;
q = buf + len;
for (p = buf; p < q; p++) {
octet = *p; /* Cast to unsigned octet. */
crc = (crc >> 8) ^ table[(crc & 0xff) ^ octet];
}
return ~crc;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// End // End
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -20,9 +20,9 @@
#ifndef _MY_VERSION_H #ifndef _MY_VERSION_H
#define _MY_VERSION_H #define _MY_VERSION_H
#define MY_VERSION_BINARY 5,42,1 #define MY_VERSION_BINARY 5,43
#define MY_VERSION_STRING "5.42.1" #define MY_VERSION_STRING "5.43"
#define MY_VERSION_COMPAT "5.42" #define MY_VERSION_COMPAT "5.43"
// These #defines are used by either Resource Compiler, or by NSIC installer // These #defines are used by either Resource Compiler, or by NSIC installer
#define SBIE_INSTALLER_PATH "..\\Bin\\" #define SBIE_INSTALLER_PATH "..\\Bin\\"

View File

@ -46,6 +46,8 @@ extern __declspec(dllexport) int __CRTDECL Sbie_sprintf(char *_Buffer, const cha
#define TRUE_NAME_BUFFER 0 #define TRUE_NAME_BUFFER 0
#define COPY_NAME_BUFFER 1 #define COPY_NAME_BUFFER 1
#define TMPL_NAME_BUFFER 2
#define NAME_BUFFER_COUNT 3
#define NAME_BUFFER_DEPTH 12 #define NAME_BUFFER_DEPTH 12
@ -151,8 +153,8 @@ typedef struct _THREAD_DATA {
// name buffers: first index is for true name, second for copy name // name buffers: first index is for true name, second for copy name
// //
WCHAR *name_buffer[2][NAME_BUFFER_DEPTH]; WCHAR *name_buffer[NAME_BUFFER_COUNT][NAME_BUFFER_DEPTH];
ULONG name_buffer_len[2][NAME_BUFFER_DEPTH]; ULONG name_buffer_len[NAME_BUFFER_COUNT][NAME_BUFFER_DEPTH];
int depth; int depth;
// //

View File

@ -291,6 +291,9 @@ skip_e9_rewrite: ;
return NULL; return NULL;
} }
ULONG ByteCount = *(ULONG*)(tramp + 80);
ULONG UsedCount = 0;
// //
// create the detour // create the detour
// //
@ -330,10 +333,12 @@ skip_e9_rewrite: ;
func[0] = 0x48; // 32bit relative JMP DetourFunc func[0] = 0x48; // 32bit relative JMP DetourFunc
func[1] = 0xE9; // 32bit relative JMP DetourFunc func[1] = 0xE9; // 32bit relative JMP DetourFunc
*(ULONG *)(&func[2]) = (ULONG)diff; *(ULONG *)(&func[2]) = (ULONG)diff;
UsedCount = 1 + 1 + 4;
} }
else { else {
func[0] = 0xE9; // 32bit relative JMP DetourFunc func[0] = 0xE9; // 32bit relative JMP DetourFunc
*(ULONG *)(&func[1]) = (ULONG)diff; *(ULONG *)(&func[1]) = (ULONG)diff;
UsedCount = 1 + 4;
} }
} }
@ -400,6 +405,7 @@ skip_e9_rewrite: ;
((ULONG_PTR *)ptrVTable->offset)[ptrVTable->index] = (ULONG_PTR)DetourFunc; ((ULONG_PTR *)ptrVTable->offset)[ptrVTable->index] = (ULONG_PTR)DetourFunc;
*(USHORT *)&func[0] = 0x25ff; *(USHORT *)&func[0] = 0x25ff;
*(ULONG *)&func[2] = (ULONG)diff; *(ULONG *)&func[2] = (ULONG)diff;
UsedCount = 2 + 4;
ptrVTable->index++; ptrVTable->index++;
hookset = TRUE; hookset = TRUE;
} }
@ -425,8 +431,13 @@ skip_e9_rewrite: ;
diff = (UCHAR *)DetourFunc - (func + 5); diff = (UCHAR *)DetourFunc - (func + 5);
func[0] = 0xE9; // JMP DetourFunc func[0] = 0xE9; // JMP DetourFunc
*(ULONG *)(&func[1]) = (ULONG)diff; *(ULONG *)(&func[1]) = (ULONG)diff;
UsedCount = 1 + 4;
#endif #endif
// just in case nop out the rest of the code we moved to the trampoline
for(; UsedCount < ByteCount; UsedCount++)
func[UsedCount] = 0x90; // nop
VirtualProtect(&func[-8], 20, prot, &dummy_prot); VirtualProtect(&func[-8], 20, prot, &dummy_prot);
// the trampoline code begins at trampoline + 16 bytes // the trampoline code begins at trampoline + 16 bytes

View File

@ -303,6 +303,11 @@ _FX void Dll_FreeTlsData(void)
if (buf) if (buf)
Dll_Free(buf); Dll_Free(buf);
data->name_buffer[COPY_NAME_BUFFER][depth] = NULL; data->name_buffer[COPY_NAME_BUFFER][depth] = NULL;
buf = data->name_buffer[TMPL_NAME_BUFFER][depth];
if (buf)
Dll_Free(buf);
data->name_buffer[TMPL_NAME_BUFFER][depth] = NULL;
} }
Dll_Free(data); Dll_Free(data);
@ -431,6 +436,8 @@ _FX void Dll_PopTlsNameBuffer(THREAD_DATA *data)
__debugbreak(); __debugbreak();
} }
// todo: snapshots TMPL_NAME_BUFFER
} }
#endif // DEBUG_MEMORY #endif // DEBUG_MEMORY

View File

@ -95,6 +95,15 @@ typedef struct _FILE_LINK FILE_LINK;
typedef struct _FILE_DRIVE FILE_DRIVE; typedef struct _FILE_DRIVE FILE_DRIVE;
typedef struct _FILE_SNAPSHOT {
WCHAR ID[17];
ULONG IDlen;
ULONG ScramKey;
//WCHAR Name[34];
struct _FILE_SNAPSHOT* Parent;
} FILE_SNAPSHOT, *PFILE_SNAPSHOT;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Functions // Functions
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -128,6 +137,10 @@ static NTSTATUS File_GetName_FromFileId(
OBJECT_ATTRIBUTES *ObjectAttributes, OBJECT_ATTRIBUTES *ObjectAttributes,
WCHAR **OutTruePath, WCHAR **OutCopyPath); WCHAR **OutTruePath, WCHAR **OutCopyPath);
static WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, WCHAR* CopyPath);
static BOOLEAN File_FindSnapshotPath(WCHAR** CopyPath);
static ULONG File_MatchPath(const WCHAR *path, ULONG *FileFlags); static ULONG File_MatchPath(const WCHAR *path, ULONG *FileFlags);
static ULONG File_MatchPath2(const WCHAR *path, ULONG *FileFlags, BOOLEAN bCheckObjectExists, BOOLEAN bMonitorLog); static ULONG File_MatchPath2(const WCHAR *path, ULONG *FileFlags, BOOLEAN bCheckObjectExists, BOOLEAN bMonitorLog);
@ -258,6 +271,9 @@ static BOOLEAN File_RecordRecover(HANDLE FileHandle, const WCHAR *TruePath);
static NTSTATUS File_SetReparsePoint( static NTSTATUS File_SetReparsePoint(
HANDLE FileHandle, UCHAR *Data, ULONG DataLen); HANDLE FileHandle, UCHAR *Data, ULONG DataLen);
static void File_ScrambleShortName(WCHAR* ShortName, CCHAR* ShortNameLength, ULONG ScramKey);
static void File_UnScrambleShortName(WCHAR* ShortName, ULONG ScramKey);
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -341,6 +357,10 @@ static WCHAR *File_AltBoxPath = NULL;
static ULONG File_AltBoxPathLen = 0; static ULONG File_AltBoxPathLen = 0;
static FILE_SNAPSHOT *File_Snapshot = NULL;
static ULONG File_Snapshot_Count = 0;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// File (other modules) // File (other modules)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -742,6 +762,31 @@ check_sandbox_prefix:
is_boxed_path = TRUE; is_boxed_path = TRUE;
} }
//
// If its a sandboxed file, check if its in the current image or in a snapshot
// If its in a snapshot remove teh snapshot prefix
//
if (is_boxed_path) {
if (length >= 10 &&
0 == Dll_NlsStrCmp(
*OutTruePath, L"\\snapshot-", 10))
{
WCHAR* path = wcschr(*OutTruePath + 10, L'\\');
if (path == NULL) {
//
// caller specified just the sandbox snapshot prefix
//
*OutTruePath = TruePath;
return STATUS_BAD_INITIAL_PC;
}
length -= (ULONG)(path - *OutTruePath);
*OutTruePath = path;
}
}
// //
// the true path may now begin with "\drive\x", for instance, // the true path may now begin with "\drive\x", for instance,
// if the process specified a RootDirectory handle that leads // if the process specified a RootDirectory handle that leads
@ -1390,6 +1435,136 @@ copy_suffix:
} }
//---------------------------------------------------------------------------
// File_MakeSnapshotPath
//---------------------------------------------------------------------------
_FX WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, WCHAR* CopyPath)
{
if (!Cur_Snapshot)
return NULL;
ULONG length = wcslen(CopyPath);
ULONG prefixLen = 0;
if (length >= Dll_BoxFilePathLen && 0 == Dll_NlsStrCmp(CopyPath, Dll_BoxFilePath, Dll_BoxFilePathLen))
prefixLen = Dll_BoxFilePathLen;
if (File_AltBoxPath && length >= File_AltBoxPathLen && 0 == Dll_NlsStrCmp(CopyPath, File_AltBoxPath, File_AltBoxPathLen))
prefixLen = File_AltBoxPathLen;
if (prefixLen == 0)
return NULL;
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
WCHAR* TmplName = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER, (wcslen(CopyPath) + 9 + 17 + 1) * sizeof(WCHAR));
wcsncpy(TmplName, CopyPath, prefixLen + 1);
wcscpy(TmplName + prefixLen + 1, L"snapshot-");
wcscpy(TmplName + prefixLen + 1 + 9, Cur_Snapshot->ID);
wcscpy(TmplName + prefixLen + 1 + 9 + Cur_Snapshot->IDlen, CopyPath + prefixLen);
return TmplName;
}
//---------------------------------------------------------------------------
// File_GetName_ExpandShortNames2
//---------------------------------------------------------------------------
_FX NTSTATUS File_GetName_ExpandShortNames2(
WCHAR *Path, ULONG index, ULONG backslash_index, PFILE_BOTH_DIRECTORY_INFORMATION info, const ULONG info_size, FILE_SNAPSHOT* Cur_Snapshot)
{
NTSTATUS status;
UNICODE_STRING uni;
OBJECT_ATTRIBUTES ObjAttrs;
HANDLE handle;
IO_STATUS_BLOCK IoStatusBlock;
WCHAR* TmplName;
WCHAR save_char;
save_char = Path[backslash_index + 1];
Path[backslash_index + 1] = L'\0';
TmplName = File_MakeSnapshotPath(Cur_Snapshot, Path);
if(TmplName != NULL)
uni.Buffer = TmplName;
else
uni.Buffer = Path;
uni.Length = wcslen(uni.Buffer) * sizeof(WCHAR);
uni.MaximumLength = uni.Length + sizeof(WCHAR);
InitializeObjectAttributes(
&ObjAttrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = __sys_NtCreateFile(
&handle,
GENERIC_READ | SYNCHRONIZE, // DesiredAccess
&ObjAttrs,
&IoStatusBlock,
NULL, // AllocationSize
0, // FileAttributes
FILE_SHARE_VALID_FLAGS, // ShareAccess
FILE_OPEN, // CreateDisposition
FILE_DIRECTORY_FILE | // CreateOptions
FILE_SYNCHRONOUS_IO_NONALERT,
NULL, // EaBuffer
0); // EaLength
//
// restore original path
//
Path[backslash_index + 1] = save_char;
if (!NT_SUCCESS(status))
return status;
// query long name for short name. if the short name is not
// found with a status of NO_SUCH_FILE, then possibly it was
// already deleted or does not even exist yet. in this case
// we leave the short name as is instead of failing.
save_char = Path[index];
Path[index] = L'\0';
WCHAR ShortName[12 + 1];
if (Cur_Snapshot && Cur_Snapshot->ScramKey && wcslen(&Path[backslash_index + 1]) <= 12)
{
//
// If we are checking in a snapshot we ned to unscramble the short name
//
wcscpy(ShortName, &Path[backslash_index + 1]);
File_UnScrambleShortName(ShortName, Cur_Snapshot->ScramKey);
uni.Buffer = ShortName;
}
else
uni.Buffer = &Path[backslash_index + 1];
uni.Length = wcslen(uni.Buffer) * sizeof(WCHAR);
uni.MaximumLength = uni.Length + sizeof(WCHAR);
status = __sys_NtQueryDirectoryFile(
handle,
NULL, NULL, NULL, // Event, ApcRoutine, ApcContext
&IoStatusBlock,
info, info_size, FileBothDirectoryInformation,
TRUE, &uni, FALSE);
NtClose(handle);
Path[index] = save_char; // restore original path
return status;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// File_GetName_ExpandShortNames // File_GetName_ExpandShortNames
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -1409,21 +1584,16 @@ _FX WCHAR *File_GetName_ExpandShortNames(
// it can only translate short names to long names outside the box. // it can only translate short names to long names outside the box.
// //
info = Dll_AllocTemp(info_size);
status = STATUS_SUCCESS; status = STATUS_SUCCESS;
for (index = 0; Path[index] != 0; ) { for (index = 0; Path[index] != 0; ) {
UNICODE_STRING uni;
OBJECT_ATTRIBUTES ObjAttrs;
HANDLE handle;
IO_STATUS_BLOCK IoStatusBlock;
// scan path string until a tilde (~) is found, but also keep // scan path string until a tilde (~) is found, but also keep
// the position of the last backslash character before the tilde. // the position of the last backslash character before the tilde.
ULONG backslash_index; ULONG backslash_index;
ULONG dot_count; ULONG dot_count;
WCHAR save_char;
ULONG len; ULONG len;
WCHAR *copy; WCHAR *copy;
@ -1456,36 +1626,19 @@ _FX WCHAR *File_GetName_ExpandShortNames(
// otherwise open the directory containing the short name component // otherwise open the directory containing the short name component
save_char = Path[backslash_index + 1]; status = File_GetName_ExpandShortNames2(Path, index, backslash_index, info, info_size, NULL);
Path[backslash_index + 1] = L'\0';
uni.Buffer = Path; if (!NT_SUCCESS(status) && File_Snapshot != NULL)
uni.Length = wcslen(uni.Buffer) * sizeof(WCHAR); {
uni.MaximumLength = uni.Length + sizeof(WCHAR); for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != NULL; Cur_Snapshot = Cur_Snapshot->Parent)
{
InitializeObjectAttributes( status = File_GetName_ExpandShortNames2(Path, index, backslash_index, info, info_size, Cur_Snapshot);
&ObjAttrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL); if (NT_SUCCESS(status))
break;
status = __sys_NtCreateFile( }
&handle, }
GENERIC_READ | SYNCHRONIZE, // DesiredAccess
&ObjAttrs,
&IoStatusBlock,
NULL, // AllocationSize
0, // FileAttributes
FILE_SHARE_VALID_FLAGS, // ShareAccess
FILE_OPEN, // CreateDisposition
FILE_DIRECTORY_FILE | // CreateOptions
FILE_SYNCHRONOUS_IO_NONALERT,
NULL, // EaBuffer
0); // EaLength
//
// restore original path
//
Path[backslash_index + 1] = save_char;
/*
// stop if we can't open the directory, but file-not-found // stop if we can't open the directory, but file-not-found
// or file-not-a-directory errors may occur because the caller is // or file-not-a-directory errors may occur because the caller is
// trying to access a directory that exists only in the copy system, // trying to access a directory that exists only in the copy system,
@ -1503,32 +1656,6 @@ _FX WCHAR *File_GetName_ExpandShortNames(
break; break;
} }
// query long name for short name. if the short name is not
// found with a status of NO_SUCH_FILE, then possibly it was
// already deleted or does not even exist yet. in this case
// we leave the short name as is instead of failing.
if (! info)
info = Dll_AllocTemp(info_size);
save_char = Path[index];
Path[index] = L'\0';
uni.Buffer = &Path[backslash_index + 1];
uni.Length = wcslen(uni.Buffer) * sizeof(WCHAR);
uni.MaximumLength = uni.Length + sizeof(WCHAR);
status = __sys_NtQueryDirectoryFile(
handle,
NULL, NULL, NULL, // Event, ApcRoutine, ApcContext
&IoStatusBlock,
info, info_size, FileBothDirectoryInformation,
TRUE, &uni, FALSE);
NtClose(handle);
Path[index] = save_char; // restore original path
if (status == STATUS_NO_SUCH_FILE) { // short name not found, if (status == STATUS_NO_SUCH_FILE) { // short name not found,
status = STATUS_SUCCESS; // so don't replace it status = STATUS_SUCCESS; // so don't replace it
continue; continue;
@ -1536,6 +1663,10 @@ _FX WCHAR *File_GetName_ExpandShortNames(
if (! NT_SUCCESS(status)) // could not query long name? if (! NT_SUCCESS(status)) // could not query long name?
break; break;
*/
if (!NT_SUCCESS(status))
continue;
// //
// expand the path with the short name into the copy name buffer, // expand the path with the short name into the copy name buffer,
@ -2074,6 +2205,50 @@ finish:
} }
//---------------------------------------------------------------------------
// File_FindSnapshotPath
//---------------------------------------------------------------------------
_FX BOOLEAN 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 TRUE; // 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))
{
*CopyPath = TmplName;
return TRUE;
}
}
return FALSE;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// File_NtOpenFile // File_NtOpenFile
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -2160,6 +2335,7 @@ _FX NTSTATUS File_NtCreateFileImpl(
BOOLEAN IsEmptyCopyFile; BOOLEAN IsEmptyCopyFile;
BOOLEAN AlreadyReparsed; BOOLEAN AlreadyReparsed;
UCHAR HaveTrueFile; UCHAR HaveTrueFile;
BOOLEAN HaveSnapshotFile;
//char *pPtr = NULL; //char *pPtr = NULL;
//if (wcsstr(Dll_ImageName, L"chrome.exe") != 0) { //if (wcsstr(Dll_ImageName, L"chrome.exe") != 0) {
@ -2426,6 +2602,24 @@ ReparseLoop:
if (! NT_SUCCESS(status)) if (! NT_SUCCESS(status))
__leave; __leave;
HaveSnapshotFile = FALSE;
if (File_Snapshot != NULL) {
WCHAR* TmplPath = CopyPath;
File_FindSnapshotPath(&TmplPath);
if (TmplPath != CopyPath) {
HaveSnapshotFile = TRUE;
TruePath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, (wcslen(TmplPath) + 1) * sizeof(WCHAR));
wcscpy(TruePath, TmplPath);
}
}
// //
// if TruePath and CopyPath contain colons that indicate an NTFS // if TruePath and CopyPath contain colons that indicate an NTFS
// alternate data stream, we remove these for now // alternate data stream, we remove these for now
@ -2580,6 +2774,19 @@ ReparseLoop:
status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); status = File_GetFileType(&objattrs, FALSE, &FileType, NULL);
} }
//
// If the "true" file is in an snapshot it can be a deleted one,
// check for this and act acrodingly.
//
if (HaveSnapshotFile) {
if (FileType & TYPE_DELETED) {
status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
if ((FileType & TYPE_REPARSE_POINT) if ((FileType & TYPE_REPARSE_POINT)
&& (CreateOptions & FILE_OPEN_REPARSE_POINT) == 0 && (CreateOptions & FILE_OPEN_REPARSE_POINT) == 0
&& (! AlreadyReparsed)) { && (! AlreadyReparsed)) {
@ -3519,6 +3726,7 @@ _FX BOOLEAN File_CheckDeletedParent(WCHAR *CopyPath)
UNICODE_STRING objname; UNICODE_STRING objname;
ULONG FileType; ULONG FileType;
WCHAR *ptr = NULL; WCHAR *ptr = NULL;
NTSTATUS status;
// //
// remove the last path component so we can open the parent directory // remove the last path component so we can open the parent directory
@ -3546,12 +3754,39 @@ _FX BOOLEAN File_CheckDeletedParent(WCHAR *CopyPath)
return FALSE; return FALSE;
} }
File_GetFileType(&objattrs, FALSE, &FileType, NULL); status = File_GetFileType(&objattrs, FALSE, &FileType, NULL);
if (status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND)
continue;
if (FileType & TYPE_DELETED) { if (FileType & TYPE_DELETED) {
*ptr = L'\\'; *ptr = L'\\';
return TRUE; return TRUE;
} }
//
// If we have snapshots check thair status, if we have a entry in the most recent snapshot
// than older delete markings are not relevant
//
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)
continue;
if (FileType & TYPE_DELETED) {
*ptr = L'\\';
return TRUE;
}
if (NT_SUCCESS(status))
break;
}
} }
} }
@ -4696,6 +4931,9 @@ _FX NTSTATUS File_NtQueryFullAttributesFileImpl(
__leave; __leave;
} }
if (File_Snapshot != NULL)
File_FindSnapshotPath(&CopyPath);
RtlInitUnicodeString(&objname, CopyPath); RtlInitUnicodeString(&objname, CopyPath);
status = __sys_NtQueryFullAttributesFile(&objattrs, FileInformation); status = __sys_NtQueryFullAttributesFile(&objattrs, FileInformation);
@ -6056,6 +6294,9 @@ _FX NTSTATUS File_RenameFile(
SourceTruePath = Dll_AllocTemp(len); SourceTruePath = Dll_AllocTemp(len);
memcpy(SourceTruePath, TruePath, len); memcpy(SourceTruePath, TruePath, len);
if (File_Snapshot != NULL)
File_FindSnapshotPath(&CopyPath);
len = (wcslen(CopyPath) + 1) * sizeof(WCHAR); len = (wcslen(CopyPath) + 1) * sizeof(WCHAR);
SourceCopyPath = Dll_AllocTemp(len); SourceCopyPath = Dll_AllocTemp(len);
memcpy(SourceCopyPath, CopyPath, len); memcpy(SourceCopyPath, CopyPath, len);
@ -6542,6 +6783,10 @@ _FX ULONG SbieDll_GetHandlePath(
WCHAR *src = TruePath; WCHAR *src = TruePath;
if (Dll_BoxName && // sandboxed process if (Dll_BoxName && // sandboxed process
IsBoxedPath && *IsBoxedPath) { IsBoxedPath && *IsBoxedPath) {
if (File_Snapshot != NULL)
File_FindSnapshotPath(&CopyPath);
src = CopyPath; src = CopyPath;
} }
len = wcslen(src); len = wcslen(src);

View File

@ -48,11 +48,13 @@ typedef struct _FILE_MERGE_FILE {
ULONG name_max_len; ULONG name_max_len;
UNICODE_STRING name_uni; UNICODE_STRING name_uni;
BOOLEAN have_entry; BOOLEAN have_entry;
BOOLEAN saved_have_entry;
BOOLEAN more_files; BOOLEAN more_files;
BOOLEAN RestartScan; BOOLEAN RestartScan;
BOOLEAN no_file_ids; BOOLEAN no_file_ids;
POOL *cache_pool; POOL *cache_pool;
LIST cache_list; LIST cache_list;
ULONG scram_key;
} FILE_MERGE_FILE; } FILE_MERGE_FILE;
@ -66,8 +68,9 @@ typedef struct _FILE_MERGE {
BOOLEAN first_request; BOOLEAN first_request;
UNICODE_STRING file_mask; UNICODE_STRING file_mask;
FILE_MERGE_FILE true_file; FILE_MERGE_FILE* files; // copy file, snapshot_1 file, snapshot_2 file, ..., true file
FILE_MERGE_FILE copy_file; ULONG files_count;
FILE_MERGE_FILE* true_ptr;
ULONG name_len; // in bytes, excluding NULL ULONG name_len; // in bytes, excluding NULL
WCHAR name[0]; WCHAR name[0];
@ -306,7 +309,7 @@ _FX NTSTATUS File_NtQueryDirectoryFile(
// we get an error return value, and have to add the trailing backslash // we get an error return value, and have to add the trailing backslash
// //
if (status == STATUS_BAD_INITIAL_PC && CopyPath) { if (status == STATUS_BAD_INITIAL_PC && TruePath) {
WCHAR *ptr = TruePath + wcslen(TruePath); WCHAR *ptr = TruePath + wcslen(TruePath);
ptr[0] = L'\\'; ptr[0] = L'\\';
@ -516,6 +519,9 @@ _FX NTSTATUS File_Merge(
merge = Dll_Alloc(sizeof(FILE_MERGE) + TruePath_len + sizeof(WCHAR)); merge = Dll_Alloc(sizeof(FILE_MERGE) + TruePath_len + sizeof(WCHAR));
memzero(merge, sizeof(FILE_MERGE)); memzero(merge, sizeof(FILE_MERGE));
merge->files = Dll_Alloc(sizeof(FILE_MERGE_FILE) * (2 + File_Snapshot_Count));
memzero(merge->files, sizeof(FILE_MERGE_FILE) * (2 + File_Snapshot_Count));
merge->handle = FileHandle; merge->handle = FileHandle;
merge->cant_merge = FALSE; merge->cant_merge = FALSE;
merge->first_request = TRUE; merge->first_request = TRUE;
@ -533,7 +539,7 @@ _FX NTSTATUS File_Merge(
// //
// shares provided by Remote Desktop can't provide file IDs // shares provided by Remote Desktop can't provide file IDs
// //
merge->true_file.no_file_ids = TRUE; merge->files[0].no_file_ids = TRUE;
} }
if (File_Windows2000) { if (File_Windows2000) {
@ -542,8 +548,8 @@ _FX NTSTATUS File_Merge(
// FileIdBothDirectoryInformation, although according to // FileIdBothDirectoryInformation, although according to
// documentation it is only supported on Windows XP and later // documentation it is only supported on Windows XP and later
// //
merge->true_file.no_file_ids = TRUE; for(ULONG i = 0; i < 2 + File_Snapshot_Count; i++)
merge->copy_file.no_file_ids = TRUE; merge->files[i].no_file_ids = TRUE;
} }
List_Insert_After(&File_DirHandles, NULL, merge); List_Insert_After(&File_DirHandles, NULL, merge);
@ -562,7 +568,7 @@ _FX NTSTATUS File_Merge(
status = STATUS_BAD_INITIAL_PC; status = STATUS_BAD_INITIAL_PC;
} else if (! merge->copy_file.handle) { } else if (!merge->files[0].handle) {
// //
// open the true and copy directories, if we haven't already. // open the true and copy directories, if we haven't already.
@ -609,6 +615,8 @@ _FX NTSTATUS File_OpenForMerge(
ULONG len; ULONG len;
WCHAR *ptr; WCHAR *ptr;
// BOOLEAN TruePathIsRoot; // BOOLEAN TruePathIsRoot;
BOOLEAN TruePathDeleted = FALSE; // indicates that one of the parent snapshots deleted the true directory
BOOLEAN NoCopyPath = FALSE;
InitializeObjectAttributes( InitializeObjectAttributes(
&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
@ -623,7 +631,7 @@ _FX NTSTATUS File_OpenForMerge(
RtlInitUnicodeString(&objname, CopyPath); RtlInitUnicodeString(&objname, CopyPath);
status = __sys_NtCreateFile( status = __sys_NtCreateFile(
&merge->copy_file.handle, &merge->files[0].handle,
FILE_GENERIC_READ, // DesiredAccess FILE_GENERIC_READ, // DesiredAccess
&objattrs, &objattrs,
&IoStatusBlock, &IoStatusBlock,
@ -644,7 +652,7 @@ _FX NTSTATUS File_OpenForMerge(
// //
status = __sys_NtQueryInformationFile( status = __sys_NtQueryInformationFile(
merge->copy_file.handle, &IoStatusBlock, &info, merge->files[0].handle, &IoStatusBlock, &info,
sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); sizeof(FILE_BASIC_INFORMATION), FileBasicInformation);
if (NT_SUCCESS(status)) { if (NT_SUCCESS(status)) {
@ -653,7 +661,8 @@ _FX NTSTATUS File_OpenForMerge(
status = STATUS_OBJECT_NAME_NOT_FOUND; status = STATUS_OBJECT_NAME_NOT_FOUND;
} else if ((info.basic.FileAttributes & }
else if ((info.basic.FileAttributes &
FILE_ATTRIBUTE_DIRECTORY) == 0) { FILE_ATTRIBUTE_DIRECTORY) == 0) {
status = STATUS_INVALID_PARAMETER; status = STATUS_INVALID_PARAMETER;
@ -662,8 +671,8 @@ _FX NTSTATUS File_OpenForMerge(
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
__sys_NtClose(merge->copy_file.handle); __sys_NtClose(merge->files[0].handle);
merge->copy_file.handle = NULL; merge->files[0].handle = NULL;
return status; return status;
} }
@ -671,10 +680,11 @@ _FX NTSTATUS File_OpenForMerge(
// copy file passed all checks; indicate it is ready for use // copy file passed all checks; indicate it is ready for use
// //
merge->copy_file.more_files = TRUE; merge->files[0].more_files = TRUE;
merge->copy_file.RestartScan = TRUE; merge->files[0].RestartScan = TRUE;
merge->files_count++;
} else { }
else {
// //
// if there is no copy file, we don't need to merge anything, // if there is no copy file, we don't need to merge anything,
@ -685,12 +695,111 @@ _FX NTSTATUS File_OpenForMerge(
status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND ||
status == STATUS_ACCESS_DENIED) { status == STATUS_ACCESS_DENIED) {
status = STATUS_BAD_INITIAL_PC; NoCopyPath = TRUE;
} }
else
return status;
}
//
// Now open the parent snapshots if present, and it's aprent and so on....
//
if (File_Snapshot != NULL)
{
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 = __sys_NtCreateFile(
&merge->files[merge->files_count].handle,
FILE_GENERIC_READ, // DesiredAccess
&objattrs,
&IoStatusBlock,
NULL, // AllocationSize
0, // FileAttributes
FILE_SHARE_VALID_FLAGS, // ShareAccess
FILE_OPEN, // CreateDisposition
FILE_SYNCHRONOUS_IO_NONALERT, // CreateOptions
NULL, // EaBuffer
0); // EaLength
if (NT_SUCCESS(status)) {
//
// if the copy file exists, check if it is marked as deleted,
// and if so, close it and pretend it doesn't exist; otherwise
// make sure it is a directory file
//
// todo reduce redundant code, combine with the code for the copy_file
status = __sys_NtQueryInformationFile(
merge->files[merge->files_count].handle, &IoStatusBlock, &info,
sizeof(FILE_BASIC_INFORMATION), FileBasicInformation);
if (NT_SUCCESS(status)) {
if (IS_DELETE_MARK(&info.basic.CreationTime)) {
status = STATUS_OBJECT_NAME_NOT_FOUND;
}
else if ((info.basic.FileAttributes &
FILE_ATTRIBUTE_DIRECTORY) == 0) {
status = STATUS_INVALID_PARAMETER;
}
}
if (!NT_SUCCESS(status)) {
__sys_NtClose(merge->files[merge->files_count].handle);
merge->files[merge->files_count].handle = NULL;
TruePathDeleted = TRUE;
break; // dont look any further
}
//
// copy file passed all checks; indicate it is ready for use
//
merge->files[merge->files_count].more_files = TRUE;
merge->files[merge->files_count].RestartScan = TRUE;
merge->files[merge->files_count].scram_key = Cur_Snapshot->ScramKey;
merge->files_count++;
}
else {
//
// Ignroe errors here for now // todo
//
}
}
}
//
// if there is no copy file, we don't need to merge anything,
// and can let the system work directly on the true file
//
if (merge->files_count == 0) {
status = STATUS_BAD_INITIAL_PC;
return status; return status;
} }
if (TruePathDeleted)
goto skip_true_file;
// //
// true path must end with a backslash, so that we are able to // true path must end with a backslash, so that we are able to
// open the root directory of the volume device // open the root directory of the volume device
@ -705,11 +814,13 @@ _FX NTSTATUS File_OpenForMerge(
ptr[1] = L'\\'; ptr[1] = L'\\';
ptr[2] = L'\0'; ptr[2] = L'\0';
len += sizeof(WCHAR); len += sizeof(WCHAR);
} else { }
else {
ptr = NULL; ptr = NULL;
// TruePathIsRoot = TRUE; // TruePathIsRoot = TRUE;
} }
} else }
else
ptr = NULL; ptr = NULL;
objname.Length = (USHORT)len; objname.Length = (USHORT)len;
@ -720,8 +831,10 @@ _FX NTSTATUS File_OpenForMerge(
// open the true file // open the true file
// //
merge->true_ptr = &merge->files[merge->files_count];
status = __sys_NtCreateFile( status = __sys_NtCreateFile(
&merge->true_file.handle, &merge->true_ptr->handle,
FILE_GENERIC_READ, // DesiredAccess FILE_GENERIC_READ, // DesiredAccess
&objattrs, &objattrs,
&IoStatusBlock, &IoStatusBlock,
@ -746,14 +859,17 @@ _FX NTSTATUS File_OpenForMerge(
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
merge->true_file.handle = NULL; merge->true_ptr->handle = NULL;
merge->true_ptr = NULL;
if (status != STATUS_NOT_A_DIRECTORY && if (status != STATUS_NOT_A_DIRECTORY &&
status != STATUS_OBJECT_NAME_NOT_FOUND && status != STATUS_OBJECT_NAME_NOT_FOUND &&
status != STATUS_OBJECT_PATH_NOT_FOUND) { status != STATUS_OBJECT_PATH_NOT_FOUND) {
__sys_NtClose(merge->copy_file.handle); for (ULONG i = 0; i < merge->files_count; i++) {
merge->copy_file.handle = NULL; __sys_NtClose(merge->files[i].handle);
merge->files[i].handle = NULL;
}
if (status == STATUS_ACCESS_DENIED) if (status == STATUS_ACCESS_DENIED)
status = STATUS_BAD_INITIAL_PC; status = STATUS_BAD_INITIAL_PC;
@ -763,16 +879,20 @@ _FX NTSTATUS File_OpenForMerge(
status = STATUS_SUCCESS; status = STATUS_SUCCESS;
} else { }
else {
// //
// true file passed all checks; indicate it is ready for use // true file passed all checks; indicate it is ready for use
// //
merge->true_file.more_files = TRUE; merge->true_ptr->more_files = TRUE;
merge->true_file.RestartScan = TRUE; merge->true_ptr->RestartScan = TRUE;
merge->files_count++;
} }
skip_true_file:
// //
// now that both copy and true directories were opened, we will need to // now that both copy and true directories were opened, we will need to
// merge them. for this to work, we need a sorted directory listing. // merge them. for this to work, we need a sorted directory listing.
@ -785,7 +905,7 @@ _FX NTSTATUS File_OpenForMerge(
// versa: if the copy path is cached, make sure the true path is cached // versa: if the copy path is cached, make sure the true path is cached
// //
if (merge->true_file.handle) { if (merge->true_ptr) {
BOOLEAN ForceCache = FALSE; BOOLEAN ForceCache = FALSE;
if (merge->name_len >= File_MupLen * sizeof(WCHAR) if (merge->name_len >= File_MupLen * sizeof(WCHAR)
@ -801,33 +921,36 @@ _FX NTSTATUS File_OpenForMerge(
} }
status = File_MergeCache( status = File_MergeCache(
&merge->true_file, &merge->file_mask, ForceCache); merge->true_ptr, &merge->file_mask, ForceCache);
if (NT_SUCCESS(status)) { if (NT_SUCCESS(status)) {
BOOLEAN HaveTrueCache = (merge->true_file.cache_pool != NULL); BOOLEAN HaveTrueCache = (merge->true_ptr->cache_pool != NULL);
BOOLEAN HaveCopyCache = FALSE;
for (ULONG i = 0; i < merge->files_count - 1; i++) {
status = File_MergeCache( status = File_MergeCache(
&merge->copy_file, &merge->file_mask, HaveTrueCache); &merge->files[i], &merge->file_mask, HaveTrueCache);
if (NT_SUCCESS(status) && (! HaveTrueCache) && if (NT_SUCCESS(status) && merge->files[i].cache_pool != NULL)
(merge->copy_file.cache_pool != NULL)) { HaveCopyCache = TRUE;
}
if (!HaveTrueCache && HaveCopyCache) {
status = File_MergeCache( status = File_MergeCache(
&merge->true_file, &merge->file_mask, TRUE); merge->true_ptr, &merge->file_mask, TRUE);
} }
} }
if (! NT_SUCCESS(status)) { if (! NT_SUCCESS(status)) {
if (merge->copy_file.handle) { for (ULONG i = 0; i < merge->files_count; i++) {
__sys_NtClose(merge->copy_file.handle); if (merge->files[i].handle) {
merge->copy_file.handle = NULL; __sys_NtClose(merge->files[i].handle);
merge->files[i].handle = NULL;
} }
if (merge->true_file.handle) {
__sys_NtClose(merge->true_file.handle);
merge->true_file.handle = NULL;
} }
} }
} }
@ -1145,23 +1268,22 @@ _FX NTSTATUS File_MergeCacheWin2000(
_FX void File_MergeFree(FILE_MERGE *merge) _FX void File_MergeFree(FILE_MERGE *merge)
{ {
if (merge->true_file.handle) if (merge->files)
__sys_NtClose(merge->true_file.handle); {
if (merge->true_file.info) for (ULONG i = 0; i < merge->files_count; i++)
Dll_Free(merge->true_file.info); {
if (merge->true_file.name) if (merge->files[i].handle)
Dll_Free(merge->true_file.name); __sys_NtClose(merge->files[i].handle);
if (merge->true_file.cache_pool) if (merge->files[i].info)
Pool_Delete(merge->true_file.cache_pool); Dll_Free(merge->files[i].info);
if (merge->files[i].name)
Dll_Free(merge->files[i].name);
if (merge->files[i].cache_pool)
Pool_Delete(merge->files[i].cache_pool);
}
if (merge->copy_file.handle) Dll_Free(merge->files);
__sys_NtClose(merge->copy_file.handle); }
if (merge->copy_file.info)
Dll_Free(merge->copy_file.info);
if (merge->copy_file.name)
Dll_Free(merge->copy_file.name);
if (merge->copy_file.cache_pool)
Pool_Delete(merge->copy_file.cache_pool);
if (merge->file_mask.Buffer) if (merge->file_mask.Buffer)
Dll_Free(merge->file_mask.Buffer); Dll_Free(merge->file_mask.Buffer);
@ -1182,11 +1304,9 @@ _FX NTSTATUS File_GetMergedInformation(
FILE_INFORMATION_CLASS FileInformationClass, FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry) BOOLEAN ReturnSingleEntry)
{ {
NTSTATUS status; NTSTATUS status = STATUS_SUCCESS;
ULONG info_entry_length; ULONG info_entry_length;
FILE_ID_BOTH_DIR_INFORMATION *ptr_info; FILE_ID_BOTH_DIR_INFORMATION *ptr_info;
BOOLEAN save_true_file_have_entry;
BOOLEAN save_copy_file_have_entry;
PVOID prev_entry; PVOID prev_entry;
PVOID next_entry; PVOID next_entry;
WCHAR *name_ptr; WCHAR *name_ptr;
@ -1220,13 +1340,11 @@ _FX NTSTATUS File_GetMergedInformation(
// get directory entries from both directories // get directory entries from both directories
for (ULONG i = 0; i < merge->files_count && NT_SUCCESS(status); i++)
{
status = File_GetFullInformation( status = File_GetFullInformation(
&merge->copy_file, &merge->file_mask, TRUE); &merge->files[i], &merge->file_mask, TRUE);
if (! NT_SUCCESS(status)) }
break;
status = File_GetFullInformation(
&merge->true_file, &merge->file_mask, FALSE);
if (! NT_SUCCESS(status)) if (! NT_SUCCESS(status))
break; break;
@ -1235,34 +1353,59 @@ _FX NTSTATUS File_GetMergedInformation(
// take info from the copy directory if a file exists in both // take info from the copy directory if a file exists in both
ptr_info = NULL; ptr_info = NULL;
save_true_file_have_entry = merge->true_file.have_entry; for (ULONG i = 0; i < merge->files_count; i++)
save_copy_file_have_entry = merge->copy_file.have_entry; merge->files[i].saved_have_entry = merge->files[i].have_entry;
if (merge->copy_file.have_entry && // both directories /*if (merge->files[0].have_entry && // both directories
merge->true_file.have_entry) { // have an entry merge->true_ptr && merge->true_ptr->have_entry) { // have an entry
int cmp = RtlCompareUnicodeString( int cmp = RtlCompareUnicodeString(
&merge->true_file.name_uni, &merge->true_ptr->name_uni,
&merge->copy_file.name_uni, &merge->files[0].name_uni,
TRUE); // CaseInSensitive TRUE); // CaseInSensitive
if (cmp < 0) { // true name sorts before copy name if (cmp < 0) { // true name sorts before copy name
ptr_info = merge->true_file.info; ptr_info = merge->true_ptr->info;
merge->true_file.have_entry = FALSE; merge->true_ptr->have_entry = FALSE;
} else { // true name equal to or after copy name } else { // true name equal to or after copy name
ptr_info = merge->copy_file.info; ptr_info = merge->files[0].info;
merge->copy_file.have_entry = FALSE; merge->files[0].have_entry = FALSE;
if (cmp == 0) // equal if (cmp == 0) // equal
merge->true_file.have_entry = FALSE; merge->true_ptr->have_entry = FALSE;
} }
} else if (merge->copy_file.have_entry) { // only copy } else if (merge->files[0].have_entry) { // only copy
merge->copy_file.have_entry = FALSE; merge->files[0].have_entry = FALSE;
ptr_info = merge->copy_file.info; ptr_info = merge->files[0].info;
} else if (merge->true_file.have_entry) { // only true } else if (merge->true_ptr && merge->true_ptr->have_entry) { // only true
ptr_info = merge->true_file.info; ptr_info = merge->true_ptr->info;
merge->true_file.have_entry = FALSE; merge->true_ptr->have_entry = FALSE;
}*/
FILE_MERGE_FILE* best = &merge->files[0];
for (ULONG i = 1; i < merge->files_count; i++) {
FILE_MERGE_FILE* cur = &merge->files[i];
if (!best->have_entry) {
best = cur;
}
else if (cur->have_entry) {
int cmp = RtlCompareUnicodeString(&best->name_uni, &cur->name_uni, TRUE); // CaseInSensitive
if (cmp == 0) // equal - same file in booth, use newer (best)
cur->have_entry = FALSE;
else if (cmp > 0)
best = cur;
}
}
if (best->have_entry) {
ptr_info = best->info;
best->have_entry = FALSE;
} }
// if the entry found was in the copy directory, then the file // if the entry found was in the copy directory, then the file
@ -1270,7 +1413,7 @@ _FX NTSTATUS File_GetMergedInformation(
// details). if it is marked so, we pretend this entry does // details). if it is marked so, we pretend this entry does
// not exist by fetching the following one // not exist by fetching the following one
if (ptr_info == merge->copy_file.info && if (ptr_info && (!merge->true_ptr || ptr_info != merge->true_ptr->info) &&
IS_DELETE_MARK(&ptr_info->CreationTime)) IS_DELETE_MARK(&ptr_info->CreationTime))
continue; continue;
@ -1306,9 +1449,8 @@ _FX NTSTATUS File_GetMergedInformation(
// current entries have not been used yet, // current entries have not been used yet,
// reset flags so they are used again next time // reset flags so they are used again next time
for (ULONG i = 0; i < merge->files_count; i++)
merge->true_file.have_entry = save_true_file_have_entry; merge->files[i].have_entry = merge->files[i].saved_have_entry;
merge->copy_file.have_entry = save_copy_file_have_entry;
*(ULONG *)prev_entry = 0; // reset NextEntryOffset *(ULONG *)prev_entry = 0; // reset NextEntryOffset
@ -1357,8 +1499,8 @@ _FX NTSTATUS File_GetMergedInformation(
// current entries have not gotten used yet, // current entries have not gotten used yet,
// reset flags so they are used again next time // reset flags so they are used again next time
merge->true_file.have_entry = save_true_file_have_entry; for (ULONG i = 0; i < merge->files_count; i++)
merge->copy_file.have_entry = save_copy_file_have_entry; merge->files[i].have_entry = merge->files[i].saved_have_entry;
*(ULONG *)prev_entry = 0; // reset NextEntryOffset *(ULONG *)prev_entry = 0; // reset NextEntryOffset
@ -1491,6 +1633,13 @@ _FX NTSTATUS File_GetFullInformation(
} }
} }
//
// Scramble the short file name to ensure each snapshot has unique short names
//
if (NT_SUCCESS(status) && qfile->scram_key && qfile->info->ShortNameLength > 0)
File_ScrambleShortName(qfile->info->ShortName, &qfile->info->ShortNameLength, qfile->scram_key);
if (status == STATUS_BUFFER_OVERFLOW) { if (status == STATUS_BUFFER_OVERFLOW) {
Dll_Free(qfile->info); Dll_Free(qfile->info);
@ -2074,7 +2223,8 @@ _FX NTSTATUS File_MarkChildrenDeleted(const WCHAR *ParentTruePath)
while (NT_SUCCESS(status)) { while (NT_SUCCESS(status)) {
status = __sys_NtQueryDirectoryFile( //status = __sys_NtQueryDirectoryFile(
status = NtQueryDirectoryFile(
handle, NULL, NULL, NULL, &IoStatusBlock, handle, NULL, NULL, NULL, &IoStatusBlock,
info, info_len, FileDirectoryInformation, info, info_len, FileDirectoryInformation,
TRUE, NULL, RestartScan); TRUE, NULL, RestartScan);
@ -3179,6 +3329,9 @@ _FX NTSTATUS File_SetReparsePoint(
__leave; __leave;
} }
if (File_Snapshot != NULL)
File_FindSnapshotPath(&CopyPath);
SourcePath = Dll_Alloc((wcslen(CopyPath) + 4) * sizeof(WCHAR)); SourcePath = Dll_Alloc((wcslen(CopyPath) + 4) * sizeof(WCHAR));
wcscpy(SourcePath, CopyPath); wcscpy(SourcePath, CopyPath);
@ -3546,3 +3699,115 @@ _FX BOOLEAN File_MsoDll(HMODULE module)
File_MsoDllLoaded = TRUE; File_MsoDllLoaded = TRUE;
return TRUE; return TRUE;
} }
//---------------------------------------------------------------------------
// 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;
}

View File

@ -107,6 +107,8 @@ static void File_AdjustDrives(
static void File_InitCopyLimit(void); static void File_InitCopyLimit(void);
static void File_InitSnapshots(void);
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Variables // Variables
@ -149,6 +151,8 @@ _FX BOOLEAN File_Init(void)
return FALSE; return FALSE;
} }
File_InitSnapshots();
File_InitRecoverFolders(); File_InitRecoverFolders();
File_InitCopyLimit(); File_InitCopyLimit();
@ -1742,3 +1746,58 @@ _FX void File_GetSetDeviceMap(WCHAR *DeviceMap96)
} }
} }
} }
//---------------------------------------------------------------------------
// File_InitCopyLimit
//---------------------------------------------------------------------------
/* CRC */
#define CRC_WITH_ADLERTZUK64
#include "common/crc.c"
_FX void File_InitSnapshots(void)
{
WCHAR ShapshotsIni[MAX_PATH] = { 0 };
wcscpy(ShapshotsIni, Dll_BoxFilePath);
wcscat(ShapshotsIni, L"\\Snapshots.ini");
SbieDll_TranslateNtToDosPath(ShapshotsIni);
WCHAR Shapshot[16] = { 0 };
GetPrivateProfileStringW(L"Current", L"Snapshot", L"", Shapshot, 16, ShapshotsIni);
if (*Shapshot == 0)
return; // not using snapshots
File_Snapshot = Dll_Alloc(sizeof(FILE_SNAPSHOT *));
memzero(File_Snapshot, sizeof(FILE_SNAPSHOT *));
wcscpy(File_Snapshot->ID, Shapshot);
File_Snapshot->IDlen = wcslen(Shapshot);
FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot;
File_Snapshot_Count = 1;
for (;;)
{
Cur_Snapshot->ScramKey = CRC32(Cur_Snapshot->ID, Cur_Snapshot->IDlen * sizeof(WCHAR));
WCHAR ShapshotId[26] = L"Snapshot_";
wcscat(ShapshotId, Shapshot);
//WCHAR ShapshotName[34] = { 0 };
//GetPrivateProfileStringW(ShapshotId, L"Name", L"", ShapshotName, 34, ShapshotsIni);
//wcscpy(Cur_Snapshot->Name, ShapshotName);
GetPrivateProfileStringW(ShapshotId, L"Parent", L"", Shapshot, 16, ShapshotsIni);
if (*Shapshot == 0)
break; // no more snapshots
Cur_Snapshot->Parent = Dll_Alloc(sizeof(FILE_SNAPSHOT *));
memzero(Cur_Snapshot->Parent, sizeof(FILE_SNAPSHOT *));
wcscpy(Cur_Snapshot->Parent->ID, Shapshot);
Cur_Snapshot->Parent->IDlen = wcslen(Shapshot);
Cur_Snapshot = Cur_Snapshot->Parent;
File_Snapshot_Count++;
}
}

View File

@ -328,6 +328,9 @@ _FX void File_ReplaceFileW_3(
(*FileFlags) &= FGN_IS_BOXED_PATH; (*FileFlags) &= FGN_IS_BOXED_PATH;
if (*FileFlags) { if (*FileFlags) {
if (File_Snapshot != NULL)
File_FindSnapshotPath(&CopyPath);
len = (wcslen(CopyPath) + 1) * sizeof(WCHAR); len = (wcslen(CopyPath) + 1) * sizeof(WCHAR);
path = Dll_AllocTemp(len); path = Dll_AllocTemp(len);
memcpy(path, CopyPath, len); memcpy(path, CopyPath, len);

View File

@ -56,17 +56,6 @@ static NTSTATUS File_CheckFileObject(
PROCESS *proc, void *Object, UNICODE_STRING *NameString, PROCESS *proc, void *Object, UNICODE_STRING *NameString,
ACCESS_MASK GrantedAccess); ACCESS_MASK GrantedAccess);
static void File_CheckFontAccess(
PFLT_CALLBACK_DATA Data,
FLT_IO_PARAMETER_BLOCK *Iopb,
NTSTATUS *out_status);
static PFLT_FILTER File_Get_Trusteer_Filter(void);
static BOOLEAN g_bTrusteerLoaded = FALSE;
BOOLEAN File_TrusteerLoaded(void);
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Filter Manager Registration // Filter Manager Registration
@ -250,16 +239,6 @@ _FX BOOLEAN File_Init_Filter(void)
// successful initialization // successful initialization
// //
{
PFLT_FILTER pFltTrusteer = File_Get_Trusteer_Filter();
if (pFltTrusteer)
{
g_bTrusteerLoaded = TRUE;
FltObjectDereference(pFltTrusteer);
}
}
return TRUE; return TRUE;
} }
@ -775,77 +754,3 @@ _FX NTSTATUS File_CheckFileObject(
proc, FileObject, FileObject->DeviceObject->DeviceType, proc, FileObject, FileObject->DeviceObject->DeviceType,
&FileName, &MyContext, FALSE); &FileName, &MyContext, FALSE);
} }
_FX PFLT_FILTER File_Get_Trusteer_Filter(void)
{
PFLT_FILTER pRet = NULL;
NTSTATUS status;
ULONG NumberFiltersReturned = 0;
PFLT_FILTER *FilterList = NULL;
UNICODE_STRING usRapportCerberus;
RtlInitUnicodeString(&usRapportCerberus, L"RapportCerberus");
status = FltEnumerateFilters(NULL, 0, &NumberFiltersReturned);
if ((status == STATUS_BUFFER_TOO_SMALL) && (NumberFiltersReturned > 0))
{
int len = sizeof(PFLT_FILTER) * NumberFiltersReturned;
FilterList = Mem_AllocEx(Driver_Pool, len, TRUE);
if (FilterList != NULL)
{
ULONG i;
status = FltEnumerateFilters(FilterList, sizeof(PFLT_FILTER) * NumberFiltersReturned, &NumberFiltersReturned);
for (i = 0; (i < NumberFiltersReturned) && NT_SUCCESS(status); i++)
{
if (!pRet)
{
ULONG BytesReturned = 0;
status = FltGetFilterInformation(FilterList[i], FilterFullInformation, NULL, 0, &BytesReturned);
if ((status == STATUS_BUFFER_TOO_SMALL) && (BytesReturned > 0))
{
ULONG nBytesNeeded = BytesReturned;
PFILTER_FULL_INFORMATION myFilterFullInformation = Mem_AllocEx(Driver_Pool, nBytesNeeded, TRUE);
if (myFilterFullInformation != NULL)
{
status = FltGetFilterInformation(FilterList[i], FilterFullInformation, myFilterFullInformation, BytesReturned, &BytesReturned);
if (NT_SUCCESS(status) && myFilterFullInformation->FilterNameLength > usRapportCerberus.Length)
{
UNICODE_STRING usFilterName;
usFilterName.Buffer = myFilterFullInformation->FilterNameBuffer;
usFilterName.MaximumLength = usFilterName.Length = usRapportCerberus.Length;
if (0 == RtlCompareUnicodeString(&usFilterName, &usRapportCerberus, TRUE))
{
// DbgPrint("filter found %wZ\n", &usFilterName);
pRet = FilterList[i];
FltObjectReference(pRet);
}
}
Mem_Free(myFilterFullInformation, nBytesNeeded);
}
}
}
FltObjectDereference(FilterList[i]);
}
Mem_Free(FilterList, len);
}
}
return pRet;
}
_FX BOOLEAN File_TrusteerLoaded(void)
{
return g_bTrusteerLoaded;
}

View File

@ -327,13 +327,13 @@ _FX NTSTATUS Hook_Api_Tramp(PROCESS *proc, ULONG64 *parms)
if (! Source) if (! Source)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
// Trampoline is expected to point to a 80-byte writable buffer, // Trampoline is expected to point to a 96-byte writable buffer,
// aligned on a 16-byte boundary. // aligned on a 16-byte boundary.
Trampoline = (void *)parms[2]; Trampoline = (void *)parms[2];
if (! Trampoline) if (! Trampoline)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
ProbeForWrite(Trampoline, 80 /* sizeof(HOOK_TRAMP) */, 16); ProbeForWrite(Trampoline, 96 /* sizeof(HOOK_TRAMP) */, 16);
// //
// build the trampoline // build the trampoline

View File

@ -83,6 +83,8 @@ typedef struct _HOOK_TRAMP {
__declspec(align(16)) __declspec(align(16))
UCHAR code[64]; // (16) source code + extra jmp UCHAR code[64]; // (16) source code + extra jmp
ULONG count; // original length of relocated code
} HOOK_TRAMP; } HOOK_TRAMP;
#pragma pack(pop) #pragma pack(pop)

View File

@ -24,8 +24,6 @@
#include "hook.h" #include "hook.h"
#include "util.h" #include "util.h"
BOOLEAN File_TrusteerLoaded(void);
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Structures and Types // Structures and Types
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -185,7 +183,8 @@ _FX BOOLEAN Hook_Tramp_CountBytes(
void *SysProc, ULONG *ByteCount, BOOLEAN is64, BOOLEAN probe) void *SysProc, ULONG *ByteCount, BOOLEAN is64, BOOLEAN probe)
{ {
UCHAR *addr = (UCHAR *)SysProc; UCHAR *addr = (UCHAR *)SysProc;
ULONG needlen = (is64 == 9 ? 13 : (is64 ? 12 : (File_TrusteerLoaded()?6:5))); //ULONG needlen = (is64 == 9 ? 13 : (is64 ? 12 : (File_TrusteerLoaded()?6:5)));
ULONG needlen = (is64 ? 12 : 5);
ULONG copylen = 0; ULONG copylen = 0;
// count at least the (needlen) bytes of instructions from the original // count at least the (needlen) bytes of instructions from the original
@ -232,6 +231,7 @@ _FX BOOLEAN Hook_Tramp_Copy(
tramp->eyecatcher = tzuk; tramp->eyecatcher = tzuk;
tramp->target = src + ByteCount; tramp->target = src + ByteCount;
tramp->count = ByteCount;
// copy ByteCount bytes from the original source function into // copy ByteCount bytes from the original source function into
// the code area of the trampoline stub, adjustmenting it as needed // the code area of the trampoline stub, adjustmenting it as needed

View File

@ -56,8 +56,8 @@ extern const ULONG tzuk;
/* CRC */ /* CRC */
#define CRC_WITH_ADLERTZUK64 //#define CRC_WITH_ADLERTZUK64
#include "common/crc.c" //#include "common/crc.c"
/* BigNum */ /* BigNum */

View File

@ -1524,74 +1524,4 @@ FltReleaseFileNameInformation(
__in PFLT_FILE_NAME_INFORMATION FileNameInformation __in PFLT_FILE_NAME_INFORMATION FileNameInformation
); );
//---------------------------------------------------------------------------
// Trusteer support
//---------------------------------------------------------------------------
typedef enum _FILTER_INFORMATION_CLASS {
FilterFullInformation,
FilterAggregateBasicInformation, //Added to XP SP2 via QFE
FilterAggregateStandardInformation //Longhorn and later
} FILTER_INFORMATION_CLASS, *PFILTER_INFORMATION_CLASS;
//
// The structures for the information returned from the query of
// information on a Filter.
//
typedef struct _FILTER_FULL_INFORMATION {
ULONG NextEntryOffset;
ULONG FrameID;
ULONG NumberOfInstances;
USHORT FilterNameLength;
WCHAR FilterNameBuffer[1];
} FILTER_FULL_INFORMATION, *PFILTER_FULL_INFORMATION;
NTSTATUS
FLTAPI
FltEnumerateFilters(
__out_ecount_part_opt(FilterListSize, *NumberFiltersReturned) PFLT_FILTER *FilterList,
__in ULONG FilterListSize,
__out PULONG NumberFiltersReturned
);
VOID
FLTAPI
FltObjectDereference(
__inout PVOID FltObject
);
NTSTATUS
FLTAPI
FltGetFilterInformation(
__in PFLT_FILTER Filter,
__in FILTER_INFORMATION_CLASS InformationClass,
__out_bcount_part_opt(BufferSize, *BytesReturned) PVOID Buffer,
__in ULONG BufferSize,
__out PULONG BytesReturned
);
NTSTATUS
FLTAPI
FltObjectReference(
__inout PVOID FltObject
);
NTSTATUS
FLTAPI
FltEnumerateInstances(
__in_opt PFLT_VOLUME Volume,
__in_opt PFLT_FILTER Filter,
__out_ecount_part_opt(InstanceListSize, *NumberInstancesReturned) PFLT_INSTANCE *InstanceList,
__in ULONG InstanceListSize,
__out PULONG NumberInstancesReturned
);
#endif _MY_FLTKERNEL_H #endif _MY_FLTKERNEL_H

Binary file not shown.

View File

@ -486,6 +486,16 @@ int CTreeItemModel::rowCount(const QModelIndex &parent) const
return pNode->Children.count(); return pNode->Children.count();
} }
QVariant CSimpleTreeModel::GetItemID(const QModelIndex &index) const
{
if (!index.isValid())
return QVariant();
STreeNode* pNode = static_cast<STreeNode*>(index.internalPointer());
return pNode->ID;
}
int CSimpleTreeModel::columnCount(const QModelIndex &parent) const int CSimpleTreeModel::columnCount(const QModelIndex &parent) const
{ {
return m_Headers.count(); return m_Headers.count();

View File

@ -108,6 +108,8 @@ public:
void Sync(const QMap<QVariant, QVariantMap>& List); void Sync(const QMap<QVariant, QVariantMap>& List);
QVariant GetItemID(const QModelIndex &index) const;
void setHeaderLabels(const QStringList& Columns) { m_Headers = Columns; } void setHeaderLabels(const QStringList& Columns) { m_Headers = Columns; }
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;

View File

@ -73,19 +73,19 @@
</ImportGroup> </ImportGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<QtInstall>msvc2015_64</QtInstall> <QtInstall>msvc2015_64</QtInstall>
<QtModules>core</QtModules> <QtModules>concurrent;core</QtModules>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="QtSettings">
<QtInstall>msvc2015_64</QtInstall> <QtInstall>msvc2015_64</QtInstall>
<QtModules>core</QtModules> <QtModules>concurrent;core</QtModules>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<QtInstall>msvc2015_64</QtInstall> <QtInstall>msvc2015_64</QtInstall>
<QtModules>core</QtModules> <QtModules>concurrent;core</QtModules>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="QtSettings">
<QtInstall>msvc2015</QtInstall> <QtInstall>msvc2015</QtInstall>
<QtModules>core</QtModules> <QtModules>concurrent;core</QtModules>
</PropertyGroup> </PropertyGroup>
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')"> <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
<Import Project="$(QtMsBuild)\qt.props" /> <Import Project="$(QtMsBuild)\qt.props" />
@ -104,7 +104,7 @@
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile> <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<PreprocessorDefinitions>QSBIEAPI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>QSBIEAPI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>.;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -189,6 +189,7 @@
<ClCompile Include="Sandboxie\BoxedProcess.cpp" /> <ClCompile Include="Sandboxie\BoxedProcess.cpp" />
<ClCompile Include="Sandboxie\SandBox.cpp" /> <ClCompile Include="Sandboxie\SandBox.cpp" />
<ClCompile Include="Sandboxie\SbieIni.cpp" /> <ClCompile Include="Sandboxie\SbieIni.cpp" />
<ClCompile Include="Sandboxie\SbieTemplates.cpp" />
<ClCompile Include="SbieAPI.cpp" /> <ClCompile Include="SbieAPI.cpp" />
<ClCompile Include="SbieUtils.cpp" /> <ClCompile Include="SbieUtils.cpp" />
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
@ -206,8 +207,9 @@
<QtMoc Include="Sandboxie\SandBox.h" /> <QtMoc Include="Sandboxie\SandBox.h" />
<QtMoc Include="Sandboxie\SbieIni.h" /> <QtMoc Include="Sandboxie\SbieIni.h" />
<QtMoc Include="Sandboxie\BoxBorder.h" /> <QtMoc Include="Sandboxie\BoxBorder.h" />
<QtMoc Include="Sandboxie\SbieTemplates.h" />
<ClInclude Include="SbieDefs.h" /> <ClInclude Include="SbieDefs.h" />
<ClInclude Include="SbieError.h" /> <QtMoc Include="SbieStatus.h" />
<ClInclude Include="SbieUtils.h" /> <ClInclude Include="SbieUtils.h" />
<ClInclude Include="stdafx.h" /> <ClInclude Include="stdafx.h" />
</ItemGroup> </ItemGroup>

View File

@ -48,21 +48,21 @@
<ClCompile Include="Sandboxie\SbieIni.cpp"> <ClCompile Include="Sandboxie\SbieIni.cpp">
<Filter>Sandboxie</Filter> <Filter>Sandboxie</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Sandboxie\SbieTemplates.cpp">
<Filter>Sandboxie</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h"> <ClInclude Include="stdafx.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="SbieError.h">
<Filter>SbieAPI</Filter>
</ClInclude>
<ClInclude Include="..\..\Sandboxie\common\win32_ntddk.h"> <ClInclude Include="..\..\Sandboxie\common\win32_ntddk.h">
<Filter>SbieAPI</Filter> <Filter>SbieAPI</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="SbieUtils.h"> <ClInclude Include="SbieDefs.h">
<Filter>SbieAPI</Filter> <Filter>SbieAPI</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="SbieDefs.h"> <ClInclude Include="SbieUtils.h">
<Filter>SbieAPI</Filter> <Filter>SbieAPI</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
@ -87,5 +87,11 @@
<QtMoc Include="Sandboxie\SbieIni.h"> <QtMoc Include="Sandboxie\SbieIni.h">
<Filter>Sandboxie</Filter> <Filter>Sandboxie</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="SbieStatus.h">
<Filter>SbieAPI</Filter>
</QtMoc>
<QtMoc Include="Sandboxie\SbieTemplates.h">
<Filter>Sandboxie</Filter>
</QtMoc>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -20,7 +20,7 @@
#include "../qsbieapi_global.h" #include "../qsbieapi_global.h"
#include "../SbieError.h" #include "../SbieStatus.h"
class QSBIEAPI_EXPORT CBoxedProcess : public QObject class QSBIEAPI_EXPORT CBoxedProcess : public QObject
{ {

View File

@ -16,9 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "stdafx.h" #include "stdafx.h"
#include <QtConcurrent>
#include "SandBox.h" #include "SandBox.h"
#include "../SbieAPI.h" #include "../SbieAPI.h"
#include <ntstatus.h>
#define WIN32_NO_STATUS
typedef long NTSTATUS;
#include <windows.h>
#include "..\..\Sandboxie\common\win32_ntddk.h"
//struct SSandBox //struct SSandBox
//{ //{
//}; //};
@ -79,21 +87,41 @@ SB_STATUS CSandBox::TerminateAll()
return m_pAPI->TerminateAll(m_Name); return m_pAPI->TerminateAll(m_Name);
} }
SB_STATUS CSandBox::CleanBox() SB_PROGRESS CSandBox::CleanBox()
{ {
SB_STATUS Status = m_pAPI->TerminateAll(m_Name); if (GetBool("NeverDelete", false))
return SB_ERR(tr("Delete protection is enabled for the sandbox"));
SB_STATUS Status = TerminateAll();
if (Status.IsError()) if (Status.IsError())
return Status; return Status;
QProcess* pProcess = new QProcess(this); QString TempPath;
connect(pProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SIGNAL(BoxCleaned())); Status = RenameForDelete(m_FilePath, TempPath);
if (Status.IsError()) {
// ToDo-later: do that manually if (Status.GetStatus() == STATUS_OBJECT_NAME_NOT_FOUND || Status.GetStatus() == STATUS_OBJECT_PATH_NOT_FOUND)
Status = m_pAPI->RunStart(m_Name, "delete_sandbox", pProcess); return SB_OK; // no sandbox folder, nothing to do
return Status; return Status;
} }
return CleanBoxFolders(QStringList(TempPath));
}
SB_PROGRESS CSandBox::CleanBoxFolders(const QStringList& BoxFolders)
{
// cache the DeleteCommand as GetText is not thread safe
QString DeleteCommand = GetText("DeleteCommand", "%SystemRoot%\\System32\\cmd.exe /c rmdir /s /q \"%SANDBOX%\"");
// do the actual delete asynchroniusly in a reandom worker thread...
//QFutureWatcher<bool>* pFuture = new QFutureWatcher<bool>();
//connect(pFuture, SIGNAL(finished()), pFuture, SLOT(deleteLater()));
//pFuture->setFuture(QtConcurrent::run(CSandBox::CleanBoxAsync, pProgress, BoxFolders, DeleteCommand));
CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress());
QtConcurrent::run(CSandBox::CleanBoxAsync, pProgress, BoxFolders, DeleteCommand);
return SB_PROGRESS(OP_ASYNC, pProgress);
}
SB_STATUS CSandBox::RenameBox(const QString& NewName) SB_STATUS CSandBox::RenameBox(const QString& NewName)
{ {
if (QDir(m_FilePath).exists()) if (QDir(m_FilePath).exists())
@ -111,3 +139,501 @@ SB_STATUS CSandBox::RemoveBox()
return RemoveSection(); return RemoveSection();
} }
QList<SBoxSnapshot> CSandBox::GetSnapshots(QString* pCurrent) const
{
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
QList<SBoxSnapshot> Snapshots;
foreach(const QString& Snapshot, ini.childGroups())
{
if (Snapshot.indexOf("Snapshot_") != 0)
continue;
SBoxSnapshot BoxSnapshot;
BoxSnapshot.ID = Snapshot.mid(9);
BoxSnapshot.Parent = ini.value(Snapshot + "/Parent").toString();
BoxSnapshot.NameStr = ini.value(Snapshot + "/Name").toString();
BoxSnapshot.InfoStr = ini.value(Snapshot + "/Description").toString();
BoxSnapshot.SnapDate = ini.value(Snapshot + "/SnapshotDate").toDateTime();
Snapshots.append(BoxSnapshot);
}
if(pCurrent)
*pCurrent = ini.value("Current/Snapshot").toString();
return Snapshots;
}
SB_STATUS CSandBox__OsRename(const wstring& SrcPath, const wstring& DestDir, const wstring& DestName, int Mode);
SB_PROGRESS CSandBox::TakeSnapshot(const QString& Name)
{
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
if (m_pAPI->HasProcesses(m_Name))
return SB_ERR(tr("Can't take a snapshot while processes are running in the box."), OP_CONFIRM);
QStringList Snapshots = ini.childGroups();
QString ID;
for (int i = 1; ; i++)
{
ID = QString::number(i);
if(!Snapshots.contains("Snapshot_" + ID))
break;
}
if (!QDir().mkdir(m_FilePath + "\\snapshot-" + ID))
return SB_ERR(tr("Failed to create directory for new snapshot"));
if (!QFile::copy(m_FilePath + "\\RegHive", m_FilePath + "\\snapshot-" + ID + "\\RegHive"))
return SB_ERR(tr("Failed to copy RegHive to snapshot"));
ini.setValue("Snapshot_" + ID + "/Name", Name);
ini.setValue("Snapshot_" + ID + "/SnapshotDate", QDateTime::currentDateTime());
QString Current = ini.value("Current/Snapshot").toString();
if(!Current.isEmpty())
ini.setValue("Snapshot_" + ID + "/Parent", Current);
ini.setValue("Current/Snapshot", ID);
ini.sync();
wstring dest_dir = (m_FilePath + "\\snapshot-" + ID).toStdWString();
SB_STATUS Status = CSandBox__OsRename((m_FilePath + "\\drive").toStdWString(), dest_dir, L"drive", 1);
if (Status.IsError() && Status.GetStatus() != STATUS_OBJECT_NAME_NOT_FOUND && Status.GetStatus() != STATUS_OBJECT_PATH_NOT_FOUND)
return Status;
Status = CSandBox__OsRename((m_FilePath + "\\share").toStdWString(), dest_dir, L"share", 1);
if (Status.IsError() && Status.GetStatus() != STATUS_OBJECT_NAME_NOT_FOUND && Status.GetStatus() != STATUS_OBJECT_PATH_NOT_FOUND)
return Status;
Status = CSandBox__OsRename((m_FilePath + "\\user").toStdWString(), dest_dir, L"user", 1);
if (Status.IsError() && Status.GetStatus() != STATUS_OBJECT_NAME_NOT_FOUND && Status.GetStatus() != STATUS_OBJECT_PATH_NOT_FOUND)
return Status;
return SB_OK;
}
SB_PROGRESS CSandBox::RemoveSnapshot(const QString& ID)
{
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
if (!ini.childGroups().contains("Snapshot_" + ID))
return SB_ERR(tr("Snapshot not found"));
QString Current = ini.value("Current/Snapshot").toString();
if(Current == ID)
return SB_ERR(tr("Can't remove a currently used snapshot"));
foreach(const QString& Snapshot, ini.childGroups())
{
if (Snapshot.indexOf("Snapshot_") != 0)
continue;
if(ini.value(Snapshot + "/Parent").toString() == ID)
return SB_ERR(tr("Can't remove a snapshots that is used by an other snapshot"));
}
// ToDo: allow removel of intermediate snapshots by merging the folders
if (m_pAPI->HasProcesses(m_Name))
return SB_ERR(tr("Can't remove a snapshots while processes are running in the box."), OP_CONFIRM);
ini.remove("Snapshot_" + ID);
ini.sync();
return CleanBoxFolders(QStringList(m_FilePath + "\\snapshot-" + ID));
}
SB_PROGRESS CSandBox::SelectSnapshot(const QString& ID)
{
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
if (!ini.childGroups().contains("Snapshot_" + ID))
return SB_ERR(tr("Snapshot not found"));
if (m_pAPI->HasProcesses(m_Name))
return SB_ERR(tr("Can't switch snapshots while processes are running in the box."), OP_CONFIRM);
ini.setValue("Current/Snapshot", ID);
ini.sync();
if (!QFile::remove(m_FilePath + "\\RegHive"))
return SB_ERR(tr("Failed to remove old RegHive"));
if (!QFile::copy(m_FilePath + "\\snapshot-" + ID + "\\RegHive", m_FilePath + "\\RegHive"))
return SB_ERR(tr("Failed to copy RegHive from snapshot"));
QStringList BoxFolders;
BoxFolders.append(m_FilePath + "\\drive");
BoxFolders.append(m_FilePath + "\\share");
BoxFolders.append(m_FilePath + "\\user");
return CleanBoxFolders(BoxFolders);
}
SB_STATUS CSandBox::SetSnapshotInfo(const QString& ID, const QString& Name, const QString& Description)
{
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
if (!ini.childGroups().contains("Snapshot_" + ID))
return SB_ERR(tr("Snapshot not found"));
if (!Name.isNull())
ini.setValue("Snapshot_" + ID + "/Name", Name);
if (!Description.isNull())
ini.setValue("Snapshot_" + ID + "/Description", Description);
return SB_OK;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// SBox Deletion
//
SB_STATUS CSandBox__OsRename(const wstring& SrcPath, const wstring& DestDir, const wstring& DestName, int Mode)
{
NTSTATUS status;
IO_STATUS_BLOCK IoStatusBlock;
wstring src_path = L"\\??\\" + SrcPath;
UNICODE_STRING uni;
RtlInitUnicodeString(&uni, src_path.c_str());
OBJECT_ATTRIBUTES objattrs;
InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE src_handle = NULL; // open source file/folder
status = NtCreateFile(&src_handle, DELETE | SYNCHRONIZE, &objattrs, &IoStatusBlock, NULL,
NULL,
Mode == 1 ? (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) : 0, // mode 1 = folder, 0 = file
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT | (Mode == 1 ? (FILE_DIRECTORY_FILE) : 0), // mode 1 = folder, 0 = file
NULL, NULL);
if (!NT_SUCCESS(status)) {
return SB_ERR(CSandBox::tr("Can't open source path"), status);
}
wstring dst_path = L"\\??\\" + DestDir;
RtlInitUnicodeString(&uni, dst_path.c_str());
InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE dst_handle = NULL; // open destination fodler
status = NtCreateFile(&dst_handle, FILE_GENERIC_READ, &objattrs, &IoStatusBlock, NULL,
Mode == 1 ? 0 : FILE_ATTRIBUTE_NORMAL, // mode 1 = folder, 0 = file
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL, NULL);
if (!NT_SUCCESS(status)) {
NtClose(src_handle);
return SB_ERR(CSandBox::tr("Can't open destination folder"), status);
}
// do the rename and retry if needed
union {
FILE_RENAME_INFORMATION info;
WCHAR space[128];
} u;
u.info.ReplaceIfExists = FALSE;
u.info.RootDirectory = dst_handle;
u.info.FileNameLength = DestName.length() * sizeof(WCHAR);
wcscpy(u.info.FileName, DestName.c_str());
for (int retries = 0; retries < 20; retries++)
{
status = NtSetInformationFile(src_handle, &IoStatusBlock, &u.info, sizeof(u), FileRenameInformation);
/*if (status == STATUS_ACCESS_DENIED || status == STATUS_SHARING_VIOLATION)
{
// Please terminate programs running in the sandbox before deleting its contents - 3221
}*/
if (status != STATUS_SHARING_VIOLATION)
break;
Sleep(300);
}
NtClose(dst_handle);
NtClose(src_handle);
if (!NT_SUCCESS(status)) {
//SetLastError(RtlNtStatusToDosError(status));
return SB_ERR(CSandBox::tr("Rename operation failed"), status);
}
return SB_OK;
}
SB_STATUS CSandBox::RenameForDelete(const QString& BoxPath, QString& TempPath)
{
wstring box_path = BoxPath.toStdWString();
size_t pos = box_path.find_last_of(L'\\');
wstring box_name = box_path.substr(pos + 1);
wstring box_root = box_path.substr(0, pos);
WCHAR temp_name[64];
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
wsprintf(temp_name, L"__Delete_%s_%08X%08X", box_name.c_str(), ft.dwHighDateTime, ft.dwLowDateTime); // maintain a compatible naming convention
TempPath = QString::fromStdWString(box_root + L"\\" + temp_name);
SB_STATUS Status = CSandBox__OsRename(box_path, box_root, temp_name, 1);
if (Status.IsError())
return SB_ERR(tr("Could not move the sandbox folder out of the way %1").arg(Status.GetText()), Status.GetStatus());
return SB_OK;
}
bool CSandBox__WaitForFolder(const wstring& folder, int seconds = 10)
{
NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK IoStatusBlock;
wstring path = L"\\??\\" + folder;
UNICODE_STRING uni;
RtlInitUnicodeString(&uni, path.c_str());
OBJECT_ATTRIBUTES objattrs;
InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);
for (int retries = 0; retries < seconds * 2; retries++)
{
HANDLE handle = NULL;
status = NtCreateFile(&handle, DELETE | SYNCHRONIZE, &objattrs, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
0, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (NT_SUCCESS(status)) {
NtClose(handle);
return true;
}
Sleep(500);
}
return false;
}
bool CSandBox__RemoveFileAttributes(const WCHAR *parent, const WCHAR *child)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS status;
wstring path = L"\\??\\" + wstring(parent) + L"\\" + wstring(child);
UNICODE_STRING uni;
RtlInitUnicodeString(&uni, path.c_str());
OBJECT_ATTRIBUTES objattrs;
InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE handle = NULL;
status = NtCreateFile(&handle, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
&objattrs, &IoStatusBlock, NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (NT_SUCCESS(status))
{
union {
FILE_BASIC_INFORMATION info;
WCHAR space[128];
} u;
status = NtQueryInformationFile(handle, &IoStatusBlock, &u.info, sizeof(u), FileBasicInformation);
if (NT_SUCCESS(status))
{
u.info.FileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
if (u.info.FileAttributes == 0 || u.info.FileAttributes == FILE_ATTRIBUTE_DIRECTORY)
u.info.FileAttributes |= FILE_ATTRIBUTE_NORMAL;
status = NtSetInformationFile(handle, &IoStatusBlock, &u.info, sizeof(u), FileBasicInformation);
}
}
if (handle)
NtClose(handle);
//SetLastError(RtlNtStatusToDosError(status));
return (status == STATUS_SUCCESS);
}
SB_STATUS CSandBox__PrepareForDelete(const wstring& BoxFolder)
{
static const WCHAR *deviceNames[] = {
L"aux", L"clock$", L"con", L"nul", L"prn",
L"com1", L"com2", L"com3", L"com4", L"com5",
L"com6", L"com7", L"com8", L"com9",
L"lpt1", L"lpt2", L"lpt3", L"lpt4", L"lpt5",
L"lpt6", L"lpt7", L"lpt8", L"lpt9",
NULL
};
static const UCHAR valid_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"0123456789 ^&@{}[],$=!-#()%.+~_";
//
// prepare the removel of the folder, remove all file attributes and junction points.
// if any path is longer than MAX_PATH shorten it by copying the offending entry to the box folder root
//
list<wstring> folders;
folders.push_back(BoxFolder);
while (!folders.empty())
{
wstring folder = folders.front();
folders.pop_front();
HANDLE hFind = NULL;
for (;;)
{
WIN32_FIND_DATA data;
if (hFind == NULL)
{
hFind = FindFirstFile((folder + L"\\*").c_str(), &data);
if (hFind == INVALID_HANDLE_VALUE)
break;
}
else if (!FindNextFile(hFind, &data))
break;
WCHAR *name = data.cFileName;
if (wcscmp(name, L".") == 0 || wcscmp(name, L"..") == 0)
continue;
ULONG name_len = wcslen(name);
// clear problrmativ attributes
if (data.dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
CSandBox__RemoveFileAttributes(folder.c_str(), name);
// Check if the path is too long
bool needRename = ((folder.length() + name_len) > 220);
// Check if the file name matches a DOS device name
if ((!needRename) && (name_len <= 8)) {
for (ULONG devNum = 0; deviceNames[devNum]; ++devNum) {
const WCHAR *devName = deviceNames[devNum];
ULONG devNameLen = wcslen(devName);
if (_wcsnicmp(name, devName, devNameLen) == 0) {
needRename = true;
break;
}
}
}
// Check if the file name contains non-ASCII or invalid ASCII characters
if (!needRename) {
for (const WCHAR *nameptr = name; *nameptr; ++nameptr) {
const UCHAR *charptr;
if (*nameptr >= 0x80) {
needRename = TRUE;
break;
}
for (charptr = valid_chars; *charptr; ++charptr) {
if ((UCHAR)*nameptr == *charptr)
break;
}
if (!*charptr) {
needRename = TRUE;
break;
}
}
}
// Check if the file name ends with a dot or a space
if (!needRename) {
if (name_len > 1 && (name[name_len - 1] == L'.' || name[name_len - 1] == L' '))
needRename = TRUE;
}
// rename and move the offending file to the box folder root
if (needRename)
{
FILETIME now;
GetSystemTimeAsFileTime(&now);
static ULONG counter = 0;
WCHAR temp_name[64];
wsprintf(temp_name, L"%08X-%08X-%08X", now.dwHighDateTime, now.dwLowDateTime, ++counter);
SB_STATUS Status = CSandBox__OsRename(folder + L"\\" + name, BoxFolder, temp_name, 0);
if (Status.IsError())
return Status;
folder = BoxFolder;
wcscpy(name, temp_name);
//name_len = wcslen(name);
}
// If the filesystem item is a folder add it to the processing queue, ...
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// ... although if the directory is a reparse point delete it right away.
if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
wstring full_path = folder + L"\\" + name;
if (RemoveDirectory(full_path.c_str()))
return SB_ERR(CSandBox::tr("Failed to remove a reparse point!"));
}
else
folders.push_front(folder + L"\\" + name);
}
}
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
}
CSandBox__RemoveFileAttributes(BoxFolder.c_str(), L"");
return SB_OK;
}
bool CSandBox::CleanBoxAsync(const CSbieProgressPtr& pProgress, const QStringList& BoxFolders, const QString& DeleteCommand)
{
SB_STATUS Status;
foreach(const QString& CurFolder, BoxFolders)
{
if (!QDir().exists(CurFolder))
continue;
wstring BoxFolder = CurFolder.toStdWString();
pProgress->ShowMessage(tr("Waiting for folder"));
// Prepare the folder to be deleted
CSandBox__WaitForFolder(BoxFolder);
if (pProgress->IsCancel())
break;
pProgress->ShowMessage(tr("Preparing for deletion"));
Status = CSandBox__PrepareForDelete(BoxFolder);
if (Status.IsError()) {
Status = SB_ERR(CSandBox::tr("Error renaming one of the long file names in the sandbox: %1. The contents of the sandbox will not be deleted.").arg(Status.GetText()), Status.GetStatus());
break;
}
// Prepare and issue the delete command
CSandBox__WaitForFolder(BoxFolder);
if (pProgress->IsCancel())
break;
pProgress->ShowMessage(tr("Running delete command"));
QString Cmd = DeleteCommand;
Cmd.replace("%SANDBOX%", CurFolder); // expand %SANDBOX%
// Expand other environment variables
foreach(const QString& key, QProcessEnvironment::systemEnvironment().keys())
Cmd.replace("%" + key + "%", QProcessEnvironment::systemEnvironment().value(key));
QProcess Proc;
Proc.execute(Cmd);
Proc.waitForFinished();
if (Proc.exitCode() != 0){
Status = SB_ERR(CSandBox::tr("Error sandbox delete command returned %1. The contents of the sandbox will not be deleted.").arg(Proc.exitCode()));
break;
}
}
pProgress->Finish(Status);
return !Status.IsError();
}

View File

@ -23,6 +23,16 @@
#include "BoxedProcess.h" #include "BoxedProcess.h"
#include "SbieIni.h" #include "SbieIni.h"
struct QSBIEAPI_EXPORT SBoxSnapshot
{
QString ID;
QString Parent;
QString NameStr;
QString InfoStr;
QDateTime SnapDate;
};
class QSBIEAPI_EXPORT CSandBox : public CSbieIni class QSBIEAPI_EXPORT CSandBox : public CSbieIni
{ {
Q_OBJECT Q_OBJECT
@ -42,18 +52,27 @@ public:
virtual SB_STATUS RunCommand(const QString& Command); virtual SB_STATUS RunCommand(const QString& Command);
virtual SB_STATUS TerminateAll(); virtual SB_STATUS TerminateAll();
virtual SB_STATUS CleanBox(); virtual SB_PROGRESS CleanBox();
virtual SB_STATUS RenameBox(const QString& NewName); virtual SB_STATUS RenameBox(const QString& NewName);
virtual SB_STATUS RemoveBox(); virtual SB_STATUS RemoveBox();
class CSbieAPI* Api() { return m_pAPI; } virtual QList<SBoxSnapshot> GetSnapshots(QString* pCurrent = NULL) const;
virtual SB_PROGRESS TakeSnapshot(const QString& Name);
virtual SB_PROGRESS RemoveSnapshot(const QString& ID);
virtual SB_PROGRESS SelectSnapshot(const QString& ID);
virtual SB_STATUS SetSnapshotInfo(const QString& ID, const QString& Name, const QString& Description = QString());
signals: class CSbieAPI* Api() { return m_pAPI; }
void BoxCleaned();
protected: protected:
friend class CSbieAPI; friend class CSbieAPI;
SB_PROGRESS CleanBoxFolders(const QStringList& BoxFolders);
static SB_STATUS RenameForDelete(const QString& BoxPath, QString& TempPath);
static bool CleanBoxAsync(const CSbieProgressPtr& pProgress, const QStringList& BoxFolders, const QString& DeleteCommand);
QString m_FilePath; QString m_FilePath;
QString m_RegPath; QString m_RegPath;
QString m_IpcPath; QString m_IpcPath;

View File

@ -3,7 +3,7 @@
#include "../qsbieapi_global.h" #include "../qsbieapi_global.h"
#include "../SbieError.h" #include "../SbieStatus.h"
class QSBIEAPI_EXPORT CSbieIni: public QObject class QSBIEAPI_EXPORT CSbieIni: public QObject
{ {

View File

@ -0,0 +1,475 @@
/*
*
* Copyright (c) 2020, David Xanatos
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser 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 <http://www.gnu.org/licenses/>.
*/
#include "stdafx.h"
#include "SbieTemplates.h"
#include "../SbieAPI.h"
#include <ntstatus.h>
#define WIN32_NO_STATUS
typedef long NTSTATUS;
#include <windows.h>
#include "SbieDefs.h"
#include "..\..\Sandboxie\common\win32_ntddk.h"
#include "..\..\Sandboxie\core\drv\api_flags.h"
CSbieTemplates::CSbieTemplates(CSbieAPI* pAPI, QObject* paretn)
: QObject(paretn)
{
m_pAPI = pAPI;
InitExpandPaths(false);
InitExpandPaths(true);
}
bool CSbieTemplates::RunCheck()
{
CollectObjects();
CollectClasses();
CollectServices();
CollectProducts();
CollectTemplates();
for (QMap<QString, int>::iterator I = m_Templates.begin(); I != m_Templates.end(); ++I)
{
if ((I.value() & eRequired) != 0 && (I.value() & eConfigured) == 0)
return true;
}
return false;
}
void CSbieTemplates::CollectObjects()
{
m_Objects.clear();
QStringList objdirs;
objdirs.append("\\BaseNamedObjects");
objdirs.append("\\Sessions");
objdirs.append("\\RPC Control");
objdirs.append("\\Device");
static const WCHAR *WantedTypes[] = {
L"Directory",
L"Event", L"Mutant", L"Section", L"Semaphore",
L"Port", L"ALPC Port",
L"Device",
NULL
};
ULONG info_len = 0x8000;
OBJECT_DIRECTORY_INFORMATION *info = (OBJECT_DIRECTORY_INFORMATION *)malloc(info_len);
foreach(const QString objdir, objdirs)
{
wstring wobjdir = objdir.toStdWString();
if (wobjdir.substr(0,10) == L"\\Sessions\\" && wobjdir.length() <= 13)
wobjdir += L"\\BaseNamedObjects";
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING objname;
InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
RtlInitUnicodeString(&objname, wobjdir.c_str());
HANDLE handle;
NTSTATUS status = NtOpenDirectoryObject(&handle, DIRECTORY_QUERY, &objattrs);
if (!NT_SUCCESS(status))
continue;
for (int i = 0; i < 10; i++)
{
ULONG context;
ULONG len;
status = NtQueryDirectoryObject(handle, info, info_len, FALSE, TRUE, &context, &len);
if (status == STATUS_MORE_ENTRIES || status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_BUFFER_TOO_SMALL)
{
free(info);
info_len += 0x8000;
info = (OBJECT_DIRECTORY_INFORMATION *)malloc(info_len);
continue;
}
break;
}
NtClose(handle);
if (!NT_SUCCESS(status))
continue;
for (OBJECT_DIRECTORY_INFORMATION* info_ptr = info; info_ptr->Name.Buffer; info_ptr++)
{
int i;
for (i = 0; WantedTypes[i]; ++i) {
if (_wcsicmp(info_ptr->TypeName.Buffer, WantedTypes[i]) == 0)
break;
}
if (!WantedTypes[i])
continue;
QString objpath = objdir + "\\" + QString::fromWCharArray(info_ptr->Name.Buffer);
if (i == 0)
objdirs.append(objpath);
else
m_Objects.push_back(objpath.toLower().toStdWString());
}
}
free(info);
}
void CSbieTemplates::CollectClasses()
{
m_Classes.clear();
EnumWindows([](HWND hwnd, LPARAM lparam)
{
WCHAR clsnm[256];
GetClassName(hwnd, clsnm, 250);
clsnm[250] = L'\0';
if (clsnm[0] && wcsncmp(clsnm, L"Sandbox:", 8) != 0)
{
_wcslwr(clsnm);
((CSbieTemplates*)lparam)->m_Classes.push_back(clsnm);
}
return TRUE;
}, (LPARAM)this);
}
void CSbieTemplates::CollectServices()
{
m_Services.clear();
SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (!hManager)
return;
ULONG info_len = 10240;
ENUM_SERVICE_STATUS* info = (ENUM_SERVICE_STATUS *)malloc(info_len);
ULONG ResumeHandle = 0;
for(;;)
{
ULONG len;
ULONG num;
BOOL ret = EnumServicesStatus(hManager, SERVICE_TYPE_ALL, SERVICE_STATE_ALL, info, info_len, &len, &num, &ResumeHandle);
if (!ret && GetLastError() != ERROR_MORE_DATA)
break;
for (ULONG i = 0; i < num; ++i)
{
_wcslwr(info[i].lpServiceName);
m_Services.push_back(info[i].lpServiceName);
}
if (ret)
break;
}
free(info);
CloseServiceHandle(hManager);
}
void CSbieTemplates::CollectProducts()
{
m_Products.clear();
ULONG DesiredAccess = KEY_READ;
for(;;)
{
HKEY hkey;
LONG rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 0, DesiredAccess, &hkey);
if (rc != 0)
continue;
WCHAR name[128];
for(ULONG index = 0; rc != ERROR_NO_MORE_ITEMS; index++)
{
ULONG name_len = 120;
rc = RegEnumKeyEx(hkey, index, name, &name_len, NULL, NULL, NULL, NULL);
if (rc == 0) {
_wcslwr(name);
m_Products.push_back(name);
}
}
RegCloseKey(hkey);
#ifdef _WIN64
if (DesiredAccess & KEY_WOW64_32KEY)
break;
DesiredAccess |= KEY_WOW64_32KEY;
#else // ! _WIN64
break;
#endif _WIN64
}
}
QStringList CSbieTemplates::GetTemplateNames(const QString& forClass)
{
QStringList list;
ULONG buf_len = sizeof(WCHAR) * CONF_LINE_LEN;
WCHAR *buf = (WCHAR*)malloc(buf_len);
BOOL all_classes = (forClass.compare("*") == 0);
for(int index = 0;; index++)
{
QString section = m_pAPI->SbieIniGet(QString(), QString(), index);
if (section.isEmpty())
break;
if (section.left(9).compare("Template_", Qt::CaseInsensitive) != 0)
continue;
QString value = m_pAPI->SbieIniGet(section, "Tmpl.Class", CONF_GET_NO_GLOBAL);
if (!value.isEmpty() && (all_classes || forClass.compare(value, Qt::CaseInsensitive) == 0))
list.append(section.mid(9));
}
free(buf);
return list;
}
void CSbieTemplates::CollectTemplates()
{
m_Templates.clear();
QStringList Templates;
Templates.append(GetTemplateNames("EmailReader"));
Templates.append(GetTemplateNames("Print"));
Templates.append(GetTemplateNames("Security"));
Templates.append(GetTemplateNames("Desktop"));
Templates.append(GetTemplateNames("Download"));
Templates.append(GetTemplateNames("Misc"));
foreach(const QString& Template, Templates)
m_Templates.insert(Template, 0);
QStringList Used = m_pAPI->GetGlobalSettings()->GetTextList("Template");
QStringList Rejected = m_pAPI->GetGlobalSettings()->GetTextList("TemplateReject");
for(QMap<QString, int>::iterator I = m_Templates.begin(); I != m_Templates.end(); ++I)
{
int Value = eNone;
if (Used.contains(I.key(), Qt::CaseInsensitive))
Value |= eEnabled;
if (CheckTemplate(I.key()))
Value |= eRequired;
if (Rejected.contains(I.key() , Qt::CaseInsensitive))
Value |= eDisabled;
I.value() = Value;
}
}
template <typename T>
const T* wildcmpex(const T* Wild, const T* Str)
{
const T *cp = NULL, *mp = NULL;
while ((*Str) && (*Wild != '*'))
{
if ((*Wild != *Str) && (*Wild != '?'))
return NULL;
Wild++;
Str++;
}
while (*Str)
{
if (*Wild == '*')
{
if (!*++Wild)
return Str;
mp = Wild;
cp = Str + 1;
}
else if ((*Wild == *Str) || (*Wild == '?'))
{
Wild++;
Str++;
}
else
{
Wild = mp;
Str = cp++;
}
}
while (*Wild == '*')
Wild++;
return *Wild ? NULL : Str;
}
bool CSbieTemplates::CheckTemplate(const QString& Name)
{
QSharedPointer<CSbieIni> pTemplate = QSharedPointer<CSbieIni>(new CSbieIni("Template_" + Name, m_pAPI));
QString scan = pTemplate->GetText("Tmpl.Scan");
BOOL scanIpc = (scan.indexOf(L'i') != -1);
BOOL scanWin = (scan.indexOf(L'w') != -1);
BOOL scanSvc = (scan.indexOf(L's') != -1);
if (!(scanIpc || scanWin || scanSvc))
return false;
list<wstring> Keys, Files;
QList<QPair<QString, QString>> settings = pTemplate->GetIniSection(0, true);
for(QList<QPair<QString, QString>>::iterator I = settings.begin(); I != settings.end(); ++I)
{
QString setting = I->first;
list<wstring> *List = NULL;
if (scanIpc && setting.compare("OpenIpcPath", Qt::CaseInsensitive) == 0)
List = &m_Objects;
else if (scanSvc && setting.compare("Tmpl.ScanIpc", Qt::CaseInsensitive) == 0)
List = &m_Objects;
else if (scanWin && setting.compare("OpenWinClass", Qt::CaseInsensitive) == 0)
List = &m_Classes;
else if (scanSvc && setting.compare("Tmpl.ScanWinClass", Qt::CaseInsensitive) == 0)
List = &m_Classes;
else if (scanSvc && setting.compare("Tmpl.ScanService", Qt::CaseInsensitive) == 0)
List = &m_Services;
else if (scanSvc && setting.compare("Tmpl.ScanProduct", Qt::CaseInsensitive) == 0)
List = &m_Products;
else if (scanSvc && setting.compare("Tmpl.ScanKey", Qt::CaseInsensitive) == 0)
List = &Keys;
else if (scanSvc && setting.compare("Tmpl.ScanFile", Qt::CaseInsensitive) == 0)
List = &Files;
else
continue;
QString value = I->second;
if(!value.isEmpty())
{
if (List == &Keys) {
if (CheckRegistryKey(value))
return true;
continue;
}
else if (List == &Files) {
if (CheckFile(value))
return true;
continue;
}
// skip to unspecific entries
if (List == &m_Classes)
{
if(value.left(2).compare("*:") == 0)
continue;
}
if (List == &m_Objects)
{
if (value.compare("\\RPC Control\\epmapper") == 0)
continue;
if (value.compare("\\RPC Control\\OLE*") == 0)
continue;
if (value.compare("\\RPC Control\\LRPC*") == 0)
continue;
if (value.compare("*\\BaseNamedObjects*\\NamedBuffer*mAH*Process*API*") == 0)
continue;
}
//
wstring wild = value.toLower().toStdWString();
for (list<wstring>::iterator I = List->begin(); I != List->end(); ++I)
{
if (wildcmpex(wild.c_str(), I->c_str()) != NULL)
return true;
}
}
}
return false;
}
bool CSbieTemplates::CheckRegistryKey(const QString& Value)
{
wstring keypath = Value.toStdWString();
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING objname;
RtlInitUnicodeString(&objname, keypath.c_str());
InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE handle;
NTSTATUS status = NtOpenKey(&handle, KEY_QUERY_VALUE, &objattrs);
if (NT_SUCCESS(status))
{
NtClose(handle);
return true;
}
return false;
}
bool CSbieTemplates::CheckFile(const QString& Value)
{
wstring path = ExpandPath(Value).toStdWString();
if (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES)
return true;
return false;
}
void CSbieTemplates::InitExpandPaths(bool WithUser)
{
wstring keyPath(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\");
if (WithUser)
keyPath += L"User ";
keyPath += L"Shell Folders";
HKEY hkey;
LONG rc = RegOpenKey(HKEY_CURRENT_USER, keyPath.c_str(), &hkey);
for (ULONG index = 0; rc == 0; index++)
{
WCHAR name[64];
WCHAR value[MAX_PATH + 8];
ULONG name_len;
ULONG value_len;
ULONG type;
name_len = 60;
value_len = MAX_PATH + 4;
rc = RegEnumValue(hkey, index, name, &name_len, NULL, &type, (BYTE *)value, &value_len);
if (rc == 0 && (type == REG_SZ || type == REG_EXPAND_SZ))
{
WCHAR expand[MAX_PATH + 8];
ULONG len = ExpandEnvironmentStrings(value, expand, MAX_PATH + 4);
if (len > 0 && len <= MAX_PATH)
{
QString value = QString::fromWCharArray(expand);
if (!value.trimmed().isEmpty())
m_Expands[QString::fromWCharArray(name)] = value;
}
}
}
RegCloseKey(hkey);
}
QString CSbieTemplates::ExpandPath(QString path)
{
foreach(const QString& key, m_Expands.keys())
path.replace("%" + key + "%", m_Expands.value(key));
return path;
}

View File

@ -0,0 +1,53 @@
#pragma once
#include <QObject>
#include "../qsbieapi_global.h"
#include "../SbieStatus.h"
class QSBIEAPI_EXPORT CSbieTemplates : public QObject
{
Q_OBJECT
public:
CSbieTemplates(class CSbieAPI* pAPI, QObject* paretn = 0);
bool RunCheck();
enum EStates
{
eNone = 0x00,
eEnabled = 0x01,
eRequired = 0x02,
eDisabled = 0x04,
eConfigured = eEnabled | eDisabled
};
QMap<QString, int> GetTemplates() { return m_Templates; }
protected:
void CollectObjects();
void CollectClasses();
void CollectServices();
void CollectProducts();
void CollectTemplates();
QStringList GetTemplateNames(const QString& forClass);
bool CheckTemplate(const QString& Name);
bool CheckRegistryKey(const QString& Value);
bool CheckFile(const QString& Value);
void InitExpandPaths(bool WithUser);
QString ExpandPath(QString path);
list<wstring> m_Objects;
list<wstring> m_Classes;
list<wstring> m_Services;
list<wstring> m_Products;
QMap<QString, int> m_Templates;
QMap<QString, QString> m_Expands;
class CSbieAPI* m_pAPI;
};

View File

@ -34,6 +34,8 @@ typedef long NTSTATUS;
#include "..\..\Sandboxie\core\svc\ProcessWire.h" #include "..\..\Sandboxie\core\svc\ProcessWire.h"
#include "..\..\Sandboxie\core\svc\sbieiniwire.h" #include "..\..\Sandboxie\core\svc\sbieiniwire.h"
int _SB_STATUS_type = qRegisterMetaType<SB_STATUS>("SB_STATUS");
struct SSbieAPI struct SSbieAPI
{ {
SSbieAPI() SSbieAPI()
@ -775,23 +777,28 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep)
return SB_OK; return SB_OK;
} }
SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, const CSandBoxPtr& pBox) SB_STATUS CSbieAPI__GetProcessPIDs(SSbieAPI* m, const QString& BoxName, ULONG* boxed_pids_512)
{ {
wstring box_name = pBox->GetName().toStdWString(); // WCHAR [34] wstring box_name = BoxName.toStdWString(); // WCHAR [34]
BOOLEAN all_sessions = TRUE; BOOLEAN all_sessions = TRUE;
ULONG which_session = 0; // -1 for current session ULONG which_session = 0; // -1 for current session
ULONG boxed_pids[512]; // ULONG [512]
__declspec(align(8)) ULONG64 parms[API_NUM_ARGS]; __declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
memset(parms, 0, sizeof(parms)); memset(parms, 0, sizeof(parms));
parms[0] = API_ENUM_PROCESSES; parms[0] = API_ENUM_PROCESSES;
parms[1] = (ULONG64)boxed_pids; parms[1] = (ULONG64)boxed_pids_512;
parms[2] = (ULONG64)box_name.c_str(); parms[2] = (ULONG64)box_name.c_str();
parms[3] = (ULONG64)all_sessions; parms[3] = (ULONG64)all_sessions;
parms[4] = (ULONG64)which_session; parms[4] = (ULONG64)which_session;
NTSTATUS status = m->IoControl(parms); return m->IoControl(parms);
}
SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, const CSandBoxPtr& pBox)
{
ULONG boxed_pids[512]; // ULONG [512]
NTSTATUS status = CSbieAPI__GetProcessPIDs(m, pBox->GetName(), boxed_pids);
if (!NT_SUCCESS(status)) if (!NT_SUCCESS(status))
return SB_ERR(status); return SB_ERR(status);
@ -831,6 +838,12 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, const CSandBoxPtr& pBox)
return SB_OK; return SB_OK;
} }
bool CSbieAPI::HasProcesses(const QString& BoxName)
{
ULONG boxed_pids[512]; // ULONG [512]
return CSbieAPI__GetProcessPIDs(m, BoxName, boxed_pids) && (boxed_pids[0] > 0);
}
SB_STATUS CSbieAPI__QueryBoxPath(SSbieAPI* m, const WCHAR *box_name, WCHAR *out_file_path, WCHAR *out_key_path, WCHAR *out_ipc_path, SB_STATUS CSbieAPI__QueryBoxPath(SSbieAPI* m, const WCHAR *box_name, WCHAR *out_file_path, WCHAR *out_key_path, WCHAR *out_ipc_path,
ULONG *inout_file_path_len, ULONG *inout_key_path_len, ULONG *inout_ipc_path_len) ULONG *inout_file_path_len, ULONG *inout_key_path_len, ULONG *inout_ipc_path_len)
{ {
@ -880,9 +893,9 @@ SB_STATUS CSbieAPI::UpdateBoxPaths(const CSandBoxPtr& pSandBox)
if (!Status) if (!Status)
return Status; return Status;
pSandBox->m_FilePath = Nt2DosPath(QString::fromStdWString(FileRoot)); pSandBox->m_FilePath = Nt2DosPath(QString::fromWCharArray(FileRoot.c_str(), wcslen(FileRoot.c_str())));
pSandBox->m_RegPath = QString::fromStdWString(KeyRoot); pSandBox->m_RegPath = QString::fromWCharArray(KeyRoot.c_str(), wcslen(KeyRoot.c_str()));
pSandBox->m_IpcPath = QString::fromStdWString(IpcRoot); pSandBox->m_IpcPath = QString::fromWCharArray(IpcRoot.c_str(), wcslen(IpcRoot.c_str()));
return SB_OK; return SB_OK;
} }
@ -1446,6 +1459,11 @@ bool CSbieAPI::GetMonitor()
CResLogEntryPtr LogEntry = CResLogEntryPtr(new CResLogEntry(pid, type, QString::fromWCharArray(name))); CResLogEntryPtr LogEntry = CResLogEntryPtr(new CResLogEntry(pid, type, QString::fromWCharArray(name)));
QWriteLocker Lock(&m_ResLogMutex); QWriteLocker Lock(&m_ResLogMutex);
if (!m_ResLogList.isEmpty() && m_ResLogList.last()->GetValue() == LogEntry->GetValue())
{
m_ResLogList.last()->IncrCounter();
return true;
}
m_ResLogList.append(LogEntry); m_ResLogList.append(LogEntry);
return true; return true;
} }
@ -1485,11 +1503,22 @@ CResLogEntry::CResLogEntry(quint64 ProcessId, quint32 Type, const QString& Value
//m_Verbose = (Type & MONITOR_VERBOSE) != 0; //m_Verbose = (Type & MONITOR_VERBOSE) != 0;
//m_User = (Type & MONITOR_USER) != 0; //m_User = (Type & MONITOR_USER) != 0;
m_TimeStamp = QDateTime::currentDateTime(); // ms resolution m_TimeStamp = QDateTime::currentDateTime(); // ms resolution
m_Counter = 0;
static atomic<quint64> uid = 0; static atomic<quint64> uid = 0;
m_uid = uid.fetch_add(1); m_uid = uid.fetch_add(1);
} }
QString CResLogEntry::GetStautsStr() const
{
QString Str;
if(m_Open)
Str += "O ";
if(m_Deny)
Str += "X ";
return Str;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// //

View File

@ -22,7 +22,7 @@
#include "qsbieapi_global.h" #include "qsbieapi_global.h"
#include "SbieError.h" #include "SbieStatus.h"
#include "./Sandboxie/SandBox.h" #include "./Sandboxie/SandBox.h"
#include "./Sandboxie/BoxedProcess.h" #include "./Sandboxie/BoxedProcess.h"
@ -36,6 +36,9 @@ public:
QDateTime GetTimeStamp() const { return m_TimeStamp; } QDateTime GetTimeStamp() const { return m_TimeStamp; }
QString GetType() const { return m_Type; } QString GetType() const { return m_Type; }
QString GetValue() const { return m_Name; } QString GetValue() const { return m_Name; }
QString GetStautsStr()const;
void IncrCounter() { m_Counter++; }
int GetCount() const { return m_Counter; }
quint64 GetUID() const { return m_uid; } quint64 GetUID() const { return m_uid; }
@ -48,6 +51,7 @@ protected:
bool m_Deny; bool m_Deny;
//bool m_Verbose; //bool m_Verbose;
//bool m_User; //bool m_User;
int m_Counter;
quint64 m_uid; quint64 m_uid;
}; };
@ -151,6 +155,8 @@ protected:
virtual SB_STATUS RunStart(const QString& BoxName, const QString& Command, QProcess* pProcess = NULL); virtual SB_STATUS RunStart(const QString& BoxName, const QString& Command, QProcess* pProcess = NULL);
virtual bool HasProcesses(const QString& BoxName);
virtual bool GetLog(); virtual bool GetLog();
virtual bool GetMonitor(); virtual bool GetMonitor();

View File

@ -1,108 +0,0 @@
#pragma once
#define ERROR_OK (1)
#define OP_ASYNC (2)
class CSbieError
{
public:
CSbieError()
{
m = NULL;
}
CSbieError(const QString& Error, long Status = 0xC0000001 /*STATUS_UNSUCCESSFUL*/) : CSbieError()
{
SFlexError* p = new SFlexError();
p->Error = Error;
p->Status = Status;
Attach(p);
}
CSbieError(long Status) : CSbieError(QObject::tr("Error Code: %1").arg(Status), Status)
{
}
CSbieError(const CSbieError& other) : CSbieError()
{
if(other.m != NULL)
Attach((SFlexError*)other.m);
}
/*virtual*/ ~CSbieError()
{
Detach();
}
CSbieError& operator=(const CSbieError& Array)
{
Attach(Array.m);
return *this;
}
__inline bool IsError() const { return m != NULL; }
__inline long GetStatus() const { return m ? m->Status : 0; }
__inline QString GetText() const { return m ? m->Error: ""; }
operator bool() const {return !IsError();}
private:
struct SFlexError
{
QString Error;
long Status;
mutable atomic<int> aRefCnt;
} *m;
void Attach(SFlexError* p)
{
Detach();
if (p != NULL)
{
p->aRefCnt.fetch_add(1);
m = p;
}
}
void Detach()
{
if (m != NULL)
{
if (m->aRefCnt.fetch_sub(1) == 1)
delete m;
m = NULL;
}
}
};
typedef CSbieError SB_STATUS;
#define SB_OK CSbieError()
#define SB_ERR CSbieError
/*
template <class T>
class CSbieResult : public CSbieError
{
public:
CSbieResult(const T& value = T()) : CSbieError()
{
v = value;
}
CSbieResult(const CSbieError& other) : CSbieResult()
{
if (other.m != NULL)
Attach((SFlexError*)other.m);
}
CSbieResult(const CSbieResult& other) : CSbieResult(other)
{
v = other.v;
}
__inline T GetValue() const { return v; }
private:
T v;
};
#define SB_RESULT(x) CSbieResult<x>
#define SB_RETURN(x,y) CSbieResult<x>(y)
*/

View File

@ -0,0 +1,152 @@
#pragma once
#define ERROR_OK (1)
#define OP_ASYNC (2)
#define OP_CONFIRM (3)
#define OP_CANCELED (4)
class CSbieStatus
{
public:
CSbieStatus()
{
m = NULL;
}
CSbieStatus(const QString& Error, long Status = 0xC0000001 /*STATUS_UNSUCCESSFUL*/) : CSbieStatus()
{
SFlexError* p = new SFlexError();
p->Error = Error;
p->Status = Status;
Attach(p);
}
CSbieStatus(long Status) : CSbieStatus(QObject::tr("Error Code: %1").arg(Status), Status)
{
}
CSbieStatus(const CSbieStatus& other) : CSbieStatus()
{
if(other.m != NULL)
Attach((SFlexError*)other.m);
}
~CSbieStatus()
{
Detach();
}
CSbieStatus& operator=(const CSbieStatus& other)
{
Attach(&other);
return *this;
}
__inline bool IsError() const { return m != NULL; }
__inline long GetStatus() const { return m ? m->Status : 0; }
__inline QString GetText() const { return m ? m->Error: ""; }
operator bool() const {return !IsError();}
protected:
struct SFlexError
{
QString Error;
long Status;
mutable atomic<int> aRefCnt;
} *m;
void Attach(const CSbieStatus* p)
{
Attach(p->m);
}
void Attach(SFlexError* p)
{
Detach();
if (p != NULL)
{
p->aRefCnt.fetch_add(1);
m = p;
}
}
void Detach()
{
if (m != NULL)
{
if (m->aRefCnt.fetch_sub(1) == 1)
delete m;
m = NULL;
}
}
};
typedef CSbieStatus SB_STATUS;
#define SB_OK SB_STATUS()
#define SB_ERR SB_STATUS
template <class T>
class CSbieResult : public CSbieStatus
{
public:
CSbieResult(const T& value = T()) : CSbieStatus()
{
v = value;
}
CSbieResult(long Status, const T& value = T()) : CSbieStatus(Status)
{
v = value;
}
CSbieResult(const CSbieStatus& other) : CSbieResult()
{
Attach(&other);
}
CSbieResult(const CSbieResult& other) : CSbieResult(other)
{
v = other.v;
}
__inline T GetValue() const { return v; }
private:
T v;
};
#define SB_RESULT(x) CSbieResult<x>
#define SB_RETURN(x,y) CSbieResult<x>(y)
#include "qsbieapi_global.h"
class QSBIEAPI_EXPORT CSbieProgress : public QObject
{
Q_OBJECT
public:
CSbieProgress() : m_Status(OP_ASYNC), m_Canceled(false) {}
void Cancel() { m_Canceled = true; }
bool IsCancel() { return m_Canceled; }
void ShowMessage(const QString& text) { emit Message(text);
#ifdef _DEBUG
QThread::sleep(3);
#endif
}
void Finish(SB_STATUS status) { m_Status = m_Canceled ? SB_ERR(OP_CANCELED) : status; emit Finished(); }
long GetStatus() { return m_Status.GetStatus(); }
bool IsFinished() { return GetStatus() != OP_ASYNC; }
signals:
//void Progress(int procent);
void Message(const QString& text);
void Finished();
protected:
volatile bool m_Canceled;
SB_STATUS m_Status;
};
typedef QSharedPointer<CSbieProgress> CSbieProgressPtr;
#define SB_PROGRESS CSbieResult<CSbieProgressPtr>

View File

@ -113,7 +113,7 @@ void CSbieUtils::Install(EComponent Component, QStringList& Ops)
Ops.append(QString::fromWCharArray(L"kmdutil.exe|install|" SBIEDRV L"|") + "\"" + HomePath + "\\" + QString::fromWCharArray(SBIEDRV_SYS) + "\"" + "|type=kernel|start=demand|altitude=86900"); Ops.append(QString::fromWCharArray(L"kmdutil.exe|install|" SBIEDRV L"|") + "\"" + HomePath + "\\" + QString::fromWCharArray(SBIEDRV_SYS) + "\"" + "|type=kernel|start=demand|altitude=86900");
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) == 0) { if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) == 0) {
Ops.append(QString::fromWCharArray(L"kmdutil.exe|install|" SBIESVC L"|") + "\"" + HomePath + "\\" + QString::fromWCharArray(SBIESVC_EXE) + "\"" + "|type=own|start=auto|display=\"Sandboxie Service\"|group=UIGroup"); Ops.append(QString::fromWCharArray(L"kmdutil.exe|install|" SBIESVC L"|") + "\"" + HomePath + "\\" + QString::fromWCharArray(SBIESVC_EXE) + "\"" + "|type=own|start=auto|display=\"Sandboxie Service\"|group=UIGroup");
Ops.append("reg.exe|ADD|HKLM\\SYSTEM\\ControlSet001\\Services\\SbieSvc|/v|PreferExternalManifest|/t|REG_DWORD|/d|1"); Ops.append("reg.exe|ADD|HKLM\\SYSTEM\\ControlSet001\\Services\\SbieSvc|/v|PreferExternalManifest|/t|REG_DWORD|/d|1|/f");
} }
} }

View File

@ -2,7 +2,7 @@
#include "qsbieapi_global.h" #include "qsbieapi_global.h"
#include "SbieError.h" #include "SbieStatus.h"
class QSBIEAPI_EXPORT CSbieUtils class QSBIEAPI_EXPORT CSbieUtils
{ {

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../../MiscHelpers/Common/PanelView.h" #include "../../MiscHelpers/Common/PanelView.h"
#include "../../MiscHelpers/Common/FlexError.h" #include "../../MiscHelpers/Common/FlexError.h"
#include "../../QSbieAPI/SbieError.h" #include "../../QSbieAPI/SbieStatus.h"
class CMultiErrorDialog : public QDialog class CMultiErrorDialog : public QDialog
{ {

View File

@ -54,8 +54,31 @@
<layout class="QGridLayout" name="gridLayout_9"> <layout class="QGridLayout" name="gridLayout_9">
<item row="0" column="0"> <item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_8"> <layout class="QGridLayout" name="gridLayout_8">
<item row="6" column="4"> <item row="2" column="6">
<spacer name="horizontalSpacer"> <widget class="QSpinBox" name="spinBorderWidth">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>10</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Copy file size limit:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="3">
<spacer name="horizontalSpacer_8">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
@ -80,6 +103,16 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="4" column="1" colspan="2">
<widget class="QLineEdit" name="txtCopyLimit">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="6" column="1"> <item row="6" column="1">
<spacer name="verticalSpacer_4"> <spacer name="verticalSpacer_4">
<property name="orientation"> <property name="orientation">
@ -93,19 +126,6 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="6" column="3">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
<property name="font"> <property name="font">
@ -119,23 +139,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="5" column="1" colspan="3">
<widget class="QLabel" name="label_18"> <widget class="QCheckBox" name="chkNoCopyWarn">
<property name="text"> <property name="text">
<string>Copy file size limit:</string> <string>Issue message 2102 when a file is too large</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1" colspan="2"> <item row="4" column="3">
<widget class="QLineEdit" name="txtCopyLimit"> <widget class="QLabel" name="lblCopyLimit">
<property name="maximumSize"> <property name="text">
<size> <string>kilobytes</string>
<width>75</width>
<height>16777215</height>
</size>
</property> </property>
</widget> </widget>
</item> </item>
@ -152,26 +166,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1" colspan="3">
<widget class="QCheckBox" name="chkNoCopyWarn">
<property name="text">
<string>Issue message 2102 when a file is too large</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="lblCopyLimit">
<property name="text">
<string>kilobytes</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QComboBox" name="cmbBoxIndicator"/>
</item>
<item row="2" column="2" colspan="2">
<widget class="QComboBox" name="cmbBoxBorder"/>
</item>
<item row="1" column="0" colspan="2"> <item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_20"> <widget class="QLabel" name="label_20">
<property name="text"> <property name="text">
@ -182,6 +176,12 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2" colspan="2">
<widget class="QComboBox" name="cmbBoxBorder"/>
</item>
<item row="1" column="2" colspan="2">
<widget class="QComboBox" name="cmbBoxIndicator"/>
</item>
<item row="2" column="0" colspan="2"> <item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_21"> <widget class="QLabel" name="label_21">
<property name="text"> <property name="text">
@ -199,6 +199,29 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="5">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Width</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="5">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

View File

@ -35,7 +35,7 @@
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabs">
<property name="font"> <property name="font">
<font> <font>
<kerning>true</kerning> <kerning>true</kerning>
@ -45,9 +45,9 @@
<enum>QTabWidget::North</enum> <enum>QTabWidget::North</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="tab_1"> <widget class="QWidget" name="tabGeneral">
<attribute name="title"> <attribute name="title">
<string>General Options</string> <string>General Options</string>
</attribute> </attribute>
@ -174,7 +174,7 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_2"> <widget class="QWidget" name="tabAdvanced">
<attribute name="title"> <attribute name="title">
<string>Advanced Options</string> <string>Advanced Options</string>
</attribute> </attribute>
@ -344,6 +344,127 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabAlerts">
<attribute name="title">
<string>Program Alerts</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" rowspan="3">
<widget class="QTreeWidget" name="treeWarnProgs">
<column>
<property name="text">
<string>Name</string>
</property>
</column>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="btnAddWarnProg">
<property name="text">
<string>Add Program</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="btnDelWarnProg">
<property name="text">
<string>Remove Program</string>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>When any of following programs is launched outside any sandbox, Sandboxie will issue message SBIE1301.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabCompat">
<attribute name="title">
<string>Software Compatybility</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_3">
<item row="4" column="0">
<widget class="QCheckBox" name="chkNoCompat">
<property name="text">
<string>In the future, don't check software compatibility</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="btnAddCompat">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="btnDelCompat">
<property name="text">
<string>Disable</string>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="3">
<widget class="QTreeWidget" name="treeCompat">
<column>
<property name="text">
<string>Name</string>
</property>
</column>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Sandboxie has detected the following software applications in your system. Click OK to apply configuration settings which will improve compatibility with these applications. These configuration settings will have effect in all existing sandboxes and in any new sandboxes.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SnapshotsWindow</class>
<widget class="QWidget" name="SnapshotsWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>573</width>
<height>451</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>SandboxiePlus Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Snapshot Details</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Description:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2">
<widget class="QPlainTextEdit" name="txtInfo"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtName"/>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="btnRemove">
<property name="text">
<string>Remove Snapshot</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="btnTake">
<property name="text">
<string>Take Snapshot</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="btnSelect">
<property name="text">
<string>Goto Snapshot</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QTreeView" name="treeSnapshots"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -65,6 +65,7 @@ void CResMonModel::Sync(const QList<CResLogEntryPtr>& List, QSet<quint64> PIDs)
case eTimeStamp: Value = pEntry->GetTimeStamp(); break; case eTimeStamp: Value = pEntry->GetTimeStamp(); break;
case eType: Value = pEntry->GetType(); break; case eType: Value = pEntry->GetType(); break;
case eValue: Value = pEntry->GetValue(); break; case eValue: Value = pEntry->GetValue(); break;
case eStatus: Value = pEntry->GetStautsStr(); break;
} }
SResLogNode::SValue& ColValue = pNode->Values[section]; SResLogNode::SValue& ColValue = pNode->Values[section];
@ -126,6 +127,7 @@ QVariant CResMonModel::headerData(int section, Qt::Orientation orientation, int
case eTimeStamp: return tr("Time Stamp"); case eTimeStamp: return tr("Time Stamp");
case eType: return tr("Type"); case eType: return tr("Type");
case eValue: return tr("Value"); case eValue: return tr("Value");
case eStatus: return tr("Status");
} }
} }
return QVariant(); return QVariant();

View File

@ -24,6 +24,7 @@ public:
eTimeStamp, eTimeStamp,
eType, eType,
eValue, eValue,
eStatus,
eCount eCount
}; };

View File

@ -10,6 +10,7 @@
#include "./Dialogs/MultiErrorDialog.h" #include "./Dialogs/MultiErrorDialog.h"
#include "../QSbieAPI/SbieUtils.h" #include "../QSbieAPI/SbieUtils.h"
#include "../QSbieAPI/Sandboxie/BoxBorder.h" #include "../QSbieAPI/Sandboxie/BoxBorder.h"
#include "../QSbieAPI/Sandboxie/SbieTemplates.h"
#include "Windows/SettingsWindow.h" #include "Windows/SettingsWindow.h"
CSbiePlusAPI* theAPI = NULL; CSbiePlusAPI* theAPI = NULL;
@ -99,6 +100,8 @@ CSandMan::CSandMan(QWidget *parent)
m_pBoxBorder = new CBoxBorder(theAPI, this); m_pBoxBorder = new CBoxBorder(theAPI, this);
m_SbieTemplates = new CSbieTemplates(theAPI, this);
m_ApiLog = NULL; m_ApiLog = NULL;
m_bConnectPending = false; m_bConnectPending = false;
@ -319,6 +322,7 @@ CSandMan::CSandMan(QWidget *parent)
m_pProgressDialog = new CProgressDialog("Maintenance operation progress...", this); m_pProgressDialog = new CProgressDialog("Maintenance operation progress...", this);
m_pProgressDialog->setWindowModality(Qt::ApplicationModal); m_pProgressDialog->setWindowModality(Qt::ApplicationModal);
connect(m_pProgressDialog, SIGNAL(Cancel()), this, SLOT(OnCancelAsync()));
if (!bAutoRun) if (!bAutoRun)
show(); show();
@ -518,6 +522,16 @@ void CSandMan::OnStatusChanged()
OnLogMessage(tr("Sbie Directory: %1").arg(theAPI->GetSbiePath())); OnLogMessage(tr("Sbie Directory: %1").arg(theAPI->GetSbiePath()));
OnLogMessage(tr("Loaded Config: %1").arg(theAPI->GetIniPath())); OnLogMessage(tr("Loaded Config: %1").arg(theAPI->GetIniPath()));
if (theConf->GetBool("Options/AutoRunSoftCompat", true))
{
if (m_SbieTemplates->RunCheck())
{
CSettingsWindow* pSettingsWindow = new CSettingsWindow(this);
//connect(pSettingsWindow, SIGNAL(OptionsChanged()), this, SLOT(UpdateSettings()));
pSettingsWindow->showCompat();
}
}
if (theConf->GetBool("Options/WatchIni", true)) if (theConf->GetBool("Options/WatchIni", true))
theAPI->WatchIni(true); theAPI->WatchIni(true);
} }
@ -612,7 +626,7 @@ void CSandMan::OnNotAuthorized(bool bLoginRequired, bool& bRetry)
void CSandMan::OnNewBox() void CSandMan::OnNewBox()
{ {
QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a name for the new Sandbox."), QLineEdit::Normal, "NewBox"); QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a name for the new Sandbox."), QLineEdit::Normal, tr("NewBox"));
if (Value.isEmpty()) if (Value.isEmpty())
return; return;
theAPI->CreateBox(Value); theAPI->CreateBox(Value);
@ -866,6 +880,44 @@ void CSandMan::OnSetLogging()
} }
} }
void CSandMan::AddAsyncOp(const CSbieProgressPtr& pProgress)
{
m_pAsyncProgress.insert(pProgress.data(), pProgress);
connect(pProgress.data(), SIGNAL(Message(const QString&)), this, SLOT(OnAsyncMessage(const QString&)));
connect(pProgress.data(), SIGNAL(Finished()), this, SLOT(OnAsyncFinished()));
if (pProgress->IsFinished()) // Note: the operation runs asynchroniusly it may have already finished so we need to test for that
OnAsyncFinished(pProgress.data());
m_pProgressDialog->show();
}
void CSandMan::OnAsyncFinished()
{
OnAsyncFinished(qobject_cast<CSbieProgress*>(sender()));
}
void CSandMan::OnAsyncFinished(CSbieProgress* pSender)
{
CSbieProgressPtr pProgress = m_pAsyncProgress.take(pSender);
if (pProgress.isNull())
return;
disconnect(pProgress.data() , SIGNAL(Finished()), this, SLOT(OnAsyncFinished()));
if(m_pAsyncProgress.isEmpty())
m_pProgressDialog->hide();
}
void CSandMan::OnAsyncMessage(const QString& Text)
{
m_pProgressDialog->OnStatusMessage(Text);
}
void CSandMan::OnCancelAsync()
{
foreach(const CSbieProgressPtr& pProgress, m_pAsyncProgress)
pProgress->Cancel();
}
void CSandMan::CheckResults(QList<SB_STATUS> Results) void CSandMan::CheckResults(QList<SB_STATUS> Results)
{ {
for (QList<SB_STATUS>::iterator I = Results.begin(); I != Results.end(); ) for (QList<SB_STATUS>::iterator I = Results.begin(); I != Results.end(); )
@ -932,7 +984,7 @@ void CSandMan::OnSysTray(QSystemTrayIcon::ActivationReason Reason)
QString CSandMan::GetVersion() QString CSandMan::GetVersion()
{ {
QString Version = QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) //.rightJustified(2, '0') QString Version = QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) //.rightJustified(2, '0')
#if VERSION_REV > 0 #if VERSION_REV > 0 || VERSION_MJR == 0
+ "." + QString::number(VERSION_REV) + "." + QString::number(VERSION_REV)
#endif #endif
#if VERSION_UPD > 0 #if VERSION_UPD > 0

View File

@ -11,8 +11,8 @@
#include <QTranslator> #include <QTranslator>
#define VERSION_MJR 0 #define VERSION_MJR 0
#define VERSION_MIN 3 #define VERSION_MIN 4
#define VERSION_REV 5 #define VERSION_REV 0
#define VERSION_UPD 0 #define VERSION_UPD 0
@ -22,6 +22,7 @@
class CSbieView; class CSbieView;
class CApiLog; class CApiLog;
class CBoxBorder; class CBoxBorder;
class CSbieTemplates;
class CSandMan : public QMainWindow class CSandMan : public QMainWindow
{ {
@ -31,10 +32,11 @@ public:
CSandMan(QWidget *parent = Q_NULLPTR); CSandMan(QWidget *parent = Q_NULLPTR);
virtual ~CSandMan(); virtual ~CSandMan();
CProgressDialog* GetProgressDialog() { return m_pProgressDialog; } CSbieTemplates* GetCompat() { return m_SbieTemplates; }
static QString GetVersion(); static QString GetVersion();
void AddAsyncOp(const CSbieProgressPtr& pProgress);
static void CheckResults(QList<SB_STATUS> Results); static void CheckResults(QList<SB_STATUS> Results);
protected: protected:
@ -51,9 +53,11 @@ protected:
bool m_bConnectPending; bool m_bConnectPending;
bool m_bStopPending; bool m_bStopPending;
CBoxBorder* m_pBoxBorder; CBoxBorder* m_pBoxBorder;
CSbieTemplates* m_SbieTemplates;
CApiLog* m_ApiLog; CApiLog* m_ApiLog;
QMap<CSbieProgress*, CSbieProgressPtr> m_pAsyncProgress;
public slots: public slots:
void OnMessage(const QString&); void OnMessage(const QString&);
@ -65,6 +69,11 @@ public slots:
void UpdateSettings(); void UpdateSettings();
void OnAsyncFinished();
void OnAsyncFinished(CSbieProgress* pProgress);
void OnAsyncMessage(const QString& Text);
void OnCancelAsync();
private slots: private slots:
void OnSelectionChanged(); void OnSelectionChanged();

View File

@ -110,7 +110,7 @@
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile> <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>.;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -209,8 +209,10 @@
<ClCompile Include="Views\SbieView.cpp" /> <ClCompile Include="Views\SbieView.cpp" />
<ClCompile Include="Windows\OptionsWindow.cpp" /> <ClCompile Include="Windows\OptionsWindow.cpp" />
<ClCompile Include="Windows\SettingsWindow.cpp" /> <ClCompile Include="Windows\SettingsWindow.cpp" />
<ClCompile Include="Windows\SnapshotsWindow.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="Windows\SnapshotsWindow.h" />
<QtMoc Include="Windows\SettingsWindow.h" /> <QtMoc Include="Windows\SettingsWindow.h" />
<QtMoc Include="Windows\OptionsWindow.h" /> <QtMoc Include="Windows\OptionsWindow.h" />
<QtMoc Include="Views\SbieView.h" /> <QtMoc Include="Views\SbieView.h" />
@ -237,6 +239,7 @@
<ItemGroup> <ItemGroup>
<QtUic Include="Forms\OptionsWindow.ui" /> <QtUic Include="Forms\OptionsWindow.ui" />
<QtUic Include="Forms\SettingsWindow.ui" /> <QtUic Include="Forms\SettingsWindow.ui" />
<QtUic Include="Forms\SnapshotsWindow.ui" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')"> <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">

View File

@ -82,6 +82,9 @@
<ClCompile Include="Windows\SettingsWindow.cpp"> <ClCompile Include="Windows\SettingsWindow.cpp">
<Filter>Windows</Filter> <Filter>Windows</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Windows\SnapshotsWindow.cpp">
<Filter>Windows</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h"> <ClInclude Include="stdafx.h">
@ -125,6 +128,9 @@
<QtMoc Include="Windows\SettingsWindow.h"> <QtMoc Include="Windows\SettingsWindow.h">
<Filter>Windows</Filter> <Filter>Windows</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="Windows\SnapshotsWindow.h">
<Filter>Windows</Filter>
</QtMoc>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtRcc Include="Resources\SandMan.qrc"> <QtRcc Include="Resources\SandMan.qrc">
@ -148,5 +154,8 @@
<QtUic Include="Forms\OptionsWindow.ui"> <QtUic Include="Forms\OptionsWindow.ui">
<Filter>Form Files</Filter> <Filter>Form Files</Filter>
</QtUic> </QtUic>
<QtUic Include="Forms\SnapshotsWindow.ui">
<Filter>Form Files</Filter>
</QtUic>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,6 +5,7 @@
#include "../../MiscHelpers/Common/SortFilterProxyModel.h" #include "../../MiscHelpers/Common/SortFilterProxyModel.h"
#include "../../MiscHelpers/Common/Settings.h" #include "../../MiscHelpers/Common/Settings.h"
#include "../Windows/OptionsWindow.h" #include "../Windows/OptionsWindow.h"
#include "../Windows/SnapshotsWindow.h"
CSbieView::CSbieView(QWidget* parent) : CPanelView(parent) CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
{ {
@ -53,6 +54,7 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pMenuRunCmd = m_pMenuRun->addAction(tr("Run Cmd.exe"), this, SLOT(OnSandBoxAction())); m_pMenuRunCmd = m_pMenuRun->addAction(tr("Run Cmd.exe"), this, SLOT(OnSandBoxAction()));
m_pMenuEmptyBox = m_pMenu->addAction(tr("Terminate All Programs"), this, SLOT(OnSandBoxAction())); m_pMenuEmptyBox = m_pMenu->addAction(tr("Terminate All Programs"), this, SLOT(OnSandBoxAction()));
m_pMenu->addSeparator(); m_pMenu->addSeparator();
m_pMenuSnapshots = m_pMenu->addAction(tr("Snapshots Manager"), this, SLOT(OnSandBoxAction()));
m_pMenuCleanUp = m_pMenu->addAction(tr("Delete Content"), this, SLOT(OnSandBoxAction())); m_pMenuCleanUp = m_pMenu->addAction(tr("Delete Content"), this, SLOT(OnSandBoxAction()));
m_pMenu->addSeparator(); m_pMenu->addSeparator();
m_pMenuPresets = m_pMenu->addMenu(tr("Sandbox Presets")); m_pMenuPresets = m_pMenu->addMenu(tr("Sandbox Presets"));
@ -171,6 +173,7 @@ void CSbieView::OnMenu(const QPoint& Point)
m_pMenuPresetsNoAdmin->setChecked(pBox && pBox.objectCast<CSandBoxPlus>()->IsDropRights()); m_pMenuPresetsNoAdmin->setChecked(pBox && pBox.objectCast<CSandBoxPlus>()->IsDropRights());
m_pMenuOptions->setEnabled(iSandBoxeCount == 1); m_pMenuOptions->setEnabled(iSandBoxeCount == 1);
m_pMenuSnapshots->setEnabled(iSandBoxeCount == 1);
for (int i = m_iMenuBox; i < m_iMenuProc; i++) for (int i = m_iMenuBox; i < m_iMenuProc; i++)
MenuActions[i]->setVisible(iProcessCount > 0 && iSandBoxeCount == 0); MenuActions[i]->setVisible(iProcessCount > 0 && iSandBoxeCount == 0);
@ -215,6 +218,11 @@ void CSbieView::OnSandBoxAction()
COptionsWindow* pOptionsWindow = new COptionsWindow(SandBoxes.first(), SandBoxes.first()->GetName(), this); COptionsWindow* pOptionsWindow = new COptionsWindow(SandBoxes.first(), SandBoxes.first()->GetName(), this);
pOptionsWindow->show(); pOptionsWindow->show();
} }
else if (Action == m_pMenuSnapshots)
{
CSnapshotsWindow* pSnapshotsWindow = new CSnapshotsWindow(SandBoxes.first(), this);
pSnapshotsWindow->show();
}
else if (Action == m_pMenuRename) else if (Action == m_pMenuRename)
{ {
QString OldValue = SandBoxes.first()->GetName().replace("_", " "); QString OldValue = SandBoxes.first()->GetName().replace("_", " ");
@ -236,14 +244,13 @@ void CSbieView::OnSandBoxAction()
if (QMessageBox("Sandboxie-Plus", tr("Do you really want delete the content of the selected sandbox(es)?"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton).exec() != QMessageBox::Yes) if (QMessageBox("Sandboxie-Plus", tr("Do you really want delete the content of the selected sandbox(es)?"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton).exec() != QMessageBox::Yes)
return; return;
theGUI->GetProgressDialog()->show();
m_BoxesToClean = 0;
foreach(const CSandBoxPtr& pBox, SandBoxes) foreach(const CSandBoxPtr& pBox, SandBoxes)
{ {
m_BoxesToClean++; SB_PROGRESS Status = pBox->CleanBox();
Results.append(pBox->CleanBox()); if (Status.GetStatus() == OP_ASYNC)
connect(pBox.data(), SIGNAL(BoxCleaned()), this, SLOT(OnBoxCleaned())); theGUI->AddAsyncOp(Status.GetValue());
else if(Status.IsError())
Results.append(Status);
} }
} }
else if (Action == m_pMenuEmptyBox) else if (Action == m_pMenuEmptyBox)
@ -255,14 +262,6 @@ void CSbieView::OnSandBoxAction()
CSandMan::CheckResults(Results); CSandMan::CheckResults(Results);
} }
void CSbieView::OnBoxCleaned()
{
disconnect(sender(), SIGNAL(BoxCleaned()), this, SLOT(OnBoxCleaned()));
if(--m_BoxesToClean <= 0)
theGUI->GetProgressDialog()->hide();
}
void CSbieView::OnProcessAction() void CSbieView::OnProcessAction()
{ {
QList<SB_STATUS> Results; QList<SB_STATUS> Results;

View File

@ -27,8 +27,6 @@ private slots:
void OnSandBoxAction(); void OnSandBoxAction();
void OnProcessAction(); void OnProcessAction();
void OnBoxCleaned();
protected: protected:
virtual void OnMenu(const QPoint& Point); virtual void OnMenu(const QPoint& Point);
virtual QTreeView* GetView() { return m_pSbieTree; } virtual QTreeView* GetView() { return m_pSbieTree; }
@ -54,6 +52,7 @@ private:
QAction* m_pMenuPresetsShares; QAction* m_pMenuPresetsShares;
QAction* m_pMenuPresetsNoAdmin; QAction* m_pMenuPresetsNoAdmin;
QAction* m_pMenuOptions; QAction* m_pMenuOptions;
QAction* m_pMenuSnapshots;
QAction* m_pMenuEmptyBox; QAction* m_pMenuEmptyBox;
QAction* m_pMenuCleanUp; QAction* m_pMenuCleanUp;
QAction* m_pMenuRemove; QAction* m_pMenuRemove;
@ -64,6 +63,4 @@ private:
QAction* m_pMenuSuspend; QAction* m_pMenuSuspend;
QAction* m_pMenuResume; QAction* m_pMenuResume;
int m_iMenuProc; int m_iMenuProc;
int m_BoxesToClean;
}; };

View File

@ -83,6 +83,7 @@ COptionsWindow::COptionsWindow(const QSharedPointer<CSbieIni>& pBox, const QStri
connect(ui.cmbBoxIndicator, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged())); connect(ui.cmbBoxIndicator, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged()));
connect(ui.cmbBoxBorder, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged())); connect(ui.cmbBoxBorder, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged()));
connect(ui.btnBorderColor, SIGNAL(pressed()), this, SLOT(OnPickColor())); connect(ui.btnBorderColor, SIGNAL(pressed()), this, SLOT(OnPickColor()));
connect(ui.spinBorderWidth, SIGNAL(valueChanged(int)), this, SLOT(OnGeneralChanged()));
connect(ui.txtCopyLimit, SIGNAL(textChanged(const QString&)), this, SLOT(OnGeneralChanged())); connect(ui.txtCopyLimit, SIGNAL(textChanged(const QString&)), this, SLOT(OnGeneralChanged()));
connect(ui.chkNoCopyWarn, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged())); connect(ui.chkNoCopyWarn, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged()));
// //
@ -207,6 +208,9 @@ void COptionsWindow::LoadConfig()
ui.cmbBoxBorder->setCurrentIndex(ui.cmbBoxBorder->findData(BorderCfg.size() >= 2 ? BorderCfg[1].toLower() : "on")); ui.cmbBoxBorder->setCurrentIndex(ui.cmbBoxBorder->findData(BorderCfg.size() >= 2 ? BorderCfg[1].toLower() : "on"));
m_BorderColor = QColor("#" + BorderCfg[0].mid(5, 2) + BorderCfg[0].mid(3, 2) + BorderCfg[0].mid(1, 2)); m_BorderColor = QColor("#" + BorderCfg[0].mid(5, 2) + BorderCfg[0].mid(3, 2) + BorderCfg[0].mid(1, 2));
ui.btnBorderColor->setStyleSheet("background-color: " + m_BorderColor.name()); ui.btnBorderColor->setStyleSheet("background-color: " + m_BorderColor.name());
int BorderWidth = BorderCfg.count() >= 3 ? BorderCfg[2].toInt() : 0;
if (!BorderWidth) BorderWidth = 6;
ui.spinBorderWidth->setValue(BorderWidth);
ui.txtCopyLimit->setText(QString::number(m_pBox->GetNum("CopyLimitKb", 80 * 1024))); ui.txtCopyLimit->setText(QString::number(m_pBox->GetNum("CopyLimitKb", 80 * 1024)));
ui.chkNoCopyWarn->setChecked(!m_pBox->GetBool("CopyLimitSilent", false)); ui.chkNoCopyWarn->setChecked(!m_pBox->GetBool("CopyLimitSilent", false));
@ -271,9 +275,9 @@ void COptionsWindow::SaveConfig()
m_pBox->SetText("BoxNameTitle", ui.cmbBoxIndicator->currentData().toString()); m_pBox->SetText("BoxNameTitle", ui.cmbBoxIndicator->currentData().toString());
QStringList BorderCfg; QStringList BorderCfg;
BorderCfg.append(QString("#%1,%2,%3").arg(m_BorderColor.blue(), 2, 16, QChar('0')).arg(m_BorderColor.green(), 2, 16, QChar('0')).arg(m_BorderColor.red(), 2, 16, QChar('0'))); BorderCfg.append(QString("#%1%2%3").arg(m_BorderColor.blue(), 2, 16, QChar('0')).arg(m_BorderColor.green(), 2, 16, QChar('0')).arg(m_BorderColor.red(), 2, 16, QChar('0')));
BorderCfg.append(ui.cmbBoxBorder->currentData().toString()); BorderCfg.append(ui.cmbBoxBorder->currentData().toString());
//BorderCfg.append(5) // width BorderCfg.append(QString::number(ui.spinBorderWidth->value()));
m_pBox->SetText("BorderColor", BorderCfg.join(",")); m_pBox->SetText("BorderColor", BorderCfg.join(","));
m_pBox->SetNum("CopyLimitKb", ui.txtCopyLimit->text().toInt()); m_pBox->SetNum("CopyLimitKb", ui.txtCopyLimit->text().toInt());
@ -302,10 +306,10 @@ void COptionsWindow::SaveConfig()
{ {
m_pBox->SetBool("BlockNetworkFiles", ui.chkBlockShare->isChecked()); m_pBox->SetBool("BlockNetworkFiles", ui.chkBlockShare->isChecked());
m_pBox->SetBool("DropAdminRights", ui.chkDropRights->isChecked()); m_pBox->SetBool("DropAdminRights", ui.chkDropRights->isChecked());
m_pBox->SetBool("OpenDefaultClsid", ui.chkNoDefaultCOM->isChecked()); m_pBox->SetBool("OpenDefaultClsid", !ui.chkNoDefaultCOM->isChecked());
m_pBox->SetBool("UnrestrictedSCM", ui.chkProtectSCM->isChecked()); m_pBox->SetBool("UnrestrictedSCM", !ui.chkProtectSCM->isChecked());
m_pBox->SetBool("ProtectRpcSs", ui.chkProtectRpcSs->isChecked()); m_pBox->SetBool("ProtectRpcSs", ui.chkProtectRpcSs->isChecked());
m_pBox->SetBool("ExposeBoxedSystem", ui.chkProtectSystem->isChecked()); m_pBox->SetBool("ExposeBoxedSystem", !ui.chkProtectSystem->isChecked());
m_RestrictionChanged = false; m_RestrictionChanged = false;
} }

View File

@ -3,6 +3,7 @@
#include "SandMan.h" #include "SandMan.h"
#include "../MiscHelpers/Common/Settings.h" #include "../MiscHelpers/Common/Settings.h"
#include "Helpers/WinAdmin.h" #include "Helpers/WinAdmin.h"
#include "../QSbieAPI/Sandboxie/SbieTemplates.h"
CSettingsWindow::CSettingsWindow(QWidget *parent) CSettingsWindow::CSettingsWindow(QWidget *parent)
@ -55,6 +56,29 @@ CSettingsWindow::CSettingsWindow(QWidget *parent)
ui.chkAdminOnlyFP->setChecked(theAPI->GetGlobalSettings()->GetBool("ForceDisableAdminOnly", false)); ui.chkAdminOnlyFP->setChecked(theAPI->GetGlobalSettings()->GetBool("ForceDisableAdminOnly", false));
ui.chkClearPass->setChecked(theAPI->GetGlobalSettings()->GetBool("ForgetPassword", false)); ui.chkClearPass->setChecked(theAPI->GetGlobalSettings()->GetBool("ForgetPassword", false));
connect(ui.btnAddWarnProg, SIGNAL(pressed()), this, SLOT(OnAddWarnProg()));
connect(ui.btnDelWarnProg, SIGNAL(pressed()), this, SLOT(OnDelWarnProg()));
QStringList WarnProgs = theAPI->GetGlobalSettings()->GetTextList("AlertProcess");
foreach(const QString& Value, WarnProgs) {
QTreeWidgetItem* pItem = new QTreeWidgetItem();
pItem->setText(0, Value);
ui.treeWarnProgs->addTopLevelItem(pItem);
}
m_WarnProgsChanged = false;
connect(ui.btnAddCompat, SIGNAL(pressed()), this, SLOT(OnAddCompat()));
connect(ui.btnDelCompat, SIGNAL(pressed()), this, SLOT(OnDelCompat()));
m_CompatLoaded = 0;
m_CompatChanged = false;
ui.chkNoCompat->setChecked(!theConf->GetBool("Options/AutoRunSoftCompat", true));
connect(ui.treeCompat, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(OnTemplateClicked(QTreeWidgetItem*, int)));
connect(ui.tabs, SIGNAL(currentChanged(int)), this, SLOT(OnTab()));
connect(ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(pressed()), this, SLOT(accept())); connect(ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(pressed()), this, SLOT(accept()));
connect(ui.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(pressed()), this, SLOT(apply())); connect(ui.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(pressed()), this, SLOT(apply()));
connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
@ -69,6 +93,13 @@ CSettingsWindow::~CSettingsWindow()
theConf->SetBlob("SettingsWindow/Window_Geometry",saveGeometry()); theConf->SetBlob("SettingsWindow/Window_Geometry",saveGeometry());
} }
void CSettingsWindow::showCompat()
{
m_CompatLoaded = 2;
ui.tabs->setCurrentWidget(ui.tabCompat);
show();
}
void CSettingsWindow::closeEvent(QCloseEvent *e) void CSettingsWindow::closeEvent(QCloseEvent *e)
{ {
this->deleteLater(); this->deleteLater();
@ -122,6 +153,37 @@ void CSettingsWindow::apply()
theAPI->GetGlobalSettings()->SetBool("ForceDisableAdminOnly", ui.chkAdminOnlyFP->isChecked()); theAPI->GetGlobalSettings()->SetBool("ForceDisableAdminOnly", ui.chkAdminOnlyFP->isChecked());
theAPI->GetGlobalSettings()->SetBool("ForgetPassword", ui.chkClearPass->isChecked()); theAPI->GetGlobalSettings()->SetBool("ForgetPassword", ui.chkClearPass->isChecked());
if (m_WarnProgsChanged)
{
QStringList WarnProgs;
for (int i = 0; i < ui.treeWarnProgs->topLevelItemCount(); i++) {
QTreeWidgetItem* pItem = ui.treeWarnProgs->topLevelItem(i);
WarnProgs.append(pItem->text(0));
}
theAPI->GetGlobalSettings()->UpdateTextList("AlertProcess", WarnProgs);
m_WarnProgsChanged = false;
}
if (m_CompatChanged)
{
QStringList Used;
QStringList Rejected;
for (int i = 0; i < ui.treeCompat->topLevelItemCount(); i++) {
QTreeWidgetItem* pItem = ui.treeCompat->topLevelItem(i);
if (pItem->checkState(0) == Qt::Checked)
Used.append(pItem->text(0));
else
Rejected.append(pItem->text(0));
}
theAPI->GetGlobalSettings()->UpdateTextList("Template", Used);
theAPI->GetGlobalSettings()->UpdateTextList("TemplateReject", Rejected);
m_CompatChanged = false;
}
theConf->SetValue("Options/AutoRunSoftCompat", !ui.chkNoCompat->isChecked());
emit OptionsChanged(); emit OptionsChanged();
} }
@ -148,6 +210,32 @@ void CSettingsWindow::OnChange()
ui.btnSetPassword->setEnabled(ui.chkPassRequired->isChecked()); ui.btnSetPassword->setEnabled(ui.chkPassRequired->isChecked());
} }
void CSettingsWindow::OnTab()
{
if (ui.tabs->currentWidget() == ui.tabCompat && m_CompatLoaded != 1)
{
if(m_CompatLoaded == 0)
theGUI->GetCompat()->RunCheck();
ui.treeCompat->clear();
QMap<QString, int> Templates = theGUI->GetCompat()->GetTemplates();
for (QMap<QString, int>::iterator I = Templates.begin(); I != Templates.end(); ++I)
{
if (I.value() == CSbieTemplates::eNone)
continue;
QTreeWidgetItem* pItem = new QTreeWidgetItem();
pItem->setText(0, I.key());
pItem->setCheckState(0, (I.value() & CSbieTemplates::eEnabled) ? Qt::Checked : Qt::Unchecked);
ui.treeCompat->addTopLevelItem(pItem);
}
m_CompatLoaded = 1;
m_CompatChanged = false;
}
}
void CSettingsWindow::OnSetPassword() void CSettingsWindow::OnSetPassword()
{ {
retry: retry:
@ -166,3 +254,52 @@ retry:
m_NewPassword = Value1; m_NewPassword = Value1;
} }
void CSettingsWindow::OnAddWarnProg()
{
QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please a program file name"));
if (Value.isEmpty())
return;
QTreeWidgetItem* pItem = new QTreeWidgetItem();
pItem->setText(0, Value);
ui.treeWarnProgs->addTopLevelItem(pItem);
m_WarnProgsChanged = true;
}
void CSettingsWindow::OnDelWarnProg()
{
QTreeWidgetItem* pItem = ui.treeWarnProgs->currentItem();
if (!pItem)
return;
delete pItem;
m_WarnProgsChanged = true;
}
void CSettingsWindow::OnTemplateClicked(QTreeWidgetItem* pItem, int Column)
{
// todo: check if really changed
m_CompatChanged = true;
}
void CSettingsWindow::OnAddCompat()
{
QTreeWidgetItem* pItem = ui.treeCompat->currentItem();
if (!pItem)
return;
pItem->setCheckState(0, Qt::Checked);
m_CompatChanged = true;
}
void CSettingsWindow::OnDelCompat()
{
QTreeWidgetItem* pItem = ui.treeCompat->currentItem();
if (!pItem)
return;
pItem->setCheckState(0, Qt::Unchecked);
m_CompatChanged = true;
}

View File

@ -19,15 +19,29 @@ public slots:
void accept(); void accept();
void reject(); void reject();
void showCompat();
private slots: private slots:
void OnChange(); void OnChange();
void OnTab();
void OnSetPassword(); void OnSetPassword();
void OnAddWarnProg();
void OnDelWarnProg();
void OnTemplateClicked(QTreeWidgetItem* pItem, int Column);
void OnAddCompat();
void OnDelCompat();
protected: protected:
void closeEvent(QCloseEvent *e); void closeEvent(QCloseEvent *e);
int m_CompatLoaded;
QString m_NewPassword; QString m_NewPassword;
bool m_WarnProgsChanged;
bool m_CompatChanged;
private: private:
Ui::SettingsWindow ui; Ui::SettingsWindow ui;
}; };

View File

@ -0,0 +1,179 @@
#include "stdafx.h"
#include "SnapshotsWindow.h"
#include "SandMan.h"
#include "../MiscHelpers/Common/Settings.h"
#include "../MiscHelpers/Common/TreeItemModel.h"
CSnapshotsWindow::CSnapshotsWindow(const CSandBoxPtr& pBox, QWidget *parent)
: QMainWindow(parent)
{
QWidget* centralWidget = new QWidget();
ui.setupUi(centralWidget);
this->setCentralWidget(centralWidget);
this->setWindowTitle(tr("%1 - Snapshots").arg(pBox->GetName()));
m_pBox = pBox;
m_SaveInfoPending = 0;
#ifdef WIN32
QStyle* pStyle = QStyleFactory::create("windows");
ui.treeSnapshots->setStyle(pStyle);
#endif
m_pSnapshotModel = new CSimpleTreeModel();
m_pSnapshotModel->setHeaderLabels(tr("Snapshot").split("|"));
/*m_pSortProxy = new CSortFilterProxyModel(false, this);
m_pSortProxy->setSortRole(Qt::EditRole);
m_pSortProxy->setSourceModel(m_pSnapshotModel);
m_pSortProxy->setDynamicSortFilter(true);*/
//ui.treeSnapshots->setItemDelegate(theGUI->GetItemDelegate());
//ui.treeSnapshots->setModel(m_pSortProxy);
ui.treeSnapshots->setModel(m_pSnapshotModel);
connect(ui.treeSnapshots, SIGNAL(clicked(const QModelIndex&)), this, SLOT(UpdateSnapshot(const QModelIndex&)));
connect(ui.treeSnapshots->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(UpdateSnapshot(const QModelIndex&)));
connect(ui.treeSnapshots, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(OnSelectSnapshot()));
connect(ui.btnTake, SIGNAL(pressed()), this, SLOT(OnTakeSnapshot()));
connect(ui.btnSelect, SIGNAL(pressed()), this, SLOT(OnSelectSnapshot()));
connect(ui.btnRemove, SIGNAL(pressed()), this, SLOT(OnRemoveSnapshot()));
connect(ui.txtName, SIGNAL(textEdited(const QString&)), this, SLOT(SaveInfo()));
connect(ui.txtInfo, SIGNAL(textChanged()), this, SLOT(SaveInfo()));
statusBar();
restoreGeometry(theConf->GetBlob("SnapshotsWindow/Window_Geometry"));
for (int i = 0; i < m_pSnapshotModel->columnCount(); i++)
m_pSnapshotModel->SetColumnEnabled(i, true);
UpdateSnapshots();
QModelIndex CurIndex = m_pSnapshotModel->FindIndex(m_CurSnapshot);
if (CurIndex.isValid()) {
ui.treeSnapshots->selectionModel()->select(CurIndex, QItemSelectionModel::ClearAndSelect);
UpdateSnapshot(CurIndex);
}
}
CSnapshotsWindow::~CSnapshotsWindow()
{
theConf->SetBlob("SnapshotsWindow/Window_Geometry",saveGeometry());
}
void CSnapshotsWindow::closeEvent(QCloseEvent *e)
{
this->deleteLater();
}
void CSnapshotsWindow::UpdateSnapshots()
{
m_SnapshotMap.clear();
QList<SBoxSnapshot> SnapshotList = m_pBox->GetSnapshots(&m_CurSnapshot);
foreach(const SBoxSnapshot& Snapshot, SnapshotList)
{
QVariantMap BoxSnapshot;
BoxSnapshot["ID"] = Snapshot.ID;
BoxSnapshot["ParentID"] = Snapshot.Parent;
BoxSnapshot["Name"] = Snapshot.NameStr;
BoxSnapshot["Info"] = Snapshot.InfoStr;
BoxSnapshot["Date"] = Snapshot.SnapDate;
QVariantMap Values;
Values["0"] = Snapshot.NameStr;
BoxSnapshot["Values"] = Values;
if(m_CurSnapshot == Snapshot.ID)
BoxSnapshot["IsBold"] = true;
m_SnapshotMap.insert(Snapshot.ID, BoxSnapshot);
}
m_pSnapshotModel->Sync(m_SnapshotMap);
ui.treeSnapshots->expandAll();
}
void CSnapshotsWindow::UpdateSnapshot(const QModelIndex& Index)
{
//QModelIndex Index = ui.treeSnapshots->currentIndex();
//QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
//QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex);
QVariant ID = m_pSnapshotModel->GetItemID(Index);
OnSaveInfo();
m_SellectedID = ID;
QVariantMap BoxSnapshot = m_SnapshotMap[ID];
m_SaveInfoPending = -1;
ui.txtName->setText(BoxSnapshot["Name"].toString());
ui.txtInfo->setPlainText(BoxSnapshot["Info"].toString());
m_SaveInfoPending = 0;
statusBar()->showMessage(tr("Snapshot: %1 taken: %2").arg(BoxSnapshot["Name"].toString()).arg(BoxSnapshot["Date"].toDateTime().toString()));
}
void CSnapshotsWindow::SaveInfo()
{
if (m_SaveInfoPending)
return;
m_SaveInfoPending = 1;
QTimer::singleShot(500, this, SLOT(OnSaveInfo()));
}
void CSnapshotsWindow::OnSaveInfo()
{
if (m_SaveInfoPending != 1)
return;
m_SaveInfoPending = 0;
m_pBox->SetSnapshotInfo(m_SellectedID.toString(), ui.txtName->text(), ui.txtInfo->toPlainText());
UpdateSnapshots();
}
void CSnapshotsWindow::OnTakeSnapshot()
{
QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a name for the new Snapshot."), QLineEdit::Normal, tr("New Snapshot"));
if (Value.isEmpty())
return;
HandleResult(m_pBox->TakeSnapshot(Value));
}
void CSnapshotsWindow::OnSelectSnapshot()
{
QModelIndex Index = ui.treeSnapshots->currentIndex();
//QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
//QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex);
QVariant ID = m_pSnapshotModel->GetItemID(Index);
if (QMessageBox("Sandboxie-Plus", tr("Do you really want to switch the active snapshot? Doing so will delete the current state!"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton).exec() != QMessageBox::Yes)
return;
HandleResult(m_pBox->SelectSnapshot(ID.toString()));
}
void CSnapshotsWindow::OnRemoveSnapshot()
{
QModelIndex Index = ui.treeSnapshots->currentIndex();
//QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
//QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex);
QVariant ID = m_pSnapshotModel->GetItemID(Index);
if (QMessageBox("Sandboxie-Plus", tr("Do you really want delete the sellected snapshot?"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton).exec() != QMessageBox::Yes)
return;
HandleResult(m_pBox->RemoveSnapshot(ID.toString()));
}
void CSnapshotsWindow::HandleResult(SB_PROGRESS Status)
{
if (Status.GetStatus() == OP_ASYNC)
{
connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(UpdateSnapshots()));
theGUI->AddAsyncOp(Status.GetValue());
}
else if (Status.IsError())
CSandMan::CheckResults(QList<SB_STATUS>() << Status);
UpdateSnapshots();
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_SnapshotsWindow.h"
#include "SbiePlusAPI.h"
class CSimpleTreeModel;
class CSnapshotsWindow : public QMainWindow
{
Q_OBJECT
public:
CSnapshotsWindow(const CSandBoxPtr& pBox, QWidget *parent = Q_NULLPTR);
~CSnapshotsWindow();
signals:
void OptionsChanged();
private slots:
void UpdateSnapshots();
void UpdateSnapshot(const QModelIndex& Index);
void SaveInfo();
void OnTakeSnapshot();
void OnSelectSnapshot();
void OnRemoveSnapshot();
void OnSaveInfo();
protected:
void closeEvent(QCloseEvent *e);
void HandleResult(SB_PROGRESS Status);
CSandBoxPtr m_pBox;
QString m_CurSnapshot;
QMap<QVariant, QVariantMap> m_SnapshotMap;
QVariant m_SellectedID;
int m_SaveInfoPending;
private:
Ui::SnapshotsWindow ui;
CSimpleTreeModel* m_pSnapshotModel;
};