experimental sbie desktop

This commit is contained in:
DavidXanatos 2024-05-20 11:05:53 +02:00
parent 2c29585e5c
commit 46929668e2
24 changed files with 531 additions and 126 deletions

View File

@ -25,7 +25,7 @@
#define STR(X) STR2(X)
#define VERSION_MJR 5
#define VERSION_MIN 69
#define VERSION_MIN 70
#define VERSION_REV 0
#define VERSION_UPD 0

View File

@ -1,6 +1,6 @@
/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2020 David Xanatos, xanasoft.com
* Copyright 2020-2023 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -1152,17 +1152,11 @@ _FX NTSTATUS File_NtFsControlFile(
handle = File_GetProxyPipe(FileHandle, NULL);
if (! handle) {
status = STATUS_BAD_INITIAL_PC;
if (IoControlCode == FSCTL_SET_REPARSE_POINT) {
BOOLEAN BoxReparsTarget = SbieApi_QueryConfBool(NULL, L"BoxReparsTarget", FALSE);
if(BoxReparsTarget) {
status = File_SetReparsePoint(
FileHandle, InputBuffer, InputBufferLength);
SetLastError(LastError);
}
status = File_SetReparsePoint(
FileHandle, InputBuffer, InputBufferLength);
SetLastError(LastError);
} else if (IoControlCode == FSCTL_PIPE_WAIT) {
@ -1178,7 +1172,8 @@ _FX NTSTATUS File_NtFsControlFile(
else
status = STATUS_ACCESS_DENIED;
}
} else
status = STATUS_BAD_INITIAL_PC;
if (status == STATUS_BAD_INITIAL_PC) {

View File

@ -416,18 +416,7 @@ _FX BOOLEAN Gui_Init(HMODULE module)
GUI_IMPORT___(ClipCursor);
GUI_IMPORT___(GetClipCursor);
GUI_IMPORT___(GetCursorPos);
GUI_IMPORT___(SetCursorPos);
GUI_IMPORT___(SetTimer);
HMODULE temp = module;
module = Dll_Kernel32;
GUI_IMPORT___(Sleep);
GUI_IMPORT___(SleepEx);
GUI_IMPORT___(GetTickCount);
GUI_IMPORT___(GetTickCount64);
GUI_IMPORT___(QueryUnbiasedInterruptTime);
GUI_IMPORT___(QueryPerformanceCounter);
module = temp;
GUI_IMPORT___(SetCursorPos);
GUI_IMPORT___(SetTimer);
GUI_IMPORT___(MsgWaitForMultipleObjects);

View File

@ -285,7 +285,7 @@ _FX BOOLEAN Gui_InitMisc(HMODULE module)
__sys_GetThreadDpiAwarenessContext = (P_GetThreadDpiAwarenessContext)
Ldr_GetProcAddrNew(DllName_user32, L"GetThreadDpiAwarenessContext","GetThreadDpiAwarenessContext");
HMODULE current = module;
if (SbieApi_QueryConfBool(NULL, L"BlockInterferePower", FALSE)) {
SBIEDLL_HOOK_GUI(ShutdownBlockReasonCreate);
@ -1703,45 +1703,3 @@ _FX void Gui_SwitchToThisWindow(HWND hWnd, BOOL fAlt)
return;
__sys_SwitchToThisWindow(hWnd, fAlt);
}
_FX DWORD Gui_GetTickCount() {
return __sys_GetTickCount() * SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1) / SbieApi_QueryConfNumber(NULL,L"LowTickSpeed", 1);
}
_FX ULONGLONG Gui_GetTickCount64() {
return __sys_GetTickCount64() * SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowTickSpeed", 1);
}
_FX BOOL Gui_QueryUnbiasedInterruptTime(
PULONGLONG UnbiasedTime
) {
BOOL rtn = __sys_QueryUnbiasedInterruptTime(UnbiasedTime);
*UnbiasedTime *= SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowTickSpeed", 1);
return rtn;
}
_FX void Gui_Sleep(DWORD dwMiSecond) {
__sys_Sleep(dwMiSecond * SbieApi_QueryConfNumber(NULL, L"AddSleepSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowSleepSpeed", 1));
}
_FX DWORD Gui_SleepEx(DWORD dwMiSecond, BOOL bAlert) {
return __sys_SleepEx(dwMiSecond * SbieApi_QueryConfNumber(NULL, L"AddSleepSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowSleepSpeed", 1),bAlert);
}
_FX BOOL Gui_QueryPerformanceCounter(
LARGE_INTEGER* lpPerformanceCount
) {
BOOL rtn = __sys_QueryPerformanceCounter(lpPerformanceCount);
lpPerformanceCount->QuadPart = lpPerformanceCount->QuadPart*SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1)/ SbieApi_QueryConfNumber(NULL, L"LowTickSpeed", 1);
return rtn;
}
_FX UINT_PTR Gui_SetTimer(
HWND hWnd,
UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
)
{
return __sys_SetTimer(hWnd, nIDEvent, uElapse * SbieApi_QueryConfNumber(NULL, L"AddTimerSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowTimerSpeed", 1), lpTimerFunc);
}

View File

@ -34,6 +34,9 @@
#include <aclapi.h>
#include <dde.h>
#include "misc.h"
#include <wtsapi32.h>
#include <userenv.h>
#include "sbieiniserver.h"
#define PATTERN XPATTERN
extern "C" {
@ -906,9 +909,17 @@ bool GuiServer::QueueCallbackSlave2(void)
args.rpl_len = rpl_len;
args.rpl_buf = rpl_buf;
HDESK prev_desk;
HDESK local_desktop = SwitchToCallerDesktop(args.pid, &prev_desk);
status = (this->*SlaveFuncPtr)(&args);
if (status == 0)
rpl_len = args.rpl_len;
if (local_desktop) {
SetThreadDesktop(prev_desk);
CloseDesktop(local_desktop);
}
}
}
}
@ -1583,19 +1594,12 @@ ULONG GuiServer::GetWindowStationSlave(SlaveArgs *args)
local_winsta = GetProcessWindowStation();
WCHAR deskname[128] = { 0 };
/*SbieApi_QueryConfAsIs(boxname, L"SandboxDesktopName", 0, deskname, sizeof(deskname));
if(*value)
local_desktop = OpenDesktop(value, 0, FALSE, GENERIC_ALL);
else*/
if (SbieApi_QueryConfBool(boxname, L"UseSandboxDesktop", FALSE)) {
wsprintf(deskname, L"%s_%s_Session_%d_Desktop", //_%08X",
SANDBOXIE, boxname, m_SessionId); //GetTickCount());
local_desktop = OpenDesktop(deskname, 0, FALSE, GENERIC_ALL);
if (!local_desktop)
local_desktop = CreateDesktop(deskname, NULL, NULL, 0, GENERIC_ALL, NULL);
local_desktop = CreateBoxedDesktop(session_id, deskname);
close_desktop = TRUE;
} else
local_desktop = GetThreadDesktop(GetCurrentThreadId());
@ -1710,6 +1714,166 @@ finish:
}
//---------------------------------------------------------------------------
// CreateBoxedDesktop
//---------------------------------------------------------------------------
struct SDeskStartParam
{
ULONG session_id;
const wchar_t* desk_name;
HDESK local_desktop;
};
ULONG GuiServer__StartupWorker(void* _Param)
{
SDeskStartParam* pParam = (SDeskStartParam*)_Param;
ULONG status = 0;
const ULONG TOKEN_RIGHTS = TOKEN_QUERY | TOKEN_DUPLICATE
| TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID
| TOKEN_ADJUST_GROUPS | TOKEN_ASSIGN_PRIMARY;
HANDLE hOldToken = NULL;
HANDLE hNewToken = NULL;
//void *env = NULL;
//WCHAR cmdline[MAX_PATH];
BOOL ok = TRUE;
//
// set thread desktop and check if explorer is already running
//
SetThreadDesktop(pParam->local_desktop);
if (FindWindowW(L"Shell_TrayWnd", 0))
return 0;
//
// get the user token
//
if (ok) {
ok = WTSQueryUserToken(pParam->session_id, &hOldToken);
if (! ok)
status = 0x72000000 | GetLastError();
}
if (ok) {
ok = DuplicateTokenEx(
hOldToken, TOKEN_RIGHTS, NULL, SecurityAnonymous,
TokenPrimary, &hNewToken);
if (! ok)
status = 0x73000000 | GetLastError();
}
//
// create the new shell process
//
//ok = CreateEnvironmentBlock(&env, hNewToken, FALSE);
//if (! ok)
// status = 0x75000000 | GetLastError();
if (ok) {
//GetSystemWindowsDirectoryW(cmdline, MAX_PATH);
//wcscat_s(cmdline, MAX_PATH, L"\\Explorer.exe");
//STARTUPINFO si;
//PROCESS_INFORMATION pi;
//memzero(&si, sizeof(STARTUPINFO));
//si.cb = sizeof(STARTUPINFO);
//si.dwFlags = STARTF_USESHOWWINDOW;
//si.lpDesktop = (wchar_t*)pParam->desk_name;
//ok = CreateProcessAsUser(
// hNewToken, NULL, cmdline, NULL, NULL, FALSE,
// CREATE_UNICODE_ENVIRONMENT, env, NULL, &si, &pi);
//if (! ok)
// status = 0x76000000 | GetLastError();
//else {
// CloseHandle(pi.hThread);
// CloseHandle(pi.hProcess);
//}
SbieIniServer::RunSbieCtrl(hOldToken, pParam->desk_name);
for (int i = 0; i++ < 10 && !FindWindowW(L"Shell_TrayWnd", 0); Sleep(1000)); // wait 10 seconds
}
if (hNewToken)
CloseHandle(hNewToken);
if (hOldToken)
CloseHandle(hOldToken);
//if (env)
// DestroyEnvironmentBlock(env);
return 0;
}
HDESK GuiServer::CreateBoxedDesktop(ULONG session_id, const wchar_t* desk_name)
{
HDESK local_desktop = OpenDesktop(desk_name, 0, FALSE, GENERIC_ALL);
if (!local_desktop)
local_desktop = CreateDesktop(desk_name, NULL, NULL, 0, GENERIC_ALL, NULL);
if (local_desktop) {
SDeskStartParam* pParam = (SDeskStartParam*)HeapAlloc(GetProcessHeap(), 0, sizeof(SDeskStartParam));
pParam->session_id = session_id;
pParam->desk_name = desk_name;
pParam->local_desktop = local_desktop;
HANDLE hThread = CreateThread(NULL, 0, GuiServer__StartupWorker, (void *)pParam, 0, NULL);
WaitForSingleObject(hThread, 20 * 1000);
CloseHandle(hThread);
HeapFree(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, pParam);
}
return local_desktop;
}
//---------------------------------------------------------------------------
// SwitchToCallerDesktop
//---------------------------------------------------------------------------
HDESK GuiServer::SwitchToCallerDesktop(ULONG pid, HDESK* prev_desk)
{
ULONG status;
WCHAR boxname[BOXNAME_COUNT];
ULONG session_id;
WCHAR deskname[128] = { 0 };
HDESK local_desktop = NULL;
status = SbieApi_QueryProcess((HANDLE)(ULONG_PTR)pid, boxname, NULL, NULL, &session_id);
if (!NT_SUCCESS(status))
return NULL;
if (SbieApi_QueryConfBool(boxname, L"UseSandboxDesktop", FALSE)) {
wsprintf(deskname, L"%s_%s_Session_%d_Desktop", //_%08X",
SANDBOXIE, boxname, m_SessionId); //GetTickCount());
}
else
return NULL;
if (prev_desk) *prev_desk = GetThreadDesktop(GetCurrentThreadId());
local_desktop = OpenDesktop(deskname, 0, FALSE, GENERIC_ALL);
if (local_desktop) {
if (!SetThreadDesktop(local_desktop))
SbieApi_LogEx(session_id, 2340, L"[%d]", GetLastError());
}
return local_desktop;
}
//---------------------------------------------------------------------------
// CreateConsoleSlave
//---------------------------------------------------------------------------

