This commit is contained in:
DavidXanatos 2022-01-30 15:53:37 +01:00
parent 45152ce01d
commit d34731c1ab
17 changed files with 309 additions and 107 deletions

View File

@ -3,16 +3,19 @@ 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/).
## [1.0.9 / 5.55.9] - 2022-01-?? ## [1.0.9 / 5.55.9] - 2022-01-31
### Added ### Added
- sandman now causes all boxed processes to update thair path settings in real time when access options were modified - sandman now causes all boxed processes to update thair path settings in real time when access options were modified
- added new maintenance meu option Uninstal All to quickly remove all components when runnign in portable mode - added new maintenance meu option Uninstal All to quickly remove all components when runnign in portable mode
- added option to return not to a snapshot but to an empty box state while keeping all snapshots
- Sandboxie-Plus.ini can now be placed in C:\ProgramData\Sandboxie-Plus\ folder and takes precedence (for business use)
### Changed ### Changed
- reworked breakout mechanism to be service based and not alow the parent process to access the broken out child process - reworked breakout mechanism to be service based and not alow the parent process to access the broken out child process
- enabled creatin of directory junctions for sandboxed processes [#1375](https://github.com/sandboxie-plus/Sandboxie/issues/1375) - enabled creatin of directory junctions for sandboxed processes [#1375](https://github.com/sandboxie-plus/Sandboxie/issues/1375)
- changed back to set AutoRecover=y on box creation [#1554](https://github.com/sandboxie-plus/Sandboxie/discussions/1554) - changed back to set AutoRecover=y on box creation [#1554](https://github.com/sandboxie-plus/Sandboxie/discussions/1554)
- improved snapshot support [#1220](https://github.com/sandboxie-plus/Sandboxie/issues/1220)
### Fixed ### Fixed
- fixed BreakoutProcess not working with EnableObjectFiltering=y - fixed BreakoutProcess not working with EnableObjectFiltering=y
@ -23,6 +26,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- fixed border issues on maximized windows introduced in the last build [#1561](https://github.com/sandboxie-plus/Sandboxie/issues/1561) - fixed border issues on maximized windows introduced in the last build [#1561](https://github.com/sandboxie-plus/Sandboxie/issues/1561)
- fixed a couple if index overruns (thanks 7eRoM) - fixed a couple if index overruns (thanks 7eRoM)
- fixed issues with sysnative directroy [#1403](https://github.com/sandboxie-plus/Sandboxie/issues/1403) - fixed issues with sysnative directroy [#1403](https://github.com/sandboxie-plus/Sandboxie/issues/1403)
- fixed issue with starting sandman when running sandboxed from context menu [#1579](https://github.com/sandboxie-plus/Sandboxie/issues/1579)
- fixed dark mode flash issue with main window creation
- fixed issues with snapshot error handling

View File

@ -12,7 +12,7 @@ bool TestWriteRight(const QString& Path)
return TestFile.remove(); return TestFile.remove();
} }
CSettings::CSettings(const QString& AppName, QMap<QString, SSetting> DefaultValues, QObject* qObject) : QObject(qObject) CSettings::CSettings(const QString& AppName, bool bShared, QMap<QString, SSetting> DefaultValues, QObject* qObject) : QObject(qObject)
{ {
m_ConfigDir = QCoreApplication::applicationDirPath(); m_ConfigDir = QCoreApplication::applicationDirPath();
if (!(m_bPortable = QFile::exists(m_ConfigDir + "/" + AppName + ".ini"))) if (!(m_bPortable = QFile::exists(m_ConfigDir + "/" + AppName + ".ini")))
@ -20,8 +20,17 @@ CSettings::CSettings(const QString& AppName, QMap<QString, SSetting> DefaultValu
QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
if (dirs.isEmpty()) if (dirs.isEmpty())
m_ConfigDir = QDir::homePath() + "/." + AppName; m_ConfigDir = QDir::homePath() + "/." + AppName;
//
// if shared is set a new ini is created in the shared location
// and if present take precedence over an ini in a user location
// howeever if the only existing ini is in a user location it will be used
//
else if(bShared && dirs.count() > 2 && (
QFile::exists(dirs[1] + "/" + AppName + "/" + AppName + ".ini") ||
!QFile::exists(dirs[0] + "/" + AppName + "/" + AppName + ".ini") ))
m_ConfigDir = dirs[1] + "/" + AppName;
else else
m_ConfigDir = dirs.first() + "/" + AppName; m_ConfigDir = dirs[0] + "/" + AppName;
QDir().mkpath(m_ConfigDir); QDir().mkpath(m_ConfigDir);
} }

View File

@ -97,7 +97,7 @@ public:
virtual bool IsBlob() const {return true;} virtual bool IsBlob() const {return true;}
}; };
CSettings(const QString& AppName, QMap<QString, SSetting> DefaultValues = QMap<QString, SSetting>(), QObject* qObject = NULL); CSettings(const QString& AppName, bool bShared = false, QMap<QString, SSetting> DefaultValues = QMap<QString, SSetting>(), QObject* qObject = NULL);
virtual ~CSettings(); virtual ~CSettings();
bool SetValue(const QString& key, const QVariant& value); bool SetValue(const QString& key, const QVariant& value);

View File

@ -51,7 +51,7 @@ CSandBox::CSandBox(const QString& BoxName, class CSbieAPI* pAPI) : CSbieIni(BoxN
if (cfglvl == 0) if (cfglvl == 0)
{ {
SetBool("AutoRecover", false); SetBool("AutoRecover", true);
SetBool("BlockNetworkFiles", true); SetBool("BlockNetworkFiles", true);
// recovery // recovery
@ -235,7 +235,7 @@ SB_STATUS CSandBox::RemoveBox()
return RemoveSection(); return RemoveSection();
} }
QList<SBoxSnapshot> CSandBox::GetSnapshots(QString* pCurrent) const QList<SBoxSnapshot> CSandBox::GetSnapshots(QString* pCurrent, QString* pDefault) const
{ {
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat); QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
@ -259,12 +259,65 @@ QList<SBoxSnapshot> CSandBox::GetSnapshots(QString* pCurrent) const
if(pCurrent) if(pCurrent)
*pCurrent = ini.value("Current/Snapshot").toString(); *pCurrent = ini.value("Current/Snapshot").toString();
if(pDefault)
*pDefault = ini.value("Current/Default").toString();
return Snapshots; return Snapshots;
} }
void CSandBox::SetDefaultSnapshot(QString Default)
{
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
ini.setValue("Current/Default", Default);
ini.sync();
}
QString CSandBox::GetDefaultSnapshot(QString* pCurrent) const
{
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
if(pCurrent)
*pCurrent = ini.value("Current/Snapshot").toString();
return ini.value("Current/Default").toString();
}
QStringList CSandBox__BoxSubFolders = QStringList() << "drive" << "user" << "share"; QStringList CSandBox__BoxSubFolders = QStringList() << "drive" << "user" << "share";
struct SBoxDataFile
{
SBoxDataFile(QString name, bool required, bool recursive) : Name(name), Required(required), Recursive(recursive) {}
QString Name;
bool Required; // fail on fail
bool Recursive;
};
QList<SBoxDataFile> CSandBox__BoxDataFiles = QList<SBoxDataFile>()
<< SBoxDataFile("RegHive", true, false)
;
bool CSandBox::IsInitialized() const
{
if (IsEmpty())
return false;
foreach(const QString & BoxSubFolder, CSandBox__BoxSubFolders) {
if (QDir(m_FilePath + "\\" + BoxSubFolder).exists())
return true;
}
foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles) {
if (BoxDataFile.Required && QFile::exists(m_FilePath + "\\" + BoxDataFile.Name))
return true;
}
return false;
}
bool CSandBox::HasSnapshots() const
{
return QFile::exists(m_FilePath + "\\Snapshots.ini");
}
SB_STATUS CSandBox__MoveFolder(const QString& SourcePath, const QString& ParentFolder, const QString& TargetName) SB_STATUS CSandBox__MoveFolder(const QString& SourcePath, const QString& ParentFolder, const QString& TargetName)
{ {
SNtObject src_dir(L"\\??\\" + SourcePath.toStdWString()); SNtObject src_dir(L"\\??\\" + SourcePath.toStdWString());
@ -282,7 +335,7 @@ SB_PROGRESS CSandBox::TakeSnapshot(const QString& Name)
if (m_pAPI->HasProcesses(m_Name)) if (m_pAPI->HasProcesses(m_Name))
return SB_ERR(SB_SnapIsRunning, OP_CONFIRM); return SB_ERR(SB_SnapIsRunning, OP_CONFIRM);
if (IsEmpty()) if (!IsInitialized())
return SB_ERR(SB_SnapIsEmpty); return SB_ERR(SB_SnapIsEmpty);
QStringList Snapshots = ini.childGroups(); QStringList Snapshots = ini.childGroups();
@ -295,10 +348,18 @@ SB_PROGRESS CSandBox::TakeSnapshot(const QString& Name)
break; break;
} }
if (!QDir().mkdir(m_FilePath + "\\snapshot-" + ID)) if (!QDir().mkpath(m_FilePath + "\\snapshot-" + ID))
return SB_ERR(SB_SnapMkDirFail); return SB_ERR(SB_SnapMkDirFail);
if (!QFile::copy(m_FilePath + "\\RegHive", m_FilePath + "\\snapshot-" + ID + "\\RegHive"))
return SB_ERR(SB_SnapCopyDatFail); foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles)
{
if (!QFile::copy(m_FilePath + "\\" + BoxDataFile.Name, m_FilePath + "\\snapshot-" + ID + "\\" + BoxDataFile.Name)) {
if (BoxDataFile.Required)
return SB_ERR(SB_SnapCopyDatFail);
}
else if (BoxDataFile.Required) // this one is incremental, hence delete it from the copy root, after it was copied to the snapshot
QFile::remove(m_FilePath + "\\" + BoxDataFile.Name);
}
ini.setValue("Snapshot_" + ID + "/Name", Name); ini.setValue("Snapshot_" + ID + "/Name", Name);
ini.setValue("Snapshot_" + ID + "/SnapshotDate", QDateTime::currentDateTime().toTime_t()); ini.setValue("Snapshot_" + ID + "/SnapshotDate", QDateTime::currentDateTime().toTime_t());
@ -400,14 +461,18 @@ SB_STATUS CSandBox__MergeFolders(const CSbieProgressPtr& pProgress, const QStrin
SB_STATUS CSandBox__CleanupSnapshot(const QString& Folder) SB_STATUS CSandBox__CleanupSnapshot(const QString& Folder)
{ {
SNtObject ntHiveFile(L"\\??\\" + (Folder + "\\RegHive").toStdWString()); foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles)
SB_STATUS status = NtDeleteFile(&ntHiveFile.attr); {
if (NT_SUCCESS(status)) { SNtObject ntHiveFile(L"\\??\\" + (Folder + "\\" + BoxDataFile.Name).toStdWString());
SNtObject ntSnapshotFile(L"\\??\\" + Folder.toStdWString()); SB_STATUS status = NtDeleteFile(&ntHiveFile.attr);
status = NtDeleteFile(&ntSnapshotFile.attr); if (NT_SUCCESS(status)) {
SNtObject ntSnapshotFile(L"\\??\\" + Folder.toStdWString());
status = NtDeleteFile(&ntSnapshotFile.attr);
}
if(BoxDataFile.Required)
if (!NT_SUCCESS(status))
return SB_ERR(SB_SnapRmDirFail, QVariantList() << Folder, status);
} }
if (!NT_SUCCESS(status))
return SB_ERR(SB_SnapRmDirFail, QVariantList() << Folder, status);
return SB_OK; return SB_OK;
} }
@ -485,16 +550,30 @@ SB_PROGRESS CSandBox::SelectSnapshot(const QString& ID)
{ {
QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat); QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat);
if (!ini.childGroups().contains("Snapshot_" + ID)) if (!ID.isEmpty() && !ini.childGroups().contains("Snapshot_" + ID))
return SB_ERR(SB_SnapNotFound); return SB_ERR(SB_SnapNotFound);
if (m_pAPI->HasProcesses(m_Name)) if (m_pAPI->HasProcesses(m_Name))
return SB_ERR(SB_SnapIsRunning, OP_CONFIRM); return SB_ERR(SB_SnapIsRunning, OP_CONFIRM);
if (!QFile::remove(m_FilePath + "\\RegHive")) foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles)
return SB_ERR(SB_SnapDelDatFail); {
if (!QFile::copy(m_FilePath + "\\snapshot-" + ID + "\\RegHive", m_FilePath + "\\RegHive")) if (!QFile::exists(m_FilePath + "\\" + BoxDataFile.Name))
return SB_ERR(SB_SnapCopyDatFail); continue;
if (!QFile::remove(m_FilePath + "\\" + BoxDataFile.Name)) {
if (BoxDataFile.Required)
return SB_ERR(SB_SnapDelDatFail);
}
if (ID.isEmpty() || BoxDataFile.Recursive)
continue; // this one is incremental, don't restore it
if (!QFile::copy(m_FilePath + "\\snapshot-" + ID + "\\" + BoxDataFile.Name, m_FilePath + "\\" + BoxDataFile.Name)) {
if (BoxDataFile.Required)
return SB_ERR(SB_SnapCopyDatFail);
}
}
ini.setValue("Current/Snapshot", ID); ini.setValue("Current/Snapshot", ID);
ini.sync(); ini.sync();

