diff --git a/deploy/FortFirewall.exe.example.ini b/deploy/FortFirewall.exe.example.ini index 2b362c3a..29e1c513 100644 --- a/deploy/FortFirewall.exe.example.ini +++ b/deploy/FortFirewall.exe.example.ini @@ -43,3 +43,6 @@ ;Try to install a driver on opening error. ;canInstallDriver=false + +;Try to start a Service on startup. +;canStartService=false diff --git a/src/ui/FortFirewallUI.pro b/src/ui/FortFirewallUI.pro index 35c0be9a..d602e539 100644 --- a/src/ui/FortFirewallUI.pro +++ b/src/ui/FortFirewallUI.pro @@ -198,6 +198,7 @@ SOURCES += \ util/osutil.cpp \ util/processinfo.cpp \ util/regkey.cpp \ + util/service/servicehandle.cpp \ util/service/serviceinfo.cpp \ util/service/servicelistmonitor.cpp \ util/service/servicemanageriface.cpp \ @@ -412,6 +413,7 @@ HEADERS += \ util/osutil.h \ util/processinfo.h \ util/regkey.h \ + util/service/servicehandle.h \ util/service/serviceinfo.h \ util/service/servicelistmonitor.h \ util/service/servicemanageriface.h \ diff --git a/src/ui/fortmanager.cpp b/src/ui/fortmanager.cpp index 59244025..991e4ae4 100644 --- a/src/ui/fortmanager.cpp +++ b/src/ui/fortmanager.cpp @@ -179,6 +179,7 @@ void FortManager::initialize() loadConf(); checkInstallDriver(); + checkStartService(); } void FortManager::setupThreadPool() @@ -329,14 +330,29 @@ void FortManager::checkInstallDriver() const auto settings = IoC(); - const bool canInstallDriver = (settings->canInstallDriver() || settings->isPortable()) - && settings->isMaster() && settings->isUserAdmin(); + const bool canInstallDriver = (settings->canInstallDriver() || settings->isPortable()); + const bool isMasterAdmin = (settings->isMaster() && settings->isUserAdmin()); - if (canInstallDriver) { + if (canInstallDriver && isMasterAdmin) { installDriver(); } } +void FortManager::checkStartService() +{ + const auto settings = IoC(); + + if (settings->isMaster() || StartupUtil::isServiceRunning()) + return; + + const bool canStartService = settings->canStartService(); + const bool isAdmin = settings->isUserAdmin(); + + if (canStartService && isAdmin) { + StartupUtil::startService(); + } +} + void FortManager::setupEnvManager() { auto envManager = IoC(); diff --git a/src/ui/fortmanager.h b/src/ui/fortmanager.h index 775f11b1..d4e0a3db 100644 --- a/src/ui/fortmanager.h +++ b/src/ui/fortmanager.h @@ -45,6 +45,7 @@ private: void closeDriver(); void checkInstallDriver(); + void checkStartService(); void setupEnvManager(); void setupConfManager(); diff --git a/src/ui/fortsettings.cpp b/src/ui/fortsettings.cpp index aa10e09b..82367550 100644 --- a/src/ui/fortsettings.cpp +++ b/src/ui/fortsettings.cpp @@ -119,6 +119,7 @@ void FortSettings::setupGlobal() m_noCache = settings.value("global/noCache").toBool(); m_canInstallDriver = settings.value("global/canInstallDriver").toBool(); + m_canStartService = settings.value("global/canStartService").toBool(); m_defaultLanguage = settings.value("global/defaultLanguage").toString(); m_profilePath = settings.value("global/profileDir").toString(); diff --git a/src/ui/fortsettings.h b/src/ui/fortsettings.h index a3fbbd03..06a118a9 100644 --- a/src/ui/fortsettings.h +++ b/src/ui/fortsettings.h @@ -33,6 +33,7 @@ public: bool noCache() const { return m_noCache; } bool noSplash() const { return m_noSplash; } bool canInstallDriver() const { return m_canInstallDriver; } + bool canStartService() const { return m_canStartService; } bool isService() const { return m_isService; } bool hasService() const { return m_hasService; } @@ -129,6 +130,7 @@ private: uint m_noCache : 1 = false; uint m_noSplash : 1 = false; uint m_canInstallDriver : 1 = false; + uint m_canStartService : 1 = false; uint m_isService : 1 = false; uint m_hasService : 1 = false; uint m_isUserAdmin : 1 = false; diff --git a/src/ui/util/service/servicehandle.cpp b/src/ui/util/service/servicehandle.cpp new file mode 100644 index 00000000..638f4b1d --- /dev/null +++ b/src/ui/util/service/servicehandle.cpp @@ -0,0 +1,120 @@ +#include "servicehandle.h" + +#include + +#define WIN32_LEAN_AND_MEAN +#include + +#include "servicemanageriface.h" + +ServiceHandle::ServiceHandle( + const wchar_t *serviceName, quint32 managerAccess, quint32 serviceAccess) +{ + openService(serviceName, managerAccess, serviceAccess); +} + +ServiceHandle::~ServiceHandle() +{ + closeService(); +} + +bool ServiceHandle::queryIsRunning() +{ + SERVICE_STATUS status; + if (QueryServiceStatus(SC_HANDLE(m_serviceHandle), &status)) { + return (status.dwCurrentState == SERVICE_RUNNING); + } + return false; +} + +bool ServiceHandle::startService() +{ + return StartServiceW(SC_HANDLE(m_serviceHandle), 0, nullptr); +} + +bool ServiceHandle::stopService() +{ + int n = 3; /* count of attempts to stop the service */ + do { + SERVICE_STATUS status; + if (QueryServiceStatus(SC_HANDLE(m_serviceHandle), &status) + && status.dwCurrentState == SERVICE_STOPPED) + return true; + + const DWORD controlCode = (status.dwControlsAccepted & SERVICE_ACCEPT_STOP) != 0 + ? SERVICE_CONTROL_STOP + : FORT_SERVICE_CONTROL_UNINSTALL; + + ControlService(SC_HANDLE(m_serviceHandle), controlCode, &status); + + QThread::msleep(n * 100); + } while (--n > 0); + + return false; +} + +void ServiceHandle::createService(const wchar_t *serviceName, const wchar_t *serviceDisplay, + const wchar_t *serviceGroup, const wchar_t *dependencies, const QString &command) +{ + m_serviceHandle = qintptr(CreateServiceW(SC_HANDLE(m_managerHandle), serviceName, + serviceDisplay, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, (LPCWSTR) command.utf16(), serviceGroup, 0, dependencies, nullptr, + nullptr)); +} + +bool ServiceHandle::deleteService() +{ + return DeleteService(SC_HANDLE(m_serviceHandle)); +} + +void ServiceHandle::setServiceDescription(const wchar_t *serviceDescription) +{ + SERVICE_DESCRIPTION sd = { (LPWSTR) serviceDescription }; + + ChangeServiceConfig2(SC_HANDLE(m_serviceHandle), SERVICE_CONFIG_DESCRIPTION, &sd); +} + +void ServiceHandle::setupServiceRestartConfig() +{ + constexpr int actionsCount = 3; + + SC_ACTION actions[actionsCount]; + actions[0].Type = SC_ACTION_RESTART; + actions[0].Delay = 150; + actions[1].Type = SC_ACTION_NONE; + actions[1].Delay = 0; + actions[2].Type = SC_ACTION_NONE; + actions[2].Delay = 0; + + SERVICE_FAILURE_ACTIONS sfa; + sfa.dwResetPeriod = 0; + sfa.lpCommand = NULL; + sfa.lpRebootMsg = NULL; + sfa.cActions = actionsCount; + sfa.lpsaActions = actions; + + ChangeServiceConfig2(SC_HANDLE(m_serviceHandle), SERVICE_CONFIG_FAILURE_ACTIONS, &sfa); +} + +void ServiceHandle::openService( + const wchar_t *serviceName, quint32 managerAccess, quint32 serviceAccess) +{ + m_managerHandle = qintptr(OpenSCManagerW(nullptr, nullptr, managerAccess)); + if (!m_managerHandle) + return; + + if (serviceAccess != 0) { + m_serviceHandle = + qintptr(OpenServiceW(SC_HANDLE(m_managerHandle), serviceName, serviceAccess)); + } +} + +void ServiceHandle::closeService() +{ + if (m_serviceHandle) { + CloseServiceHandle(SC_HANDLE(m_serviceHandle)); + } + if (m_managerHandle) { + CloseServiceHandle(SC_HANDLE(m_managerHandle)); + } +} diff --git a/src/ui/util/service/servicehandle.h b/src/ui/util/service/servicehandle.h new file mode 100644 index 00000000..c011e1f3 --- /dev/null +++ b/src/ui/util/service/servicehandle.h @@ -0,0 +1,37 @@ +#ifndef SERVICEHANDLE_H +#define SERVICEHANDLE_H + +#include + +class ServiceHandle final +{ +public: + explicit ServiceHandle( + const wchar_t *serviceName, quint32 managerAccess = 0, quint32 serviceAccess = 0); + ~ServiceHandle(); + + bool isManagerOpened() const { return m_managerHandle != 0; } + bool isServiceOpened() const { return m_serviceHandle != 0; } + + bool queryIsRunning(); + + bool startService(); + bool stopService(); + + void createService(const wchar_t *serviceName, const wchar_t *serviceDisplay, + const wchar_t *serviceGroup, const wchar_t *dependencies, const QString &command); + bool deleteService(); + + void setServiceDescription(const wchar_t *serviceDescription); + void setupServiceRestartConfig(); + +private: + void openService(const wchar_t *serviceName, quint32 managerAccess, quint32 serviceAccess); + void closeService(); + +private: + qintptr m_managerHandle = 0; + qintptr m_serviceHandle = 0; +}; + +#endif // SERVICEHANDLE_H diff --git a/src/ui/util/startuputil.cpp b/src/ui/util/startuputil.cpp index 9a190284..3dc7c9d6 100644 --- a/src/ui/util/startuputil.cpp +++ b/src/ui/util/startuputil.cpp @@ -9,9 +9,10 @@ #include -#include "fileutil.h" -#include "regkey.h" -#include "service/servicemanageriface.h" +#include +#include +#include +#include namespace { @@ -91,87 +92,34 @@ void removeAutorunForAllUsers() removeAutorunForUser(regAllUsersRoot, regAllUsersRun); } -static void setupServiceRestartConfig(SC_HANDLE svc) -{ - constexpr int actionsCount = 3; - - SC_ACTION actions[actionsCount]; - actions[0].Type = SC_ACTION_RESTART; - actions[0].Delay = 150; - actions[1].Type = SC_ACTION_NONE; - actions[1].Delay = 0; - actions[2].Type = SC_ACTION_NONE; - actions[2].Delay = 0; - - SERVICE_FAILURE_ACTIONS sfa; - sfa.dwResetPeriod = 0; - sfa.lpCommand = NULL; - sfa.lpRebootMsg = NULL; - sfa.cActions = actionsCount; - sfa.lpsaActions = actions; - - ChangeServiceConfig2(svc, SERVICE_CONFIG_FAILURE_ACTIONS, &sfa); -} - bool installService(const wchar_t *serviceName, const wchar_t *serviceDisplay, const wchar_t *serviceDescription, const wchar_t *serviceGroup, const wchar_t *dependencies, const QString &command) { - bool res = false; - const SC_HANDLE mngr = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE); - if (mngr) { - const SC_HANDLE svc = CreateServiceW(mngr, serviceName, serviceDisplay, SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - (LPCWSTR) command.utf16(), serviceGroup, 0, dependencies, nullptr, nullptr); - if (svc) { - SERVICE_DESCRIPTION sd = { (LPWSTR) serviceDescription }; - ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd); + ServiceHandle svc(serviceName, SC_MANAGER_CREATE_SERVICE); + if (!svc.isManagerOpened()) + return false; - setupServiceRestartConfig(svc); + svc.createService(serviceName, serviceDisplay, serviceGroup, dependencies, command); + if (!svc.isServiceOpened()) + return false; - res = true; - CloseServiceHandle(svc); - } - CloseServiceHandle(mngr); - } - return res; -} + svc.setServiceDescription(serviceDescription); + svc.setupServiceRestartConfig(); -bool stopServiceControl(SC_HANDLE svc) -{ - int n = 3; /* count of attempts to stop the service */ - do { - SERVICE_STATUS status; - if (QueryServiceStatus(svc, &status) && status.dwCurrentState == SERVICE_STOPPED) - return true; - - const DWORD controlCode = (status.dwControlsAccepted & SERVICE_ACCEPT_STOP) != 0 - ? SERVICE_CONTROL_STOP - : FORT_SERVICE_CONTROL_UNINSTALL; - - ControlService(svc, controlCode, &status); - - QThread::msleep(n * 100); - } while (--n > 0); - - return false; + return true; } bool uninstallService(const wchar_t *serviceName) { - bool res = false; - const SC_HANDLE mngr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (mngr) { - const SC_HANDLE svc = OpenServiceW(mngr, serviceName, SERVICE_ALL_ACCESS | DELETE); - if (svc) { - stopServiceControl(svc); + ServiceHandle svc(serviceName, SC_MANAGER_ALL_ACCESS, SERVICE_ALL_ACCESS | DELETE); + if (svc.isServiceOpened()) { + svc.stopService(); - res = DeleteService(svc); - CloseServiceHandle(svc); - } - CloseServiceHandle(mngr); + return svc.deleteService(); } - return res; + + return false; } } @@ -183,17 +131,9 @@ const wchar_t *StartupUtil::serviceName() bool StartupUtil::isServiceInstalled() { - bool res = false; - const SC_HANDLE mngr = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT); - if (mngr) { - const SC_HANDLE svc = OpenServiceW(mngr, serviceNameStr, SERVICE_INTERROGATE); - if (svc) { - res = true; - CloseServiceHandle(svc); - } - CloseServiceHandle(mngr); - } - return res; + ServiceHandle svc(serviceNameStr, SC_MANAGER_CONNECT, SERVICE_INTERROGATE); + + return svc.isServiceOpened(); } void StartupUtil::setServiceInstalled(bool install) @@ -209,36 +149,38 @@ void StartupUtil::setServiceInstalled(bool install) serviceDependenciesStr, command); startService(); + QThread::msleep(100); // Let the service to start } +bool StartupUtil::isServiceRunning() +{ + ServiceHandle svc(serviceNameStr, SC_MANAGER_CONNECT, SERVICE_INTERROGATE); + if (svc.isServiceOpened()) { + return svc.queryIsRunning(); + } + + return false; +} + bool StartupUtil::startService() { - bool res = false; - const SC_HANDLE mngr = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT); - if (mngr) { - const SC_HANDLE svc = OpenServiceW(mngr, serviceNameStr, SERVICE_START); - if (svc) { - res = StartServiceW(svc, 0, nullptr); - CloseServiceHandle(svc); - } - CloseServiceHandle(mngr); + ServiceHandle svc(serviceNameStr, SC_MANAGER_CONNECT, SERVICE_START); + if (svc.isServiceOpened()) { + return svc.startService(); } - return res; + + return false; } bool StartupUtil::stopService() { - bool res = false; - const SC_HANDLE mngr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (mngr) { - const SC_HANDLE svc = OpenServiceW(mngr, serviceNameStr, SERVICE_ALL_ACCESS); - if (svc) { - res = stopServiceControl(svc); - } - CloseServiceHandle(mngr); + ServiceHandle svc(serviceNameStr, SC_MANAGER_ALL_ACCESS, SERVICE_ALL_ACCESS); + if (svc.isServiceOpened()) { + return svc.stopService(); } - return res; + + return false; } StartupUtil::AutoRunMode StartupUtil::autoRunMode() diff --git a/src/ui/util/startuputil.h b/src/ui/util/startuputil.h index ffc1872e..27c5da30 100644 --- a/src/ui/util/startuputil.h +++ b/src/ui/util/startuputil.h @@ -13,6 +13,8 @@ public: static bool isServiceInstalled(); static void setServiceInstalled(bool install); + static bool isServiceRunning(); + static bool startService(); static bool stopService();