UI: Add ability to use env vars in the app groups.

E.g. to allow all programs from home folder: %HOME%
This commit is contained in:
Nodir Temirkhodjaev 2019-11-21 13:36:18 +05:00
parent 83fe6c5127
commit 3614a46f14
17 changed files with 241 additions and 36 deletions

View File

@ -8,6 +8,7 @@ SOURCES += \
$$UIPATH/util/conf/addressrange.cpp \
$$UIPATH/util/conf/confutil.cpp \
$$UIPATH/util/dateutil.cpp \
$$UIPATH/util/envmanager.cpp \
$$UIPATH/util/fileutil.cpp \
$$UIPATH/util/net/ip4range.cpp \
$$UIPATH/util/net/netutil.cpp \
@ -22,6 +23,7 @@ HEADERS += \
$$UIPATH/util/conf/addressrange.h \
$$UIPATH/util/conf/confutil.h \
$$UIPATH/util/dateutil.h \
$$UIPATH/util/envmanager.h \
$$UIPATH/util/fileutil.h \
$$UIPATH/util/net/ip4range.h \
$$UIPATH/util/net/netutil.h \

View File

@ -6,11 +6,13 @@
#include "conf/firewallconf.h"
#include "fortcommon.h"
#include "util/conf/confutil.h"
#include "util/envmanager.h"
#include "util/fileutil.h"
#include "util/net/netutil.h"
void Test::confWriteRead()
{
EnvManager envManager;
FirewallConf conf;
AddressGroup *inetGroup = conf.inetAddressGroup();
@ -55,7 +57,7 @@ void Test::confWriteRead()
ConfUtil confUtil;
QByteArray buf;
const int confIoSize = confUtil.write(conf, buf);
const int confIoSize = confUtil.write(conf, envManager, buf);
QVERIFY(confIoSize != 0);
// Check the buffer
@ -107,3 +109,28 @@ void Test::checkPeriod()
QVERIFY(FortCommon::isTimeInPeriod(h, m, 15,35, 15,37));
QVERIFY(!FortCommon::isTimeInPeriod(h, m, 15,35, 15,36));
}
void Test::checkEnvManager()
{
EnvManager envManager;
envManager.setCachedEnvVar("a", "a");
envManager.setCachedEnvVar("b", "b");
envManager.setCachedEnvVar("c", "c");
QCOMPARE("%abc-cba%", envManager.expandString("%%%a%%b%%c%-%c%%b%%a%%%"));
envManager.setCachedEnvVar("d", "%e%");
envManager.setCachedEnvVar("e", "%f%");
envManager.setCachedEnvVar("f", "%d%");
QCOMPARE("", envManager.expandString("%d%"));
envManager.setCachedEnvVar("d", "%e%");
envManager.setCachedEnvVar("e", "%f%");
envManager.setCachedEnvVar("f", "%a%");
QCOMPARE("a", envManager.expandString("%d%"));
QVERIFY(!envManager.expandString("%HOME%").isEmpty());
}

View File

@ -10,6 +10,7 @@ class Test : public QObject
private slots:
void confWriteRead();
void checkPeriod();
void checkEnvManager();
};
#endif // TEST_H

View File

@ -15,6 +15,7 @@ SOURCES += \
$$UIPATH/util/conf/confutil.cpp \
$$UIPATH/util/dateutil.cpp \
$$UIPATH/util/device.cpp \
$$UIPATH/util/envmanager.cpp \
$$UIPATH/util/fileutil.cpp \
$$UIPATH/util/net/ip4range.cpp \
$$UIPATH/util/net/netutil.cpp \
@ -36,6 +37,7 @@ HEADERS += \
$$UIPATH/util/conf/confutil.h \
$$UIPATH/util/dateutil.h \
$$UIPATH/util/device.h \
$$UIPATH/util/envmanager.h \
$$UIPATH/util/fileutil.h \
$$UIPATH/util/net/ip4range.h \
$$UIPATH/util/net/netutil.h \

View File

