From 446fd25eed4a4b74962ca4d4e9151e3e9b5c401e Mon Sep 17 00:00:00 2001 From: DavidXanatos <3890945+DavidXanatos@users.noreply.github.com> Date: Sat, 28 Jan 2023 14:05:37 +0100 Subject: [PATCH] 1.7.0c --- CHANGELOG.md | 7 + Sandboxie/core/dll/file.c | 2 +- Sandboxie/core/dll/file_del.c | 2 +- Sandboxie/core/dll/file_dir.c | 2 +- Sandboxie/core/dll/file_init.c | 2 +- Sandboxie/core/dll/key.c | 2 +- Sandboxie/core/dll/key_del.c | 2 +- SandboxiePlus/SandMan/Forms/NewBoxWindow.ui | 72 +-- .../SandMan/Forms/SelectBoxWindow.ui | 83 +-- SandboxiePlus/SandMan/SandMan.pri | 2 + SandboxiePlus/SandMan/SandMan.vcxproj | 2 + SandboxiePlus/SandMan/SandMan.vcxproj.filters | 6 + SandboxiePlus/SandMan/Views/SbieView.cpp | 24 +- .../SandMan/Windows/SelectBoxWindow.cpp | 11 +- .../SandMan/Wizards/NewBoxWizard.cpp | 556 ++++++++++++++++++ SandboxiePlus/SandMan/Wizards/NewBoxWizard.h | 130 ++++ 16 files changed, 814 insertions(+), 91 deletions(-) create mode 100644 SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp create mode 100644 SandboxiePlus/SandMan/Wizards/NewBoxWizard.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 5783c19a..7e92285e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [1.7.1 / 5.62.1] - 2022-12- +### Added +- added option to create a new sandbox to run in from the box picker dialog +- added sandbox creation wizard (not available in vintage view mode) + + ### Fixed - fixed BlockNetworkFiles=y not workign tigether with RestrictDevices=y [#2629](https://github.com/sandboxie-plus/Sandboxie/issues/2629) - fixed sandman crash issue introduced in 1.7.0 @@ -18,6 +23,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). + + ## [1.7.0 / 5.62.0] - 2022-12-27 diff --git a/Sandboxie/core/dll/file.c b/Sandboxie/core/dll/file.c index 25d0ef68..dcb2f0c1 100644 --- a/Sandboxie/core/dll/file.c +++ b/Sandboxie/core/dll/file.c @@ -1,6 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC - * Copyright 2020-2022 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 diff --git a/Sandboxie/core/dll/file_del.c b/Sandboxie/core/dll/file_del.c index a6fe61fb..f03c2f98 100644 --- a/Sandboxie/core/dll/file_del.c +++ b/Sandboxie/core/dll/file_del.c @@ -1,5 +1,5 @@ /* - * Copyright 2022 David Xanatos, xanasoft.com + * Copyright 2022-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 diff --git a/Sandboxie/core/dll/file_dir.c b/Sandboxie/core/dll/file_dir.c index f4f0f649..6591fad3 100644 --- a/Sandboxie/core/dll/file_dir.c +++ b/Sandboxie/core/dll/file_dir.c @@ -1,6 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC - * Copyright 2020-2022 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 diff --git a/Sandboxie/core/dll/file_init.c b/Sandboxie/core/dll/file_init.c index f9bff1f8..5db611fc 100644 --- a/Sandboxie/core/dll/file_init.c +++ b/Sandboxie/core/dll/file_init.c @@ -1,6 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC - * Copyright 2020-2022 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 diff --git a/Sandboxie/core/dll/key.c b/Sandboxie/core/dll/key.c index cb1e6d37..6b9ae423 100644 --- a/Sandboxie/core/dll/key.c +++ b/Sandboxie/core/dll/key.c @@ -1,6 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC - * Copyright 2021-2022 David Xanatos, xanasoft.com + * Copyright 2021-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 diff --git a/Sandboxie/core/dll/key_del.c b/Sandboxie/core/dll/key_del.c index 392352b8..0b64a4f4 100644 --- a/Sandboxie/core/dll/key_del.c +++ b/Sandboxie/core/dll/key_del.c @@ -1,5 +1,5 @@ /* - * Copyright 2022 David Xanatos, xanasoft.com + * Copyright 2022-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 diff --git a/SandboxiePlus/SandMan/Forms/NewBoxWindow.ui b/SandboxiePlus/SandMan/Forms/NewBoxWindow.ui index 4a9eeb91..ac2506d7 100644 --- a/SandboxiePlus/SandMan/Forms/NewBoxWindow.ui +++ b/SandboxiePlus/SandMan/Forms/NewBoxWindow.ui @@ -7,7 +7,7 @@ 0 0 500 - 300 + 328 @@ -34,30 +34,13 @@ - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + 32 - - - - Sandbox Name: - - - - - - - Box Type Preset: - - - - - - @@ -71,6 +54,37 @@ + + + + Box Type Preset: + + + + + + + Sandbox Name: + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + @@ -81,13 +95,6 @@ - - - - 32 - - - @@ -101,13 +108,6 @@ - - - - - - - diff --git a/SandboxiePlus/SandMan/Forms/SelectBoxWindow.ui b/SandboxiePlus/SandMan/Forms/SelectBoxWindow.ui index 000120ab..a1571a40 100644 --- a/SandboxiePlus/SandMan/Forms/SelectBoxWindow.ui +++ b/SandboxiePlus/SandMan/Forms/SelectBoxWindow.ui @@ -6,8 +6,8 @@ 0 0 - 280 - 400 + 263 + 430 @@ -34,36 +34,10 @@ - - - - Select the sandbox in which to start the program, installer or document. - - - true - - - - - - - - Sandbox - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - Run As UAC Administrator + + + Qt::Horizontal @@ -77,24 +51,53 @@ - + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + Sandbox + + + + + Run Outside the Sandbox - - - - Qt::Horizontal + + + + Run As UAC Administrator - - - - Qt::Horizontal + + + + Select the sandbox in which to start the program, installer or document. + + + true + + + + + + + Run in a new Sandboxed + + + false diff --git a/SandboxiePlus/SandMan/SandMan.pri b/SandboxiePlus/SandMan/SandMan.pri index e63129d4..977cfe54 100644 --- a/SandboxiePlus/SandMan/SandMan.pri +++ b/SandboxiePlus/SandMan/SandMan.pri @@ -31,6 +31,7 @@ HEADERS += ./stdafx.h \ ./Windows/SelectBoxWindow.h \ ./Windows/SupportDialog.h\ ./OnlineUpdater.h \ + ./Wizards/NewBoxWizard.h \ ./Wizards/SetupWizard.h SOURCES += ./main.cpp \ @@ -63,6 +64,7 @@ SOURCES += ./main.cpp \ ./Windows/SelectBoxWindow.cpp \ ./Windows/SupportDialog.cpp\ ./OnlineUpdater.cpp \ + ./Wizards/NewBoxWizard.cpp \ ./Wizards/SetupWizard.cpp FORMS += ./Forms/NewBoxWindow.ui \ diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj b/SandboxiePlus/SandMan/SandMan.vcxproj index 81103e6c..7a7aa49f 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj +++ b/SandboxiePlus/SandMan/SandMan.vcxproj @@ -316,9 +316,11 @@ + + diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj.filters b/SandboxiePlus/SandMan/SandMan.vcxproj.filters index 22d5d4b0..e67d8bc4 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj.filters +++ b/SandboxiePlus/SandMan/SandMan.vcxproj.filters @@ -183,6 +183,9 @@ Helpers + + Helpers + @@ -283,6 +286,9 @@ SandMan + + Wizards + diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp index 6127db44..22a0bf54 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.cpp +++ b/SandboxiePlus/SandMan/Views/SbieView.cpp @@ -12,6 +12,7 @@ #include "../Windows/RecoveryWindow.h" #include "../Windows/NewBoxWindow.h" #include "../Views/FileView.h" +#include "../Wizards/NewBoxWizard.h" #include "qt_windows.h" #include "qwindowdefs_win.h" @@ -960,17 +961,24 @@ bool CSbieView::MoveItem(const QString& Name, const QString& To, int pos) QString CSbieView::AddNewBox() { - CNewBoxWindow NewBoxWindow(this); - bool bAlwaysOnTop = theConf->GetBool("Options/AlwaysOnTop", false); - NewBoxWindow.setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop); - if (NewBoxWindow.exec() == 1) - { + QString BoxName; + + bool bVintage = theConf->GetInt("Options/ViewMode", 1) == 2; + + if (bVintage) { + CNewBoxWindow NewBoxWindow(this); + if (NewBoxWindow.exec() == 1) + BoxName = NewBoxWindow.m_Name; + } + else + BoxName = CNewBoxWizard::CreateNewBox(this); + + if (!BoxName.isEmpty()) { theAPI->ReloadBoxes(); Refresh(); - SelectBox(NewBoxWindow.m_Name); - return NewBoxWindow.m_Name; + SelectBox(BoxName); } - return QString(); + return BoxName; } QString CSbieView::AddNewGroup() diff --git a/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp b/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp index ee404c8c..2cb39d7a 100644 --- a/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp @@ -90,6 +90,7 @@ CSelectBoxWindow::CSelectBoxWindow(const QStringList& Commands, const QString& B ui.treeBoxes->setAlternatingRowColors(theConf->GetBool("Options/AltRowColors", false)); connect(ui.radBoxed, SIGNAL(clicked(bool)), this, SLOT(OnBoxType())); + connect(ui.radBoxedNew, SIGNAL(clicked(bool)), this, SLOT(OnBoxType())); connect(ui.radUnBoxed, SIGNAL(clicked(bool)), this, SLOT(OnBoxType())); connect(ui.buttonBox, SIGNAL(accepted()), SLOT(OnRun())); @@ -162,7 +163,7 @@ void CSelectBoxWindow::closeEvent(QCloseEvent *e) void CSelectBoxWindow::OnBoxType() { - ui.treeBoxes->setEnabled(!ui.radUnBoxed->isChecked()); + ui.treeBoxes->setEnabled(ui.radBoxed->isChecked()); } void CSelectBoxWindow::OnBoxDblClick(QTreeWidgetItem*) @@ -181,6 +182,14 @@ void CSelectBoxWindow::OnRun() return; pItem = NULL; } + else if (ui.radBoxedNew->isChecked()) + { + BoxName = theGUI->GetBoxView()->AddNewBox(); + if (BoxName.isEmpty()) { + close(); + return; + } + } else if (pItem == NULL) { QMessageBox("Sandboxie-Plus", tr("Please select a sandbox."), QMessageBox::Information, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this).exec(); return; diff --git a/SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp b/SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp new file mode 100644 index 00000000..503a07c6 --- /dev/null +++ b/SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp @@ -0,0 +1,556 @@ +#include "stdafx.h" + +#include "NewBoxWizard.h" +#include "../MiscHelpers/Common/Common.h" +#include "../Windows/SettingsWindow.h" +#include "../SandMan.h" +#include "Helpers/WinAdmin.h" +#include +#include "../QSbieAPI/SbieUtils.h" +#include "../Views/SbieView.h" + + +CNewBoxWizard::CNewBoxWizard(QWidget *parent) + : QWizard(parent) +{ + setPage(Page_Type, new CBoxTypePage); + setPage(Page_Files, new CFilesPage); + setPage(Page_Advanced, new CAdvancedPage); + setPage(Page_Summary, new CSummaryPage); + + m_bAdvanced = false; + + setWizardStyle(ModernStyle); + //setOption(HaveHelpButton, true); + setPixmap(QWizard::LogoPixmap, QPixmap(":/SandMan.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + connect(this, &QWizard::helpRequested, this, &CNewBoxWizard::showHelp); + + setWindowTitle(tr("New Box Wizard")); +} + +void CNewBoxWizard::showHelp() +{ + +} + +QString CNewBoxWizard::CreateNewBox(QWidget* pParent) +{ + CNewBoxWizard wizard(pParent); + if (!wizard.exec()) + return QString(); + + QString BoxName = wizard.field("boxName").toString(); + BoxName.replace(" ", "_"); + return BoxName; +} + +SB_STATUS CNewBoxWizard::TryToCreateBox() +{ + QString BoxName = field("boxName").toString(); + BoxName.replace(" ", "_"); + int BoxType = field("boxType").toInt(); + + SB_STATUS Status = theAPI->CreateBox(BoxName, true); + + if (!Status.IsError()) + { + CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); + + switch (BoxType) + { + case CSandBoxPlus::eHardenedPlus: + case CSandBoxPlus::eHardened: + pBox->SetBool("UseSecurityMode", true); + if(BoxType == CSandBoxPlus::eHardenedPlus) + pBox->SetBool("UsePrivacyMode", true); + break; + case CSandBoxPlus::eDefaultPlus: + case CSandBoxPlus::eDefault: + pBox->SetBool("UseSecurityMode", false); + if(BoxType == CSandBoxPlus::eDefaultPlus) + pBox->SetBool("UsePrivacyMode", true); + break; + case CSandBoxPlus::eAppBoxPlus: + case CSandBoxPlus::eAppBox: + pBox->SetBool("NoSecurityIsolation", true); + if(BoxType == CSandBoxPlus::eAppBoxPlus) + pBox->SetBool("UsePrivacyMode", true); + //pBox->InsertText("Template", "NoUACProxy"); // proxy is always needed for exes in the box + pBox->InsertText("Template", "RpcPortBindingsExt"); + break; + } + + QRgb rgb = theGUI->GetBoxColor(BoxType); + pBox->SetText("BorderColor", QString("#%1%2%3").arg(qBlue(rgb), 2, 16, QChar('0')).arg(qGreen(rgb), 2, 16, QChar('0')).arg(qRed(rgb), 2, 16, QChar('0')) + ",ttl"); + + + QString Location = field("boxLocation").toString(); + if (!Location.isEmpty()) + pBox->SetText("FileRootPath", Location); + + if (field("boxVersion").toInt() == 1) { + pBox->SetBool("UseFileDeleteV2", true); + pBox->SetBool("UseRegDeleteV2", true); + } + if(!field("separateUser").toBool()) + pBox->SetBool("SeparateUserFolders", false); + if(field("useVolumeSN").toBool()) + pBox->SetBool("UseVolumeSerialNumbers", true); + + if(field("autoDelete").toBool()) + pBox->SetBool("AutoDelete", true); + if(field("autoRecover").toBool()) + pBox->SetBool("AutoRecover", true); + + if (field("blockNetwork").toInt() == 1) // old style + pBox->InsertText("AllowNetworkAccess", "!,n"); + else if (field("blockNetwork").toInt() == 2) // WFP + pBox->InsertText("ClosedFilePath", "!,InternetAccessDevices"); + pBox->SetBool("BlockNetworkFiles", !field("shareAccess").toBool()); + + if(field("fakeAdmin").toBool()) + pBox->SetBool("FakeAdminRights", true); + if(field("msiServer").toBool()) + pBox->SetBool("MsiInstallerExemptions", true); + } + + return Status; +} + +QString CNewBoxWizard::GetDefaultLocation() +{ + QString DefaultPath = theAPI->GetGlobalSettings()->GetText("FileRootPath", "\\??\\%SystemDrive%\\Sandbox\\%USER%\\%SANDBOX%", false, false); + // HACK HACK: globally %SANDBOX% evaluates to GlobalSettings + DefaultPath.replace("\\GlobalSettings", "\\" + field("boxName").toString()); + return theAPI->Nt2DosPath(DefaultPath); +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// CBoxTypePage +// + +CBoxTypePage::CBoxTypePage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Create new Sandbox")); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); + + m_bInstant = theConf->GetBool("Options/InstantBoxWizard", false); + + int row = 0; + QGridLayout *layout = new QGridLayout; + QLabel* pTopLabel = new QLabel(tr("A sandbox isolates your host system from processes running within the box, " + "it prevents them from making permanent changes to other programs and data in your computer. " + "The level of isolation impacts your security as well as the compatibility with applications, " + "hence there will be a different level of isolation depending on the selected Box Type. " + "Sandboxie can also protect your personal data from being accessed by processes running under its supervision.")); + pTopLabel->setWordWrap(true); + layout->addWidget(pTopLabel, row++ , 0, 1, 3); + + + layout->addWidget(new QLabel(tr("Enter box name:")), row++, 0); + + m_pBoxName = new QLineEdit(); + m_pBoxName->setMaxLength(32); + QMap Boxes = theAPI->GetAllBoxes(); + for (int i=0;; i++) { + QString NewName = tr("New Box"); + if (i > 0) NewName.append(" " + QString::number(i)); + if (Boxes.contains(NewName.toLower().replace(" ", "_"))) + continue; + m_pBoxName->setText(NewName); + break; + } + m_pBoxName->setFocus(); + layout->addWidget(m_pBoxName, row++, 1, 1, 2); + registerField("boxName", m_pBoxName); + + + layout->addWidget(new QLabel(tr("Sellect box type:")), row++, 0); + + m_pBoxType = new QComboBox(); + m_pBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eHardenedPlus), tr("Hardened Sandbox with Data Protection"), (int)CSandBoxPlus::eHardenedPlus); + m_pBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eHardened), tr("Security Hardened Sandbox"), (int)CSandBoxPlus::eHardened); + m_pBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eDefaultPlus), tr("Sandbox with Data Protection"), (int)CSandBoxPlus::eDefaultPlus); + m_pBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eDefault), tr("Standard Isolation Sandbox (Default)"), (int)CSandBoxPlus::eDefault); + //m_pBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eInsecure), tr("INSECURE Configuration (please change)"), (int)CSandBoxPlus::eInsecure); + m_pBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eAppBoxPlus), tr("Application Compartment with Data Protection"), (int)CSandBoxPlus::eAppBoxPlus); + m_pBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eAppBox), tr("Application Compartment (NO Isolation)"), (int)CSandBoxPlus::eAppBox); + connect(m_pBoxType, SIGNAL(currentIndexChanged(int)), this, SLOT(OnBoxTypChanged())); + layout->addWidget(m_pBoxType, row++, 1, 1, 2); + registerField("boxType", m_pBoxType); + + m_pInfoLabel = new QLabel(); + m_pInfoLabel->setWordWrap(true); + layout->addWidget(m_pInfoLabel, row++, 0, 1, 3); + + m_pBoxType->setCurrentIndex(3); // default + + + + QWidget* pSpacer = new QWidget(); + pSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->addWidget(pSpacer, row++, 1); + + m_pAdvanced = new QCheckBox(tr("Configure advanced options")); + layout->addWidget(m_pAdvanced, row++, 2); + connect(m_pAdvanced, SIGNAL(toggled(bool)), this, SLOT(OnAdvanced())); + + setLayout(layout); +} + +void CBoxTypePage::OnBoxTypChanged() +{ + int BoxType = m_pBoxType->currentData().toInt(); + + m_pInfoLabel->setText(theGUI->GetBoxDescription(BoxType)); + + if(BoxType != CSandBoxPlus::eDefault) + theGUI->CheckCertificate(this); +} + +void CBoxTypePage::OnAdvanced() +{ + ((CNewBoxWizard*)wizard())->m_bAdvanced = m_pAdvanced->isChecked(); + if (m_bInstant) + { + QString BoxName = m_pBoxName->text(); + int BoxType = m_pBoxType->currentIndex(); + + wizard()->restart(); + + m_pBoxName->setText(BoxName); + m_pBoxType->setCurrentIndex(BoxType); + } +} + +int CBoxTypePage::nextId() const +{ + if (!m_pAdvanced->isChecked()) { + if(m_bInstant) + return -1; + return CNewBoxWizard::Page_Summary; + } + return CNewBoxWizard::Page_Files; +} + +bool CBoxTypePage::isComplete() const +{ + return true; +} + +bool CBoxTypePage::validatePage() +{ + QString BoxName = field("boxName").toString(); + if (!theGUI->GetBoxView()->TestNameAndWarn(BoxName)) + return false; + + if (m_bInstant && !m_pAdvanced->isChecked()) + return !((CNewBoxWizard*)wizard())->TryToCreateBox().IsError(); + return true; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// CFilesPage +// + +CFilesPage::CFilesPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Sandbox location and behavioure")); + setSubTitle(tr("On this page the sandbox location and its behaviorue can be customized.\nYou can use %USER% to save each users sandbox to an own fodler.")); + + int row = 0; + QGridLayout *layout = new QGridLayout; + + QLabel* pFileLabel = new QLabel(tr("Sandboxed Files"), this); + QFont fnt = pFileLabel->font(); + fnt.setBold(true); + //fnt.setWeight(QFont::DemiBold); + pFileLabel->setFont(fnt); + layout->addWidget(pFileLabel, row++, 0); + layout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2, 1, 1); + + + // Location + QLineEdit* pDummy = new QLineEdit(); + pDummy->setVisible(false); + layout->addWidget(pDummy, row, 0); + registerField("boxLocation", pDummy); + + QHBoxLayout* pLayout = new QHBoxLayout(); + pLayout->setContentsMargins(0,0,0,0); + m_pBoxLocation = new QComboBox(); + m_pBoxLocation->setEditable(true); + pLayout->addWidget(m_pBoxLocation); + QPushButton* pButton = new QPushButton("..."); + pButton->setMaximumWidth(25); + connect(pButton, &QPushButton::clicked, [&]() { + QString FilePath = QFileDialog::getExistingDirectory(this, tr("Select Directory")); + if (!FilePath.isEmpty()) + this->m_pBoxLocation->setCurrentText(FilePath.replace("/", "\\")); + }); + pLayout->addWidget(pButton); + layout->addLayout(pLayout, row++, 1, 1, 3); + // + + QLabel* pVersionLbl = new QLabel(tr("Virtualization scheme"), this); + layout->addWidget(pVersionLbl, row, 1); + + QComboBox* pVersion = new QComboBox(); + pVersion->addItem(tr("Version 1")); + pVersion->addItem(tr("Version 2")); + layout->addWidget(pVersion, row++, 2); + pVersion->setCurrentIndex(theConf->GetInt("BoxDefaults/BoxScheme", 2) - 1); // V2 default + layout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 3, 1, 1); + registerField("boxVersion", pVersion); + + QCheckBox* pUserFolders = new QCheckBox(tr("Separate user folders")); + pUserFolders->setChecked(theConf->GetBool("BoxDefaults/SeparateUser", true)); + layout->addWidget(pUserFolders, row++, 2, 1, 2); + registerField("separateUser", pUserFolders); + + QCheckBox* pUseVolumeSN = new QCheckBox(tr("Use volume serial numbers for drives")); + pUseVolumeSN->setChecked(theConf->GetBool("BoxDefaults/UseVolumeSN", false)); + layout->addWidget(pUseVolumeSN, row++, 2, 1, 2); + registerField("useVolumeSN", pUseVolumeSN); + + QCheckBox* pAutoDelete = new QCheckBox(tr("Auto delete content when last process terminates")); + pAutoDelete->setChecked(theConf->GetBool("BoxDefaults/AutoDelete", false)); + layout->addWidget(pAutoDelete, row++, 1, 1, 3); + registerField("autoDelete", pAutoDelete); + + QCheckBox* pAutoRecover = new QCheckBox(tr("Enable Immediate Recovery of files from recovery locations")); + pAutoRecover->setChecked(theConf->GetBool("BoxDefaults/AutoRecover", true)); + layout->addWidget(pAutoRecover, row++, 1, 1, 3); + registerField("autoRecover", pAutoRecover); + + + setLayout(layout); + + + int size = 16.0; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + size *= (QApplication::desktop()->logicalDpiX() / 96.0); // todo Qt6 +#endif + AddIconToLabel(pFileLabel, CSandMan::GetIcon("Folder").pixmap(size,size)); +} + +int CFilesPage::nextId() const +{ + return CNewBoxWizard::Page_Advanced; +} + +void CFilesPage::initializePage() +{ + m_pBoxLocation->clear(); + QString Location = theAPI->GetGlobalSettings()->GetText("FileRootPath", "\\??\\%SystemDrive%\\Sandbox\\%USER%\\%SANDBOX%"); + m_pBoxLocation->addItem(Location/*.replace("%SANDBOX%", field("boxName").toString())*/); +} + +bool CFilesPage::validatePage() +{ + QString Location = m_pBoxLocation->currentText(); + if (Location == m_pBoxLocation->itemText(0)) + wizard()->setField("boxLocation", ""); + else { + if (Location.mid(2).contains(QRegularExpression("[ <>:\"/\\|?*\\[\\]]"))){ + QMessageBox::critical(this, "Sandboxie-Plus", tr("The sellected box location is not a valid path.")); + return false; + } + QDir Dir(Location); + if (Dir.exists() && !Dir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty()) { + if(QMessageBox::warning(this, "Sandboxie-Plus", tr("The sellected box location exists and is not empty, it is recomended to pick a new or empty folder. " + "Are you sure you want to use an existing folder?"), QDialogButtonBox::Yes, QDialogButtonBox::No) != QDialogButtonBox::Yes) + return false; + } + if (!QDir().exists(Location.left(3))) { + QMessageBox::critical(this, "Sandboxie-Plus", tr("The sellected box location not placed on a currently available drive.")); + return false; + } + wizard()->setField("boxLocation", Location); + } + return true; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// CAdvancedPage +// + +CAdvancedPage::CAdvancedPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Advanced Sandbox options")); + setSubTitle(tr("On this page advanced sandbox options can be configured.")); + + int row = 0; + QGridLayout *layout = new QGridLayout; + + QLabel* pNetLabel = new QLabel(tr("Network Access"), this); + QFont fnt = pNetLabel->font(); + fnt.setBold(true); + //fnt.setWeight(QFont::DemiBold); + pNetLabel->setFont(fnt); + layout->addWidget(pNetLabel, row++, 0); + + QComboBox* pNetAccess = new QComboBox(); + pNetAccess->addItem(tr("Allow network/internet access")); + pNetAccess->addItem(tr("Block network/internet by denying access to Network devices")); + if (theAPI->GetGlobalSettings()->GetBool("NetworkEnableWFP", false)) + pNetAccess->addItem(tr("Block network/internet using Windows Filtering Platform")); + pNetAccess->setCurrentIndex(theConf->GetInt("BoxDefaults/BlockNetwork", 0)); + layout->addWidget(pNetAccess, row++, 1, 1, 3); + registerField("blockNetwork", pNetAccess); + + m_pShareAccess = new QCheckBox(tr("Allow access to network files and fodlers")); + m_pShareAccess->setToolTip(tr("This option is not recomended for Hardened boxes")); + m_pShareAccess->setChecked(theConf->GetBool("BoxDefaults/ShareAccess", false)); + layout->addWidget(m_pShareAccess, row++, 1, 1, 3); + registerField("shareAccess", m_pShareAccess); + + + QLabel* pAdminLabel = new QLabel(tr("Admin Options"), this); + pAdminLabel->setFont(fnt); + layout->addWidget(pAdminLabel, row++, 0); + + QCheckBox* pFakeAdmin = new QCheckBox(tr("Make applications think they are running elevated")); + pFakeAdmin->setChecked(theConf->GetBool("BoxDefaults/FakeAdmin", false)); + layout->addWidget(pFakeAdmin, row++, 1, 1, 3); + registerField("fakeAdmin", pFakeAdmin); + + m_pMSIServer = new QCheckBox(tr("Allow MSIServer to run with a sandboxed system token")); + m_pMSIServer->setToolTip(tr("This option is not recomended for Hardened boxes")); + m_pMSIServer->setChecked(theConf->GetBool("BoxDefaults/MsiExemptions", false)); + layout->addWidget(m_pMSIServer, row++, 1, 1, 3); + registerField("msiServer", m_pMSIServer); + + setLayout(layout); + + + int size = 16.0; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + size *= (QApplication::desktop()->logicalDpiX() / 96.0); // todo Qt6 +#endif + AddIconToLabel(pNetLabel, CSandMan::GetIcon("Network").pixmap(size,size)); + AddIconToLabel(pAdminLabel, CSandMan::GetIcon("Shield9").pixmap(size,size)); +} + +int CAdvancedPage::nextId() const +{ + return CNewBoxWizard::Page_Summary; +} + +void CAdvancedPage::initializePage() +{ + int BoxType = wizard()->field("boxType").toInt(); + bool bHardened = (BoxType == CSandBoxPlus::eHardenedPlus || BoxType == CSandBoxPlus::eHardened); + m_pMSIServer->setEnabled(!bHardened); + m_pShareAccess->setEnabled(!bHardened); +} + +bool CAdvancedPage::validatePage() +{ + return true; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// CSummaryPage +// + +CSummaryPage::CSummaryPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Create the new Sandbox")); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); + + int row = 0; + QGridLayout *layout = new QGridLayout; + + QLabel* pLabel = new QLabel; + pLabel->setWordWrap(true); + pLabel->setText(tr("Almost complete, click Finish to create a new sandbox and conclude the wizard.")); + layout->addWidget(pLabel, row++ , 0, 1, 3); + + + m_pSummary = new QTextEdit(); + m_pSummary->setReadOnly(true); + m_pSummary->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->addWidget(m_pSummary, row++ , 0, 1, 3); + + m_pSetDefault = new QCheckBox(tr("Save options as new defaults")); + layout->addWidget(m_pSetDefault, row++, 2); + + //QWidget* pSpacer = new QWidget(); + //pSpacer->setMinimumHeight(16); + //layout->addWidget(pSpacer); + + QWidget* pSpacer = new QWidget(); + pSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->addWidget(pSpacer, row++, 1); + + m_pSetInstant = new QCheckBox(tr("Don't show the summary page in future (unless advanced options were set)")); + m_pSetInstant->setChecked(theConf->GetBool("Options/InstantBoxWizard", false)); + layout->addWidget(m_pSetInstant, row++, 1, 1, 2); + + setLayout(layout); +} + +int CSummaryPage::nextId() const +{ + return -1; +} + +void CSummaryPage::initializePage() +{ + m_pSummary->setText(theGUI->GetBoxDescription(wizard()->field("boxType").toInt())); + + QString Location = field("boxLocation").toString(); + if (Location.isEmpty()) + Location = ((CNewBoxWizard*)wizard())->GetDefaultLocation(); + m_pSummary->append(tr("\nThis Sandbox will be saved to: %1").arg(Location)); + + if (field("autoDelete").toBool()) + m_pSummary->append(tr("\nThis box will DISCARD its content when its closed, its suitable only for temporary data.")); + if (field("blockNetwork").toInt()) + m_pSummary->append(tr("\nProcesses in this box will not be able to access the internet or the local network, this ensures all accessed data to stay confidential.")); + if (field("msiServer").toBool()) + m_pSummary->append(tr("\nThis box will run the MSIServer (*.msi installer service) with a system token, this improves the compatybility but reduces the security isolation.")); + else if(field("fakeAdmin").toBool()) + m_pSummary->append(tr("\nProcesses in this box will think they are run with administrative privileges, without actually having them, hence installers can be used even in a security hardened box.")); + + m_pSetDefault->setVisible(((CNewBoxWizard*)wizard())->m_bAdvanced); +} + +bool CSummaryPage::validatePage() +{ + if (m_pSetDefault->isChecked()) + { + theConf->SetValue("BoxDefaults/BoxScheme", field("boxVersion").toInt() + 1); + theConf->SetValue("BoxDefaults/SeparateUser", field("separateUser").toBool()); + theConf->SetValue("BoxDefaults/UseVolumeSN", field("useVolumeSN").toBool()); + + + theConf->SetValue("BoxDefaults/AutoDelete", field("autoDelete").toBool()); + theConf->SetValue("BoxDefaults/AutoRecover", field("autoRecover").toBool()); + + theConf->SetValue("BoxDefaults/BlockNetwork", field("blockNetwork").toInt()); + theConf->SetValue("BoxDefaults/ShareAccess", field("shareAccess").toBool()); + + theConf->SetValue("BoxDefaults/FakeAdmin", field("fakeAdmin").toBool()); + theConf->SetValue("BoxDefaults/MsiExemptions", field("msiServer").toBool()); + } + + theConf->SetValue("Options/InstantBoxWizard", m_pSetInstant->isChecked()); + + SB_STATUS Status = ((CNewBoxWizard*)wizard())->TryToCreateBox(); + if (Status.IsError()) { + QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to create new box: %1").arg(theGUI->FormatError(Status))); + return false; + } + return true; +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Wizards/NewBoxWizard.h b/SandboxiePlus/SandMan/Wizards/NewBoxWizard.h new file mode 100644 index 00000000..d266c41b --- /dev/null +++ b/SandboxiePlus/SandMan/Wizards/NewBoxWizard.h @@ -0,0 +1,130 @@ +#pragma once + +#include +#include "../../QSbieAPI/SbieStatus.h" + +QT_BEGIN_NAMESPACE +class QCheckBox; +class QLabel; +class QLineEdit; +class QRadioButton; +QT_END_NAMESPACE + +class CNewBoxWizard : public QWizard +{ + Q_OBJECT + +public: + enum { Page_Type, Page_Files, Page_Advanced, Page_Summary }; + + CNewBoxWizard(QWidget *parent = nullptr); + + static QString CreateNewBox(QWidget* pParent = NULL); + + QString GetDefaultLocation(); + +private slots: + void showHelp(); + +protected: + friend class CBoxTypePage; + friend class CSummaryPage; + + SB_STATUS TryToCreateBox(); + + bool m_bAdvanced; +}; + + +////////////////////////////////////////////////////////////////////////////////////////// +// CBoxTypePage +// + +class CBoxTypePage : public QWizardPage +{ + Q_OBJECT + +public: + CBoxTypePage(QWidget *parent = nullptr); + + int nextId() const override; + bool isComplete() const override; + bool validatePage() override; + +private slots: + void OnBoxTypChanged(); + void OnAdvanced(); + +private: + QComboBox* m_pBoxType; + QLabel* m_pInfoLabel; + QLineEdit* m_pBoxName; + QCheckBox* m_pAdvanced; + + bool m_bInstant; +}; + + +////////////////////////////////////////////////////////////////////////////////////////// +// CFilesPage +// + +class CFilesPage : public QWizardPage +{ + Q_OBJECT + +public: + CFilesPage(QWidget *parent = nullptr); + + int nextId() const override; + void initializePage() override; + bool validatePage() override; + +private: + QComboBox* m_pBoxLocation; +}; + + +////////////////////////////////////////////////////////////////////////////////////////// +// CAdvancedPage +// + +class CAdvancedPage : public QWizardPage +{ + Q_OBJECT + +public: + CAdvancedPage(QWidget *parent = nullptr); + + int nextId() const override; + void initializePage() override; + bool validatePage() override; + +private: + QCheckBox* m_pShareAccess; + QCheckBox* m_pMSIServer; +}; + + +////////////////////////////////////////////////////////////////////////////////////////// +// CSummaryPage +// + +class CSummaryPage : public QWizardPage +{ + Q_OBJECT + +public: + CSummaryPage(QWidget *parent = nullptr); + + int nextId() const override; + void initializePage() override; + bool validatePage() override; + +private: + QTextEdit* m_pSummary; + QCheckBox* m_pSetDefault; + QCheckBox* m_pSetInstant; +}; + +