summaryrefslogtreecommitdiffhomepage
path: root/windows
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2022-08-26 10:42:38 +0200
committerDavid Lönnhager <david.l@mullvad.net>2022-08-26 10:42:38 +0200
commit1499e2ab919b853e714cb18a323b77db640e0a51 (patch)
tree6104e6bd86cfff5875833f71589964a7a7165b49 /windows
parent32e61accd7e01ffe08cdcf2fc743aa36346d3b43 (diff)
parent48938553008cb32fd1b5358f5f47ec82865dab27 (diff)
downloadmullvadvpn-1499e2ab919b853e714cb18a323b77db640e0a51.tar.xz
mullvadvpn-1499e2ab919b853e714cb18a323b77db640e0a51.zip
Merge branch 'install-st-on-demand'
Diffstat (limited to 'windows')
-rw-r--r--windows/driverlogic/driverlogic.vcxproj2
-rw-r--r--windows/driverlogic/driverlogic.vcxproj.filters2
-rw-r--r--windows/driverlogic/src/device.cpp170
-rw-r--r--windows/driverlogic/src/device.h7
-rw-r--r--windows/driverlogic/src/driverlogic.cpp115
-rw-r--r--windows/driverlogic/src/service.cpp96
-rw-r--r--windows/driverlogic/src/service.h2
-rw-r--r--windows/driverlogic/src/version.cpp125
-rw-r--r--windows/driverlogic/src/version.h30
9 files changed, 90 insertions, 459 deletions
diff --git a/windows/driverlogic/driverlogic.vcxproj b/windows/driverlogic/driverlogic.vcxproj
index cc46c1ac72..3172356a60 100644
--- a/windows/driverlogic/driverlogic.vcxproj
+++ b/windows/driverlogic/driverlogic.vcxproj
@@ -104,7 +104,6 @@
<ClCompile Include="src\service.cpp" />
<ClCompile Include="src\stdafx.cpp" />
<ClCompile Include="src\util.cpp" />
- <ClCompile Include="src\version.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\devenum.h" />
@@ -115,7 +114,6 @@
<ClInclude Include="src\stdafx.h" />
<ClInclude Include="src\targetver.h" />
<ClInclude Include="src\util.h" />
- <ClInclude Include="src\version.h" />
<ClInclude Include="src\wintun.h" />
<ClInclude Include="src\wireguard.h" />
</ItemGroup>
diff --git a/windows/driverlogic/driverlogic.vcxproj.filters b/windows/driverlogic/driverlogic.vcxproj.filters
index 9665231376..bd73d30029 100644
--- a/windows/driverlogic/driverlogic.vcxproj.filters
+++ b/windows/driverlogic/driverlogic.vcxproj.filters
@@ -13,7 +13,6 @@
<ClCompile Include="src\device.cpp" />
<ClCompile Include="src\service.cpp" />
<ClCompile Include="src\log.cpp" />
- <ClCompile Include="src\version.cpp" />
<ClCompile Include="src\util.cpp" />
<ClCompile Include="src\devenum.cpp" />
</ItemGroup>
@@ -24,7 +23,6 @@
<ClInclude Include="src\device.h" />
<ClInclude Include="src\service.h" />
<ClInclude Include="src\log.h" />
- <ClInclude Include="src\version.h" />
<ClInclude Include="src\util.h" />
<ClInclude Include="src\wintun.h" />
<ClInclude Include="src\devenum.h" />
diff --git a/windows/driverlogic/src/device.cpp b/windows/driverlogic/src/device.cpp
index e38709f01d..71abb56266 100644
--- a/windows/driverlogic/src/device.cpp
+++ b/windows/driverlogic/src/device.cpp
@@ -38,47 +38,6 @@ constexpr SIZE_T ST_DRIVER_STATE_STARTED = 1;
// Onwards.
//
-void
-ThrowUpdateException
-(
- DWORD lastError,
- const char *operation
-)
-{
- if (ERROR_DEVICE_INSTALLER_NOT_READY == lastError)
- {
- bool deviceInstallDisabled = false;
-
- try
- {
- const auto key = common::registry::Registry::OpenKey
- (
- HKEY_LOCAL_MACHINE,
- L"SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters"
- );
-
- deviceInstallDisabled = (0 != key->readUint32(L"DeviceInstallDisabled"));
- }
- catch (...)
- {
- }
-
- if (deviceInstallDisabled)
- {
- throw common::error::WindowsException
- (
- "Device installs must be enabled to continue. "
- "Enable them in the Local Group Policy editor, or "
- "update the registry value DeviceInstallDisabled in "
- "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters]",
- lastError
- );
- }
- }
-
- THROW_SETUPAPI_ERROR(lastError, operation);
-}
-
} // anonymous namespace
std::wstring
@@ -196,135 +155,6 @@ GetDeviceNetCfgInstanceId
}
void
-CreateDevice
-(
- const GUID &classGuid,
- const std::wstring &deviceName,
- const std::wstring &deviceHardwareId
-)
-{
- Log(L"Attempting to create device");
-
- const auto deviceInfoSet = SetupDiCreateDeviceInfoList(&classGuid, 0);
-
- if (INVALID_HANDLE_VALUE == deviceInfoSet)
- {
- THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCreateDeviceInfoList");
- }
-
- common::memory::ScopeDestructor scopeDestructor;
-
- scopeDestructor += [&deviceInfoSet]()
- {
- SetupDiDestroyDeviceInfoList(deviceInfoSet);
- };
-
- SP_DEVINFO_DATA devInfoData {0};
- devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
-
- auto status = SetupDiCreateDeviceInfoW
- (
- deviceInfoSet,
- deviceName.c_str(),
- &classGuid,
- nullptr,
- 0,
- DICD_GENERATE_ID,
- &devInfoData
- );
-
- if (FALSE == status)
- {
- THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCreateDeviceInfoW");
- }
-
- status = SetupDiSetDeviceRegistryPropertyW
- (
- deviceInfoSet,
- &devInfoData,
- SPDRP_HARDWAREID,
- reinterpret_cast<const BYTE *>(deviceHardwareId.c_str()),
- static_cast<DWORD>(deviceHardwareId.size() * sizeof(wchar_t))
- );
-
- if (FALSE == status)
- {
- THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiSetDeviceRegistryPropertyW");
- }
-
- //
- // Create a devnode in the PnP HW tree
- //
- status = SetupDiCallClassInstaller
- (
- DIF_REGISTERDEVICE,
- deviceInfoSet,
- &devInfoData
- );
-
- if (FALSE == status)
- {
- THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCallClassInstaller");
- }
-
- Log(L"Created new device successfully");
-}
-
-void
-InstallDriverForDevice
-(
- const std::wstring &deviceHardwareId,
- const std::wstring &infPath
-)
-{
- Log(L"Attempting to install new driver");
-
- DWORD installFlags = 0;
- BOOL rebootRequired = FALSE;
-
- for (;;)
- {
- auto result = UpdateDriverForPlugAndPlayDevicesW
- (
- nullptr,
- deviceHardwareId.c_str(),
- infPath.c_str(),
- installFlags,
- &rebootRequired
- );
-
- if (FALSE != result)
- {
- break;
- }
-
- const auto lastError = GetLastError();
-
- if (ERROR_NO_MORE_ITEMS == lastError
- && (0 == (installFlags & INSTALLFLAG_FORCE)))
- {
- Log(L"Driver installation/update failed. Attempting forced install.");
- installFlags |= INSTALLFLAG_FORCE;
-
- continue;
- }
-
- ThrowUpdateException(lastError, "UpdateDriverForPlugAndPlayDevicesW");
- }
-
- //
- // Driver successfully installed or updated
- //
-
- std::wstringstream ss;
-
- ss << L"Device driver update complete. Reboot required: "
- << rebootRequired;
-
- Log(ss.str());
-}
-
-void
UninstallDevice
(
const EnumeratedDevice &device
diff --git a/windows/driverlogic/src/device.h b/windows/driverlogic/src/device.h
index b8bc0e7f41..4dc8c4500d 100644
--- a/windows/driverlogic/src/device.h
+++ b/windows/driverlogic/src/device.h
@@ -39,13 +39,6 @@ CreateDevice
);
void
-InstallDriverForDevice
-(
- const std::wstring &deviceHardwareId,
- const std::wstring &infPath
-);
-
-void
UninstallDevice
(
const EnumeratedDevice &device
diff --git a/windows/driverlogic/src/driverlogic.cpp b/windows/driverlogic/src/driverlogic.cpp
index 2fdcc3046c..895272fa4f 100644
--- a/windows/driverlogic/src/driverlogic.cpp
+++ b/windows/driverlogic/src/driverlogic.cpp
@@ -3,7 +3,6 @@
#include "device.h"
#include "service.h"
#include "log.h"
-#include "version.h"
#include "wintun.h"
#include "wireguard.h"
#include "devenum.h"
@@ -20,8 +19,6 @@
namespace
{
-constexpr wchar_t SPLIT_TUNNEL_HARDWARE_ID[] = L"Root\\mullvad-split-tunnel";
-
DEFINE_GUID(WFP_CALLOUTS_CLASS_ID,
0x57465043, 0x616C, 0x6C6F, 0x75, 0x74, 0x5F, 0x63, 0x6C, 0x61, 0x73, 0x73);
@@ -30,11 +27,7 @@ constexpr wchar_t SPLIT_TUNNEL_DEVICE_NAME[] = L"Mullvad Split Tunnel Device";
enum ReturnCode
{
GENERAL_SUCCESS = 0,
- GENERAL_ERROR = 1,
- ST_DRIVER_NONE_INSTALLED = 2,
- ST_DRIVER_SAME_VERSION_INSTALLED = 3,
- ST_DRIVER_OLDER_VERSION_INSTALLED = 4,
- ST_DRIVER_NEWER_VERSION_INSTALLED = 5
+ GENERAL_ERROR = 1
};
class ArgumentContext
@@ -105,74 +98,6 @@ std::unique_ptr<DeviceEnumerator> CreateSplitTunnelDeviceEnumerator()
}
//
-// CommandSplitTunnelEvaluate()
-//
-// Search for existing device.
-// Evaluate if provided inf can/should be installed.
-//
-ReturnCode CommandSplitTunnelEvaluate(const std::vector<std::wstring> &args)
-{
- ArgumentContext argsContext(args);
-
- argsContext.ensureExactArgumentCount(1);
-
- const auto infPath = argsContext.next();
-
- //
- // Find first matching device
- //
-
- auto enumerator = CreateSplitTunnelDeviceEnumerator();
-
- EnumeratedDevice device;
-
- if (!enumerator->next(device))
- {
- return ReturnCode::ST_DRIVER_NONE_INSTALLED;
- }
-
- //
- // Retrieve driver versions
- //
-
- auto existingVersion = GetDriverVersion(device);
- auto proposedVersion = InfGetDriverVersion(infPath);
-
- //
- // Compare driver versions
- //
-
- switch (EvaluateDriverUpgrade(existingVersion, proposedVersion))
- {
- case DRIVER_UPGRADE_STATUS::WOULD_UPGRADE:
- return ReturnCode::ST_DRIVER_OLDER_VERSION_INSTALLED;
- case DRIVER_UPGRADE_STATUS::WOULD_DOWNGRADE:
- return ReturnCode::ST_DRIVER_NEWER_VERSION_INSTALLED;
- case DRIVER_UPGRADE_STATUS::WOULD_INSTALL_SAME_VERSION:
- return ReturnCode::ST_DRIVER_SAME_VERSION_INSTALLED;
- default:
- Log(L"Unexpected return value from EvaluateDriverUpgrade()");
- }
-
- return ReturnCode::GENERAL_ERROR;
-}
-
-ReturnCode CommandSplitTunnelNewInstall(const std::vector<std::wstring> &args)
-{
- ArgumentContext argsContext(args);
-
- argsContext.ensureExactArgumentCount(1);
-
- const auto infPath = argsContext.next();
-
- CreateDevice(WFP_CALLOUTS_CLASS_ID, SPLIT_TUNNEL_DEVICE_NAME, SPLIT_TUNNEL_HARDWARE_ID);
-
- InstallDriverForDevice(SPLIT_TUNNEL_HARDWARE_ID, infPath);
-
- return ReturnCode::GENERAL_SUCCESS;
-}
-
-//
// CommandSplitTunnelRemove()
//
// Reset driver
@@ -186,48 +111,29 @@ ReturnCode CommandSplitTunnelRemove(const std::vector<std::wstring> &args)
argsContext.ensureExactArgumentCount(0);
+ if (ServiceIsRunning(L"mullvad-split-tunnel"))
+ {
+ ResetDriverState();
+ }
+
//
- // Find first matching device
+ // Uninstall device, if it exists
//
auto enumerator = CreateSplitTunnelDeviceEnumerator();
EnumeratedDevice device;
- if (!enumerator->next(device))
+ if (enumerator->next(device))
{
- Log(L"Could not find split tunnel device");
-
- return ReturnCode::GENERAL_SUCCESS;
+ UninstallDevice(device);
}
- ResetDriverState();
-
- UninstallDevice(device);
-
PokeService(L"mullvad-split-tunnel", true, true);
return ReturnCode::GENERAL_SUCCESS;
}
-//
-// CommandSplitTunnelForceInstall()
-//
-// There's an existing device that needs to be stopped and removed.
-// After this, create a new device and associate the specified inf.
-//
-ReturnCode CommandSplitTunnelForceInstall(const std::vector<std::wstring> &args)
-{
- auto status = CommandSplitTunnelRemove({});
-
- if (ReturnCode::GENERAL_SUCCESS != status)
- {
- return status;
- }
-
- return CommandSplitTunnelNewInstall(args);
-}
-
ReturnCode CommandWintunDeleteDriver(const std::vector<std::wstring> &args)
{
ArgumentContext argsContext(args);
@@ -336,9 +242,6 @@ int wmain(int argc, const wchar_t *argv[])
std::vector<CommandHandler> handlers =
{
- { L"st-evaluate", CommandSplitTunnelEvaluate },
- { L"st-new-install", CommandSplitTunnelNewInstall },
- { L"st-force-install", CommandSplitTunnelForceInstall },
{ L"st-remove", CommandSplitTunnelRemove },
{ L"wintun-delete-driver", CommandWintunDeleteDriver },
{ L"wintun-delete-abandoned-device", CommandWintunDeleteAbandonedDevice },
diff --git a/windows/driverlogic/src/service.cpp b/windows/driverlogic/src/service.cpp
index 14ed7880fa..cdaaf77ea9 100644
--- a/windows/driverlogic/src/service.cpp
+++ b/windows/driverlogic/src/service.cpp
@@ -43,29 +43,46 @@ private:
TTime m_maxWaitTime;
};
+SERVICE_STATUS_PROCESS GetServiceProcessStatus(SC_HANDLE service)
+{
+ SERVICE_STATUS_PROCESS ssp;
+
+ DWORD bytesNeeded;
+
+ auto status = QueryServiceStatusEx
+ (
+ service,
+ SC_STATUS_PROCESS_INFO,
+ reinterpret_cast<BYTE*>(&ssp),
+ sizeof(ssp),
+ &bytesNeeded
+ );
+
+ if (status != 0)
+ {
+ return ssp;
+ }
+
+ THROW_WINDOWS_ERROR(GetLastError(), "QueryServiceStatusEx");
+}
+
void WaitUntilServiceStopped(SC_HANDLE service, DWORD maxWaitMs)
{
TimeBox timer(maxWaitMs);
for (;;)
{
- SERVICE_STATUS_PROCESS ssp;
-
- DWORD bytesNeeded;
-
- auto status = QueryServiceStatusEx
- (
- service,
- SC_STATUS_PROCESS_INFO,
- reinterpret_cast<BYTE*>(&ssp),
- sizeof(ssp),
- &bytesNeeded
- );
+ try
+ {
+ const auto status = GetServiceProcessStatus(service);
- if (status != 0
- && ssp.dwCurrentState == SERVICE_STOPPED)
+ if (status.dwCurrentState == SERVICE_STOPPED)
+ {
+ return;
+ }
+ }
+ catch (...)
{
- return;
}
if (timer.expired())
@@ -77,6 +94,44 @@ void WaitUntilServiceStopped(SC_HANDLE service, DWORD maxWaitMs)
}
}
+bool ServiceIsRunning(const std::wstring &serviceName)
+{
+ const auto serviceManager = OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
+
+ if (serviceManager == NULL)
+ {
+ THROW_WINDOWS_ERROR(GetLastError(), "OpenSCManagerW");
+ }
+
+ common::memory::ScopeDestructor dtor;
+
+ dtor += [serviceManager]()
+ {
+ CloseServiceHandle(serviceManager);
+ };
+
+ const auto service = OpenServiceW(serviceManager, serviceName.c_str(), SERVICE_ALL_ACCESS);
+
+ if (service == NULL)
+ {
+ const auto error = GetLastError();
+
+ if (error != ERROR_SERVICE_DOES_NOT_EXIST)
+ {
+ THROW_WINDOWS_ERROR(error, "OpenServiceW");
+ }
+
+ return false;
+ }
+
+ dtor += [service]()
+ {
+ CloseServiceHandle(service);
+ };
+
+ return GetServiceProcessStatus(service).dwCurrentState == SERVICE_RUNNING;
+}
+
void PokeService(const std::wstring &serviceName, bool stopService, bool deleteService)
{
auto serviceManager = OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
@@ -97,7 +152,16 @@ void PokeService(const std::wstring &serviceName, bool stopService, bool deleteS
if (service == NULL)
{
- THROW_WINDOWS_ERROR(GetLastError(), "OpenServiceW");
+ const auto error = GetLastError();
+
+ if (error != ERROR_SERVICE_DOES_NOT_EXIST)
+ {
+ THROW_WINDOWS_ERROR(error, "OpenServiceW");
+ }
+
+ // If the service does not exist, we're done.
+
+ return;
}
dtor += [service]()
diff --git a/windows/driverlogic/src/service.h b/windows/driverlogic/src/service.h
index 87632faf1b..423d16c0f0 100644
--- a/windows/driverlogic/src/service.h
+++ b/windows/driverlogic/src/service.h
@@ -2,6 +2,6 @@
#include <windows.h>
-void WaitUntilServiceStopped(SC_HANDLE service, DWORD maxWaitMs);
+bool ServiceIsRunning(const std::wstring &serviceName);
void PokeService(const std::wstring &serviceName, bool stopService, bool deleteService);
diff --git a/windows/driverlogic/src/version.cpp b/windows/driverlogic/src/version.cpp
deleted file mode 100644
index d7394e224b..0000000000
--- a/windows/driverlogic/src/version.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-#include "stdafx.h"
-#include "version.h"
-#include "device.h"
-#include <setupapi.h>
-#include <initguid.h>
-#include <devpkey.h>
-#include <libcommon/string.h>
-#include <libcommon/memory.h>
-#include <stdexcept>
-
-DRIVER_UPGRADE_STATUS
-EvaluateDriverUpgrade
-(
- const std::wstring &existingVersion,
- const std::wstring &proposedVersion
-)
-{
- //
- // "x.y.z.a"
- //
-
- using namespace common::string;
-
- auto et = Tokenize(existingVersion, L".");
- auto pt = Tokenize(proposedVersion, L".");
-
- auto items = min(et.size(), pt.size());
-
- for (auto index = 0; index < items; ++index)
- {
- auto ev = wcstoul(et[index].c_str(), nullptr, 10);
- auto pv = wcstoul(pt[index].c_str(), nullptr, 10);
-
- if (pv > ev)
- {
- return DRIVER_UPGRADE_STATUS::WOULD_UPGRADE;
- }
-
- if (ev > pv)
- {
- return DRIVER_UPGRADE_STATUS::WOULD_DOWNGRADE;
- }
- }
-
- if (pt.size() > et.size())
- {
- return DRIVER_UPGRADE_STATUS::WOULD_UPGRADE;
- }
-
- if (et.size() > pt.size())
- {
- return DRIVER_UPGRADE_STATUS::WOULD_DOWNGRADE;
- }
-
- return DRIVER_UPGRADE_STATUS::WOULD_INSTALL_SAME_VERSION;
-}
-
-std::wstring
-InfGetDriverVersion
-(
- const std::wstring &filePath
-)
-{
- auto infHandle = SetupOpenInfFileW(filePath.c_str(), nullptr, INF_STYLE_WIN4, nullptr);
-
- if (infHandle == INVALID_HANDLE_VALUE)
- {
- throw std::runtime_error("SetupOpenInfFileW()");
- }
-
- common::memory::ScopeDestructor dtor;
-
- dtor += [infHandle]()
- {
- SetupCloseInfFile(infHandle);
- };
-
- INFCONTEXT infContext { 0 };
-
- auto status = SetupFindFirstLineW(infHandle, L"Version", L"DriverVer", &infContext);
-
- if (status == FALSE)
- {
- throw std::runtime_error("SetupFindFirstLineW()");
- }
-
- DWORD requiredSize;
-
- //
- // This is a multi-value key.
- // 0 = key, 1 = driver date
- //
- const DWORD VersionFieldIndex = 2;
-
- status = SetupGetStringFieldW(&infContext, VersionFieldIndex, nullptr, 0, &requiredSize);
-
- if (status == FALSE || requiredSize < 2)
- {
- throw std::runtime_error("SetupGetStringFieldW()");
- }
-
- std::vector<wchar_t> buffer(requiredSize);
-
- status = SetupGetStringFieldW(&infContext, VersionFieldIndex,
- &buffer[0], static_cast<DWORD>(buffer.size()), nullptr);
-
- if (status == FALSE)
- {
- throw std::runtime_error("SetupGetStringFieldW()");
- }
-
- // Remove null terminator.
- buffer.resize(requiredSize - 1);
-
- return buffer.data();
-}
-
-std::wstring
-GetDriverVersion
-(
- const EnumeratedDevice &device
-)
-{
- return GetDeviceStringProperty(device.deviceInfoSet, device.deviceInfo, &DEVPKEY_Device_DriverVersion);
-}
diff --git a/windows/driverlogic/src/version.h b/windows/driverlogic/src/version.h
deleted file mode 100644
index fc88b3b232..0000000000
--- a/windows/driverlogic/src/version.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include <string>
-#include "device.h"
-
-enum class DRIVER_UPGRADE_STATUS
-{
- WOULD_DOWNGRADE,
- WOULD_INSTALL_SAME_VERSION,
- WOULD_UPGRADE
-};
-
-DRIVER_UPGRADE_STATUS
-EvaluateDriverUpgrade
-(
- const std::wstring &existingVersion,
- const std::wstring &proposedVersion
-);
-
-std::wstring
-InfGetDriverVersion
-(
- const std::wstring &filePath
-);
-
-std::wstring
-GetDriverVersion
-(
- const EnumeratedDevice &device
-);