@ -11,6 +11,7 @@
#include "log/logentryblocked.h"
#include "util/conf/confutil.h"
#include "util/device.h"
#include "util/envmanager.h"
#include "util/fileutil.h"
#include "util/net/netutil.h"
#include "util/osutil.h"
@ -37,6 +38,7 @@ void Test::logRead()
void Test::setConf(Device &device)
{
EnvManager envManager;
FirewallConf conf;
conf.setProvBoot(true);
@ -58,7 +60,7 @@ void Test::setConf(Device &device)
ConfUtil confUtil;
QByteArray buf;
const int confIoSize = confUtil.write(conf, buf);
const int confIoSize = confUtil.write(conf, envManager, buf);
QVERIFY(confIoSize != 0);
QVERIFY(device.ioctl(FortCommon::ioctlSetConf(),

View File

@ -61,6 +61,7 @@ SOURCES += \
util/conf/confutil.cpp \
util/dateutil.cpp \
util/device.cpp \
util/envmanager.cpp \
util/fileutil.cpp \
util/guiutil.cpp \
util/hotkeymanager.cpp \
@ -135,6 +136,7 @@ HEADERS += \
util/conf/confutil.h \
util/dateutil.h \
util/device.h \
util/envmanager.h \
util/fileutil.h \
util/guiutil.h \
util/hotkeymanager.h \

View File

@ -83,12 +83,12 @@ bool DriverManager::validate()
buf, verSize);
}
bool DriverManager::writeConf(const FirewallConf &conf)
bool DriverManager::writeConf(const FirewallConf &conf, EnvManager &envManager)
{
ConfUtil confUtil;
QByteArray buf;
const int confSize = confUtil.write(conf, buf);
const int confSize = confUtil.write(conf, envManager, buf);
if (!confSize) {
setErrorMessage(confUtil.errorMessage());
return false;

View File

@ -7,6 +7,7 @@
QT_FORWARD_DECLARE_CLASS(Device)
QT_FORWARD_DECLARE_CLASS(DriverWorker)
QT_FORWARD_DECLARE_CLASS(EnvManager)
QT_FORWARD_DECLARE_CLASS(FirewallConf)
class DriverManager : public QObject
@ -39,7 +40,7 @@ public slots:
bool validate();
bool writeConf(const FirewallConf &conf);
bool writeConf(const FirewallConf &conf, EnvManager &envManager);
bool writeConfFlags(const FirewallConf &conf);
private:

View File

@ -35,6 +35,7 @@
#include "util/app/appinfocache.h"
#include "util/app/appinfomanager.h"
#include "util/dateutil.h"
#include "util/envmanager.h"
#include "util/fileutil.h"
#include "util/guiutil.h"
#include "util/hotkeymanager.h"
@ -69,6 +70,7 @@ FortManager::FortManager(FortSettings *fortSettings,
m_confManager(new ConfManager(fortSettings->confFilePath(),
fortSettings, this)),
m_driverManager(new DriverManager(this)),
m_envManager(new EnvManager(this)),
m_logManager(new LogManager(m_statManager,
m_driverManager->driverWorker(), this)),
m_nativeEventFilter(new NativeEventFilter(this)),
@ -80,13 +82,14 @@ FortManager::FortManager(FortSettings *fortSettings,
setupLogger();
setupAppInfoCache();
setupEnvManager();
setupStatManager();
setupConfManager();
setupLogManager();
setupDriver();
loadSettings(m_firewallConf);
loadSettings();
registerQmlTypes();
@ -160,7 +163,7 @@ void FortManager::installDriver()
DriverManager::reinstallDriver();
if (setupDriver()) {
updateDriverConf(m_firewallConf);
updateDriverConf();
}
}
@ -202,6 +205,16 @@ void FortManager::closeLogManager()
m_logManager->close();
}
void FortManager::setupEnvManager()
{
connect(m_nativeEventFilter, &NativeEventFilter::environmentChanged,
m_envManager, &EnvManager::onEnvironmentChanged);
connect(m_envManager, &EnvManager::environmentUpdated, this, [&] {
updateDriverConf();
});
}
void FortManager::setupStatManager()
{
m_statManager->initialize();
@ -535,7 +548,7 @@ void FortManager::setFirewallConfToEdit(FirewallConf *conf)
updateTrayMenu();
}
bool FortManager::loadSettings(FirewallConf *conf)
bool FortManager::loadSettings()
{
QString viaVersion;
if (!m_fortSettings->confCanMigrate(viaVersion)) {
@ -544,12 +557,12 @@ bool FortManager::loadSettings(FirewallConf *conf)
abort(); // Abort the program
}
if (!m_confManager->load(*conf)) {
if (!m_confManager->load(*m_firewallConf)) {
showErrorBox("Load Settings: " + m_confManager->errorMessage());
return false;
}
return updateDriverConf(conf);
return updateDriverConf();
}
bool FortManager::saveSettings(FirewallConf *newConf, bool onlyFlags,
@ -570,10 +583,10 @@ bool FortManager::saveSettings(FirewallConf *newConf, bool onlyFlags,
updateTrayMenu();
}
return updateDriverConf(m_firewallConf, onlyFlags);
return updateDriverConf(onlyFlags);
}
bool FortManager::updateDriverConf(FirewallConf *conf, bool onlyFlags)
bool FortManager::updateDriverConf(bool onlyFlags)
{
if (!m_driverManager->isDeviceOpened())
return true;
@ -582,11 +595,11 @@ bool FortManager::updateDriverConf(FirewallConf *conf, bool onlyFlags)
// Update driver
const bool res = onlyFlags
? m_driverManager->writeConfFlags(*conf)
: m_driverManager->writeConf(*conf);
? m_driverManager->writeConfFlags(*m_firewallConf)
: m_driverManager->writeConf(*m_firewallConf, *m_envManager);
if (res) {
updateStatManager(conf);
updateStatManager(m_firewallConf);
updateLogManager(true);
} else {
closeDriver();
@ -630,7 +643,7 @@ void FortManager::saveTrayFlags()
m_fortSettings->writeConfIni(*m_firewallConf);
updateDriverConf(m_firewallConf, true);
updateDriverConf(true);
}
void FortManager::saveWindowState()

View File

@ -12,6 +12,7 @@ QT_FORWARD_DECLARE_CLASS(QSystemTrayIcon)
QT_FORWARD_DECLARE_CLASS(AppInfoCache)
QT_FORWARD_DECLARE_CLASS(ConfManager)
QT_FORWARD_DECLARE_CLASS(DriverManager)
QT_FORWARD_DECLARE_CLASS(EnvManager)
QT_FORWARD_DECLARE_CLASS(FirewallConf)
QT_FORWARD_DECLARE_CLASS(FortSettings)
QT_FORWARD_DECLARE_CLASS(GraphWindow)
@ -107,6 +108,7 @@ private:
void setupLogManager();
void closeLogManager();
void setupEnvManager();
void setupStatManager();
void setupConfManager();
@ -124,11 +126,11 @@ private:
void closeUi();
bool loadSettings(FirewallConf *conf);
bool loadSettings();
bool saveSettings(FirewallConf *newConf, bool onlyFlags = false,
bool immediateFlags = false);
bool updateDriverConf(FirewallConf *conf, bool onlyFlags = false);
bool updateDriverConf(bool onlyFlags = false);
void updateLogManager(bool active);
void updateStatManager(FirewallConf *conf);
@ -179,6 +181,7 @@ private:
StatManager *m_statManager;
ConfManager *m_confManager;
DriverManager *m_driverManager;
EnvManager *m_envManager;
LogManager *m_logManager;
NativeEventFilter *m_nativeEventFilter;
HotKeyManager *m_hotKeyManager;

View File

@ -14,6 +14,7 @@
#include "../../conf/firewallconf.h"
#include "../../fortcommon.h"
#include "../dateutil.h"
#include "../envmanager.h"
#include "../fileutil.h"
#include "../net/ip4range.h"
@ -34,7 +35,7 @@ void ConfUtil::setErrorMessage(const QString &errorMessage)
}
}
int ConfUtil::write(const FirewallConf &conf, QByteArray &buf)
int ConfUtil::write(const FirewallConf &conf, EnvManager &envManager, QByteArray &buf)
{
quint32 addressGroupsSize = 0;
longs_arr_t addressGroupOffsets;
@ -51,7 +52,7 @@ int ConfUtil::write(const FirewallConf &conf, QByteArray &buf)
chars_arr_t appPeriods;
appgroups_map_t appGroupIndexes;
if (!parseAppGroups(conf.appGroupsList(),
if (!parseAppGroups(envManager, conf.appGroupsList(),
appPaths, appPathsLen, appPerms,
appPeriods, appPeriodsCount, appGroupIndexes))
return false;
@ -169,7 +170,8 @@ bool ConfUtil::parseAddressGroups(const QList<AddressGroup *> &addressGroups,
return true;
}
bool ConfUtil::parseAppGroups(const QList<AppGroup *> &appGroups,
bool ConfUtil::parseAppGroups(EnvManager &envManager,
const QList<AppGroup *> &appGroups,
QStringList &appPaths,
quint32 &appPathsLen,
longs_arr_t &appPerms,
@ -184,6 +186,8 @@ bool ConfUtil::parseAppGroups(const QList<AppGroup *> &appGroups,
return false;
}
envManager.clearCache(); // evaluate env vars on each save to GC
appperms_map_t appPermsMap;
for (int i = 0; i < groupsCount; ++i) {
@ -196,10 +200,11 @@ bool ConfUtil::parseAppGroups(const QList<AppGroup *> &appGroups,
return false;
}
if (!parseApps(appGroup->blockText(), true,
appPermsMap, appGroupIndexes, i)
|| !parseApps(appGroup->allowText(), false,
appPermsMap, appGroupIndexes, i))
const auto blockText = envManager.expandString(appGroup->blockText());
const auto allowText = envManager.expandString(appGroup->allowText());
if (!parseApps(blockText, true, appPermsMap, appGroupIndexes, i)
|| !parseApps(allowText, false, appPermsMap, appGroupIndexes, i))
return false;
// Enabled Period

View File

@ -11,6 +11,7 @@
QT_FORWARD_DECLARE_CLASS(AddressGroup)
QT_FORWARD_DECLARE_CLASS(AppGroup)
QT_FORWARD_DECLARE_CLASS(EnvManager)
QT_FORWARD_DECLARE_CLASS(FirewallConf)
QT_FORWARD_DECLARE_STRUCT(fort_traf)
@ -38,7 +39,7 @@ signals:
void errorMessageChanged();
public slots:
int write(const FirewallConf &conf, QByteArray &buf);
int write(const FirewallConf &conf, EnvManager &envManager, QByteArray &buf);
int writeFlags(const FirewallConf &conf, QByteArray &buf);
int writeVersion(QByteArray &buf);
@ -51,7 +52,8 @@ private:
quint32 &addressGroupsSize);
// Convert app. groups to plain lists
bool parseAppGroups(const QList<AppGroup *> &appGroups,
bool parseAppGroups(EnvManager &envManager,
const QList<AppGroup *> &appGroups,
QStringList &appPaths,
quint32 &appPathsLen,
longs_arr_t &appPerms,

100
src/ui/util/envmanager.cpp Normal file
View File

@ -0,0 +1,100 @@
#include "envmanager.h"
#include <QRegularExpression>
#include <QSettings>
EnvManager::EnvManager(QObject *parent) :
QObject(parent)
{
}
QString EnvManager::expandString(const QString &text)
{
return expandStringRecursive(text);
}
void EnvManager::clearCache()
{
m_cache.clear();
}
void EnvManager::onEnvironmentChanged()
{
auto it = m_cache.constBegin();
for (; it != m_cache.constEnd(); ++it) {
const auto key = it.key();
const auto value = it.value();
const auto newValue = readEnvVar(key);
if (value != newValue) {
emit environmentUpdated();
break;
}
}
}
QString EnvManager::expandStringRecursive(const QString &text, quint16 callLevel)
{
if (!text.contains(QLatin1Char('%')))
return text;
constexpr int maxCallLevel = 9;
if (callLevel >= maxCallLevel)
return QString(); // avoid infinite cycling
QString res = text;
QRegularExpression re("%([^%]+)%");
auto i = re.globalMatch(text);
while (i.hasNext()) {
const auto match = i.next();
const auto subKey = match.captured(1);
QString value = envVar(subKey);
value = expandStringRecursive(value, callLevel + 1);
res.replace('%' + subKey + '%', value);
}
res.replace("%%", "%"); // normalize escaped symbol
return res;
}
QString EnvManager::envVar(const QString &key)
{
auto value = m_cache.value(key);
if (value.isNull()) {
value = readEnvVar(key);
setCachedEnvVar(key, value);
}
return value.toString();
}
void EnvManager::setCachedEnvVar(const QString &key, const QVariant &value)
{
m_cache.insert(key, value);
}
QVariant EnvManager::readEnvVar(const QString &key)
{
const auto userVar = readRegVar(key, "HKEY_CURRENT_USER\\Environment");
if (!userVar.isNull())
return userVar;
const auto sysVar = readRegVar(key, "HKEY_LOCAL_MACHINE\\SYSTEM"
"\\CurrentControlSet\\Control"
"\\Session Manager\\Environment");
if (!sysVar.isNull())
return sysVar;
return qEnvironmentVariable(key.toLatin1());
}
QVariant EnvManager::readRegVar(const QString &key, const char *envPath)
{
const QSettings reg(envPath, QSettings::NativeFormat);
return reg.value(key);
}

38
src/ui/util/envmanager.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef ENVMANAGER_H
#define ENVMANAGER_H
#include <QHash>
#include <QObject>
class EnvManager : public QObject
{
Q_OBJECT
public:
explicit EnvManager(QObject *parent = nullptr);
QString expandString(const QString &text);
QString envVar(const QString &key);
void setCachedEnvVar(const QString &key, const QVariant &value);
signals:
void environmentUpdated();
public slots:
void clearCache();
void onEnvironmentChanged();
private:
QString expandStringRecursive(const QString &text,
quint16 callLevel = 0);
static QVariant readEnvVar(const QString &key);
static QVariant readRegVar(const QString &key, const char *envPath);
private:
QHash<QString, QVariant> m_cache;
};
#endif // ENVMANAGER_H

View File

@ -1,6 +1,7 @@
#include "hotkeymanager.h"
#include <QAction>
#include <QKeySequence>
#include "nativeeventfilter.h"
@ -17,7 +18,7 @@ bool HotKeyManager::addAction(QAction *action, const QKeySequence &shortcut)
{
const int hotKeyId = m_actions.size();
if (!m_nativeEventFilter->registerHotKey(hotKeyId, shortcut))
if (!m_nativeEventFilter->registerHotKey(hotKeyId, shortcut[0]))
return false;
action->setText(action->text() + '\t' + shortcut.toString());

View File

@ -1,7 +1,6 @@
#include "nativeeventfilter.h"
#include <QCoreApplication>
#include <QKeySequence>
#define WIN32_LEAN_AND_MEAN
#include <qt_windows.h>
@ -35,12 +34,9 @@ bool NativeEventFilter::registerHotKey(int hotKeyId,
return true;
}
bool NativeEventFilter::registerHotKey(int hotKeyId,
const QKeySequence &shortcut,
bool NativeEventFilter::registerHotKey(int hotKeyId, int key,
bool autoRepeat)
{
const int key = shortcut[0];
return registerHotKey(hotKeyId,
Qt::Key(key & ~Qt::KeyboardModifierMask),
Qt::KeyboardModifiers(key & Qt::KeyboardModifierMask),
@ -93,12 +89,22 @@ bool NativeEventFilter::nativeEventFilter(const QByteArray &eventType,
const MSG *msg = static_cast<MSG *>(message);
if (msg->message == WM_HOTKEY) {
switch (msg->message) {
case WM_HOTKEY: {
const int hotKeyId = getKeyId(LOWORD(msg->lParam), HIWORD(msg->lParam));
if (hotKeyId >= 0) {
emit hotKeyPressed(hotKeyId);
}
break;
}
case WM_SETTINGCHANGE: {
const auto src = reinterpret_cast<const wchar_t *>(msg->lParam);
if (src != nullptr && wcscmp(src, L"Environment") == 0) {
emit environmentChanged();
}
break;
}
}
return false;

View File

@ -23,8 +23,7 @@ public:
Qt::Key keyCode,
Qt::KeyboardModifiers modifiers,
bool autoRepeat = false);
bool registerHotKey(int hotKeyId,
const QKeySequence &shortcut,
bool registerHotKey(int hotKeyId, int key,
bool autoRepeat = false);
void unregisterHotKey(int hotKeyId);
@ -32,6 +31,7 @@ public:
signals:
void hotKeyPressed(int hotKeyId);
void environmentChanged();
public slots: