From 44498bd1451c009705afae0aad5bf0065c83f0ed Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Mon, 29 Mar 2021 12:33:17 +0300 Subject: [PATCH] UI: StartupUtil: Add service (un)install functions. --- src/ui/form/opt/pages/optionspage.cpp | 7 +-- src/ui/fortsettings.cpp | 10 ++++ src/ui/fortsettings.h | 2 + src/ui/service/servicemanager.cpp | 26 +-------- src/ui/service/servicemanager.h | 7 +-- src/ui/util/startuputil.cpp | 76 +++++++++++++++++++++++++-- src/ui/util/startuputil.h | 4 ++ 7 files changed, 94 insertions(+), 38 deletions(-) diff --git a/src/ui/form/opt/pages/optionspage.cpp b/src/ui/form/opt/pages/optionspage.cpp index 4e88592b..c2189451 100644 --- a/src/ui/form/opt/pages/optionspage.cpp +++ b/src/ui/form/opt/pages/optionspage.cpp @@ -118,13 +118,14 @@ void OptionsPage::retranslateComboStartMode() const QStringList list = { tr("Disabled"), tr("For current user"), tr("For all users"), tr("For all users in background") }; - const int currentIndex = m_comboStartMode->currentIndex(); + const int currentIndex = m_comboStartMode->currentIndex() >= 0 + ? m_comboStartMode->currentIndex() + : StartupUtil::getStartupMode(); m_comboStartMode->clear(); m_comboStartMode->addItems(list); - m_comboStartMode->setCurrentIndex( - currentIndex < 0 ? StartupUtil::getStartupMode() : currentIndex); + m_comboStartMode->setCurrentIndex(currentIndex); // Disable some items if user is not an administrator if (OsUtil::isUserAdmin()) diff --git a/src/ui/fortsettings.cpp b/src/ui/fortsettings.cpp index 46704f78..6c487f7a 100644 --- a/src/ui/fortsettings.cpp +++ b/src/ui/fortsettings.cpp @@ -31,6 +31,7 @@ FortSettings::FortSettings(QObject *parent) : QObject(parent), m_iniExists(false), m_noCache(false), + m_isService(false), m_bulkUpdating(false), m_bulkIniChanged(false) { @@ -99,6 +100,10 @@ void FortSettings::processArguments(const QStringList &args, EnvManager *envMana const QCommandLineOption langOption(QStringList() << "lang", "Default language.", "lang", "en"); parser.addOption(langOption); + const QCommandLineOption serviceOption( + QStringList() << "service", "Is running as a service?", "service"); + parser.addOption(serviceOption); + const QCommandLineOption controlOption(QStringList() << "c" << "control", "Control running instance by executing the command.", "control"); @@ -119,6 +124,11 @@ void FortSettings::processArguments(const QStringList &args, EnvManager *envMana m_defaultLanguage = parser.value(langOption); } + // Is service + if (parser.isSet(serviceOption)) { + m_isService = true; + } + // Profile Path if (parser.isSet(profileOption)) { m_profilePath = parser.value(profileOption); diff --git a/src/ui/fortsettings.h b/src/ui/fortsettings.h index 8c1cd32a..8f112a4e 100644 --- a/src/ui/fortsettings.h +++ b/src/ui/fortsettings.h @@ -18,6 +18,7 @@ public: explicit FortSettings(QObject *parent = nullptr); bool noCache() const { return m_noCache; } + bool isService() const { return m_isService; } bool debug() const { return iniBool("base/debug"); } void setDebug(bool on) { setIniValue("base/debug", on); } @@ -276,6 +277,7 @@ private: private: bool m_iniExists : 1; bool m_noCache : 1; + bool m_isService : 1; bool m_bulkUpdating : 1; bool m_bulkIniChanged : 1; diff --git a/src/ui/service/servicemanager.cpp b/src/ui/service/servicemanager.cpp index 3bd5a69b..cb2b0093 100644 --- a/src/ui/service/servicemanager.cpp +++ b/src/ui/service/servicemanager.cpp @@ -1,27 +1,3 @@ #include "servicemanager.h" -#define WIN32_LEAN_AND_MEAN -#include - -namespace { - -const char *const serviceName = "FortFirewallSvc"; - -} - -ServiceManager::ServiceManager(QObject *parent) : QObject(parent) { } - -bool ServiceManager::isServiceInstalled() -{ - bool res = false; - const SC_HANDLE scHandle = OpenSCManagerA(nullptr, nullptr, SC_MANAGER_CONNECT); - if (scHandle) { - const SC_HANDLE serviceHandle = OpenServiceA(scHandle, serviceName, SERVICE_INTERROGATE); - if (serviceHandle) { - res = true; - CloseServiceHandle(serviceHandle); - } - CloseServiceHandle(scHandle); - } - return res; -} +#include diff --git a/src/ui/service/servicemanager.h b/src/ui/service/servicemanager.h index 382d954a..cac223ef 100644 --- a/src/ui/service/servicemanager.h +++ b/src/ui/service/servicemanager.h @@ -3,14 +3,9 @@ #include -class ServiceManager : public QObject +class ServiceManager { - Q_OBJECT - public: - explicit ServiceManager(QObject *parent = nullptr); - - static bool isServiceInstalled(); }; #endif // SERVICEMANAGER_H diff --git a/src/ui/util/startuputil.cpp b/src/ui/util/startuputil.cpp index f90ed960..97876a0a 100644 --- a/src/ui/util/startuputil.cpp +++ b/src/ui/util/startuputil.cpp @@ -2,6 +2,10 @@ #include #include +#include + +#define WIN32_LEAN_AND_MEAN +#include #include @@ -9,11 +13,19 @@ namespace { +const char *const serviceName = "FortFirewallSvc"; + const char *const regCurUserRun = R"(HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run)"; const char *const regAllUsersRun = R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run)"; +QString appFilePath() +{ + const auto filePath = QCoreApplication::applicationFilePath().replace('/', '\\'); + return QString("\"%1\"").arg(filePath); +} + bool isAutorunForUser(const char *key) { const QSettings reg(key, QSettings::Registry64Format); @@ -33,7 +45,7 @@ bool isAutorunForAllUsers() void setAutorunForUser(const char *key) { QSettings reg(key, QSettings::Registry64Format); - reg.setValue(APP_NAME, QString("\"%1\"").arg(QCoreApplication::applicationFilePath())); + reg.setValue(APP_NAME, appFilePath()); } void setAutorunForCurrentUser() @@ -64,9 +76,65 @@ void removeAutorunForAllUsers() } +bool StartupUtil::isServiceInstalled() +{ + bool res = false; + const SC_HANDLE mngr = OpenSCManagerA(nullptr, nullptr, SC_MANAGER_CONNECT); + if (mngr) { + const SC_HANDLE svc = OpenServiceA(mngr, serviceName, SERVICE_INTERROGATE); + if (svc) { + res = true; + CloseServiceHandle(svc); + } + CloseServiceHandle(mngr); + } + return res; +} + +bool StartupUtil::installService() +{ + bool res = false; + const SC_HANDLE mngr = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); + if (mngr) { + const auto command = appFilePath() + " --service"; + const SC_HANDLE svc = CreateServiceA(mngr, serviceName, APP_NAME, SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, + command.toLatin1(), 0, 0, 0, 0, 0); + if (svc) { + res = true; + CloseServiceHandle(svc); + } + CloseServiceHandle(mngr); + } + return res; +} + +bool StartupUtil::uninstallService() +{ + bool res = false; + const SC_HANDLE mngr = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); + if (mngr) { + const SC_HANDLE svc = OpenServiceA(mngr, serviceName, SERVICE_ALL_ACCESS | DELETE); + if (svc) { + int n = 2; /* count of attempts to stop the service */ + do { + SERVICE_STATUS status; + if (QueryServiceStatus(svc, &status) && status.dwCurrentState == SERVICE_STOPPED) + break; + ControlService(svc, SERVICE_CONTROL_STOP, &status); + QThread::msleep(1000); + } while (--n > 0); + res = DeleteService(svc); + CloseServiceHandle(svc); + } + CloseServiceHandle(mngr); + } + return res; +} + StartupUtil::StartupMode StartupUtil::getStartupMode() { - return ServiceManager::isServiceInstalled() + return isServiceInstalled() ? (isAutorunForAllUsers() ? StartupAllUsers : StartupAllUsersBackground) : (isAutorunForCurrentUser() ? StartupCurrentUser : StartupDisabled); } @@ -75,7 +143,7 @@ void StartupUtil::setStartupMode(StartupMode mode) { removeAutorunForCurrentUser(); removeAutorunForAllUsers(); - // TODO: ServiceManager::uninstallService(); + uninstallService(); switch (mode) { case StartupDisabled: @@ -87,7 +155,7 @@ void StartupUtil::setStartupMode(StartupMode mode) setAutorunForAllUsers(); Q_FALLTHROUGH(); case StartupAllUsersBackground: - // TODO: ServiceManager::installService(); + installService(); break; } } diff --git a/src/ui/util/startuputil.h b/src/ui/util/startuputil.h index 45767d10..31342b04 100644 --- a/src/ui/util/startuputil.h +++ b/src/ui/util/startuputil.h @@ -13,6 +13,10 @@ public: StartupAllUsersBackground }; + static bool isServiceInstalled(); + static bool installService(); + static bool uninstallService(); + static StartupMode getStartupMode(); static void setStartupMode(StartupMode mode); };