View File

@ -74,6 +74,10 @@ protected:
bool QueueCallbackSlave2(void);
HDESK CreateBoxedDesktop(ULONG session_id, const wchar_t* deskname);
HDESK SwitchToCallerDesktop(ULONG pid, HDESK* prev_desk);
HANDLE GetJobObjectForAssign(const WCHAR *boxname);
HANDLE GetJobObjectForGrant(ULONG pid);

View File

@ -486,6 +486,11 @@ ULONG SbieIniServer::CheckRequest(MSG_HEADER *msg)
bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken)
{
return SetUserSettingsSectionName(hToken, m_username, m_sectionname);
}
bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken, WCHAR* m_username, WCHAR* m_sectionname)
{
union {
TOKEN_USER user;
@ -493,8 +498,6 @@ bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken)
WCHAR value[4];
} info;
m_admin = FALSE;
//
// if the UserSettings_Portable section exists, use that
//
@ -521,7 +524,7 @@ bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken)
if (! ok)
return false;
ULONG username_len = sizeof(m_username) / sizeof(WCHAR) - 4;
ULONG username_len = 256 - 4; // ULONG username_len = sizeof(m_username) / sizeof(WCHAR) - 4;
WCHAR domain[256];
ULONG domain_len = sizeof(domain) / sizeof(WCHAR) - 4;
SID_NAME_USE use;
@ -533,7 +536,7 @@ bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken)
if (! ok || ! m_username[0])
return false;
m_username[sizeof(m_username) / sizeof(WCHAR) - 4] = L'\0';
m_username[username_len] = L'\0'; //m_username[sizeof(m_username) / sizeof(WCHAR) - 4] = L'\0';
_wcslwr(m_username);
//
@ -2245,7 +2248,6 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i
NTSTATUS status = STATUS_UNSUCCESSFUL;
HANDLE hToken = NULL;
BOOL ok = TRUE;
WCHAR ctrlCmd[128] = { 0 };
//
// get token from caller session or caller process. note that on
@ -2309,14 +2311,42 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i
}
}
if (ok)
{
if(isSandboxed || msg->length <= sizeof(MSG_HEADER))
status = RunSbieCtrl(hToken, NULL);
else
status = RunSbieCtrl(hToken, NULL, (WCHAR*)((UCHAR*)msg + sizeof(MSG_HEADER)), (msg->length - sizeof(MSG_HEADER)) / sizeof(WCHAR));
}
//
// finish
//
if (hToken)
CloseHandle(hToken);
return SHORT_REPLY(status);
}
NTSTATUS SbieIniServer::RunSbieCtrl(HANDLE hToken, const WCHAR* DeskName, const WCHAR* CtrlCmd, size_t CtrlCmdLen)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
BOOL ok = TRUE;
WCHAR ctrlCmd[128] = { 0 };
//
// get the agent binary name
//
if (isSandboxed) {
if (!CtrlCmd) {
WCHAR m_username[256];
WCHAR m_sectionname[128];
const WCHAR* _Setting2 = SBIECTRL_ L"AutoStartAgent";
bool ok2 = SetUserSettingsSectionName(hToken);
bool ok2 = SetUserSettingsSectionName(hToken, m_username, m_sectionname);
if (ok2) {
SbieApi_QueryConfAsIs(
m_sectionname, _Setting2, 0, ctrlCmd, sizeof(ctrlCmd) - 2);
@ -2327,11 +2357,10 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i
m_sectionname, _Setting2, 0, ctrlCmd, sizeof(ctrlCmd) - 2);
}
} else if (msg->length > sizeof(MSG_HEADER)) {
} else if (CtrlCmdLen > 0) {
ULONG len = (ULONG)(msg->length - sizeof(MSG_HEADER));
memcpy(ctrlCmd, (UCHAR*)msg + sizeof(MSG_HEADER), len);
ctrlCmd[len / sizeof(WCHAR)] = L'\0';
memcpy(ctrlCmd, CtrlCmd, CtrlCmdLen * sizeof(WCHAR));
ctrlCmd[CtrlCmdLen] = L'\0';
}
//
@ -2370,6 +2399,10 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i
memzero(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_FORCEOFFFEEDBACK;
if (DeskName) {
si.dwFlags |= STARTF_USESHOWWINDOW;
si.lpDesktop = (wchar_t*)DeskName;
}
ok = CreateProcessAsUser(
hToken, NULL, CmdLine, NULL, NULL, FALSE,
@ -2391,14 +2424,7 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i
}
}
//
// finish
//
if (hToken)
CloseHandle(hToken);
return SHORT_REPLY(status);
return status;
}

