diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4523ab..96418479 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - added hwid display - added Language Spoof "CustomLCID=1033" [#4024](https://github.com/sandboxie-plus/Sandboxie/pull/4024) (thanks Yeyixiao) +- added option to always run the sandman UI as admin [#4090](https://github.com/sandboxie-plus/Sandboxie/issues/4090) ### Fixed - fixed Getting two advanced supporter certificate popups everytime I open Sandbox Settings on any sandbox [#4074](https://github.com/sandboxie-plus/Sandboxie/issues/4074) diff --git a/SandboxiePlus/SandMan/Forms/SettingsWindow.ui b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui index 073b00c6..d83142cb 100644 --- a/SandboxiePlus/SandMan/Forms/SettingsWindow.ui +++ b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui @@ -2196,7 +2196,41 @@ Unlike the preview channel, it does not include untested, potentially breaking, Sandboxie.ini Presets - + + + + Only Administrator user accounts can use Pause Forcing Programs command + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Watch Sandboxie.ini for changes + + + + + + + Only Administrator user accounts can make changes + + + + Qt::Vertical @@ -2209,46 +2243,10 @@ Unlike the preview channel, it does not include untested, potentially breaking, - - - - Clear password when main window becomes hidden - - - - - - - Only Administrator user accounts can use Pause Forcing Programs command - - - - - - - Watch Sandboxie.ini for changes - - - - - - - Change Password - - - - - - - Only Administrator user accounts can make changes - - - - + - 75 true true @@ -2258,25 +2256,33 @@ Unlike the preview channel, it does not include untested, potentially breaking, - + + + + Clear password when main window becomes hidden + + + + Password must be entered in order to make changes - - - - Qt::Horizontal + + + + Change Password - - - 40 - 20 - + + + + + + Always run SandMan UI as Admin - + diff --git a/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp b/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp index 52535ac9..54ca5a88 100644 --- a/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp +++ b/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp @@ -164,4 +164,336 @@ bool AutorunEnable (bool is_enable) } return false; -} \ No newline at end of file +} + +////////////////////////////////////////////////////////////////////////////////// +// Skip UAC + +#define SKIP_UAC_TASK_NAME APP_NAME L"_SkipUac" + +#include +#include + +struct MBSTR +{ + MBSTR (LPCWSTR asString = nullptr) + { + ms_bstr = asString ? SysAllocString (asString) : nullptr; + } + + ~MBSTR () + { + Free (); + } + + operator BSTR() const + { + return ms_bstr; + } + + MBSTR& operator=(LPCWSTR asString) + { + if (asString != ms_bstr) + { + Free (); + ms_bstr = asString ? ::SysAllocString (asString) : NULL; + } + + return *this; + } + + void Free () + { + if (ms_bstr) + { + SysFreeString (ms_bstr); + ms_bstr = nullptr; + } + } +protected: + BSTR ms_bstr; +}; + +bool SkipUacEnable (bool is_enable) +{ + bool result = false; + bool action_result = false; + + ITaskService* service = nullptr; + ITaskFolder* folder = nullptr; + ITaskDefinition* task = nullptr; + IRegistrationInfo* reginfo = nullptr; + IPrincipal* principal = nullptr; + ITaskSettings* settings = nullptr; + IActionCollection* action_collection = nullptr; + IAction* action = nullptr; + IExecAction* exec_action = nullptr; + IRegisteredTask* registered_task = nullptr; + + wchar_t szPath[MAX_PATH]; + if (!GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) + return false; + std::wstring::size_type pos = std::wstring(szPath).find_last_of( L"\\/" ); + std::wstring dir = std::wstring(szPath).substr(0, pos); + + MBSTR root (L"\\"); + MBSTR name (SKIP_UAC_TASK_NAME); + MBSTR author (APP_NAME); + MBSTR path (szPath); + MBSTR directory (dir.c_str()); + MBSTR args (L"$(Arg0)"); + MBSTR timelimit (L"PT0S"); + + VARIANT vtEmpty = {VT_EMPTY}; + + if (SUCCEEDED (CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED))) + { + //if (SUCCEEDED (CoInitializeSecurity (nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 0, nullptr))) + { + if (SUCCEEDED (CoCreateInstance (CLSID_TaskScheduler, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID*)&service))) + { + if (SUCCEEDED (service->Connect (vtEmpty, vtEmpty, vtEmpty, vtEmpty))) + { + if (SUCCEEDED (service->GetFolder (root, &folder))) + { + // create task + if (is_enable) + { + if (SUCCEEDED (service->NewTask (0, &task))) + { + if (SUCCEEDED (task->get_RegistrationInfo (®info))) + { + reginfo->put_Author (author); + reginfo->Release (); + } + + if (SUCCEEDED (task->get_Principal (&principal))) + { + principal->put_RunLevel (TASK_RUNLEVEL_HIGHEST); + principal->Release (); + } + + if (SUCCEEDED (task->get_Settings (&settings))) + { + settings->put_AllowHardTerminate (VARIANT_BOOL (FALSE)); + settings->put_StartWhenAvailable (VARIANT_BOOL (FALSE)); + settings->put_DisallowStartIfOnBatteries (VARIANT_BOOL (FALSE)); + settings->put_StopIfGoingOnBatteries (VARIANT_BOOL (FALSE)); + settings->put_MultipleInstances (TASK_INSTANCES_PARALLEL); + settings->put_ExecutionTimeLimit (timelimit); + + settings->Release (); + } + + if (SUCCEEDED (task->get_Actions (&action_collection))) + { + if (SUCCEEDED (action_collection->Create (TASK_ACTION_EXEC, &action))) + { + if (SUCCEEDED (action->QueryInterface (IID_IExecAction, (LPVOID*)&exec_action))) + { + if ( + SUCCEEDED (exec_action->put_Path (path)) && + SUCCEEDED (exec_action->put_WorkingDirectory (directory)) && + SUCCEEDED (exec_action->put_Arguments (args)) + ) + { + action_result = true; + } + + exec_action->Release (); + } + + action->Release (); + } + + action_collection->Release (); + } + + if (action_result) + { + if (SUCCEEDED (folder->RegisterTaskDefinition ( + name, + task, + TASK_CREATE_OR_UPDATE, + vtEmpty, + vtEmpty, + TASK_LOGON_INTERACTIVE_TOKEN, + vtEmpty, + ®istered_task) + )) + { + { + //ConfigSet (L"SkipUacIsEnabled", true); + result = true; + + registered_task->Release (); + } + } + + task->Release (); + } + } + } + else + { + // remove task + result = SUCCEEDED (folder->DeleteTask (name, 0)); + + //ConfigSet (L"SkipUacIsEnabled", false); + } + + folder->Release (); + } + } + + service->Release (); + } + } + + CoUninitialize (); + } + + return result; +} + +bool SkipUacRun (bool test_only) +{ + bool result = false; + + ITaskService* service = nullptr; + ITaskFolder* folder = nullptr; + IRegisteredTask* registered_task = nullptr; + + ITaskDefinition* task = nullptr; + IActionCollection* action_collection = nullptr; + IAction* action = nullptr; + IExecAction* exec_action = nullptr; + + IRunningTask* running_task = nullptr; + + wchar_t szPath[MAX_PATH]; + if (!GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) + return false; + + MBSTR root (L"\\"); + MBSTR name (SKIP_UAC_TASK_NAME); + + VARIANT vtEmpty = {VT_EMPTY}; + + if (SUCCEEDED (CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED))) + { + //if (SUCCEEDED (CoInitializeSecurity (nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 0, nullptr))) + { + if (SUCCEEDED (CoCreateInstance (CLSID_TaskScheduler, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID*)&service))) + { + if (SUCCEEDED (service->Connect (vtEmpty, vtEmpty, vtEmpty, vtEmpty))) + { + if (SUCCEEDED (service->GetFolder (root, &folder))) + { + if (SUCCEEDED (folder->GetTask (name, ®istered_task))) + { + if (SUCCEEDED (registered_task->get_Definition (&task))) + { + if (SUCCEEDED (task->get_Actions (&action_collection))) + { + if (SUCCEEDED (action_collection->get_Item (1, &action))) + { + if (SUCCEEDED (action->QueryInterface (IID_IExecAction, (LPVOID*)&exec_action))) + { + BSTR path = nullptr; + + exec_action->get_Path (&path); + + PathUnquoteSpaces (path); + + // check path is to current module + if (_wcsicmp (path, szPath) == 0) + { + if (test_only) + { + result = true; + } + else + { + std::wstring args; + + // get arguments + { + INT numargs = 0; + LPWSTR* arga = CommandLineToArgvW(GetCommandLine(), &numargs); + + for (INT i = 1; i < numargs; i++) { + if (i > 1) + args.append(L" "); + args.append(arga[i]); + } + + LocalFree(arga); + } + + variant_t params = args.c_str(); + + if (SUCCEEDED(registered_task->RunEx(params, TASK_RUN_NO_FLAGS, 0, nullptr, &running_task))) + { + UINT8 count = 3; // try count + + do + { + QThread::msleep(250); + + TASK_STATE state = TASK_STATE_UNKNOWN; + + running_task->Refresh(); + running_task->get_State(&state); + + if ( + state == TASK_STATE_RUNNING || + state == TASK_STATE_READY || + state == TASK_STATE_DISABLED + ) + { + if ( + state == TASK_STATE_RUNNING || + state == TASK_STATE_READY + ) + { + result = true; + } + + break; + } + } while (count--); + + running_task->Release(); + } + } + } + + exec_action->Release (); + } + + action->Release (); + } + + action_collection->Release (); + } + + task->Release (); + } + + registered_task->Release (); + } + + folder->Release (); + } + } + + service->Release (); + } + } + + CoUninitialize (); + } + + return result; +} diff --git a/SandboxiePlus/SandMan/Helpers/WinAdmin.h b/SandboxiePlus/SandMan/Helpers/WinAdmin.h index 6c6a8215..211c1f6b 100644 --- a/SandboxiePlus/SandMan/Helpers/WinAdmin.h +++ b/SandboxiePlus/SandMan/Helpers/WinAdmin.h @@ -10,3 +10,6 @@ bool IsAdminUser(bool OnlyFull = false); bool IsAutorunEnabled(); bool AutorunEnable(bool is_enable); + +bool SkipUacRun(bool test_only = false); +bool SkipUacEnable(bool is_enable); \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp index 7559f36e..2f2f41df 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp @@ -433,6 +433,10 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) connect(ui.chkWatchConfig, SIGNAL(stateChanged(int)), this, SLOT(OnOptChanged())); // not sbie ini + connect(ui.chkSkipUAC, SIGNAL(stateChanged(int)), this, SLOT(OnSkipUAC())); + ui.chkSkipUAC->setEnabled(IsElevated()); + m_SkipUACChanged = false; + connect(ui.chkAdminOnly, SIGNAL(stateChanged(int)), this, SLOT(OnProtectionChange())); connect(ui.chkPassRequired, SIGNAL(stateChanged(int)), this, SLOT(OnProtectionChange())); connect(ui.btnSetPassword, SIGNAL(clicked(bool)), this, SLOT(OnSetPassword())); @@ -953,6 +957,7 @@ void CSettingsWindow::LoadSettings() ui.chkMonitorSize->setChecked(theConf->GetBool("Options/WatchBoxSize", false)); ui.chkWatchConfig->setChecked(theConf->GetBool("Options/WatchIni", true)); + ui.chkSkipUAC->setChecked(SkipUacRun(true)); ui.chkScanMenu->setChecked(theConf->GetBool("Options/ScanStartMenu", true)); ui.cmbIntegrateMenu->setCurrentIndex(theConf->GetInt("Options/IntegrateStartMenu", 0)); @@ -1657,6 +1662,8 @@ void CSettingsWindow::SaveSettings() theConf->SetValue("Options/WatchBoxSize", ui.chkMonitorSize->isChecked()); theConf->SetValue("Options/WatchIni", ui.chkWatchConfig->isChecked()); + if (m_SkipUACChanged) + SkipUacEnable(ui.chkSkipUAC->isChecked()); theConf->SetValue("Options/ScanStartMenu", ui.chkScanMenu->isChecked()); int OldIntegrateStartMenu = theConf->GetInt("Options/IntegrateStartMenu", 0); diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.h b/SandboxiePlus/SandMan/Windows/SettingsWindow.h index ab11cfa6..058970d7 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.h +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.h @@ -88,6 +88,8 @@ private slots: void OnOptChanged(); + void OnSkipUAC() { m_SkipUACChanged = true; OnOptChanged(); } + void OnChangeGUI() { m_bRebuildUI = true; OnOptChanged(); } void OnFeaturesChanged() { m_FeaturesChanged = true; OnGeneralChanged(); } void OnGeneralChanged() { m_GeneralChanged = true; OnOptChanged(); } @@ -176,6 +178,7 @@ protected: bool m_VolumeChanged; bool m_CompatChanged; bool m_RunChanged; + bool m_SkipUACChanged; bool m_ProtectionChanged; bool m_GeneralChanged; bool m_FeaturesChanged;