View File

@ -59,11 +59,15 @@ public:
virtual bool IsEnabled() const { return m_IsEnabled; } virtual bool IsEnabled() const { return m_IsEnabled; }
virtual bool IsEmpty() const; virtual bool IsEmpty() const;
virtual bool IsInitialized() const;
virtual bool HasSnapshots() const;
virtual SB_PROGRESS 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();
virtual QList<SBoxSnapshot> GetSnapshots(QString* pCurrent = NULL) const; virtual QList<SBoxSnapshot> GetSnapshots(QString* pCurrent = NULL, QString* pDefault = NULL) const;
virtual void SetDefaultSnapshot(QString Default);
virtual QString GetDefaultSnapshot(QString* pCurrent = NULL) const;
virtual SB_PROGRESS TakeSnapshot(const QString& Name); virtual SB_PROGRESS TakeSnapshot(const QString& Name);
virtual SB_PROGRESS RemoveSnapshot(const QString& ID); virtual SB_PROGRESS RemoveSnapshot(const QString& ID);
virtual SB_PROGRESS SelectSnapshot(const QString& ID); virtual SB_PROGRESS SelectSnapshot(const QString& ID);

View File

@ -91,19 +91,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="3">
<widget class="QPushButton" name="btnDeleteAll">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Delete all</string>
</property>
</widget>
</item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="chkShowAll"> <widget class="QCheckBox" name="chkShowAll">
<property name="text"> <property name="text">
@ -154,6 +141,25 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="3">
<widget class="QToolButton" name="btnDeleteAll">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>75</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Delete Content</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -163,7 +169,6 @@
<tabstops> <tabstops>
<tabstop>treeFiles</tabstop> <tabstop>treeFiles</tabstop>
<tabstop>chkShowAll</tabstop> <tabstop>chkShowAll</tabstop>
<tabstop>btnDeleteAll</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -60,12 +60,8 @@
<string>Selected Snapshot Details</string> <string>Selected Snapshot Details</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0"> <item row="0" column="1">
<widget class="QLabel" name="label"> <widget class="QLineEdit" name="txtName"/>
<property name="text">
<string>Name:</string>
</property>
</widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
@ -77,11 +73,25 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1" rowspan="2"> <item row="0" column="0">
<widget class="QPlainTextEdit" name="txtInfo"/> <widget class="QLabel" name="label">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="2">
<widget class="QLineEdit" name="txtName"/> <widget class="QCheckBox" name="chkDefault">
<property name="toolTip">
<string>When deleting a snapshots content, it will be returned to this snapshot instead of to none.</string>
</property>
<property name="text">
<string>Default shapsnot</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2" colspan="2">
<widget class="QPlainTextEdit" name="txtInfo"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -98,20 +108,6 @@
<string>Snapshot Actions</string> <string>Snapshot Actions</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="0">
<widget class="QPushButton" name="btnRemove">
<property name="text">
<string>Remove Snapshot</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="btnSelect">
<property name="text">
<string>Go to Snapshot</string>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QPushButton" name="btnTake"> <widget class="QPushButton" name="btnTake">
<property name="text"> <property name="text">
@ -132,6 +128,32 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="3" column="0">
<widget class="QPushButton" name="btnRemove">
<property name="text">
<string>Remove Snapshot</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QToolButton" name="btnSelect">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Go to Snapshot</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -147,7 +169,6 @@
<tabstops> <tabstops>
<tabstop>btnTake</tabstop> <tabstop>btnTake</tabstop>
<tabstop>treeSnapshots</tabstop> <tabstop>treeSnapshots</tabstop>
<tabstop>btnSelect</tabstop>
<tabstop>btnRemove</tabstop> <tabstop>btnRemove</tabstop>
<tabstop>txtName</tabstop> <tabstop>txtName</tabstop>
<tabstop>txtInfo</tabstop> <tabstop>txtInfo</tabstop>