View File

@ -62,6 +62,8 @@ protected:
bool SetUserSettingsSectionName(HANDLE hToken);
static bool SetUserSettingsSectionName(HANDLE hToken, WCHAR* m_username, WCHAR* m_sectionname);
bool UserCanEdit(HANDLE hToken);
#ifdef NEW_INI_MODE
@ -107,6 +109,9 @@ protected:
MSG_HEADER *RC4Crypt(MSG_HEADER *msg, HANDLE idProcess, bool isSandboxed);
public:
static NTSTATUS RunSbieCtrl(HANDLE hToken, const WCHAR* DeskName, const WCHAR* CtrlCmd = NULL, size_t CtrlCmdLen = 0);
protected:
@ -122,7 +127,6 @@ protected:
WCHAR m_line[1500];
//BOOLEAN m_insertbom;
#endif
BOOLEAN m_admin;
HANDLE m_hLockFile;
ULONG m_session_id;

View File

@ -767,6 +767,10 @@ SBIE2337 Failed to start program: %2
SBIE2338 Encountered unsupported architecture in process: %2
.
2340;pop;err;01
SBIE2340 Desktop worker failed to switch to caller Desktop: %2
.
# 2398;txt;01
# SBIE2398 Service suffers exception ... at address ...
# .
@ -921,7 +925,7 @@ Programs
.
3198;txt;01
Do you want to start a new program in the %2 sandbox?
Do you want to start a new program into the sandbox %2?
You received this message because you set AlertBeforeStart=y.
.

