723 lines
24 KiB
C++
723 lines
24 KiB
C++
#include "stdafx.h"
|
|
#include "OptionsWindow.h"
|
|
#include "SandMan.h"
|
|
#include "SettingsWindow.h"
|
|
#include "../MiscHelpers/Common/Settings.h"
|
|
#include "../MiscHelpers/Common/Common.h"
|
|
#include "../MiscHelpers/Common/ComboInputDialog.h"
|
|
#include "../MiscHelpers/Common/SettingsWidgets.h"
|
|
#include "../MiscHelpers/Common/CheckableMessageBox.h"
|
|
#include "Helpers/WinAdmin.h"
|
|
|
|
|
|
void COptionsWindow::CreateAccess()
|
|
{
|
|
// Resource Access
|
|
connect(ui.chkPrivacy, SIGNAL(clicked(bool)), this, SLOT(OnAccessChanged()));
|
|
connect(ui.chkUseSpecificity, SIGNAL(clicked(bool)), this, SLOT(OnAccessChanged()));
|
|
connect(ui.chkCloseForBox, SIGNAL(clicked(bool)), this, SLOT(OnAccessChanged()));
|
|
connect(ui.chkNoOpenForBox, SIGNAL(clicked(bool)), this, SLOT(OnAccessChanged()));
|
|
//
|
|
|
|
connect(ui.btnAddFile, SIGNAL(clicked(bool)), this, SLOT(OnAddFile()));
|
|
QMenu* pFileBtnMenu = new QMenu(ui.btnAddFile);
|
|
pFileBtnMenu->addAction(tr("Browse for File"), this, SLOT(OnBrowseFile()));
|
|
pFileBtnMenu->addAction(tr("Browse for Folder"), this, SLOT(OnBrowseFolder()));
|
|
ui.btnAddFile->setPopupMode(QToolButton::MenuButtonPopup);
|
|
ui.btnAddFile->setMenu(pFileBtnMenu);
|
|
connect(ui.chkShowFilesTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowFilesTmpl()));
|
|
connect(ui.btnDelFile, SIGNAL(clicked(bool)), this, SLOT(OnDelFile()));
|
|
connect(ui.btnAddKey, SIGNAL(clicked(bool)), this, SLOT(OnAddKey()));
|
|
connect(ui.chkShowKeysTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowKeysTmpl()));
|
|
connect(ui.btnDelKey, SIGNAL(clicked(bool)), this, SLOT(OnDelKey()));
|
|
connect(ui.btnAddIPC, SIGNAL(clicked(bool)), this, SLOT(OnAddIPC()));
|
|
connect(ui.chkShowIPCTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowIPCTmpl()));
|
|
connect(ui.btnDelIPC, SIGNAL(clicked(bool)), this, SLOT(OnDelIPC()));
|
|
connect(ui.btnAddWnd, SIGNAL(clicked(bool)), this, SLOT(OnAddWnd()));
|
|
connect(ui.chkShowWndTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowWndTmpl()));
|
|
connect(ui.btnDelWnd, SIGNAL(clicked(bool)), this, SLOT(OnDelWnd()));
|
|
connect(ui.btnAddCOM, SIGNAL(clicked(bool)), this, SLOT(OnAddCOM()));
|
|
connect(ui.chkShowCOMTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowCOMTmpl()));
|
|
connect(ui.btnDelCOM, SIGNAL(clicked(bool)), this, SLOT(OnDelCOM()));
|
|
//connect(ui.chkShowAccessTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowAccessTmpl()));
|
|
//connect(ui.btnDelAccess, SIGNAL(clicked(bool)), this, SLOT(OnDelAccess()));
|
|
|
|
QTreeWidget* pTrees[] = { ui.treeFiles, ui.treeKeys , ui.treeIPC, ui.treeWnd, ui.treeCOM, NULL};
|
|
for (QTreeWidget** pTree = pTrees; *pTree; pTree++) {
|
|
//connect(*pTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(OnAccessItemClicked(QTreeWidgetItem*, int)));
|
|
connect(*pTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnAccessItemDoubleClicked(QTreeWidgetItem*, int)));
|
|
connect(*pTree, SIGNAL(itemSelectionChanged()), this, SLOT(OnAccessSelectionChanged()));
|
|
connect(*pTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnAccessChanged(QTreeWidgetItem *, int)));
|
|
}
|
|
|
|
connect(ui.tabsAccess, SIGNAL(currentChanged(int)), this, SLOT(OnAccessTab()));
|
|
}
|
|
|
|
void COptionsWindow::OnAccessChanged()
|
|
{
|
|
if (sender() == ui.chkPrivacy || sender() == ui.chkUseSpecificity) {
|
|
if (ui.chkPrivacy->isChecked() || (ui.chkUseSpecificity->isEnabled() && ui.chkUseSpecificity->isChecked()))
|
|
theGUI->CheckCertificate(this);
|
|
}
|
|
|
|
UpdateAccessPolicy();
|
|
|
|
if ((sender() == ui.chkPrivacy || sender() == ui.chkRestrictDevices) && !(ui.chkPrivacy->isChecked() || ui.chkRestrictDevices->isChecked())) {
|
|
ui.chkUseSpecificity->setChecked(m_pBox->GetBool("UseRuleSpecificity", false));
|
|
}
|
|
|
|
m_AccessChanged = true;
|
|
OnOptChanged();
|
|
}
|
|
|
|
void COptionsWindow::UpdateAccessPolicy()
|
|
{
|
|
ui.chkUseSpecificity->setEnabled(!(ui.chkPrivacy->isChecked() || ui.chkRestrictDevices->isChecked()));
|
|
|
|
if (ui.chkPrivacy->isChecked() || ui.chkRestrictDevices->isChecked()) {
|
|
ui.chkUseSpecificity->setChecked(true);
|
|
}
|
|
}
|
|
|
|
QTreeWidgetItem* COptionsWindow::GetAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path)
|
|
{
|
|
QTreeWidget* pTree = GetAccessTree(Type);
|
|
for (int i = 0; i < pTree->topLevelItemCount(); i++)
|
|
{
|
|
QTreeWidgetItem* pItem = pTree->topLevelItem(i);
|
|
if (pItem->data(0, Qt::UserRole).toInt() == Type
|
|
&& pItem->data(1, Qt::UserRole).toString().compare(Program, Qt::CaseInsensitive) == 0
|
|
&& pItem->data(2, Qt::UserRole).toInt() == Mode
|
|
&& pItem->data(3, Qt::UserRole).toString().compare(Path, Qt::CaseInsensitive) == 0)
|
|
return pItem;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void COptionsWindow::SetAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path)
|
|
{
|
|
if (GetAccessEntry(Type, Program, Mode, Path) != NULL)
|
|
return; // already set
|
|
m_AccessChanged = true;
|
|
OnOptChanged();
|
|
AddAccessEntry(Type, Mode, Program, Path);
|
|
}
|
|
|
|
void COptionsWindow::DelAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path)
|
|
{
|
|
if(QTreeWidgetItem* pItem = GetAccessEntry(Type, Program, Mode, Path))
|
|
{
|
|
delete pItem;
|
|
m_AccessChanged = true;
|
|
OnOptChanged();
|
|
}
|
|
}
|
|
|
|
QString COptionsWindow::AccessTypeToName(EAccessEntry Type)
|
|
{
|
|
switch (Type)
|
|
{
|
|
case eNormalFilePath: return "NormalFilePath";
|
|
case eOpenFilePath: return "OpenFilePath";
|
|
case eOpenPipePath: return "OpenPipePath";
|
|
case eClosedFilePath: return "ClosedFilePath";
|
|
case eReadFilePath: return "ReadFilePath";
|
|
case eWriteFilePath: return "WriteFilePath";
|
|
|
|
case eNormalKeyPath: return "NormalKeyPath";
|
|
case eOpenKeyPath: return "OpenKeyPath";
|
|
case eOpenConfPath: return "OpenConfPath";
|
|
case eClosedKeyPath: return "ClosedKeyPath";
|
|
case eReadKeyPath: return "ReadKeyPath";
|
|
case eWriteKeyPath: return "WriteKeyPath";
|
|
|
|
case eNormalIpcPath: return "NormalIpcPath";
|
|
case eOpenIpcPath: return "OpenIpcPath";
|
|
case eClosedIpcPath: return "ClosedIpcPath";
|
|
case eReadIpcPath: return "ReadIpcPath";
|
|
|
|
case eOpenWinClass: return "OpenWinClass";
|
|
case eNoRenameWinClass: return "NoRenameWinClass";
|
|
|
|
case eOpenCOM: return "OpenClsid";
|
|
case eClosedCOM: return "ClosedClsid";
|
|
case eClosedCOM_RT: return "ClosedRT";
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
void COptionsWindow::LoadAccessList()
|
|
{
|
|
ui.chkPrivacy->setChecked(m_pBox->GetBool("UsePrivacyMode", false));
|
|
ui.chkUseSpecificity->setChecked(m_pBox->GetBool("UseRuleSpecificity", false));
|
|
ui.chkCloseForBox->setChecked(m_pBox->GetBool("AlwaysCloseForBoxed", true));
|
|
ui.chkNoOpenForBox->setChecked(m_pBox->GetBool("DontOpenForBoxed", true));
|
|
|
|
QTreeWidget* pTrees[] = { ui.treeFiles, ui.treeKeys , ui.treeIPC, ui.treeWnd, ui.treeCOM, NULL};
|
|
for (QTreeWidget** pTree = pTrees; *pTree; pTree++)
|
|
(*pTree )->clear();
|
|
|
|
for (int i = 0; i < eMaxAccessEntry; i++)
|
|
{
|
|
foreach(const QString& Value, m_pBox->GetTextList(AccessTypeToName((EAccessEntry)i), m_Template))
|
|
ParseAndAddAccessEntry((EAccessEntry)i, Value);
|
|
|
|
foreach(const QString& Value, m_pBox->GetTextList(AccessTypeToName((EAccessEntry)i) + "Disabled", m_Template))
|
|
ParseAndAddAccessEntry((EAccessEntry)i, Value, true);
|
|
}
|
|
|
|
LoadAccessListTmpl();
|
|
|
|
UpdateAccessPolicy();
|
|
|
|
m_AccessChanged = false;
|
|
}
|
|
|
|
void COptionsWindow::LoadAccessListTmpl(bool bUpdate)
|
|
{
|
|
for (int i = 0; i < eMaxAccessType; i++) {
|
|
QCheckBox* pCheck = NULL;
|
|
switch (i)
|
|
{
|
|
case eFile: pCheck = ui.chkShowFilesTmpl; break;
|
|
case eKey: pCheck = ui.chkShowKeysTmpl; break;
|
|
case eIPC: pCheck = ui.chkShowIPCTmpl; break;
|
|
case eWnd: pCheck = ui.chkShowWndTmpl; break;
|
|
case eCOM: pCheck = ui.chkShowCOMTmpl; break;
|
|
}
|
|
LoadAccessListTmpl((EAccessType)i, pCheck->isChecked(), bUpdate);
|
|
}
|
|
}
|
|
|
|
QTreeWidget* COptionsWindow::GetAccessTree(EAccessType Type)
|
|
{
|
|
QTreeWidget* pTree = NULL;
|
|
switch (Type)
|
|
{
|
|
case eFile: pTree = ui.treeFiles; break;
|
|
case eKey: pTree = ui.treeKeys; break;
|
|
case eIPC: pTree = ui.treeIPC; break;
|
|
case eWnd: pTree = ui.treeWnd; break;
|
|
case eCOM: pTree = ui.treeCOM; break;
|
|
}
|
|
return pTree;
|
|
}
|
|
|
|
void COptionsWindow::LoadAccessListTmpl(EAccessType Type, bool bChecked, bool bUpdate)
|
|
{
|
|
if (bChecked)
|
|
{
|
|
foreach(EAccessMode Mode, GetAccessModes((EAccessType)Type))
|
|
{
|
|
foreach(const QString & Template, m_pBox->GetTemplates())
|
|
{
|
|
foreach(const QString & Value, m_pBox->GetTextListTmpl(MakeAccessStr(Type, Mode), Template))
|
|
ParseAndAddAccessEntry(Type, Mode, Value, false, Template);
|
|
}
|
|
}
|
|
}
|
|
else if (bUpdate)
|
|
{
|
|
QTreeWidget* pTree = GetAccessTree(Type);
|
|
for (int i = 0; i < pTree->topLevelItemCount(); )
|
|
{
|
|
QTreeWidgetItem* pItem = pTree->topLevelItem(i);
|
|
int Type = pItem->data(0, Qt::UserRole).toInt();
|
|
if (Type == -1) {
|
|
delete pItem;
|
|
continue; // entry from template
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void COptionsWindow::ParseAndAddAccessEntry(EAccessEntry EntryType, const QString& Value, bool disabled, const QString& Template)
|
|
{
|
|
EAccessType Type;
|
|
EAccessMode Mode;
|
|
switch (EntryType)
|
|
{
|
|
case eNormalFilePath: Type = eFile; Mode = eNormal; break;
|
|
case eOpenFilePath: Type = eFile; Mode = eOpen; break;
|
|
case eOpenPipePath: Type = eFile; Mode = eOpen4All; break;
|
|
case eClosedFilePath: Type = eFile; Mode = eClosed; break;
|
|
case eReadFilePath: Type = eFile; Mode = eReadOnly; break;
|
|
case eWriteFilePath: Type = eFile; Mode = eBoxOnly; break;
|
|
|
|
case eNormalKeyPath: Type = eKey; Mode = eNormal; break;
|
|
case eOpenKeyPath: Type = eKey; Mode = eOpen; break;
|
|
case eOpenConfPath: Type = eKey; Mode = eOpen4All; break;
|
|
case eClosedKeyPath: Type = eKey; Mode = eClosed; break;
|
|
case eReadKeyPath: Type = eKey; Mode = eReadOnly; break;
|
|
case eWriteKeyPath: Type = eKey; Mode = eBoxOnly; break;
|
|
|
|
case eNormalIpcPath: Type = eIPC; Mode = eNormal; break;
|
|
case eOpenIpcPath: Type = eIPC; Mode = eOpen; break;
|
|
case eClosedIpcPath: Type = eIPC; Mode = eClosed; break;
|
|
case eReadIpcPath: Type = eIPC; Mode = eReadOnly; break;
|
|
|
|
case eOpenWinClass: Type = eWnd; Mode = eOpen; break;
|
|
case eNoRenameWinClass: Type = eWnd; Mode = eNoRename; break;
|
|
|
|
case eOpenCOM: Type = eCOM; Mode = eOpen; break;
|
|
case eClosedCOM: Type = eCOM; Mode = eClosed; break;
|
|
case eClosedCOM_RT: Type = eCOM; Mode = eClosedRT; break;
|
|
|
|
default: return;
|
|
}
|
|
|
|
ParseAndAddAccessEntry(Type, Mode, Value, disabled, Template);
|
|
}
|
|
|
|
void COptionsWindow::ParseAndAddAccessEntry(EAccessType Type, EAccessMode Mode, const QString& Value, bool disabled, const QString& Template)
|
|
{
|
|
//
|
|
// Mind this special cases
|
|
// OpenIpcPath=$:program.exe <- full access into the address space of a target process running outside the sandbox.
|
|
// OpenWinClass=$:program.exe <- permits to use the PostThreadMessage API to send a message directly to a thread running outside the sandbox.
|
|
// This form of the setting does not support wildcards.
|
|
//
|
|
|
|
QStringList Values = Value.split(",");
|
|
|
|
if (Type == eWnd && Mode == eOpen) {
|
|
int pos = Values.count() >= 2 ? 1 : 0;
|
|
if (Values[pos].right(11).compare("/IgnoreUIPI", Qt::CaseInsensitive) == 0) {
|
|
Mode = eIgnoreUIPI;
|
|
Values[pos].truncate(Values[pos].length() - 11);
|
|
}
|
|
}
|
|
|
|
if (Values.count() >= 2)
|
|
AddAccessEntry(Type, Mode, Values[0], Values[1], disabled, Template);
|
|
else // all programs
|
|
AddAccessEntry(Type, Mode, "", Values[0], disabled, Template);
|
|
}
|
|
|
|
QString COptionsWindow::GetAccessModeStr(EAccessMode Mode)
|
|
{
|
|
switch (Mode)
|
|
{
|
|
case eNormal: return tr("Normal");
|
|
case eOpen: return tr("Open");
|
|
case eOpen4All: return tr("Open for All");
|
|
case eNoRename: return tr("No Rename");
|
|
case eClosed: return tr("Closed");
|
|
case eClosedRT: return tr("Closed RT");
|
|
case eReadOnly: return tr("Read Only");
|
|
case eBoxOnly: return tr("Box Only (Write Only)");
|
|
case eIgnoreUIPI: return tr("Ignore UIPI");
|
|
}
|
|
return tr("Unknown");
|
|
}
|
|
|
|
QString COptionsWindow::GetAccessModeTip(EAccessMode Mode)
|
|
{
|
|
switch (Mode)
|
|
{
|
|
case eNormal: return tr("Regular Sandboxie behavior - allow read and also copy on write.");
|
|
case eOpen: return tr("Allow write-access outside the sandbox.");
|
|
case eOpen4All: return tr("Allow write-access outside the sandbox, also for applications installed inside the sandbox.");
|
|
case eNoRename: return tr("Don't rename window classes.");
|
|
case eClosed: return tr("Deny access to host location and prevent creation of sandboxed copies.");
|
|
case eClosedRT: return tr("Block access to WinRT class.");
|
|
case eReadOnly: return tr("Allow read-only access only.");
|
|
case eBoxOnly: return tr("Hide host files, folders or registry keys from sandboxed processes.");
|
|
case eIgnoreUIPI: return tr("Ignore UIPI restrictions for processes.");
|
|
}
|
|
return tr("Unknown");
|
|
}
|
|
|
|
QString COptionsWindow::GetAccessTypeStr(EAccessType Type)
|
|
{
|
|
switch (Type)
|
|
{
|
|
case eFile: return tr("File/Folder");
|
|
case eKey: return tr("Registry");
|
|
case eIPC: return tr("IPC Path");
|
|
case eWnd: return tr("Wnd Class");
|
|
case eCOM: return tr("COM Object");
|
|
}
|
|
return tr("Unknown");
|
|
}
|
|
|
|
void COptionsWindow::OnBrowseFile()
|
|
{
|
|
QString Value = QFileDialog::getOpenFileName(this, tr("Select File"), "", tr("All Files (*.*)")).replace("/", "\\");
|
|
if (Value.isEmpty())
|
|
return;
|
|
|
|
AddAccessEntry(eFile, eOpen, "", Value);
|
|
|
|
m_AccessChanged = true;
|
|
OnOptChanged();
|
|
}
|
|
|
|
void COptionsWindow::OnBrowseFolder()
|
|
{
|
|
QString Value = QFileDialog::getExistingDirectory(this, tr("Select Directory")).replace("/", "\\");
|
|
if (Value.isEmpty())
|
|
return;
|
|
|
|
AddAccessEntry(eFile, eOpen, "", Value);
|
|
|
|
m_AccessChanged = true;
|
|
OnOptChanged();
|
|
}
|
|
|
|
void COptionsWindow::AddAccessEntry(EAccessType Type, EAccessMode Mode, QString Program, const QString& Path, bool disabled, const QString& Template)
|
|
{
|
|
QTreeWidgetItem* pItem = new QTreeWidgetItem();
|
|
|
|
pItem->setText(0, GetAccessTypeStr(Type) + (Template.isEmpty() ? "" : " (" + Template + ")"));
|
|
pItem->setData(0, Qt::UserRole, !Template.isEmpty() ? -1 : (int)Type);
|
|
|
|
pItem->setData(1, Qt::UserRole, Program);
|
|
bool bAll = Program.isEmpty();
|
|
if (bAll)
|
|
Program = tr("All Programs");
|
|
bool Not = Program.left(1) == "!";
|
|
if (Not)
|
|
Program.remove(0, 1);
|
|
if (Program.left(1) == "<")
|
|
Program = tr("Group: %1").arg(Program.mid(1, Program.length() - 2));
|
|
else if(!bAll)
|
|
m_Programs.insert(Program);
|
|
pItem->setText(1, (Not ? "NOT " : "") + Program);
|
|
|
|
pItem->setText(2, GetAccessModeStr(Mode));
|
|
pItem->setData(2, Qt::UserRole, (int)Mode);
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// File and Registry entries auto append a '*' wildcard
|
|
// when they don't contain any.
|
|
// Prepending '|' disables this behaviour
|
|
//
|
|
|
|
QString sPath = Path;
|
|
if (Type == eFile || Type == eKey) {
|
|
if (!sPath.isEmpty() && sPath.left(1) != "|" && !sPath.contains("*") && sPath.right(1) != "*")
|
|
sPath.append("*");
|
|
}
|
|
pItem->setText(3, sPath);
|
|
pItem->setData(3, Qt::UserRole, Path);
|
|
|
|
if(Template.isEmpty())
|
|
pItem->setCheckState(0, disabled ? Qt::Unchecked : Qt::Checked);
|
|
|
|
QTreeWidget* pTree = GetAccessTree(Type);
|
|
pTree->addTopLevelItem(pItem);
|
|
}
|
|
|
|
QString COptionsWindow::MakeAccessStr(EAccessType Type, EAccessMode Mode)
|
|
{
|
|
switch (Type)
|
|
{
|
|
case eFile:
|
|
switch (Mode)
|
|
{
|
|
case eNormal: return "NormalFilePath";
|
|
case eOpen: return "OpenFilePath";
|
|
case eOpen4All: return "OpenPipePath";
|
|
case eClosed: return "ClosedFilePath";
|
|
case eReadOnly: return "ReadFilePath";
|
|
case eBoxOnly: return "WriteFilePath";
|
|
}
|
|
break;
|
|
case eKey:
|
|
switch (Mode)
|
|
{
|
|
case eNormal: return "NormalKeyPath";
|
|
case eOpen: return "OpenKeyPath";
|
|
case eOpen4All: return "OpenConfPath";
|
|
case eClosed: return "ClosedKeyPath";
|
|
case eReadOnly: return "ReadKeyPath";
|
|
case eBoxOnly: return "WriteKeyPath";
|
|
}
|
|
break;
|
|
case eIPC:
|
|
switch (Mode)
|
|
{
|
|
case eNormal: return "NormalIpcPath";
|
|
case eOpen: return "OpenIpcPath";
|
|
case eClosed: return "ClosedIpcPath";
|
|
case eReadOnly: return "ReadIpcPath";
|
|
}
|
|
break;
|
|
case eWnd:
|
|
switch (Mode)
|
|
{
|
|
case eOpen: return "OpenWinClass";
|
|
case eNoRename: return "NoRenameWinClass";
|
|
}
|
|
break;
|
|
case eCOM:
|
|
switch (Mode)
|
|
{
|
|
case eOpen: return "OpenClsid";
|
|
case eClosed: return "ClosedClsid";
|
|
case eClosedRT: return "ClosedRT";
|
|
}
|
|
break;
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
/*void COptionsWindow::OnAccessItemClicked(QTreeWidgetItem* pItem, int Column)
|
|
{
|
|
if (Column != 0)
|
|
return;
|
|
|
|
CloseAccessEdit(pItem);
|
|
}*/
|
|
|
|
void COptionsWindow::CloseAccessEdit(bool bSave)
|
|
{
|
|
QTreeWidget* pTrees[] = { ui.treeFiles, ui.treeKeys , ui.treeIPC, ui.treeWnd, ui.treeCOM, NULL};
|
|
for (QTreeWidget** pTree = pTrees; *pTree; pTree++) {
|
|
for (int i = 0; i < (*pTree)->topLevelItemCount(); i++)
|
|
{
|
|
QTreeWidgetItem* pItem = (*pTree)->topLevelItem(i);
|
|
CloseAccessEdit(pItem, bSave);
|
|
}
|
|
}
|
|
}
|
|
|
|
void COptionsWindow::CloseAccessEdit(QTreeWidgetItem* pItem, bool bSave)
|
|
{
|
|
QTreeWidget* pTree = pItem->treeWidget();
|
|
|
|
QWidget* pProgram = pTree->itemWidget(pItem, 1);
|
|
if (!pProgram)
|
|
return;
|
|
|
|
if (bSave)
|
|
{
|
|
QHBoxLayout* pLayout = (QHBoxLayout*)pProgram->layout();
|
|
QToolButton* pNot = (QToolButton*)pLayout->itemAt(0)->widget();
|
|
QComboBox* pCombo = (QComboBox*)pLayout->itemAt(1)->widget();
|
|
|
|
QComboBox* pMode = (QComboBox*)pTree->itemWidget(pItem, 2);
|
|
QLineEdit* pPath = (QLineEdit*)pTree->itemWidget(pItem, 3);
|
|
|
|
QString Program = pCombo->currentText();
|
|
int Index = pCombo->findText(Program);
|
|
if (Index != -1)
|
|
Program = pCombo->itemData(Index, Qt::UserRole).toString();
|
|
if (!Program.isEmpty() && Program.left(1) != "<")
|
|
m_Programs.insert(Program);
|
|
|
|
EAccessMode Mode = (EAccessMode)pMode->currentData().toInt();
|
|
QString Path = pPath->text();
|
|
|
|
if (pItem->data(0, Qt::UserRole).toInt() == eCOM && !Path.isEmpty())
|
|
{
|
|
bool isGUID = Path.length() == 38 && Path.left(1) == "{" && Path.right(1) == "}";
|
|
switch (Mode)
|
|
{
|
|
case eOpen:
|
|
case eClosed:
|
|
if (!isGUID) {
|
|
QMessageBox::critical(this, "SandboxiePlus", tr("COM objects must be specified by their GUID, like: {00000000-0000-0000-0000-000000000000}"));
|
|
return;
|
|
}
|
|
break;
|
|
case eClosedRT:
|
|
if (isGUID) {
|
|
QMessageBox::critical(this, "SandboxiePlus", tr("RT interfaces must be specified by their name."));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pItem->data(0, Qt::UserRole).toInt() == eIPC && Mode == eOpen
|
|
&& ((Path == "*" && pItem->data(3, Qt::UserRole).toString() != "*")
|
|
|| (Path == "\\*" && pItem->data(3, Qt::UserRole).toString() != "\\*"))
|
|
&& !m_BoxTemplates.contains("BoxedCOM"))
|
|
{
|
|
if (theConf->GetInt("Options/WarnOpenCOM", -1) == -1) {
|
|
bool State = false;
|
|
if (CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Opening all IPC access also opens COM access, do you still want to restrict COM to the sandbox?")
|
|
, tr("Don't ask in future"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) == QDialogButtonBox::Yes)
|
|
SetTemplate("BoxedCOM", true); // Normal overrides Open even without rule specificity :D
|
|
if (State)
|
|
theConf->SetValue("Options/WarnOpenCOM", 1);
|
|
}
|
|
}
|
|
|
|
if (pItem->data(0, Qt::UserRole).toInt() == eWnd && Mode == eOpen && Path == "#" && !Program.isEmpty())
|
|
{
|
|
QMessageBox::warning(this, "Sandboxie-Plus", tr("'OpenWinClass=program.exe,#' is not supported, use 'NoRenameWinClass=program.exe,*' instead"));
|
|
Mode = eNoRename;
|
|
Path = "*";
|
|
}
|
|
|
|
pItem->setText(1, (pNot->isChecked() ? "NOT " : "") + pCombo->currentText());
|
|
pItem->setData(1, Qt::UserRole, (pNot->isChecked() ? "!" : "") + Program);
|
|
pItem->setText(2, GetAccessModeStr(Mode));
|
|
pItem->setData(2, Qt::UserRole, (int)Mode);
|
|
pItem->setText(3, Path);
|
|
pItem->setData(3, Qt::UserRole, Path);
|
|
|
|
m_AccessChanged = true;
|
|
OnOptChanged();
|
|
}
|
|
|
|
pTree->setItemWidget(pItem, 1, NULL);
|
|
pTree->setItemWidget(pItem, 2, NULL);
|
|
pTree->setItemWidget(pItem, 3, NULL);
|
|
}
|
|
|
|
QList<COptionsWindow::EAccessMode> COptionsWindow::GetAccessModes(EAccessType Type)
|
|
{
|
|
switch (Type)
|
|
{
|
|
case eFile: return QList<EAccessMode>() << eNormal << eOpen << eOpen4All << eClosed << eReadOnly << eBoxOnly;
|
|
case eKey: return QList<EAccessMode>() << eNormal << eOpen << eOpen4All << eClosed << eReadOnly << eBoxOnly;
|
|
case eIPC: return QList<EAccessMode>() << eNormal << eOpen << eClosed << eReadOnly;
|
|
case eWnd: return QList<EAccessMode>() << eOpen << eNoRename << eIgnoreUIPI;
|
|
case eCOM: return QList<EAccessMode>() << eOpen << eClosed << eClosedRT;
|
|
}
|
|
return QList<EAccessMode>();
|
|
}
|
|
|
|
void COptionsWindow::OnAccessItemDoubleClicked(QTreeWidgetItem* pItem, int Column)
|
|
{
|
|
//if (Column == 0)
|
|
// return;
|
|
|
|
QTreeWidget* pTree = (QTreeWidget*)sender();
|
|
|
|
int Type = pItem->data(0, Qt::UserRole).toInt();
|
|
if (Type == -1) {
|
|
QMessageBox::warning(this, "SandboxiePlus", tr("Template values can not be edited."));
|
|
return;
|
|
}
|
|
|
|
QString Program = pItem->data(1, Qt::UserRole).toString();
|
|
|
|
QWidget* pProgram = new QWidget();
|
|
pProgram->setAutoFillBackground(true);
|
|
QHBoxLayout* pLayout = new QHBoxLayout();
|
|
pLayout->setContentsMargins(0,0,0,0);
|
|
pLayout->setSpacing(0);
|
|
pProgram->setLayout(pLayout);
|
|
QToolButton* pNot = new QToolButton(pProgram);
|
|
pNot->setText("!");
|
|
pNot->setCheckable(true);
|
|
if (Program.left(1) == "!"){
|
|
pNot->setChecked(true);
|
|
Program.remove(0, 1);
|
|
}
|
|
pLayout->addWidget(pNot);
|
|
QComboBox* pCombo = new QComboBox(pProgram);
|
|
pCombo->addItem(tr("All Programs"), "");
|
|
|
|
foreach(const QString Group, GetCurrentGroups()){
|
|
QString GroupName = Group.mid(1, Group.length() - 2);
|
|
pCombo->addItem(tr("Group: %1").arg(GroupName), Group);
|
|
}
|
|
|
|
foreach(const QString & Name, m_Programs)
|
|
pCombo->addItem(Name, Name);
|
|
|
|
pCombo->setEditable(true);
|
|
int Index = pCombo->findData(Program);
|
|
pCombo->setCurrentIndex(Index);
|
|
if(Index == -1)
|
|
pCombo->setCurrentText(Program);
|
|
pLayout->addWidget(pCombo);
|
|
|
|
pTree->setItemWidget(pItem, 1, pProgram);
|
|
|
|
QComboBox* pMode = new QComboBox();
|
|
foreach(EAccessMode Mode, GetAccessModes((EAccessType)Type)) {
|
|
pMode->addItem(GetAccessModeStr(Mode), (int)Mode);
|
|
pMode->setItemData(pMode->count() - 1, GetAccessModeTip(Mode), Qt::ToolTipRole);
|
|
}
|
|
pMode->setCurrentIndex(pMode->findData(pItem->data(2, Qt::UserRole)));
|
|
pTree->setItemWidget(pItem, 2, pMode);
|
|
|
|
QLineEdit* pPath = new QLineEdit();
|
|
pPath->setText(pItem->data(3, Qt::UserRole).toString());
|
|
pTree->setItemWidget(pItem, 3, pPath);
|
|
}
|
|
|
|
void COptionsWindow::OnAccessChanged(QTreeWidgetItem* pItem, int Column)
|
|
{
|
|
if (Column != 0)
|
|
return;
|
|
|
|
m_AccessChanged = true;
|
|
OnOptChanged();
|
|
}
|
|
|
|
void COptionsWindow::DeleteAccessEntry(QTreeWidgetItem* pItem, int Column)
|
|
{
|
|
if (!pItem)
|
|
return;
|
|
|
|
if (pItem->data(Column, Qt::UserRole).toInt() == -1) {
|
|
QMessageBox::warning(this, "SandboxiePlus", tr("Template values can not be removed."));
|
|
return;
|
|
}
|
|
|
|
delete pItem;
|
|
}
|
|
|
|
void COptionsWindow::SaveAccessList()
|
|
{
|
|
WriteAdvancedCheck(ui.chkPrivacy, "UsePrivacyMode", "y", "");
|
|
WriteAdvancedCheck(ui.chkUseSpecificity, "UseRuleSpecificity", "y", "");
|
|
WriteAdvancedCheck(ui.chkCloseForBox, "AlwaysCloseForBoxed", "", "n");
|
|
WriteAdvancedCheck(ui.chkNoOpenForBox, "DontOpenForBoxed", "", "n");
|
|
|
|
CloseAccessEdit(true);
|
|
|
|
QStringList Keys = QStringList()
|
|
<< "NormalFilePath" << "OpenFilePath" << "OpenPipePath" << "ClosedFilePath" << "ReadFilePath" << "WriteFilePath"
|
|
<< "NormalKeyPath" << "OpenKeyPath" << "OpenConfPath" << "ClosedKeyPath" << "ReadKeyPath" << "WriteKeyPath"
|
|
<< "NormalIpcPath"<< "OpenIpcPath" << "ClosedIpcPath" << "ReadIpcPath"
|
|
<< "OpenWinClass" << "NoRenameWinClass"
|
|
<< "OpenClsid" << "ClosedClsid" << "ClosedRT";
|
|
|
|
QMap<QString, QList<QString>> AccessMap;
|
|
|
|
|
|
QTreeWidget* pTrees[] = { ui.treeFiles, ui.treeKeys , ui.treeIPC, ui.treeWnd, ui.treeCOM, NULL};
|
|
for (QTreeWidget** pTree = pTrees; *pTree; pTree++)
|
|
{
|
|
for (int i = 0; i < (*pTree)->topLevelItemCount(); i++)
|
|
{
|
|
QTreeWidgetItem* pItem = (*pTree)->topLevelItem(i);
|
|
int Type = pItem->data(0, Qt::UserRole).toInt();
|
|
if (Type == -1)
|
|
continue; // entry from template
|
|
int Mode = pItem->data(2, Qt::UserRole).toInt();
|
|
QString Program = pItem->data(1, Qt::UserRole).toString();
|
|
QString Value = pItem->data(3, Qt::UserRole).toString();
|
|
if (!Program.isEmpty())
|
|
Value.prepend(Program + ",");
|
|
|
|
if (Type == eWnd && Mode == eIgnoreUIPI) {
|
|
Mode = eOpen;
|
|
Value.append("/IgnoreUIPI");
|
|
}
|
|
|
|
QString AccessStr = MakeAccessStr((EAccessType)Type, (EAccessMode)Mode);
|
|
if (pItem->checkState(0) == Qt::Unchecked)
|
|
AccessStr += "Disabled";
|
|
AccessMap[AccessStr].append(Value);
|
|
}
|
|
}
|
|
|
|
foreach(const QString & Key, Keys) {
|
|
WriteTextList(Key, AccessMap[Key]);
|
|
WriteTextList(Key + "Disabled", AccessMap[Key + "Disabled"]);
|
|
}
|
|
|
|
m_AccessChanged = false;
|
|
}
|