View File

@ -116,10 +116,6 @@ CSandMan::CSandMan(QWidget *parent)
QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion()); QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion());
if (QFile::exists(QCoreApplication::applicationDirPath() + "\\Certificate.dat")) {
CSettingsWindow::LoadCertificate();
}
this->setWindowTitle(appTitle); this->setWindowTitle(appTitle);
setAcceptDrops(true); setAcceptDrops(true);
@ -303,9 +299,6 @@ CSandMan::CSandMan(QWidget *parent)
m_pProgressDialog->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop); m_pProgressDialog->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
if (!bAutoRun && g_PendingMessage.isEmpty())
show();
//connect(theAPI, SIGNAL(LogMessage(const QString&, bool)), this, SLOT(OnLogMessage(const QString&, bool))); //connect(theAPI, SIGNAL(LogMessage(const QString&, bool)), this, SLOT(OnLogMessage(const QString&, bool)));
connect(theAPI, SIGNAL(LogSbieMessage(quint32, const QStringList&, quint32)), this, SLOT(OnLogSbieMessage(quint32, const QStringList&, quint32))); connect(theAPI, SIGNAL(LogSbieMessage(quint32, const QStringList&, quint32)), this, SLOT(OnLogSbieMessage(quint32, const QStringList&, quint32)));
connect(theAPI, SIGNAL(NotAuthorized(bool, bool&)), this, SLOT(OnNotAuthorized(bool, bool&)), Qt::DirectConnection); connect(theAPI, SIGNAL(NotAuthorized(bool, bool&)), this, SLOT(OnNotAuthorized(bool, bool&)), Qt::DirectConnection);
@ -315,6 +308,9 @@ CSandMan::CSandMan(QWidget *parent)
m_uTimerID = startTimer(1000); m_uTimerID = startTimer(1000);
if (!bAutoRun && g_PendingMessage.isEmpty())
SafeShow(this);
OnStatusChanged(); OnStatusChanged();
if (CSbieUtils::IsRunning(CSbieUtils::eAll) || theConf->GetBool("Options/StartIfStopped", true)) if (CSbieUtils::IsRunning(CSbieUtils::eAll) || theConf->GetBool("Options/StartIfStopped", true))
{ {
@ -899,11 +895,20 @@ void CSandMan::OnBoxClosed(const QString& BoxName)
if (!pBox->GetBool("NeverDelete", false) && pBox->GetBool("AutoDelete", false) && !pBox->IsEmpty()) if (!pBox->GetBool("NeverDelete", false) && pBox->GetBool("AutoDelete", false) && !pBox->IsEmpty())
{ {
bool DeleteShapshots = false;
// if this box auto deletes first show the recovry dialog with the option to abort deletion // if this box auto deletes first show the recovry dialog with the option to abort deletion
if(!theGUI->OpenRecovery(pBox, true)) // unless no files are found than continue silently if(!theGUI->OpenRecovery(pBox, DeleteShapshots, true)) // unless no files are found than continue silently
return; return;
SB_PROGRESS Status = pBox->CleanBox(); SB_PROGRESS Status;
if (!DeleteShapshots && pBox->HasSnapshots()) { // in auto delete mdoe always return to last snapshot
QString Current;
pBox->GetDefaultSnapshot(&Current);
Status = pBox->SelectSnapshot(Current);
}
else // if there are no snapshots jut use the normal cleaning procedure
Status = pBox->CleanBox();
if (Status.GetStatus() == OP_ASYNC) if (Status.GetStatus() == OP_ASYNC)
AddAsyncOp(Status.GetValue()); AddAsyncOp(Status.GetValue());
} }
@ -932,9 +937,10 @@ void CSandMan::OnStatusChanged()
if (isConnected) if (isConnected)
{ {
QString SbiePath = theAPI->GetSbiePath(); QString SbiePath = theAPI->GetSbiePath();
OnLogMessage(tr("Sbie Directory: %1").arg(SbiePath)); OnLogMessage(tr("Installation Directory: %1").arg(SbiePath));
OnLogMessage(tr("Sbie+ Version: %1 (%2)").arg(GetVersion()).arg(theAPI->GetVersion())); OnLogMessage(tr("Sandboxie-Plus Version: %1 (%2)").arg(GetVersion()).arg(theAPI->GetVersion()));
OnLogMessage(tr("Loaded Config: %1").arg(theAPI->GetIniPath())); OnLogMessage(tr("Loaded Config: %1").arg(theAPI->GetIniPath()));
OnLogMessage(tr("Data Directory: %1").arg(QString(theConf->GetConfigDir()).replace("/","\\")));
//statusBar()->showMessage(tr("Driver version: %1").arg(theAPI->GetVersion())); //statusBar()->showMessage(tr("Driver version: %1").arg(theAPI->GetVersion()));
@ -1006,6 +1012,10 @@ void CSandMan::OnStatusChanged()
else { else {
g_Certificate.clear(); g_Certificate.clear();
g_CertInfo.State = 0; g_CertInfo.State = 0;
QString CertPath = QCoreApplication::applicationDirPath() + "\\Certificate.dat";
if(QFile::exists(CertPath)) // always delete invalid certificates
WindowsMoveFile(CertPath.replace("/", "\\"), "");
} }
g_FeatureFlags = theAPI->GetFeatureFlags(); g_FeatureFlags = theAPI->GetFeatureFlags();
@ -1237,7 +1247,7 @@ void CSandMan::OnFileToRecover(const QString& BoxName, const QString& FilePath,
m_pPopUpWindow->AddFileToRecover(FilePath, BoxPath, pBox, ProcessId); m_pPopUpWindow->AddFileToRecover(FilePath, BoxPath, pBox, ProcessId);
} }
bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool bCloseEmpty) bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool bCloseEmpty)
{ {
auto pBoxEx = pBox.objectCast<CSandBoxPlus>(); auto pBoxEx = pBox.objectCast<CSandBoxPlus>();
if (pBoxEx->m_pRecoveryWnd != NULL) { if (pBoxEx->m_pRecoveryWnd != NULL) {
@ -1251,6 +1261,7 @@ bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool bCloseEmpty)
} }
else if (pRecoveryWindow->exec() != 1) else if (pRecoveryWindow->exec() != 1)
return false; return false;
DeleteShapshots = pRecoveryWindow->IsDeleteShapshots();
return true; return true;
} }