View File

@ -293,6 +293,17 @@ private slots:
}
protected:
void mouseDoubleClickEvent(QMouseEvent* event) override
{
QModelIndex index = indexAt(event->pos());
if (!index.isValid()) {
emit doubleClicked(index);
return;
}
QTreeView::mouseDoubleClickEvent(event);
}
QMenu* m_pMenu;
QMap<QAction*, int> m_Columns;
QSet<int> m_FixedColumns;

View File

@ -823,4 +823,11 @@ SB_STATUS CSandBox::ImBoxMount(const QString& Password, bool bProtect, bool bAut
SB_STATUS CSandBox::ImBoxUnmount()
{
return m_pAPI->ImBoxUnmount(this);
}
SB_STATUS CSandBox::SwitchToDesktop()
{
if (m_Desktop.isEmpty())
return SB_OK; // nothign to do
return m_pAPI->SwitchToDesktop(m_Desktop);
}

View File

@ -84,6 +84,10 @@ public:
virtual SB_STATUS ImBoxMount(const QString& Password = QString(), bool bProtect = false, bool bAutoUnmount = false);
virtual SB_STATUS ImBoxUnmount();
// Desktop Manager
virtual QString GetDesktop() const { return m_Desktop; }
virtual SB_STATUS SwitchToDesktop();
class CSbieAPI* Api() { return m_pAPI; }
protected:
@ -101,6 +105,8 @@ protected:
QString m_RegPath;
QString m_IpcPath;
QString m_Mount;
QString m_Desktop;
bool m_IsEnabled;

View File

@ -2626,6 +2626,84 @@ SB_RESULT(QVariantMap) CSbieAPI::ImBoxQuery(const QString& Root)
return CSbieResult<QVariantMap>(Info);
}
///////////////////////////////////////////////////////////////////////////////
// Desktop Manager
//
BOOL CALLBACK CSbieAPI__EnumDesktopsProc(LPWSTR lpszDesktop, LPARAM lParam)
{
CSbieAPI::TDesktopMap* pDesktops = (CSbieAPI::TDesktopMap*)lParam;
QString Name = QString::fromWCharArray(lpszDesktop); // Sandboxie_[BoxName]_Session_[Num]_Desktop
QStringList Names = Name.split("_");
if (Names.count() > 3 && Names[0] == "Sandboxie" && Names[2] == "Session")
pDesktops->insert(Names[1].toLower(), Name);
return TRUE;
}
SB_RESULT(CSbieAPI::TDesktopMap) CSbieAPI::EnumBoxDesktops()
{
TDesktopMap Desktops;
HWINSTA hWinSta = GetProcessWindowStation();
if (hWinSta == NULL)
return SB_ERR(STATUS_UNSUCCESSFUL);
// Enumerate all desktops associated with the current window station
if (!EnumDesktopsW(hWinSta, CSbieAPI__EnumDesktopsProc, (LPARAM)&Desktops))
return SB_ERR(STATUS_UNSUCCESSFUL);
foreach(const CSandBoxPtr & pBox, m_SandBoxes)
pBox->m_Desktop = Desktops.value(pBox->m_Name.toLower());
return CSbieResult<TDesktopMap>(Desktops);
}
SB_STATUS CSbieAPI::SwitchToDesktop(const QString& Desktop)
{
BOOL ok = FALSE;
HDESK hDesktop = OpenDesktop(Desktop.toStdWString().c_str(), 0, FALSE, DESKTOP_SWITCHDESKTOP);
if (hDesktop != NULL)
{
ok = SwitchDesktop(hDesktop);
CloseDesktop(hDesktop);
}
if(!ok)
return SB_ERR(STATUS_UNSUCCESSFUL);
return SB_OK;
}
QString CSbieAPI__GetDesktopName(HDESK hDesktop)
{
wchar_t desktopName[MAX_PATH];
DWORD neededLength = sizeof(desktopName);
if (!GetUserObjectInformationW(hDesktop, UOI_NAME, desktopName, neededLength, &neededLength))
return QString();
return QString::fromWCharArray(desktopName);
}
QString CSbieAPI::GetCurrentDesktopName()
{
HDESK hDesktop = GetThreadDesktop(GetCurrentThreadId());
if (hDesktop == NULL)
return QString();
return CSbieAPI__GetDesktopName(hDesktop);
}
bool CSbieAPI::IsCurrentDesktopActive()
{
QString CurrentDesktop = CSbieAPI::GetCurrentDesktopName();
QString ActiveDesktop;
HDESK hInputDesktop = OpenInputDesktop(0, FALSE, DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP);
if (hInputDesktop) {
ActiveDesktop = CSbieAPI__GetDesktopName(hInputDesktop);
CloseDesktop(hInputDesktop);
}
return CurrentDesktop.compare(ActiveDesktop, Qt::CaseInsensitive) == 0;
}
///////////////////////////////////////////////////////////////////////////////
// Monitor

View File

@ -140,6 +140,13 @@ public:
virtual SB_RESULT(QVariantMap) ImBoxQuery(const QString& Root = QString());
//virtual SB_STATUS ImBoxUpdate( // todo
// Desktop Manager
typedef QMultiMap<QString, QString> TDesktopMap;
virtual SB_RESULT(TDesktopMap) EnumBoxDesktops();
virtual SB_STATUS SwitchToDesktop(const QString& Desktop);
static QString GetCurrentDesktopName();
static bool IsCurrentDesktopActive();
// Monitor
virtual SB_STATUS EnableMonitor(bool Enable);
virtual bool IsMonitoring();