View File

@ -122,7 +122,7 @@ public slots:
void OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data); void OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data);
void OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId); void OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId);
bool OpenRecovery(const CSandBoxPtr& pBox, bool bCloseEmpty = false); bool OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool bCloseEmpty = false);
class CRecoveryWindow* ShowRecovery(const CSandBoxPtr& pBox, bool bFind = true); class CRecoveryWindow* ShowRecovery(const CSandBoxPtr& pBox, bool bFind = true);
void UpdateSettings(); void UpdateSettings();

View File

@ -911,6 +911,9 @@ void CSbieView::OnSandBoxAction(QAction* Action)
{ {
for (QList<QPair<QString, QString>>::iterator I = Settings.begin(); I != Settings.end(); ++I) for (QList<QPair<QString, QString>>::iterator I = Settings.begin(); I != Settings.end(); ++I)
{ {
if (I->first == "FileRootPath" && !I->second.toUpper().contains("%SANDBOX%"))
continue; // skip the FileRootPath if it does not contain a %SANDBOX%
Status = theAPI->SbieIniSet(Name, I->first, I->second, CSbieAPI::eIniInsert, false); Status = theAPI->SbieIniSet(Name, I->first, I->second, CSbieAPI::eIniInsert, false);
if (Status.IsError()) if (Status.IsError())
break; break;
@ -957,6 +960,8 @@ void CSbieView::OnSandBoxAction(QAction* Action)
} }
else if (Action == m_pMenuCleanUp) else if (Action == m_pMenuCleanUp)
{ {
bool DeleteShapshots = false;
if (SandBoxes.count() == 1) if (SandBoxes.count() == 1)
{ {
if (SandBoxes.first()->IsEmpty()) { if (SandBoxes.first()->IsEmpty()) {
@ -967,18 +972,27 @@ void CSbieView::OnSandBoxAction(QAction* Action)
if (theConf->GetBool("Options/ShowRecovery", false)) if (theConf->GetBool("Options/ShowRecovery", false))
{ {
// Use recovery dialog in place of the confirmation messagebox for box clean up // Use recovery dialog in place of the confirmation messagebox for box clean up
if(!theGUI->OpenRecovery(SandBoxes.first())) if(!theGUI->OpenRecovery(SandBoxes.first(), DeleteShapshots))
return; return;
} }
else if(QMessageBox("Sandboxie-Plus", tr("Do you want to delete the content of the selected sandbox?"), QMessageBox::Question, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) else if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to delete the content of the selected sandbox?")
return; , tr("Also delete all Snapshots"), &DeleteShapshots, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes)
return;
} }
else if (QMessageBox("Sandboxie-Plus", tr("Do you really want to delete the content of multiple sandboxes?"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) else if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you really want to delete the content of all sellected sandboxes?")
return; , tr("Also delete all Snapshots"), &DeleteShapshots, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes)
return;
foreach(const CSandBoxPtr & pBox, SandBoxes) foreach(const CSandBoxPtr & pBox, SandBoxes)
{ {
SB_PROGRESS Status = pBox->CleanBox(); SB_PROGRESS Status;
if (!DeleteShapshots && pBox->HasSnapshots()) {
QString Default = pBox->GetDefaultSnapshot();
Status = pBox->SelectSnapshot(Default);
}
else // if there are no snapshots jut use the normal cleaning procedure
Status = pBox->CleanBox();
if (Status.GetStatus() == OP_ASYNC) if (Status.GetStatus() == OP_ASYNC)
theGUI->AddAsyncOp(Status.GetValue()); theGUI->AddAsyncOp(Status.GetValue());
else if (Status.IsError()) else if (Status.IsError())
@ -991,7 +1005,7 @@ void CSbieView::OnSandBoxAction(QAction* Action)
{ {
bool State = false; bool State = false;
if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to terminate all processes in the selected sandbox(es)?") if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to terminate all processes in the selected sandbox(es)?")
, tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) != QDialogButtonBox::Yes) , tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes)
return; return;
if (State) if (State)
@ -1067,7 +1081,7 @@ void CSbieView::OnProcessAction()
bool State = false; bool State = false;
if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to %1 %2?").arg(((QAction*)sender())->text().toLower()).arg(Processes.count() == 1 ? Processes[0]->GetProcessName() : tr("the selected processes")) if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to %1 %2?").arg(((QAction*)sender())->text().toLower()).arg(Processes.count() == 1 ? Processes[0]->GetProcessName() : tr("the selected processes"))
, tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) != QDialogButtonBox::Yes) , tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes)
return; return;
if (State) if (State)
@ -1243,21 +1257,6 @@ QList<CBoxedProcessPtr> CSbieView::GetSelectedProcesses()
return List; return List;
} }
/*void CSbieView::UpdateRunMenu()
{
while (m_iMenuRun < m_pMenuRun->actions().count())
m_pMenuRun->removeAction(m_pMenuRun->actions().at(m_iMenuRun));
QStringList RunOptions = theConf->ListKeys("RunOptions");
foreach(const QString& RunOption, RunOptions)
{
StrPair NameCmd = Split2(theConf->GetString("RunOptions/" + RunOption), "|");
QAction* pAction = m_pMenuRun->addAction(NameCmd.first, this, SLOT(OnSandBoxAction()));
pAction->setData(NameCmd.second);
}
}*/
void CSbieView::UpdateRunMenu(const CSandBoxPtr& pBox) void CSbieView::UpdateRunMenu(const CSandBoxPtr& pBox)
{ {
while (m_iMenuRun < m_pMenuRun->actions().count()) while (m_iMenuRun < m_pMenuRun->actions().count())

View File

@ -49,6 +49,7 @@ CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent)
m_LastTargetIndex = 0; m_LastTargetIndex = 0;
m_bTargetsChanged = false; m_bTargetsChanged = false;
m_bReloadPending = false; m_bReloadPending = false;
m_DeleteShapshots = false;
#ifdef WIN32 #ifdef WIN32
QStyle* pStyle = QStyleFactory::create("windows"); QStyle* pStyle = QStyleFactory::create("windows");
@ -99,6 +100,10 @@ CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent)
ui.btnRecover->setPopupMode(QToolButton::MenuButtonPopup); ui.btnRecover->setPopupMode(QToolButton::MenuButtonPopup);
ui.btnRecover->setMenu(pRecMenu); ui.btnRecover->setMenu(pRecMenu);
QMenu* pDelMenu = new QMenu(ui.btnDeleteAll);
pDelMenu->addAction(tr("Delete evertyhign including all snapshots"), this, SLOT(OnDeleteEverything()));
ui.btnDeleteAll->setPopupMode(QToolButton::MenuButtonPopup);
ui.btnDeleteAll->setMenu(pDelMenu);
restoreGeometry(theConf->GetBlob("RecoveryWindow/Window_Geometry")); restoreGeometry(theConf->GetBlob("RecoveryWindow/Window_Geometry"));
@ -145,6 +150,7 @@ int CRecoveryWindow::exec()
{ {
//QDialog::setWindowModality(Qt::WindowModal); //QDialog::setWindowModality(Qt::WindowModal);
ui.btnDeleteAll->setVisible(true); ui.btnDeleteAll->setVisible(true);
SafeShow(this);
return QDialog::exec(); return QDialog::exec();
} }
@ -223,6 +229,12 @@ void CRecoveryWindow::OnDeleteAll()
this->close(); this->close();
} }
void CRecoveryWindow::OnDeleteEverything()
{
m_DeleteShapshots = true;
OnDeleteAll();
}
void CRecoveryWindow::AddFile(const QString& FilePath, const QString& BoxPath) void CRecoveryWindow::AddFile(const QString& FilePath, const QString& BoxPath)
{ {
ui.chkShowAll->setTristate(true); ui.chkShowAll->setTristate(true);

View File

@ -39,6 +39,8 @@ public:
CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent = Q_NULLPTR); CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent = Q_NULLPTR);
~CRecoveryWindow(); ~CRecoveryWindow();
bool IsDeleteShapshots() { return m_DeleteShapshots; }
virtual void accept() {} virtual void accept() {}
virtual void reject() { this->close(); } virtual void reject() { this->close(); }
@ -56,6 +58,7 @@ private slots:
void OnRecover(); void OnRecover();
void OnTargetChanged(); void OnTargetChanged();
void OnDeleteAll(); void OnDeleteAll();
void OnDeleteEverything();
void OnCloseUntil(); void OnCloseUntil();
void OnCount(quint32 fileCount, quint32 folderCount, quint64 totalSize); void OnCount(quint32 fileCount, quint32 folderCount, quint64 totalSize);
@ -80,6 +83,7 @@ protected:
int m_LastTargetIndex; int m_LastTargetIndex;
bool m_bTargetsChanged; bool m_bTargetsChanged;
bool m_bReloadPending; bool m_bReloadPending;
bool m_DeleteShapshots;
private: private:
Ui::RecoveryWindow ui; Ui::RecoveryWindow ui;

View File

@ -811,7 +811,7 @@ void CSettingsWindow::CertChanged()
void CSettingsWindow::LoadCertificate() void CSettingsWindow::LoadCertificate()
{ {
QString CertPath; QString CertPath;
if (theAPI->IsConnected()) if (theAPI && theAPI->IsConnected())
CertPath = theAPI->GetSbiePath() + "\\Certificate.dat"; CertPath = theAPI->GetSbiePath() + "\\Certificate.dat";
else else
CertPath = QCoreApplication::applicationDirPath() + "\\Certificate.dat"; CertPath = QCoreApplication::applicationDirPath() + "\\Certificate.dat";

View File

@ -96,10 +96,11 @@ union SCertInfo {
quint64 State; quint64 State;
struct { struct {
quint32 quint32
valid : 1, valid : 1, // certificate is active
expired : 1, expired : 1, // certificate is expired but may be active
outdated : 1, outdated : 1, // certificate is expired, not anymore valid for the current build
reservd_1 : 5, business : 1, // certificate is siutable for business use
reservd_1 : 4,
reservd_2 : 8, reservd_2 : 8,
reservd_3 : 8, reservd_3 : 8,
reservd_4 : 8; reservd_4 : 8;

View File

@ -49,11 +49,18 @@ CSnapshotsWindow::CSnapshotsWindow(const CSandBoxPtr& pBox, QWidget *parent)
connect(ui.treeSnapshots->selectionModel(), SIGNAL(currentChanged(QModelIndex, 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.treeSnapshots, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(OnSelectSnapshot()));
QMenu* pSelMenu = new QMenu(ui.btnSelect);
pSelMenu->addAction(tr("Revert to empty box"), this, SLOT(OnSelectEmpty()));
ui.btnSelect->setPopupMode(QToolButton::MenuButtonPopup);
ui.btnSelect->setMenu(pSelMenu);
connect(ui.btnTake, SIGNAL(clicked(bool)), this, SLOT(OnTakeSnapshot())); connect(ui.btnTake, SIGNAL(clicked(bool)), this, SLOT(OnTakeSnapshot()));
connect(ui.btnSelect, SIGNAL(clicked(bool)), this, SLOT(OnSelectSnapshot())); connect(ui.btnSelect, SIGNAL(clicked(bool)), this, SLOT(OnSelectSnapshot()));
connect(ui.btnRemove, SIGNAL(clicked(bool)), this, SLOT(OnRemoveSnapshot())); connect(ui.btnRemove, SIGNAL(clicked(bool)), this, SLOT(OnRemoveSnapshot()));
connect(ui.txtName, SIGNAL(textEdited(const QString&)), this, SLOT(SaveInfo())); connect(ui.txtName, SIGNAL(textEdited(const QString&)), this, SLOT(SaveInfo()));
connect(ui.chkDefault, SIGNAL(clicked(bool)), this, SLOT(OnChangeDefault()));
connect(ui.txtInfo, SIGNAL(textChanged()), this, SLOT(SaveInfo())); connect(ui.txtInfo, SIGNAL(textChanged()), this, SLOT(SaveInfo()));
ui.groupBox->setEnabled(false); ui.groupBox->setEnabled(false);
@ -84,13 +91,16 @@ void CSnapshotsWindow::closeEvent(QCloseEvent *e)
void CSnapshotsWindow::UpdateSnapshots(bool AndSelect) void CSnapshotsWindow::UpdateSnapshots(bool AndSelect)
{ {
m_SnapshotMap.clear(); m_SnapshotMap.clear();
QList<SBoxSnapshot> SnapshotList = m_pBox->GetSnapshots(&m_CurSnapshot); QList<SBoxSnapshot> SnapshotList = m_pBox->GetSnapshots(&m_CurSnapshot, &m_DefaultSnapshot);
foreach(const SBoxSnapshot& Snapshot, SnapshotList) foreach(const SBoxSnapshot& Snapshot, SnapshotList)
{ {
QVariantMap BoxSnapshot; QVariantMap BoxSnapshot;
BoxSnapshot["ID"] = Snapshot.ID; BoxSnapshot["ID"] = Snapshot.ID;
BoxSnapshot["ParentID"] = Snapshot.Parent; BoxSnapshot["ParentID"] = Snapshot.Parent;
BoxSnapshot["Name"] = Snapshot.NameStr; if(m_DefaultSnapshot == Snapshot.ID)
BoxSnapshot["Name"] = Snapshot.NameStr + tr(" (default)");
else
BoxSnapshot["Name"] = Snapshot.NameStr;
BoxSnapshot["Info"] = Snapshot.InfoStr; BoxSnapshot["Info"] = Snapshot.InfoStr;
BoxSnapshot["Date"] = Snapshot.SnapDate; BoxSnapshot["Date"] = Snapshot.SnapDate;
if(m_CurSnapshot == Snapshot.ID) if(m_CurSnapshot == Snapshot.ID)
@ -131,6 +141,7 @@ void CSnapshotsWindow::UpdateSnapshot(const QModelIndex& Index)
m_SaveInfoPending = -1; m_SaveInfoPending = -1;
ui.txtName->setText(BoxSnapshot["Name"].toString()); ui.txtName->setText(BoxSnapshot["Name"].toString());
ui.chkDefault->setChecked(ID == m_DefaultSnapshot);
ui.txtInfo->setPlainText(BoxSnapshot["Info"].toString()); ui.txtInfo->setPlainText(BoxSnapshot["Info"].toString());
m_SaveInfoPending = 0; m_SaveInfoPending = 0;
@ -173,10 +184,37 @@ void CSnapshotsWindow::OnSelectSnapshot()
//QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex); //QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex);
QVariant ID = m_pSnapshotModel->GetItemID(Index); QVariant ID = m_pSnapshotModel->GetItemID(Index);
SelectSnapshot(ID.toString());
}
void CSnapshotsWindow::OnSelectEmpty()
{
SelectSnapshot(QString());
}
void CSnapshotsWindow::SelectSnapshot(const QString& ID)
{
if (QMessageBox("Sandboxie-Plus", tr("Do you really want to switch the active snapshot? Doing so will delete the current state!"), QMessageBox::Question, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) if (QMessageBox("Sandboxie-Plus", tr("Do you really want to switch the active snapshot? Doing so will delete the current state!"), QMessageBox::Question, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes)
return; return;
HandleResult(m_pBox->SelectSnapshot(ID.toString())); HandleResult(m_pBox->SelectSnapshot(ID));
}
void CSnapshotsWindow::OnChangeDefault()
{
QModelIndex Index = ui.treeSnapshots->currentIndex();
//QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
//QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex);
QVariant ID = m_pSnapshotModel->GetItemID(Index);
if (ui.chkDefault->isChecked())
m_DefaultSnapshot = ID.toString();
else
m_DefaultSnapshot.clear();
m_pBox->SetDefaultSnapshot(m_DefaultSnapshot);
UpdateSnapshots();
} }
void CSnapshotsWindow::OnRemoveSnapshot() void CSnapshotsWindow::OnRemoveSnapshot()

View File

@ -27,6 +27,8 @@ private slots:
void OnTakeSnapshot(); void OnTakeSnapshot();
void OnSelectSnapshot(); void OnSelectSnapshot();
void OnSelectEmpty();
void OnChangeDefault();
void OnRemoveSnapshot(); void OnRemoveSnapshot();
void OnSaveInfo(); void OnSaveInfo();
@ -34,10 +36,12 @@ private slots:
protected: protected:
void closeEvent(QCloseEvent *e); void closeEvent(QCloseEvent *e);
void SelectSnapshot(const QString& ID);
void HandleResult(SB_PROGRESS Status); void HandleResult(SB_PROGRESS Status);
CSandBoxPtr m_pBox; CSandBoxPtr m_pBox;
QString m_CurSnapshot; QString m_CurSnapshot;
QString m_DefaultSnapshot;
QMap<QVariant, QVariantMap> m_SnapshotMap; QMap<QVariant, QVariantMap> m_SnapshotMap;
QVariant m_SellectedID; QVariant m_SellectedID;

View File

@ -7,6 +7,7 @@
//#include "../MiscHelpers/Common/qRC4.h" //#include "../MiscHelpers/Common/qRC4.h"
#include "../MiscHelpers/Common/Common.h" #include "../MiscHelpers/Common/Common.h"
#include <windows.h> #include <windows.h>
#include "./Windows/SettingsWindow.h"
CSettings* theConf = NULL; CSettings* theConf = NULL;
@ -85,10 +86,18 @@ int main(int argc, char *argv[])
else if (app.sendMessage("ShowWnd")) else if (app.sendMessage("ShowWnd"))
return 0; return 0;
theConf = new CSettings("Sandboxie-Plus");
if (QFile::exists(QCoreApplication::applicationDirPath() + "\\Certificate.dat")) {
CSettingsWindow::LoadCertificate();
g_CertInfo.business = GetArguments(g_Certificate, L'\n', L':').value("TYPE").toUpper().contains("BUSINESS");
}
// use a shared setting location when used in a business environment for easier administration
theConf = new CSettings("Sandboxie-Plus", g_CertInfo.business);
//QThreadPool::globalInstance()->setMaxThreadCount(theConf->GetInt("Options/MaxThreadPool", 10)); //QThreadPool::globalInstance()->setMaxThreadCount(theConf->GetInt("Options/MaxThreadPool", 10));
CSandMan* pWnd = new CSandMan(); CSandMan* pWnd = new CSandMan();
QObject::connect(&app, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&))); QObject::connect(&app, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&)));