View File

@ -169,4 +169,27 @@ QString GetProductVersion(const QString &filePath)
}
}
return QString();
}
bool KillProcessById(DWORD processId)
{
bool ok = false;
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, processId);
if (hProcess && hProcess != INVALID_HANDLE_VALUE) {
if (TerminateProcess(hProcess, 0))
ok = true;
CloseHandle(hProcess);
}
return ok;
}
bool KillProcessByWnd(const QString& WndName)
{
HWND hwnd = FindWindowW(WndName.toStdWString().c_str(), 0);
if (hwnd) {
DWORD processId;
if (GetWindowThreadProcessId(hwnd, &processId))
return KillProcessById(processId);
}
return false;
}

View File

@ -8,4 +8,6 @@ bool PickWindowsIcon(QWidget* pParent, QString& Path, quint32& Index);
void ProtectWindow(void* hWnd);
QString GetProductVersion(const QString& filePath);
QString GetProductVersion(const QString& filePath);
bool KillProcessByWnd(const QString& WndName);

View File

@ -115,7 +115,7 @@ CSandMan* theGUI = NULL;
extern QString g_PendingMessage;
CSandMan::CSandMan(QWidget *parent)
CSandMan::CSandMan(const QString& BoxDesktop, bool bAutoRun, QWidget *parent)
: QMainWindow(parent)
{
#if defined(Q_OS_WIN)
@ -126,6 +126,8 @@ CSandMan::CSandMan(QWidget *parent)
CArchive::Init();
m_BoxDesktop = BoxDesktop;
theGUI = this;
m_DarkTheme = false;
@ -181,6 +183,7 @@ CSandMan::CSandMan(QWidget *parent)
connect(theAPI, SIGNAL(StatusChanged()), this, SLOT(OnStatusChanged()));
connect(theAPI, SIGNAL(BoxAdded(const CSandBoxPtr&)), this, SLOT(OnBoxAdded(const CSandBoxPtr&)));
connect(theAPI, SIGNAL(BoxOpened(const CSandBoxPtr&)), this, SLOT(OnBoxOpened(const CSandBoxPtr&)));
connect(theAPI, SIGNAL(BoxClosed(const CSandBoxPtr&)), this, SLOT(OnBoxClosed(const CSandBoxPtr&)));
connect(theAPI, SIGNAL(BoxCleaned(CSandBoxPlus*)), this, SLOT(OnBoxCleaned(CSandBoxPlus*)));
@ -256,7 +259,7 @@ CSandMan::CSandMan(QWidget *parent)
m_BoxColors[CSandBoxPlus::eOpen] = qRgb(255,255,255);
m_BoxColors[CSandBoxPlus::ePrivate] = qRgb(56,56,56);
CreateTrayIcon();
CreateTrayIcon(bAutoRun);
LoadState();
@ -284,7 +287,6 @@ CSandMan::CSandMan(QWidget *parent)
m_uTimerID = startTimer(1000);
bool bAutoRun = QApplication::arguments().contains("-autorun");
if (!bAutoRun && g_PendingMessage.isEmpty())
SafeShow(this);
@ -537,6 +539,8 @@ void CSandMan::CreateMenus(bool bAdvanced)
//m_pUpdateCore = NULL;
}
m_pDefaultDesktop = m_pMenuFile->addAction(CSandMan::GetIcon("Monitor"), tr("Return to Default Desktop"), this, SLOT(OnDefaultDesktop()));
if (m_BoxDesktop.isEmpty()) m_pDefaultDesktop->setEnabled(false);
m_pMenuFile->addSeparator();
m_pRestart = m_pMenuFile->addAction(CSandMan::GetIcon("Shield9"), tr("Restart As Admin"), this, SLOT(OnRestartAsAdmin()));
m_pExit = m_pMenuFile->addAction(CSandMan::GetIcon("Exit"), tr("Exit"), this, SLOT(OnExit()));
@ -694,6 +698,8 @@ void CSandMan::CreateOldMenus()
m_pSetupWizard = NULL;
//m_pUpdateCore = NULL;
}
m_pDefaultDesktop = m_pMenuFile->addAction(CSandMan::GetIcon("Monitor"), tr("Return to Default Desktop"), this, SLOT(OnDefaultDesktop()));
if (m_BoxDesktop.isEmpty()) m_pDefaultDesktop->setEnabled(false);
m_pRestart = m_pMenuFile->addAction(CSandMan::GetIcon("Shield9"), tr("Restart As Admin"), this, SLOT(OnRestartAsAdmin()));
m_pExit = m_pMenuFile->addAction(CSandMan::GetIcon("Exit"), tr("Exit"), this, SLOT(OnExit()));
@ -866,6 +872,8 @@ QList<ToolBarAction> CSandMan::GetAvailableToolBarActions()
ToolBarAction{ "CheckForUpdates", m_pUpdate },
ToolBarAction{ "About", m_pAbout },
ToolBarAction{ "", nullptr }, // separator
ToolBarAction{ "pApp", m_pDefaultDesktop },
ToolBarAction{ "", nullptr }, // separator
ToolBarAction{ "RestartAsAdmin", m_pRestart },
ToolBarAction{ "Exit", m_pExit },
ToolBarAction{ "", nullptr }, // separator
@ -1300,24 +1308,35 @@ void CSandMan::CheckForUpdates(bool bManual)
m_pUpdater->CheckForUpdates(bManual);
}
#include "SandManTray.cpp"
void CSandMan::OnDefaultDesktop()
{
theAPI->SwitchToDesktop("Default");
}
void CSandMan::OnRestartAsAdmin()
{
theAPI->Disconnect();
Restart(true);
OnExit();
}
void CSandMan::Restart(bool AsAdmin)
{
WCHAR buf[255] = { 0 };
GetModuleFileNameW(NULL, buf, 255);
SHELLEXECUTEINFO se;
memset(&se, 0, sizeof(SHELLEXECUTEINFO));
se.cbSize = sizeof(SHELLEXECUTEINFO);
se.lpVerb = L"runas";
if(AsAdmin)
se.lpVerb = L"runas";
se.lpFile = buf;
se.nShow = SW_HIDE;
se.nShow = SW_SHOWNORMAL;
se.fMask = 0;
ShellExecuteEx(&se);
OnExit();
}
#include "SandManTray.cpp"
void CSandMan::OnExit()
{
m_bExit = true;
@ -1353,7 +1372,17 @@ void CSandMan::closeEvent(QCloseEvent *e)
emit Closed();
if (IsFullyPortable() && theAPI->IsConnected())
if (!m_BoxDesktop.isEmpty())
{
auto pBoxEx = theAPI->GetBoxByName(m_BoxDesktop).objectCast<CSandBoxPlus>();
if (pBoxEx) pBoxEx->TerminateAll();
theAPI->SwitchToDesktop("Default");
if (!KillProcessByWnd("Shell_TrayWnd")) {
e->ignore();
return;
}
}
else if (IsFullyPortable() && theAPI->IsConnected())
{
int PortableStop = theConf->GetInt("Options/PortableStop", -1);
if (PortableStop == -1)
@ -1716,14 +1745,24 @@ bool CSandMan::RunSandboxed(const QStringList& Commands, QString BoxName, const
SB_RESULT(quint32) CSandMan::RunStart(const QString& BoxName, const QString& Command, CSbieAPI::EStartFlags Flags, const QString& WorkingDir, QProcess* pProcess)
{
auto pBoxEx = theAPI->GetBoxByName(BoxName).objectCast<CSandBoxPlus>();
if (pBoxEx && pBoxEx->UseImageFile() && pBoxEx->GetMountRoot().isEmpty()) {
if (pBoxEx && pBoxEx->UseImageFile() && pBoxEx->GetMountRoot().isEmpty())
{
SB_STATUS Status = ImBoxMount(pBoxEx, true);
if (Status.IsError())
return Status;
}
return theAPI->RunStart(BoxName, Command, Flags, WorkingDir, pProcess);
auto Res = theAPI->RunStart(BoxName, Command, Flags, WorkingDir, pProcess);
if (!Res.IsError() && pBoxEx->GetBool("UseSandboxDesktop", false) && theConf->GetBool("Options/AutoDesktopSwitch", true))
{
QTimer::singleShot(1000, this, [pBoxEx]() {
theAPI->EnumBoxDesktops();
pBoxEx->SwitchToDesktop();
});
}
return Res;
}
SB_STATUS CSandMan::ImBoxMount(const CSandBoxPtr& pBox, bool bAutoUnmount)
@ -2121,6 +2160,7 @@ finish:
void CSandMan::UpdateProcesses()
{
theAPI->UpdateProcesses(KeepTerminated() ? -1 : 1500, ShowAllSessions()); // keep for 1.5 sec
theAPI->EnumBoxDesktops();
}
void CSandMan::OnBoxAdded(const CSandBoxPtr& pBox)
@ -2297,8 +2337,19 @@ void CSandMan::OnStartMenuChanged()
}
}
void CSandMan::OnBoxOpened(const CSandBoxPtr& pBox)
{
}
void CSandMan::OnBoxClosed(const CSandBoxPtr& pBox)
{
if (!m_BoxDesktop.isEmpty())
{
if (!theAPI->IsCurrentDesktopActive())
OnExit();
return;
}
foreach(const QString & Value, pBox->GetTextList("OnBoxTerminate", true, false, true)) {
QString Value2 = pBox->Expand(Value);
CSbieProgressPtr pProgress = CSbieUtils::RunCommand(Value2, true);

View File

@ -39,7 +39,7 @@ class CSandMan : public QMainWindow
Q_OBJECT
public:
CSandMan(QWidget *parent = Q_NULLPTR);
CSandMan(const QString& BoxDesktop, bool bAutoRun, QWidget *parent = Q_NULLPTR);
virtual ~CSandMan();
CSbieTemplatesEx* GetCompat() { return m_SbieTemplates; }
@ -79,6 +79,7 @@ public:
bool IsShowHidden() { return m_pShowHidden && m_pShowHidden->isChecked(); }
bool KeepTerminated();
bool ShowAllSessions() { return m_pShowAllSessions && m_pShowAllSessions->isChecked(); }
const QString& GetBoxDesktop() const { return m_BoxDesktop; }
bool IsSilentMode();
bool IsDisableRecovery() {return IsSilentMode() || m_pDisableRecovery && m_pDisableRecovery->isChecked();}
bool IsDisableMessages() {return IsSilentMode() || m_pDisableMessages && m_pDisableMessages->isChecked();}
@ -119,6 +120,8 @@ public:
void SaveMessageLog(QIODevice* pFile);
static void Restart(bool AsAdmin = false);
signals:
void DrivesChanged();
@ -154,6 +157,7 @@ protected:
bool m_bConnectPending;
bool m_bStopPending;
CBoxBorder* m_pBoxBorder;
QString m_BoxDesktop;
CSbieTemplatesEx* m_SbieTemplates;
CScriptManager* m_SbieScripts;
@ -226,6 +230,7 @@ public slots:
void OnCancelAsync();
void OnBoxAdded(const CSandBoxPtr& pBox);
void OnBoxOpened(const CSandBoxPtr& pBox);
void OnBoxClosed(const CSandBoxPtr& pBox);
void OnBoxCleaned(CSandBoxPlus* pBoxEx);
@ -262,6 +267,7 @@ private slots:
void OnDisableForce2();
void OnDisablePopUp();
void OnMaintenance();
void OnDefaultDesktop();
void OnViewMode(QAction* action);
void OnAlwaysTop();
@ -311,7 +317,7 @@ private:
void CreateToolBar(bool bRebuild);
void CreateLabel();
void CreateView(int iViewMode);
void CreateTrayIcon();
void CreateTrayIcon(bool bAutoRun);
void CreateTrayMenu();
void CreateBoxMenu(QMenu* pMenu, int iOffset = 0, int iSysTrayFilter = 0);
@ -371,7 +377,6 @@ private:
QHBoxLayout* m_pMenuLayout;
QMenu* m_pMenuFile;
QAction* m_pRestart;
QAction* m_pRunBoxed;
QAction* m_pNewBox;
QAction* m_pNewGroup;
@ -401,6 +406,8 @@ private:
QAction* m_pImDiskCpl;
QAction* m_pUninstallAll;
QAction* m_pSetupWizard;
QAction* m_pDefaultDesktop;
QAction* m_pRestart;
QAction* m_pExit;
QMenu* m_pMenuView;

View File

@ -18,7 +18,7 @@ public:
bool CTrayBoxesItemDelegate::m_Hold = false;
void CSandMan::CreateTrayIcon()
void CSandMan::CreateTrayIcon(bool bAutoRun)
{
m_pTrayIcon = new QSystemTrayIcon(GetTrayIcon(), this);
m_pTrayIcon->setToolTip(GetTrayText());
@ -30,8 +30,6 @@ void CSandMan::CreateTrayIcon()
CreateTrayMenu();
bool bAutoRun = QApplication::arguments().contains("-autorun");
if(g_PendingMessage.isEmpty()){
m_pTrayIcon->show(); // Note: qt bug; hide does not work if not showing first :/
if(!bAutoRun && theConf->GetInt("Options/SysTrayIcon", 1) == 0)
@ -125,6 +123,11 @@ void CSandMan::CreateTrayMenu()
//m_pTrayMenu->addAction(pBoxWidget);
//m_pTrayMenu->addSeparator();
if (m_pDefaultDesktop->isEnabled()) {
m_pTrayMenu->addAction(m_pDefaultDesktop);
m_pTrayMenu->addSeparator();
}
m_pTrayMenu->addAction(m_pExit);
}

View File

@ -197,6 +197,8 @@ void CSbieView::CreateMenu()
m_iMenuRun = m_pMenuRun->actions().count();
m_pMenuEmptyBox = m_pMenuBox->addAction(CSandMan::GetIcon("EmptyAll"), tr("Terminate All Programs"), this, SLOT(OnSandBoxAction()));
m_pMenuBox->addSeparator();
m_pMenuSwitchDesk = m_pMenuBox->addAction(CSandMan::GetIcon("Monitor"), tr("Switch to Isoalted Desktop"), this, SLOT(OnSandBoxAction()));
m_pMenuBox->addSeparator();
m_pMenuContent = m_pMenuBox->addMenu(CSandMan::GetIcon("Compatibility"), tr("Box Content"));
m_pMenuBrowse = m_pMenuContent->addAction(CSandMan::GetIcon("Folder"), tr("Browse Files"), this, SLOT(OnSandBoxAction()));
m_pMenuContent->addSeparator();
@ -327,6 +329,7 @@ void CSbieView::CreateOldMenu()
m_pMenuBox->addSeparator();
m_pMenuEmptyBox = m_pMenuBox->addAction(CSandMan::GetIcon("EmptyAll"), tr("Terminate Programs"), this, SLOT(OnSandBoxAction()));
m_pMenuSwitchDesk = m_pMenuBox->addAction(CSandMan::GetIcon("Monitor"), tr("Switch to Isoalted Desktop"), this, SLOT(OnSandBoxAction()));
m_pMenuMount = m_pMenuBox->addAction(CSandMan::GetIcon("LockOpen"), tr("Mount Box Image"), this, SLOT(OnSandBoxAction()));
m_pMenuUnmount = m_pMenuBox->addAction(CSandMan::GetIcon("LockClosed"), tr("Unmount Box Image"), this, SLOT(OnSandBoxAction()));
m_pMenuRecover = m_pMenuBox->addAction(CSandMan::GetIcon("Recover"), tr("Quick Recover"), this, SLOT(OnSandBoxAction()));
@ -416,6 +419,8 @@ void CSbieView::CreateTrayMenu()
m_pMenuTray->addMenu(m_pMenuRun);
m_pMenuTray->addAction(m_pMenuEmptyBox);
m_pMenuTray->addSeparator();
m_pMenuTray->addAction(m_pMenuSwitchDesk);
m_pMenuTray->addSeparator();
m_pMenuTray->addAction(m_pMenuBrowse);
m_pMenuTray->addAction(m_pMenuExplore);
m_pMenuTray->addAction(m_pMenuRegEdit);
@ -477,7 +482,16 @@ QString CSbieView__SerializeGroup(QMap<QString, QStringList>& m_Groups, const QS
void CSbieView::Refresh()
{
QList<QVariant> Added = m_pSbieModel->Sync(theAPI->GetAllBoxes(), m_Groups, theGUI->IsShowHidden());
QMap<QString, CSandBoxPtr> Boxes;
if (!theGUI->GetBoxDesktop().isEmpty()
#ifdef _DEBUG
&& !theGUI->ShowAllSessions()
#endif
)
Boxes.insert(theGUI->GetBoxDesktop().toLower(), theAPI->GetBoxByName(theGUI->GetBoxDesktop()));
else
Boxes = theAPI->GetAllBoxes();
QList<QVariant> Added = m_pSbieModel->Sync(Boxes, m_Groups, theGUI->IsShowHidden());
if (m_pSbieModel->IsTree())
{
@ -628,6 +642,7 @@ bool CSbieView::UpdateMenu(bool bAdvanced, const CSandBoxPtr &pBox, int iSandBox
m_pMenuCleanUp->setEnabled(iSandBoxeCount > 0);
if (m_pMenuContent) m_pMenuContent->setEnabled(iSandBoxeCount > 0);
m_pMenuEmptyBox->setEnabled(iSandBoxeCount > 0);
m_pMenuSwitchDesk->setEnabled(iSandBoxeCount == 1 && !pBoxEx->GetDesktop().isEmpty());
m_pMenuBrowse->setEnabled(iSandBoxeCount == 1);
m_pMenuExplore->setEnabled(iSandBoxeCount == 1);
@ -1551,6 +1566,10 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList<CSandBoxPtr>& SandB
foreach(const CSandBoxPtr& pBox, SandBoxes)
Results.append(pBox->TerminateAll());
}
else if (Action == m_pMenuSwitchDesk)
{
Results.append(SandBoxes.first()->SwitchToDesktop());
}
else if (Action == m_pMenuMkLink)
{
if (theConf->GetInt("Options/InfoMkLink", -1) == -1)
@ -1759,6 +1778,12 @@ void CSbieView::ShowBrowse(const CSandBoxPtr& pBox)
void CSbieView::OnDoubleClicked(const QModelIndex& index)
{
if (!index.isValid()) {
if (!theGUI->GetBoxDesktop().isEmpty() && theConf->GetBool("Options/QuickDesktopSwitch", true))
theAPI->SwitchToDesktop("Default");
return;
}
QModelIndex ModelIndex = m_pSortProxy->mapToSource(index);
CSandBoxPtr pBox = m_pSbieModel->GetSandBox(ModelIndex);
if (pBox.isNull())
@ -1774,6 +1799,11 @@ void CSbieView::OnDoubleClicked(const QModelIndex& index)
return;
}
if (!pBox->GetDesktop().isEmpty() && theConf->GetBool("Options/QuickDesktopSwitch", true) && theGUI->GetBoxDesktop().compare(pBox->GetName(), Qt::CaseInsensitive) != 0) {
pBox->SwitchToDesktop();
return;
}
//if (index.column() != CSbieModel::eName)
// return;
@ -2207,7 +2237,7 @@ void CSbieView::ClearUserUIConfig(const QMap<QString, CSandBoxPtr> AllBoxes)
void CSbieView::SaveBoxGrouping()
{
if (!theAPI->IsConnected())
if (!theAPI->IsConnected() || !theGUI->GetBoxDesktop().isEmpty())
return;
theAPI->GetUserSettings()->SetRefreshOnChange(false);

View File

@ -186,6 +186,7 @@ private:
QAction* m_pMenuOptions;
QAction* m_pMenuSnapshots;
QAction* m_pMenuEmptyBox;
QAction* m_pMenuSwitchDesk;
QMenu* m_pMenuContent;
QAction* m_pMenuExplore;
QAction* m_pMenuBrowse;

View File

@ -32,6 +32,8 @@ int main(int argc, char *argv[])
// use a shared setting location when used in a business environment for easier administration
theConf = new CSettings(ConfDir, "Sandboxie-Plus");
QString AppID = "SandMan";
#ifndef _DEBUG
InitMiniDumpWriter(QString("SandMan-v%1").arg(CSandMan::GetVersion()).toStdWString().c_str() , QString(theConf->GetConfigDir()).replace("/", "\\").toStdWString().c_str());
#endif
@ -60,8 +62,37 @@ int main(int argc, char *argv[])
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
QtSingleApplication app(argc, argv);
app.setQuitOnLastWindowClosed(false);
QString BoxDesktop;
QString CurDesk = CSbieAPI::GetCurrentDesktopName();
QStringList CurDeskNames = CurDesk.split("_");
if (CurDeskNames.length() >= 3 && CurDeskNames[0] == "Sandboxie" && CurDeskNames[2] == "Session")
BoxDesktop = CurDeskNames[1];
if (!BoxDesktop.isEmpty())
{
for (int i = 1; i < argc; i++)
{
if (stricmp(argv[i], "-autorun") != 0)
continue;
WCHAR cmdline[MAX_PATH];
GetSystemWindowsDirectoryW(cmdline, MAX_PATH);
wcscat_s(cmdline, MAX_PATH, L"\\Explorer.exe");
QStringList StartArgs;
StartArgs << "/Box:" + BoxDesktop;
StartArgs << "/fcp";
StartArgs << QString::fromWCharArray(cmdline);
QProcess::startDetached(AppDir + "\\start.exe", StartArgs);
CSandMan::Restart();
return 0;
}
AppID.append("_" + BoxDesktop);
}
QtSingleApplication* pApp = new QtSingleApplication(AppID, argc, argv);
pApp->setQuitOnLastWindowClosed(false);
//InitConsole(false);
@ -165,30 +196,34 @@ int main(int argc, char *argv[])
return -1;
}
bool bAutoRun = pApp->arguments().contains("-autorun");
if (!g_PendingMessage.isEmpty()) {
if(app.sendMessage(g_PendingMessage))
if(pApp->sendMessage(g_PendingMessage))
return 0;
app.disableSingleApp(); // we start to do one job and exit, don't interfere with starting a regular instance
pApp->disableSingleApp(); // we start to do one job and exit, don't interfere with starting a regular instance
}
else {
if (app.arguments().contains("-autorun") && app.isRunning())
if (bAutoRun && pApp->isRunning())
return 0;
if (app.sendMessage("ShowWnd"))
if (pApp->sendMessage("ShowWnd"))
return 0;
}
//QThreadPool::globalInstance()->setMaxThreadCount(theConf->GetInt("Options/MaxThreadPool", 10));
CSandMan* pWnd = new CSandMan();
CSandMan* pWnd = new CSandMan(BoxDesktop, bAutoRun);
QObject::connect(&app, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&)), Qt::QueuedConnection);
QObject::connect(pApp, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&)), Qt::QueuedConnection);
int ret = app.exec();
int ret = pApp->exec();
delete pWnd;
delete theConf;
theConf = NULL;
delete pApp;
return ret;
}

View File

@ -1,7 +1,7 @@
#pragma once
#define VERSION_MJR 1
#define VERSION_MIN 14
#define VERSION_MIN 15
#define VERSION_REV 0
#define VERSION_UPD 0