diff options
author | 2021-10-05 01:33:38 +0000 | |
---|---|---|
committer | 2021-10-06 18:05:46 +0000 | |
commit | 5030636183d926573cae769bc87d8522cc734626 (patch) | |
tree | e39b57481de6d8bc8ca28a20eaec88faff911f48 | |
parent | api: adapter: set suggested instance ID using INF instead of ourselves (diff) | |
download | wireguard-nt-5030636183d926573cae769bc87d8522cc734626.tar.xz wireguard-nt-5030636183d926573cae769bc87d8522cc734626.zip |
api: migrate to swdevice and rework entire api
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | api/adapter.c | 1966 | ||||
-rw-r--r-- | api/adapter.h | 109 | ||||
-rw-r--r-- | api/adapter_win7.h | 310 | ||||
-rw-r--r-- | api/api.vcxproj | 16 | ||||
-rw-r--r-- | api/api.vcxproj.filters | 15 | ||||
-rw-r--r-- | api/driver.c | 752 | ||||
-rw-r--r-- | api/driver.h | 34 | ||||
-rw-r--r-- | api/exports.def | 8 | ||||
-rw-r--r-- | api/main.c | 15 | ||||
-rw-r--r-- | api/main.h | 13 | ||||
-rw-r--r-- | api/namespace.c | 121 | ||||
-rw-r--r-- | api/namespace.h | 9 | ||||
-rw-r--r-- | api/registry.c | 42 | ||||
-rw-r--r-- | api/registry.h | 19 | ||||
-rw-r--r-- | api/resources.rc | 14 | ||||
-rw-r--r-- | api/rundll32.c | 261 | ||||
-rw-r--r-- | api/rundll32.h | 21 | ||||
-rw-r--r-- | api/wireguard.h | 125 | ||||
-rw-r--r-- | example/example.c | 41 | ||||
-rw-r--r-- | setupapihost/host.c | 183 | ||||
-rw-r--r-- | setupapihost/host_win7.h | 102 | ||||
-rw-r--r-- | setupapihost/setupapihost.vcxproj | 37 | ||||
-rw-r--r-- | wireguard-nt.proj | 8 | ||||
-rw-r--r-- | wireguard-nt.sln | 19 |
25 files changed, 2121 insertions, 2127 deletions
@@ -17,12 +17,12 @@ WireGuardNT is deployed as a platform-specific `wireguard.dll` file. Install the Include the [`wireguard.h` file](https://git.zx2c4.com/wireguard-nt/tree/api/wireguard.h) in your project simply by copying it there and dynamically load the `wireguard.dll` using [`LoadLibraryEx()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa) and [`GetProcAddress()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress) to resolve each function, using the typedefs provided in the header file. The [`InitializeWireGuardNT` function in the example.c code](https://git.zx2c4.com/wireguard-nt/tree/example/example.c) provides this in a function that you can simply copy and paste. -With the library setup, WireGuardNT can then be used by first creating an adapter, configuring it, and then setting its status to "up". Adapters have names (e.g. "OfficeNet"), and each one belongs to a _pool_ (e.g. "WireGuard"). So, for example, the WireGuard application app creates multiple tunnels all inside of its "WireGuard" _pool_: +With the library setup, WireGuardNT can then be used by first creating an adapter, configuring it, and then setting its status to "up". Adapters have names (e.g. "OfficeNet") and types (e.g. "WireGuard"). ```C -WIREGUARD_ADAPTER_HANDLE Adapter1 = WireGuardCreateAdapter(L"WireGuard", L"OfficeNet", &SomeFixedGUID1, NULL); -WIREGUARD_ADAPTER_HANDLE Adapter2 = WireGuardCreateAdapter(L"WireGuard", L"HomeNet", &SomeFixedGUID2, NULL); -WIREGUARD_ADAPTER_HANDLE Adapter3 = WireGuardCreateAdapter(L"WireGuard", L"Data Center", &SomeFixedGUID3, NULL); +WIREGUARD_ADAPTER_HANDLE Adapter1 = WireGuardCreateAdapter(L"OfficeNet", L"WireGuard", &SomeFixedGUID1); +WIREGUARD_ADAPTER_HANDLE Adapter2 = WireGuardCreateAdapter(L"HomeNet", L"WireGuard", &SomeFixedGUID2); +WIREGUARD_ADAPTER_HANDLE Adapter3 = WireGuardCreateAdapter(L"Data Center", L"WireGuard", &SomeFixedGUID3); ``` After creating an adapter, we can use it by setting a configuration and setting its status to "up": diff --git a/api/adapter.c b/api/adapter.c index 158db0e..4d4f3c6 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -3,17 +3,15 @@ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. */ -#include <WinSock2.h> #include <Windows.h> #include <winternl.h> #include <cfgmgr32.h> #include <devguid.h> -#include <ws2tcpip.h> #include <iphlpapi.h> +#include <objbase.h> #include <ndisguid.h> #include <SetupAPI.h> #include <Shlwapi.h> -#include <shellapi.h> #include <wchar.h> #include <initguid.h> /* Keep these two at bottom in this order, so that we only generate extra GUIDs for devpkey. The other keys we'll get from uuid.lib like usual. */ #include <devpkey.h> @@ -23,543 +21,36 @@ # undef NTDDI_VERSION # define NTDDI_VERSION NTDDI_WIN8 # include <devquery.h> +# include <swdevice.h> # undef NTDDI_VERSION # define NTDDI_VERSION NTDDI_WIN7 +#else +# include <devquery.h> +# include <swdevice.h> #endif -#include "../driver/ioctl.h" #include "adapter.h" +#include "driver.h" #include "logger.h" #include "main.h" #include "namespace.h" #include "nci.h" #include "ntdll.h" -#include "registry.h" -#include "resource.h" #include "rundll32.h" -#include "wireguard-inf.h" +#include "registry.h" +#include "adapter_win7.h" #pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ -#define MAX_POOL_DEVICE_TYPE (WIREGUARD_MAX_POOL + 8) /* Should accommodate a pool name with " Tunnel" appended */ - -static const DEVPROPKEY DEVPKEY_WireGuard_Pool = { - { 0x65726957, 0x7547, 0x7261, { 0x64, 0x50, 0x6f, 0x6f, 0x6c, 0x4b, 0x65, 0x79 } }, - DEVPROPID_FIRST_USABLE + 0 -}; - -static const DEVPROPKEY DEVPKEY_WireGuard_Name = { +const DEVPROPKEY DEVPKEY_WireGuard_Name = { { 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, DEVPROPID_FIRST_USABLE + 1 }; -typedef struct _SP_DEVINFO_DATA_LIST -{ - SP_DEVINFO_DATA Data; - VOID *Configuration; - DWORD ConfigurationBytes; - WIREGUARD_ADAPTER_STATE AdapterState; - struct _SP_DEVINFO_DATA_LIST *Next; -} SP_DEVINFO_DATA_LIST; - -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -SP_DRVINFO_DETAIL_DATA_W * -GetAdapterDrvInfoDetail( - _In_ HDEVINFO DevInfo, - _In_opt_ SP_DEVINFO_DATA *DevInfoData, - _In_ SP_DRVINFO_DATA_W *DrvInfoData) -{ - DWORD Size = sizeof(SP_DRVINFO_DETAIL_DATA_W) + 0x100; - for (;;) - { - SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = Alloc(Size); - if (!DrvInfoDetailData) - return NULL; - DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); - if (SetupDiGetDriverInfoDetailW(DevInfo, DevInfoData, DrvInfoData, DrvInfoDetailData, Size, &Size)) - return DrvInfoDetailData; - DWORD LastError = GetLastError(); - Free(DrvInfoDetailData); - if (LastError != ERROR_INSUFFICIENT_BUFFER) - { - if (DevInfoData) - LOG_ERROR(LastError, L"Failed for adapter %u", DevInfoData->DevInst); - else - LOG_ERROR(LastError, L"Failed"); - SetLastError(LastError); - return NULL; - } - } -} - -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -_Post_writable_byte_size_(*BufLen) -VOID * -GetDeviceRegistryProperty( - _In_ HDEVINFO DevInfo, - _In_ SP_DEVINFO_DATA *DevInfoData, - _In_ DWORD Property, - _Out_opt_ DWORD *ValueType, - _Inout_ DWORD *BufLen) -{ - for (;;) - { - BYTE *Data = Alloc(*BufLen); - if (!Data) - return NULL; - if (SetupDiGetDeviceRegistryPropertyW(DevInfo, DevInfoData, Property, ValueType, Data, *BufLen, BufLen)) - return Data; - DWORD LastError = GetLastError(); - Free(Data); - if (LastError != ERROR_INSUFFICIENT_BUFFER) - { - SetLastError( - LOG_ERROR(LastError, L"Failed to query adapter %u property 0x%x", DevInfoData->DevInst, Property)); - return NULL; - } - } -} - -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -LPWSTR -GetDeviceRegistryString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) -{ - DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); - LPWSTR Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); - if (!Buf) - return NULL; - switch (ValueType) - { - case REG_SZ: - case REG_EXPAND_SZ: - case REG_MULTI_SZ: - if (RegistryGetString(&Buf, Size / sizeof(*Buf), ValueType)) - return Buf; - LastError = GetLastError(); - break; - default: - LOG(WIREGUARD_LOG_ERR, - L"Adapter %u property 0x%x is not a string (type: %u)", - DevInfoData->DevInst, - Property, - ValueType); - LastError = ERROR_INVALID_DATATYPE; - } - Free(Buf); - SetLastError(LastError); - return NULL; -} - -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -PZZWSTR -GetDeviceRegistryMultiString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) -{ - DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); - PZZWSTR Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); - if (!Buf) - return NULL; - switch (ValueType) - { - case REG_SZ: - case REG_EXPAND_SZ: - case REG_MULTI_SZ: - if (RegistryGetMultiString(&Buf, Size / sizeof(*Buf), ValueType)) - return Buf; - LastError = GetLastError(); - break; - default: - LOG(WIREGUARD_LOG_ERR, - L"Adapter %u property 0x%x is not a string (type: %u)", - DevInfoData->DevInst, - Property, - ValueType); - LastError = ERROR_INVALID_DATATYPE; - } - Free(Buf); - SetLastError(LastError); - return NULL; -} - -static BOOL -IsOurHardwareID(_In_z_ PCZZWSTR Hwids) -{ - for (; Hwids[0]; Hwids += wcslen(Hwids) + 1) - if (!_wcsicmp(Hwids, WIREGUARD_HWID)) - return TRUE; - return FALSE; -} - -static BOOL -IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) -{ - PZZWSTR Hwids = GetDeviceRegistryMultiString(DevInfo, DevInfoData, SPDRP_HARDWAREID); - if (!Hwids) - { - LOG_LAST_ERROR(L"Failed to get adapter %u hardware ID", DevInfoData->DevInst); - return FALSE; - } - BOOL IsOurs = IsOurHardwareID(Hwids); - Free(Hwids); - return IsOurs; -} - -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -LPWSTR -GetDeviceObjectFileName(_In_z_ LPCWSTR InstanceId) -{ - ULONG InterfacesLen; - DWORD LastError = CM_MapCrToWin32Err( - CM_Get_Device_Interface_List_SizeW( - &InterfacesLen, - (GUID *)&GUID_DEVINTERFACE_NET, - (DEVINSTID_W)InstanceId, - CM_GET_DEVICE_INTERFACE_LIST_PRESENT), - ERROR_GEN_FAILURE); - if (LastError != ERROR_SUCCESS) - { - SetLastError(LOG_ERROR(LastError, L"Failed to query adapter %s associated instances size", InstanceId)); - return NULL; - } - LPWSTR Interfaces = AllocArray(InterfacesLen, sizeof(*Interfaces)); - if (!Interfaces) - return NULL; - LastError = CM_MapCrToWin32Err( - CM_Get_Device_Interface_ListW( - (GUID *)&GUID_DEVINTERFACE_NET, - (DEVINSTID_W)InstanceId, - Interfaces, - InterfacesLen, - CM_GET_DEVICE_INTERFACE_LIST_PRESENT), - ERROR_GEN_FAILURE); - if (LastError != ERROR_SUCCESS) - { - LOG_ERROR(LastError, L"Failed to get adapter %s associated instances", InstanceId); - Free(Interfaces); - SetLastError(LastError); - return NULL; - } - if (!Interfaces[0]) - { - Free(Interfaces); - SetLastError(ERROR_DEVICE_NOT_AVAILABLE); - return NULL; - } - return Interfaces; -} - -_Must_inspect_result_ -static _Return_type_success_(return != INVALID_HANDLE_VALUE) -HANDLE -OpenDeviceObject(_In_z_ LPCWSTR InstanceId) -{ - LPWSTR Filename = GetDeviceObjectFileName(InstanceId); - if (!Filename) - return INVALID_HANDLE_VALUE; - HANDLE Handle = CreateFileW( - Filename, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - 0, - NULL); - if (Handle == INVALID_HANDLE_VALUE) - LOG_LAST_ERROR(L"Failed to connect to adapter %s associated instance %s", InstanceId, Filename); - Free(Filename); - return Handle; -} - -static BOOL -EnsureDeviceObject(_In_z_ LPCWSTR InstanceId) -{ - LPWSTR Filename = GetDeviceObjectFileName(InstanceId); - if (!Filename) - { - LOG_LAST_ERROR(L"Failed to determine adapter %s device object", InstanceId); - return FALSE; - } - BOOL Exists = TRUE; - const int Attempts = 100; - for (int i = 0; i < Attempts; ++i) - { - HANDLE Handle = CreateFileW(Filename, 0, 0, NULL, OPEN_EXISTING, 0, NULL); - if (Handle != INVALID_HANDLE_VALUE) - { - CloseHandle(Handle); - goto out; - } - if (i != Attempts - 1) - Sleep(50); - } - Exists = FALSE; - LOG_LAST_ERROR(L"Failed to connect to adapter %s associated instance %s", InstanceId, Filename); -out: - Free(Filename); - return Exists; -} - -static _Return_type_success_(return != FALSE) -BOOL -SnapshotConfigurationAndState( - _In_ HDEVINFO DevInfo, - _In_ SP_DEVINFO_DATA *DevInfoData, - _Out_ VOID **Configuration, - _Out_ DWORD *ConfigurationBytes, - _Out_ WIREGUARD_ADAPTER_STATE *State) -{ - DWORD LastError = ERROR_SUCCESS; - DWORD RequiredBytes; - if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) || - (LastError = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) - { - LOG_ERROR(LastError, L"Failed to query adapter %u instance ID size", DevInfoData->DevInst); - return FALSE; - } - LastError = ERROR_SUCCESS; - LPWSTR InstanceId = ZallocArray(RequiredBytes, sizeof(*InstanceId)); - if (!InstanceId) - return FALSE; - if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes)) - { - LastError = LOG_LAST_ERROR(L"Failed to get adapter %u instance ID", DevInfoData->DevInst); - goto cleanupInstanceId; - } - HANDLE NdisHandle = OpenDeviceObject(InstanceId); - if (NdisHandle == INVALID_HANDLE_VALUE) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to get adapter %u object", DevInfoData->DevInst); - goto cleanupInstanceId; - } - WG_IOCTL_ADAPTER_STATE Op = WG_IOCTL_ADAPTER_STATE_QUERY; - if (!DeviceIoControl( - NdisHandle, WG_IOCTL_SET_ADAPTER_STATE, &Op, sizeof(Op), State, sizeof(*State), &RequiredBytes, NULL)) - { - LastError = LOG_LAST_ERROR(L"Failed to query adapter state on adapter %u", DevInfoData->DevInst); - goto cleanupHandle; - } - for (RequiredBytes = 512;; RequiredBytes = *ConfigurationBytes) - { - *Configuration = Alloc(RequiredBytes); - if (!*Configuration) - { - LastError = LOG_LAST_ERROR( - L"Failed to allocate %u bytes for configuration on adapter %u", RequiredBytes, DevInfoData->DevInst); - goto cleanupHandle; - } - if (DeviceIoControl(NdisHandle, WG_IOCTL_GET, NULL, 0, *Configuration, RequiredBytes, ConfigurationBytes, NULL)) - break; - Free(*Configuration); - *Configuration = NULL; - if (GetLastError() != ERROR_MORE_DATA) - { - LastError = LOG_LAST_ERROR(L"Failed to query configuration on adapter %u", DevInfoData->DevInst); - goto cleanupHandle; - } - } -cleanupHandle: - CloseHandle(NdisHandle); -cleanupInstanceId: - Free(InstanceId); - return RET_ERROR(TRUE, LastError); -} - -static _Return_type_success_(return != FALSE) -BOOL -RestoreConfigurationAndState( - _In_ HDEVINFO DevInfo, - _In_ SP_DEVINFO_DATA *DevInfoData, - _In_ VOID *Configuration, - _In_ DWORD ConfigurationBytes, - _In_ WIREGUARD_ADAPTER_STATE State) -{ - DWORD LastError = ERROR_SUCCESS; - DWORD RequiredBytes; - if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) || - (LastError = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) - { - LOG_ERROR(LastError, L"Failed to query adapter %u instance ID size", DevInfoData->DevInst); - return FALSE; - } - LastError = ERROR_SUCCESS; - LPWSTR InstanceId = ZallocArray(RequiredBytes, sizeof(*InstanceId)); - if (!InstanceId) - return FALSE; - if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes)) - { - LastError = LOG_LAST_ERROR(L"Failed to get adapter %u instance ID", DevInfoData->DevInst); - goto cleanupInstanceId; - } - HANDLE NdisHandle = OpenDeviceObject(InstanceId); - if (NdisHandle == INVALID_HANDLE_VALUE) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to get adapter %u object", DevInfoData->DevInst); - goto cleanupInstanceId; - } - if (!DeviceIoControl(NdisHandle, WG_IOCTL_SET, NULL, 0, Configuration, ConfigurationBytes, &RequiredBytes, NULL)) - { - LastError = LOG_LAST_ERROR(L"Failed to set configuration on adapter %u", DevInfoData->DevInst); - goto cleanupHandle; - } - if (!DeviceIoControl(NdisHandle, WG_IOCTL_SET_ADAPTER_STATE, &State, sizeof(State), NULL, 0, &RequiredBytes, NULL)) - { - LastError = LOG_LAST_ERROR(L"Failed to set adapter state on adapter %u", DevInfoData->DevInst); - goto cleanupHandle; - } -cleanupHandle: - CloseHandle(NdisHandle); -cleanupInstanceId: - Free(InstanceId); - return RET_ERROR(TRUE, LastError); -} - -static _Return_type_success_(return != FALSE) -BOOL -DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters) -{ - SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_PROPERTYCHANGE }, - .StateChange = DICS_DISABLE, - .Scope = DICS_FLAG_GLOBAL }; - DWORD LastError = ERROR_SUCCESS; - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - SP_DEVINFO_DATA_LIST *DeviceNode = Zalloc(sizeof(*DeviceNode)); - if (!DeviceNode) - return FALSE; - DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA); - if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - { - Free(DeviceNode); - break; - } - goto cleanupDeviceNode; - } - if (!IsOurAdapter(DevInfo, &DeviceNode->Data)) - goto cleanupDeviceNode; - - ULONG Status, ProblemCode; - if (CM_Get_DevNode_Status(&Status, &ProblemCode, DeviceNode->Data.DevInst, 0) != CR_SUCCESS || - ((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED)) - goto cleanupDeviceNode; - - LOG(WIREGUARD_LOG_INFO, L"Snapshotting configuration of adapter %u", DeviceNode->Data.DevInst); - if (!SnapshotConfigurationAndState( - DevInfo, - &DeviceNode->Data, - &DeviceNode->Configuration, - &DeviceNode->ConfigurationBytes, - &DeviceNode->AdapterState)) - LOG(WIREGUARD_LOG_WARN, L"Failed to snapshot configuration of adapter %u", DeviceNode->Data.DevInst); - - LOG(WIREGUARD_LOG_INFO, L"Disabling adapter %u", DeviceNode->Data.DevInst); - if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data)) - { - LOG_LAST_ERROR(L"Failed to disable adapter %u", DeviceNode->Data.DevInst); - LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); - goto cleanupDeviceNode; - } - - DeviceNode->Next = *DisabledAdapters; - *DisabledAdapters = DeviceNode; - continue; - - cleanupDeviceNode: - Free(DeviceNode); - } - return RET_ERROR(TRUE, LastError); -} - -static _Return_type_success_(return != FALSE) -BOOL -EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable) -{ - SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_PROPERTYCHANGE }, - .StateChange = DICS_ENABLE, - .Scope = DICS_FLAG_GLOBAL }; - DWORD LastError = ERROR_SUCCESS; - for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next) - { - LOG(WIREGUARD_LOG_INFO, L"Enabling adapter %u", DeviceNode->Data.DevInst); - if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data)) - { - LOG_LAST_ERROR(L"Failed to enable adapter %u", DeviceNode->Data.DevInst); - LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); - } - LOG(WIREGUARD_LOG_INFO, L"Restoring configuration of adapter %u", DeviceNode->Data.DevInst); - if (!RestoreConfigurationAndState( - DevInfo, - &DeviceNode->Data, - DeviceNode->Configuration, - DeviceNode->ConfigurationBytes, - DeviceNode->AdapterState)) - LOG(WIREGUARD_LOG_WARN, L"Failed to restore configuration of adapter %u", DeviceNode->Data.DevInst); - } - return RET_ERROR(TRUE, LastError); -} - -static BOOL -CheckReboot(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) -{ - SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(SP_DEVINSTALL_PARAMS_W) }; - if (!SetupDiGetDeviceInstallParamsW(DevInfo, DevInfoData, &DevInstallParams)) - { - LOG_LAST_ERROR(L"Failed to retrieve adapter %u device installation parameters", DevInfoData->DevInst); - return FALSE; - } - SetLastError(ERROR_SUCCESS); - return (DevInstallParams.Flags & (DI_NEEDREBOOT | DI_NEEDRESTART)) != 0; -} - _Must_inspect_result_ static _Return_type_success_(return != FALSE) BOOL -GetPoolDeviceTypeName(_In_z_ LPCWSTR Pool, _Out_writes_z_(MAX_POOL_DEVICE_TYPE) LPWSTR Name) -{ - if (_snwprintf_s(Name, MAX_POOL_DEVICE_TYPE, _TRUNCATE, L"%s Tunnel", Pool) == -1) - { - LOG(WIREGUARD_LOG_ERR, L"Pool name too long: %s", Pool); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - return TRUE; -} - -static BOOL -IsPoolMember(_In_z_ LPCWSTR Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) -{ - WCHAR PoolProp[MAX_POOL_DEVICE_TYPE]; - DEVPROPTYPE PropType; - if (!SetupDiGetDevicePropertyW( - DevInfo, DevInfoData, &DEVPKEY_WireGuard_Pool, &PropType, (PBYTE)PoolProp, sizeof(PoolProp), NULL, 0)) - return FALSE; - if (PropType != DEVPROP_TYPE_STRING) - { - SetLastError(ERROR_BAD_DEVICE); - return FALSE; - } - SetLastError(ERROR_SUCCESS); - return !_wcsicmp(PoolProp, Pool); -} - -_Must_inspect_result_ -static _Return_type_success_(return != FALSE) -BOOL -PopulateAdapterData(_Inout_ WIREGUARD_ADAPTER *Adapter, _In_z_ LPCWSTR Pool) +PopulateAdapterData(_Inout_ WIREGUARD_ADAPTER *Adapter) { DWORD LastError = ERROR_SUCCESS; @@ -568,7 +59,7 @@ PopulateAdapterData(_Inout_ WIREGUARD_ADAPTER *Adapter, _In_z_ LPCWSTR Pool) SetupDiOpenDevRegKey(Adapter->DevInfo, &Adapter->DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); if (Key == INVALID_HANDLE_VALUE) { - LOG_LAST_ERROR(L"Failed to open adapter %u device registry key", Adapter->DevInfoData.DevInst); + LOG_LAST_ERROR(L"Failed to open adapter device registry key"); return FALSE; } @@ -607,18 +98,10 @@ PopulateAdapterData(_Inout_ WIREGUARD_ADAPTER *Adapter, _In_z_ LPCWSTR Pool) goto cleanupKey; } - DWORD Size; - if (!SetupDiGetDeviceInstanceIdW( - Adapter->DevInfo, &Adapter->DevInfoData, Adapter->DevInstanceID, _countof(Adapter->DevInstanceID), &Size)) - { - LastError = LOG_LAST_ERROR(L"Failed to get adapter %u instance ID", Adapter->DevInfoData.DevInst); - goto cleanupKey; - } - - if (wcsncpy_s(Adapter->Pool, _countof(Adapter->Pool), Pool, _TRUNCATE) == STRUNCATE) + Adapter->InterfaceFilename = AdapterGetDeviceObjectFileName(Adapter->DevInstanceID); + if (!Adapter->InterfaceFilename) { - LOG(WIREGUARD_LOG_ERR, L"Pool name too long: %s", Pool); - LastError = ERROR_INVALID_PARAMETER; + LastError = LOG_LAST_ERROR(L"Unable to determine device object file name"); goto cleanupKey; } @@ -627,39 +110,149 @@ cleanupKey: return RET_ERROR(TRUE, LastError); } +static volatile LONG OrphanThreadIsWorking = FALSE; + +static DWORD +DoOrphanedDeviceCleanup(_In_opt_ LPVOID Ctx) +{ + AdapterCleanupOrphanedDevices(); + OrphanThreadIsWorking = FALSE; + return 0; +} + +static VOID QueueUpOrphanedDeviceCleanupRoutine(VOID) +{ + if (InterlockedCompareExchange(&OrphanThreadIsWorking, TRUE, FALSE) == FALSE) + QueueUserWorkItem(DoOrphanedDeviceCleanup, NULL, 0); +} + +VOID AdapterCleanupOrphanedDevices(VOID) +{ + HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex(); + if (!DeviceInstallationMutex) + { + LOG_LAST_ERROR(L"Failed to take device installation mutex"); + return; + } + + if (IsWindows7) + { + AdapterCleanupOrphanedDevicesWin7(); + goto cleanupDeviceInstallationMutex; + } + + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WIREGUARD_ENUMERATOR, NULL, 0, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LOG_LAST_ERROR(L"Failed to get adapters"); + goto cleanupDeviceInstallationMutex; + } + + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + ULONG Status, Code; + if (CM_Get_DevNode_Status(&Status, &Code, DevInfoData.DevInst, 0) == CR_SUCCESS && !(Status & DN_HAS_PROBLEM)) + continue; + + DEVPROPTYPE PropType; + WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; + SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_WireGuard_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + if (!AdapterRemoveInstance(DevInfo, &DevInfoData)) + { + LOG_LAST_ERROR(L"Failed to remove orphaned adapter \"%s\"", Name); + continue; + } + LOG(WIREGUARD_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name); + } + SetupDiDestroyDeviceInfoList(DevInfo); +cleanupDeviceInstallationMutex: + NamespaceReleaseMutex(DeviceInstallationMutex); +} + _Use_decl_annotations_ VOID WINAPI -WireGuardFreeAdapter(WIREGUARD_ADAPTER *Adapter) +WireGuardCloseAdapter(WIREGUARD_ADAPTER *Adapter) { if (!Adapter) return; WireGuardSetAdapterLogging(Adapter, WIREGUARD_ADAPTER_LOG_OFF); + Free(Adapter->InterfaceFilename); + if (Adapter->SwDevice) + SwDeviceClose(Adapter->SwDevice); if (Adapter->DevInfo) + { + if (!AdapterRemoveInstance(Adapter->DevInfo, &Adapter->DevInfoData)) + LOG_LAST_ERROR(L"Failed to remove adapter when closing"); SetupDiDestroyDeviceInfoList(Adapter->DevInfo); + } Free(Adapter); + QueueUpOrphanedDeviceCleanupRoutine(); } -_Use_decl_annotations_ -BOOL WINAPI -WireGuardGetAdapterName(WIREGUARD_ADAPTER *Adapter, LPWSTR Name) +static _Return_type_success_(return != FALSE) +BOOL +RenameByNetGUID(_In_ GUID *Guid, _In_reads_or_z_(MAX_ADAPTER_NAME) LPCWSTR Name) { - DEVPROPTYPE PropType; - if (!SetupDiGetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_WireGuard_Name, - &PropType, - (PBYTE)Name, - MAX_ADAPTER_NAME * sizeof(*Name), - NULL, - 0)) - return FALSE; - if (PropType != DEVPROP_TYPE_STRING || !*Name) + DWORD LastError = ERROR_NOT_FOUND; + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WIREGUARD_ENUMERATOR, NULL, 0, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) { - SetLastError(ERROR_BAD_DEVICE); - return FALSE; + LastError = GetLastError(); + goto cleanup; } - return TRUE; + + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + + HKEY Key = SetupDiOpenDevRegKey(DevInfo, &DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + if (Key == INVALID_HANDLE_VALUE) + continue; + LPWSTR ValueStr = RegistryQueryString(Key, L"NetCfgInstanceId", TRUE); + RegCloseKey(Key); + if (!ValueStr) + continue; + GUID Guid2; + HRESULT HRet = CLSIDFromString(ValueStr, &Guid2); + Free(ValueStr); + if (FAILED(HRet) || memcmp(Guid, &Guid2, sizeof(*Guid))) + continue; + LastError = SetupDiSetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_WireGuard_Name, + DEVPROP_TYPE_STRING, + (PBYTE)Name, + (DWORD)((wcslen(Name) + 1) * sizeof(Name[0])), + 0) + ? ERROR_SUCCESS + : GetLastError(); + break; + } + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + return RET_ERROR(TRUE, LastError); } _Must_inspect_result_ @@ -683,36 +276,20 @@ ConvertInterfaceAliasToGuid(_In_z_ LPCWSTR Name, _Out_ GUID *Guid) return TRUE; } -_Use_decl_annotations_ -BOOL WINAPI -WireGuardSetAdapterName(WIREGUARD_ADAPTER *Adapter, LPCWSTR Name) +static _Return_type_success_(return != FALSE) +BOOL +NciSetAdapterName(_In_ GUID *Guid, _In_reads_or_z_(MAX_ADAPTER_NAME) LPCWSTR Name) { const int MaxSuffix = 1000; WCHAR AvailableName[MAX_ADAPTER_NAME]; if (wcsncpy_s(AvailableName, _countof(AvailableName), Name, _TRUNCATE) == STRUNCATE) { - LOG(WIREGUARD_LOG_ERR, L"Adapter name too long: %s", Name); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (!SetupDiSetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_WireGuard_Name, - DEVPROP_TYPE_STRING, -#pragma warning(suppress : 4090) - (const BYTE *)Name, - (DWORD)((wcslen(Name) + 1) * sizeof(*Name)), - 0)) - { - LOG_LAST_ERROR(L"Failed to set adapter %u name", Adapter->DevInfoData.DevInst); + SetLastError(ERROR_BUFFER_OVERFLOW); return FALSE; } - for (int i = 0;; ++i) { - DWORD LastError = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); + DWORD LastError = NciSetConnectionName(Guid, AvailableName); if (LastError == ERROR_DUP_NAME) { GUID Guid2; @@ -723,8 +300,7 @@ WireGuardSetAdapterName(WIREGUARD_ADAPTER *Adapter, LPCWSTR Name) WCHAR Proposal[MAX_ADAPTER_NAME]; if (_snwprintf_s(Proposal, _countof(Proposal), _TRUNCATE, L"%s %d", Name, j + 1) == -1) { - LOG(WIREGUARD_LOG_ERR, L"Adapter name too long: %s %d", Name, j + 1); - SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_BUFFER_OVERFLOW); return FALSE; } if (_wcsnicmp(Proposal, AvailableName, MAX_ADAPTER_NAME) == 0) @@ -732,9 +308,11 @@ WireGuardSetAdapterName(WIREGUARD_ADAPTER *Adapter, LPCWSTR Name) DWORD LastError2 = NciSetConnectionName(&Guid2, Proposal); if (LastError2 == ERROR_DUP_NAME) continue; + if (!RenameByNetGUID(&Guid2, Proposal)) + LOG_LAST_ERROR(L"Failed to set foreign adapter name to \"%s\"", Proposal); if (LastError2 == ERROR_SUCCESS) { - LastError = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); + LastError = NciSetConnectionName(Guid, AvailableName); if (LastError == ERROR_SUCCESS) break; } @@ -746,142 +324,19 @@ WireGuardSetAdapterName(WIREGUARD_ADAPTER *Adapter, LPCWSTR Name) break; if (i >= MaxSuffix || LastError != ERROR_DUP_NAME) { - SetLastError(LOG_ERROR(LastError, L"Failed to set adapter name")); + SetLastError(LastError); return FALSE; } if (_snwprintf_s(AvailableName, _countof(AvailableName), _TRUNCATE, L"%s %d", Name, i + 1) == -1) { - LOG(WIREGUARD_LOG_ERR, L"Adapter name too long: %s %d", Name, i + 1); - SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_BUFFER_OVERFLOW); return FALSE; } } - - if (!SetupDiSetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_WireGuard_Pool, - DEVPROP_TYPE_STRING, -#pragma warning(suppress : 4090) - (const BYTE *)Adapter->Pool, - (DWORD)((wcslen(Adapter->Pool) + 1) * sizeof(*Adapter->Pool)), - 0)) - { - LOG_LAST_ERROR(L"Failed to set adapter %u pool", Adapter->DevInfoData.DevInst); - return FALSE; - } - - WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; - if (!GetPoolDeviceTypeName(Adapter->Pool, PoolDeviceTypeName)) - return FALSE; - if (!SetupDiSetDeviceRegistryPropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - SPDRP_FRIENDLYNAME, - (const BYTE *)PoolDeviceTypeName, - (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(*PoolDeviceTypeName)))) - { - LOG_LAST_ERROR(L"Failed to set adapter %u friendly name", Adapter->DevInfoData.DevInst); - return FALSE; - } - return TRUE; } _Use_decl_annotations_ -WIREGUARD_ADAPTER_HANDLE WINAPI -WireGuardOpenAdapter(LPCWSTR Pool, LPCWSTR Name) -{ - WIREGUARD_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); - if (!Adapter) - return FALSE; - - DWORD LastError = ERROR_SUCCESS; - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to take %s pool mutex", Pool); - goto cleanup; - } - - Adapter->DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (Adapter->DevInfo == INVALID_HANDLE_VALUE) - { - LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); - goto cleanupMutex; - } - - Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - if (!SetupDiEnumDeviceInfo(Adapter->DevInfo, EnumIndex, &Adapter->DevInfoData)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } - - WCHAR Name2[MAX_ADAPTER_NAME]; - if (!WireGuardGetAdapterName(Adapter, Name2)) - continue; - if (_wcsicmp(Name, Name2)) - continue; - - /* Check the Hardware ID to make sure it's a real WireGuard device. */ - if (!IsOurAdapter(Adapter->DevInfo, &Adapter->DevInfoData)) - { - LOG(WIREGUARD_LOG_ERR, L"Foreign adapter %u named %s exists", Adapter->DevInfoData.DevInst, Name); - LastError = ERROR_ALREADY_EXISTS; - goto cleanupMutex; - } - - if (!IsPoolMember(Pool, Adapter->DevInfo, &Adapter->DevInfoData)) - { - if ((LastError = GetLastError()) == ERROR_SUCCESS) - { - LOG(WIREGUARD_LOG_ERR, - L"Adapter %u named %s is not a member of %s pool", - Adapter->DevInfoData.DevInst, - Name, - Pool); - LastError = ERROR_ALREADY_EXISTS; - goto cleanupMutex; - } - else - { - LOG(WIREGUARD_LOG_ERR, L"Failed to get adapter %u pool membership", Adapter->DevInfoData.DevInst); - goto cleanupMutex; - } - } - - if (!PopulateAdapterData(Adapter, Pool)) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); - goto cleanupMutex; - } - - if (!EnsureDeviceObject(Adapter->DevInstanceID)) - { - LastError = GetLastError(); - goto cleanupMutex; - } - - /* Our comparison was case-insensitive, and we also might want to reenforce the NCI connection. */ - WireGuardSetAdapterName(Adapter, Name); - - LastError = ERROR_SUCCESS; - goto cleanupMutex; - } - LastError = ERROR_FILE_NOT_FOUND; -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - if (LastError != ERROR_SUCCESS) - WireGuardFreeAdapter(Adapter); - return RET_ERROR(Adapter, LastError); -} - -_Use_decl_annotations_ VOID WINAPI WireGuardGetAdapterLUID(WIREGUARD_ADAPTER *Adapter, NET_LUID *Luid) { @@ -894,457 +349,61 @@ _Use_decl_annotations_ HANDLE WINAPI AdapterOpenDeviceObject(const WIREGUARD_ADAPTER *Adapter) { - return OpenDeviceObject(Adapter->DevInstanceID); -} - -static BOOL -IsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData) -{ - if (DrvInfoDetailData->CompatIDsOffset > 1 && !_wcsicmp(DrvInfoDetailData->HardwareID, WIREGUARD_HWID)) - return TRUE; - if (DrvInfoDetailData->CompatIDsLength && - IsOurHardwareID(DrvInfoDetailData->HardwareID + DrvInfoDetailData->CompatIDsOffset)) - return TRUE; - return FALSE; -} - -static BOOL -IsNewer( - _In_ const FILETIME *DriverDate1, - _In_ DWORDLONG DriverVersion1, - _In_ const FILETIME *DriverDate2, - _In_ DWORDLONG DriverVersion2) -{ - if (DriverDate1->dwHighDateTime > DriverDate2->dwHighDateTime) - return TRUE; - if (DriverDate1->dwHighDateTime < DriverDate2->dwHighDateTime) - return FALSE; - - if (DriverDate1->dwLowDateTime > DriverDate2->dwLowDateTime) - return TRUE; - if (DriverDate1->dwLowDateTime < DriverDate2->dwLowDateTime) - return FALSE; - - if (DriverVersion1 > DriverVersion2) - return TRUE; - if (DriverVersion1 < DriverVersion2) - return FALSE; - - return FALSE; -} - -static _Return_type_success_(return != 0) -DWORD -VersionOfFile(_In_z_ LPCWSTR Filename) -{ - DWORD Zero; - DWORD Len = GetFileVersionInfoSizeW(Filename, &Zero); - if (!Len) - { - LOG_LAST_ERROR(L"Failed to query %s version info size", Filename); - return 0; - } - VOID *VersionInfo = Alloc(Len); - if (!VersionInfo) - return 0; - DWORD LastError = ERROR_SUCCESS, Version = 0; - VS_FIXEDFILEINFO *FixedInfo; - UINT FixedInfoLen = sizeof(*FixedInfo); - if (!GetFileVersionInfoW(Filename, 0, Len, VersionInfo)) - { - LastError = LOG_LAST_ERROR(L"Failed to get %s version info", Filename); - goto out; - } - if (!VerQueryValueW(VersionInfo, L"\\", &FixedInfo, &FixedInfoLen)) - { - LastError = LOG_LAST_ERROR(L"Failed to get %s version info root", Filename); - goto out; - } - Version = FixedInfo->dwFileVersionMS; - if (!Version) - { - LOG(WIREGUARD_LOG_WARN, L"Determined version of %s, but was v0.0, so returning failure", Filename); - LastError = ERROR_VERSION_PARSE_ERROR; - } -out: - Free(VersionInfo); - return RET_ERROR(Version, LastError); -} - -static DWORD WINAPI -MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion) -{ - PRTL_PROCESS_MODULES Modules; - ULONG BufferSize = 128 * 1024; - for (;;) - { - Modules = Alloc(BufferSize); - if (!Modules) - return 0; - NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize); - if (NT_SUCCESS(Status)) - break; - Free(Modules); - if (Status == STATUS_INFO_LENGTH_MISMATCH) - continue; - LOG(WIREGUARD_LOG_ERR, L"Failed to enumerate drivers (status: 0x%x)", Status); - SetLastError(RtlNtStatusToDosError(Status)); - return 0; - } - DWORD LastError = ERROR_SUCCESS, Version = 0; - for (ULONG i = Modules->NumberOfModules; i-- > 0;) - { - LPCSTR NtPath = (LPCSTR)Modules->Modules[i].FullPathName; - if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wireguard.sys")) - { - if (ReturnOneIfRunningInsteadOfVersion) - { - Version = 1; - goto cleanupModules; - } - WCHAR FilePath[MAX_PATH * 3 + 15]; - if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1) - continue; - Version = VersionOfFile(FilePath); - if (!Version) - LastError = GetLastError(); - goto cleanupModules; - } - } - LastError = ERROR_FILE_NOT_FOUND; -cleanupModules: - Free(Modules); - return RET_ERROR(Version, LastError); -} - -_Use_decl_annotations_ -DWORD WINAPI WireGuardGetRunningDriverVersion(VOID) -{ - return MaybeGetRunningDriverVersion(FALSE); -} - -static BOOL EnsureWireGuardUnloaded(VOID) -{ - BOOL Loaded; - for (int i = 0; (Loaded = MaybeGetRunningDriverVersion(TRUE) != 0) != FALSE && i < 300; ++i) - Sleep(50); - return !Loaded; -} - -static VOID -SelectDriverDeferredCleanup(_In_ HDEVINFO DevInfoExistingAdapters, _In_opt_ SP_DEVINFO_DATA_LIST *ExistingAdapters) -{ - if (ExistingAdapters) - { - EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters); - while (ExistingAdapters) - { - SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; - Free(ExistingAdapters->Configuration); - Free(ExistingAdapters); - ExistingAdapters = Next; - } - } - if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE) - SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters); -} - -_Must_inspect_result_ -static _Return_type_success_(return != FALSE) -BOOL -SelectDriver( - _In_ HDEVINFO DevInfo, - _In_ SP_DEVINFO_DATA *DevInfoData, - _Inout_ SP_DEVINSTALL_PARAMS_W *DevInstallParams, - _Out_ HDEVINFO *DevInfoExistingAdaptersForCleanup, - _Out_ SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup) -{ - static const FILETIME OurDriverDate = WIREGUARD_INF_FILETIME; - static const DWORDLONG OurDriverVersion = WIREGUARD_INF_VERSION; - HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); - if (!DriverInstallationLock) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to take driver installation mutex"); - return FALSE; - } - DWORD LastError; - if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER)) - { - LastError = LOG_LAST_ERROR(L"Failed building adapter %u driver info list", DevInfoData->DevInst); - goto cleanupDriverInstallationLock; - } - BOOL DestroyDriverInfoListOnCleanup = TRUE; - FILETIME DriverDate = { 0 }; - DWORDLONG DriverVersion = 0; - HDEVINFO DevInfoExistingAdapters = INVALID_HANDLE_VALUE; - SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL; - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; - if (!SetupDiEnumDriverInfoW(DevInfo, DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } - SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = GetAdapterDrvInfoDetail(DevInfo, DevInfoData, &DrvInfoData); - if (!DrvInfoDetailData) - { - LOG(WIREGUARD_LOG_WARN, L"Failed getting adapter %u driver info detail", DevInfoData->DevInst); - continue; - } - if (!IsOurDrvInfoDetail(DrvInfoDetailData)) - goto next; - if (IsNewer(&OurDriverDate, OurDriverVersion, &DrvInfoData.DriverDate, DrvInfoData.DriverVersion)) - { - if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE) - { - DevInfoExistingAdapters = - SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE) - { - LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); - Free(DrvInfoDetailData); - goto cleanupExistingAdapters; - } - _Analysis_assume_(DevInfoExistingAdapters != NULL); - DisableAllOurAdapters(DevInfoExistingAdapters, &ExistingAdapters); - LOG(WIREGUARD_LOG_INFO, L"Waiting for existing driver to unload from kernel"); - if (!EnsureWireGuardUnloaded()) - LOG(WIREGUARD_LOG_WARN, - L"Failed to unload existing driver, which means a reboot will likely be required"); - } - LOG(WIREGUARD_LOG_INFO, - L"Removing existing driver %u.%u", - (DWORD)((DrvInfoData.DriverVersion & 0xffff000000000000) >> 48), - (DWORD)((DrvInfoData.DriverVersion & 0x0000ffff00000000) >> 32)); - LPWSTR InfFileName = PathFindFileNameW(DrvInfoDetailData->InfFileName); - if (!SetupUninstallOEMInfW(InfFileName, SUOI_FORCEDELETE, NULL)) - LOG_LAST_ERROR(L"Unable to remove existing driver %s", InfFileName); - goto next; - } - if (!IsNewer(&DrvInfoData.DriverDate, DrvInfoData.DriverVersion, &DriverDate, DriverVersion)) - goto next; - if (!SetupDiSetSelectedDriverW(DevInfo, DevInfoData, &DrvInfoData)) - { - LOG_LAST_ERROR( - L"Failed to select driver %s for adapter %u", DrvInfoDetailData->InfFileName, DevInfoData->DevInst); - goto next; - } - DriverDate = DrvInfoData.DriverDate; - DriverVersion = DrvInfoData.DriverVersion; - next: - Free(DrvInfoDetailData); - } - - if (DriverVersion) - { - LOG(WIREGUARD_LOG_INFO, - L"Using existing driver %u.%u", - (DWORD)((DriverVersion & 0xffff000000000000) >> 48), - (DWORD)((DriverVersion & 0x0000ffff00000000) >> 32)); - LastError = ERROR_SUCCESS; - DestroyDriverInfoListOnCleanup = FALSE; - goto cleanupExistingAdapters; - } - - LOG(WIREGUARD_LOG_INFO, - L"Installing driver %u.%u", - (DWORD)((OurDriverVersion & 0xffff000000000000) >> 48), - (DWORD)((OurDriverVersion & 0x0000ffff00000000) >> 32)); - WCHAR RandomTempSubDirectory[MAX_PATH]; - if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory)) - { - LastError = LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory); - goto cleanupExistingAdapters; - } - - WCHAR CatPath[MAX_PATH] = { 0 }; - WCHAR SysPath[MAX_PATH] = { 0 }; - WCHAR InfPath[MAX_PATH] = { 0 }; - WCHAR DownlevelShimPath[MAX_PATH] = { 0 }; - if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wireguard.cat") || - !PathCombineW(SysPath, RandomTempSubDirectory, L"wireguard.sys") || - !PathCombineW(InfPath, RandomTempSubDirectory, L"wireguard.inf")) - { - LastError = ERROR_BUFFER_OVERFLOW; - goto cleanupDirectory; - } - - LOG(WIREGUARD_LOG_INFO, L"Extracting driver"); - if (!ResourceCopyToFile(CatPath, L"wireguard.cat") || !ResourceCopyToFile(SysPath, L"wireguard.sys") || - !ResourceCopyToFile(InfPath, L"wireguard.inf")) - { - LastError = LOG_LAST_ERROR(L"Failed to extract driver"); - goto cleanupDelete; - } - - WCHAR *WintrustKeyOriginalValue = NULL; - HKEY WintrustKey = NULL; - if (!IsWindows10) - { - LOG(WIREGUARD_LOG_INFO, L"Shimming downlevel driver loader"); - if (!PathCombineW(DownlevelShimPath, RandomTempSubDirectory, L"downlevelshim.dll")) - { - DownlevelShimPath[0] = L'\0'; - LastError = ERROR_BUFFER_OVERFLOW; - goto cleanupDelete; - } - if (!ResourceCopyToFile(DownlevelShimPath, L"downlevelshim.dll")) - { - LastError = LOG_LAST_ERROR(L"Failed to extract downlevel shim"); - goto cleanupDelete; - } - LastError = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Cryptography\\Providers\\Trust\\FinalPolicy\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}", - 0, - KEY_QUERY_VALUE | KEY_SET_VALUE, - &WintrustKey); - if (LastError != ERROR_SUCCESS) - { - LOG_ERROR(LastError, L"Failed to open Wintrust FinalPolicy key"); - goto cleanupDelete; - } - WintrustKeyOriginalValue = RegistryQueryString(WintrustKey, L"$DLL", TRUE); - if (!WintrustKeyOriginalValue) - { - LastError = LOG_LAST_ERROR(L"Failed to read current Wintrust FinalPolicy key"); - goto cleanupWintrustKey; - } - LastError = RegSetValueExW( - WintrustKey, - L"$DLL", - 0, - REG_SZ, - (BYTE *)DownlevelShimPath, - (DWORD)((wcslen(DownlevelShimPath) + 1) * sizeof(DownlevelShimPath[0]))); - if (LastError != ERROR_SUCCESS) - { - LOG_ERROR(LastError, L"Failed to set Wintrust FinalPolicy key"); - goto cleanupWintrustChangedKey; - } - } - - LOG(WIREGUARD_LOG_INFO, L"Installing driver"); - WCHAR InfStorePath[MAX_PATH]; - if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_NONE, 0, InfStorePath, MAX_PATH, NULL, NULL)) - { - LastError = LOG_LAST_ERROR(L"Could not install driver %s to store", InfPath); - goto cleanupWintrustChangedKey; - } - _Analysis_assume_nullterminated_(InfStorePath); - - SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER); - DestroyDriverInfoListOnCleanup = FALSE; - DevInstallParams->Flags |= DI_ENUMSINGLEINF; - if (wcsncpy_s(DevInstallParams->DriverPath, _countof(DevInstallParams->DriverPath), InfStorePath, _TRUNCATE) == - STRUNCATE) - { - LOG(WIREGUARD_LOG_ERR, L"Inf path too long: %s", InfStorePath); - LastError = ERROR_INVALID_PARAMETER; - goto cleanupWintrustChangedKey; - } - if (!SetupDiSetDeviceInstallParamsW(DevInfo, DevInfoData, DevInstallParams)) - { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", DevInfoData->DevInst); - goto cleanupWintrustChangedKey; - } - if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER)) - { - LastError = LOG_LAST_ERROR(L"Failed rebuilding adapter %u driver info list", DevInfoData->DevInst); - goto cleanupWintrustChangedKey; - } - DestroyDriverInfoListOnCleanup = TRUE; - SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; - if (!SetupDiEnumDriverInfoW(DevInfo, DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData)) - { - LastError = LOG_LAST_ERROR(L"Failed to get adapter %u driver", DevInfoData->DevInst); - goto cleanupWintrustChangedKey; - } - if (!SetupDiSetSelectedDriverW(DevInfo, DevInfoData, &DrvInfoData)) - { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u driver", DevInfoData->DevInst); - goto cleanupWintrustChangedKey; - } - LastError = ERROR_SUCCESS; - DestroyDriverInfoListOnCleanup = FALSE; - -cleanupWintrustChangedKey: - if (WintrustKeyOriginalValue) - RegSetValueExW( - WintrustKey, - L"$DLL", - 0, - REG_SZ, - (BYTE *)WintrustKeyOriginalValue, - (DWORD)((wcslen(WintrustKeyOriginalValue) + 1) * sizeof(WintrustKeyOriginalValue[0]))); -cleanupWintrustKey: - if (WintrustKey) - RegCloseKey(WintrustKey); - if (WintrustKeyOriginalValue) - Free(WintrustKeyOriginalValue); -cleanupDelete: - DeleteFileW(CatPath); - DeleteFileW(SysPath); - DeleteFileW(InfPath); - if (DownlevelShimPath[0]) - DeleteFileW(DownlevelShimPath); -cleanupDirectory: - RemoveDirectoryW(RandomTempSubDirectory); -cleanupExistingAdapters: - if (LastError == ERROR_SUCCESS) - { - *DevInfoExistingAdaptersForCleanup = DevInfoExistingAdapters; - *ExistingAdaptersForCleanup = ExistingAdapters; - } - else - SelectDriverDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); - if (DestroyDriverInfoListOnCleanup) - SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER); -cleanupDriverInstallationLock: - NamespaceReleaseMutex(DriverInstallationLock); - return RET_ERROR(TRUE, LastError); + HANDLE Handle = CreateFileW( + Adapter->InterfaceFilename, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (Handle == INVALID_HANDLE_VALUE) + LOG_LAST_ERROR(L"Failed to connect to adapter interface %s", Adapter->InterfaceFilename); + return Handle; } _Use_decl_annotations_ -WIREGUARD_ADAPTER * -AdapterOpenFromDevInstanceId(LPCWSTR Pool, LPCWSTR DevInstanceID) +LPWSTR +AdapterGetDeviceObjectFileName(LPCWSTR InstanceId) { - WIREGUARD_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); - if (!Adapter) - return FALSE; - - DWORD LastError = ERROR_SUCCESS; - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to take %s pool mutex", Pool); - goto cleanup; - } - Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); - if (Adapter->DevInfo == INVALID_HANDLE_VALUE) + ULONG InterfacesLen; + DWORD LastError = CM_MapCrToWin32Err( + CM_Get_Device_Interface_List_SizeW( + &InterfacesLen, + (GUID *)&GUID_DEVINTERFACE_NET, + (DEVINSTID_W)InstanceId, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT), + ERROR_GEN_FAILURE); + if (LastError != ERROR_SUCCESS) { - LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); - goto cleanupMutex; + SetLastError(LOG_ERROR(LastError, L"Failed to query adapter %s associated instances size", InstanceId)); + return NULL; } - Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); - if (!SetupDiOpenDeviceInfoW(Adapter->DevInfo, DevInstanceID, NULL, 0, &Adapter->DevInfoData)) + LPWSTR Interfaces = AllocArray(InterfacesLen, sizeof(*Interfaces)); + if (!Interfaces) + return NULL; + LastError = CM_MapCrToWin32Err( + CM_Get_Device_Interface_ListW( + (GUID *)&GUID_DEVINTERFACE_NET, + (DEVINSTID_W)InstanceId, + Interfaces, + InterfacesLen, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT), + ERROR_GEN_FAILURE); + if (LastError != ERROR_SUCCESS) { - LastError = LOG_LAST_ERROR(L"Failed to open device instance ID %s", DevInstanceID); - goto cleanupMutex; + LOG_ERROR(LastError, L"Failed to get adapter %s associated instances", InstanceId); + Free(Interfaces); + SetLastError(LastError); + return NULL; } - if (!PopulateAdapterData(Adapter, Pool)) + if (!Interfaces[0]) { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); - goto cleanupMutex; + Free(Interfaces); + SetLastError(ERROR_DEVICE_NOT_AVAILABLE); + return NULL; } -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - if (LastError != ERROR_SUCCESS) - WireGuardFreeAdapter(Adapter); - return RET_ERROR(Adapter, LastError); + return Interfaces; } typedef struct _WAIT_FOR_INTERFACE_CTX @@ -1372,60 +431,15 @@ WaitForInterfaceCallback( SetEvent(Ctx->Event); } -#if NTDDI_VERSION == NTDDI_WIN7 -_Must_inspect_result_ -static _Return_type_success_(return != FALSE) -BOOL -WaitForInterfaceWin7(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) -{ - ULONG Status, Number; - DWORD ValType, Zero; - HKEY Key = INVALID_HANDLE_VALUE; - BOOLEAN Ret = FALSE; - for (int i = 0; i < 1500; ++i) - { - if (i) - Sleep(10); - if (Key == INVALID_HANDLE_VALUE) - { - Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); - if (Key == INVALID_HANDLE_VALUE) - continue; - } - _Analysis_assume_(Key); - Zero = 0; - if (RegQueryValueExW(Key, L"NetCfgInstanceId", NULL, &ValType, NULL, &Zero) != ERROR_MORE_DATA && - CM_Get_DevNode_Status(&Status, &Number, DevInfoData->DevInst, 0) == CR_SUCCESS && - !(Status & DN_HAS_PROBLEM) && !Number) - { - Ret = TRUE; - break; - } - } - if (Key != INVALID_HANDLE_VALUE) - RegCloseKey(Key); - return Ret; -} -#endif - _Must_inspect_result_ static _Return_type_success_(return != FALSE) BOOL -WaitForInterface(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +WaitForInterface(_In_ WCHAR *InstanceId) { -#if NTDDI_VERSION == NTDDI_WIN7 if (IsWindows7) - return WaitForInterfaceWin7(DevInfo, DevInfoData); -#endif - - DWORD LastError = ERROR_SUCCESS, Size; - WCHAR InstanceId[MAX_INSTANCE_ID]; - if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, _countof(InstanceId), &Size)) - { - LastError = LOG_LAST_ERROR(L"Failed to get adapter %u instance ID", DevInfoData->DevInst); - goto cleanup; - } + return TRUE; + DWORD LastError = ERROR_SUCCESS; static const DEVPROP_BOOLEAN DevPropTrue = DEVPROP_TRUE; const DEVPROP_FILTER_EXPRESSION Filters[] = { { .Operator = DEVPROP_OPERATOR_EQUALS_IGNORE_CASE, .Property.CompKey.Key = DEVPKEY_Device_InstanceId, @@ -1463,7 +477,7 @@ WaitForInterface(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) WaitForInterfaceCallback, &Ctx, &Query); - if (HRet < 0) + if (FAILED(HRet)) { LastError = LOG_ERROR(HRet, L"Failed to create device query"); goto cleanupEvent; @@ -1488,36 +502,65 @@ cleanup: return RET_ERROR(TRUE, LastError); } +typedef struct _SW_DEVICE_CREATE_CTX +{ + HRESULT CreateResult; + WCHAR *DeviceInstanceId; + HANDLE Triggered; +} SW_DEVICE_CREATE_CTX; + +static VOID +DeviceCreateCallback( + _In_ HSWDEVICE SwDevice, + _In_ HRESULT CreateResult, + _In_ VOID *Context, + _In_opt_ PCWSTR DeviceInstanceId) +{ + SW_DEVICE_CREATE_CTX *Ctx = Context; + Ctx->CreateResult = CreateResult; + if (DeviceInstanceId) + wcsncpy_s(Ctx->DeviceInstanceId, MAX_INSTANCE_ID, DeviceInstanceId, _TRUNCATE); + SetEvent(Ctx->Triggered); +} + _Use_decl_annotations_ WIREGUARD_ADAPTER_HANDLE WINAPI -WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) +WireGuardCreateAdapter(LPCWSTR Name, LPCWSTR TunnelType, const GUID *RequestedGUID) { -#ifdef MAYBE_WOW64 - if (NativeMachine != IMAGE_FILE_PROCESS) - return CreateAdapterViaRundll32(Pool, Name, RequestedGUID); -#endif - DWORD LastError = ERROR_SUCCESS; - LOG(WIREGUARD_LOG_INFO, L"Creating adapter"); + WIREGUARD_ADAPTER *Adapter = NULL; - WIREGUARD_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); - if (!Adapter) - return NULL; + HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex(); + if (!DeviceInstallationMutex) + { + LastError = LOG_LAST_ERROR(L"Failed to take device installation mutex"); + goto cleanup; + } WCHAR InstanceIdInf[MAX_PATH]; if (!GetWindowsDirectoryW(InstanceIdInf, _countof(InstanceIdInf)) || !PathAppend(InstanceIdInf, L"INF\\wireguard-instanceid.inf")) { LastError = LOG_ERROR(ERROR_BUFFER_OVERFLOW, L"Failed to construct INF path"); - goto cleanupAdapter; + goto cleanupDeviceInstallationMutex; } - HANDLE InstanceIdMutex = NamespaceTakeInstanceIdMutex(); - if (!InstanceIdMutex) + DeleteFileW(InstanceIdInf); + + HDEVINFO DevInfoExistingAdapters; + SP_DEVINFO_DATA_LIST *ExistingAdapters; + if (!DriverInstall(&DevInfoExistingAdapters, &ExistingAdapters)) { - LastError = LOG_LAST_ERROR(L"Failed to take instance ID mutex"); - goto cleanupAdapter; + LastError = GetLastError(); + goto cleanupDeviceInstallationMutex; } - if (RequestedGUID && IsWindows10) + + LOG(WIREGUARD_LOG_INFO, L"Creating adapter"); + + Adapter = Zalloc(sizeof(*Adapter)); + if (!Adapter) + goto cleanupDriverInstall; + + if (RequestedGUID) { HANDLE InstanceIdFile = CreateFileW( InstanceIdInf, @@ -1530,7 +573,7 @@ WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) if (InstanceIdFile == INVALID_HANDLE_VALUE) { LastError = LOG_LAST_ERROR(L"Failed to open %s for writing", InstanceIdInf); - goto cleanupInstanceIdMutex; + goto cleanupDriverInstall; } static const WCHAR InfTemplate[] = L"[Version]\r\n" @@ -1576,130 +619,120 @@ WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) } CloseHandle(InstanceIdFile); } - else if (IsWindows10) - DeleteFileW(InstanceIdInf); - Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); - if (Adapter->DevInfo == INVALID_HANDLE_VALUE) - { - LastError = LOG_LAST_ERROR(L"Failed to create empty device information set"); - goto cleanupAdapter; - } - WCHAR ClassName[MAX_CLASS_NAME_LEN]; - if (!SetupDiClassNameFromGuidExW(&GUID_DEVCLASS_NET, ClassName, _countof(ClassName), NULL, NULL, NULL)) + WCHAR TunnelTypeName[MAX_ADAPTER_NAME + 8]; + if (_snwprintf_s(TunnelTypeName, _countof(TunnelTypeName), _TRUNCATE, L"%s Tunnel", TunnelType) == -1) { - LastError = LOG_LAST_ERROR(L"Failed to retrieve class name associated with class GUID"); + LastError = ERROR_BUFFER_OVERFLOW; goto cleanupAdapter; } - WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; - if (!GetPoolDeviceTypeName(Pool, PoolDeviceTypeName)) - { - LastError = GetLastError(); - goto cleanupAdapter; - } - Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); - if (!SetupDiCreateDeviceInfoW( - Adapter->DevInfo, - ClassName, - &GUID_DEVCLASS_NET, - PoolDeviceTypeName, - NULL, - DICD_GENERATE_ID, - &Adapter->DevInfoData)) - { - LastError = LOG_LAST_ERROR(L"Failed to create new device information element"); - goto cleanupAdapter; - } - SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; - if (!SetupDiGetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) + DEVINST RootNode; + WCHAR RootNodeName[200 /* rasmans.dll uses 200 hard coded instead of calling CM_Get_Device_ID_Size. */]; + CONFIGRET ConfigRet; + if ((ConfigRet = CM_Locate_DevNodeW(&RootNode, NULL, CM_LOCATE_DEVNODE_NORMAL)) != CR_SUCCESS || + (ConfigRet = CM_Get_Device_IDW(RootNode, RootNodeName, _countof(RootNodeName), 0)) != CR_SUCCESS) { - LastError = LOG_LAST_ERROR( - L"Failed to retrieve adapter %u device installation parameters", Adapter->DevInfoData.DevInst); + LastError = LOG_ERROR(CM_MapCrToWin32Err(ConfigRet, ERROR_GEN_FAILURE), L"Failed to get root node name"); goto cleanupAdapter; } - DevInstallParams.Flags |= DI_QUIETINSTALL; - if (!SetupDiSetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) - { - LastError = - LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", Adapter->DevInfoData.DevInst); - goto cleanupAdapter; - } - if (!SetupDiSetSelectedDevice(Adapter->DevInfo, &Adapter->DevInfoData)) + + GUID InstanceId; + HRESULT HRet = S_OK; + if (RequestedGUID) + memcpy(&InstanceId, RequestedGUID, sizeof(InstanceId)); + else + HRet = CoCreateGuid(&InstanceId); + WCHAR InstanceIdStr[MAX_GUID_STRING_LEN]; + if (FAILED(HRet) || !StringFromGUID2(&InstanceId, InstanceIdStr, _countof(InstanceIdStr))) { - LastError = LOG_LAST_ERROR(L"Failed to select adapter %u device", Adapter->DevInfoData.DevInst); + LastError = LOG_ERROR(HRet, L"Failed to convert GUID"); goto cleanupAdapter; } static const WCHAR Hwids[_countof(WIREGUARD_HWID) + 1 /*Multi-string terminator*/] = WIREGUARD_HWID; - if (!SetupDiSetDeviceRegistryPropertyW( - Adapter->DevInfo, &Adapter->DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) - { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u hardware ID", Adapter->DevInfoData.DevInst); - goto cleanupAdapter; - } - - HDEVINFO DevInfoExistingAdapters; - SP_DEVINFO_DATA_LIST *ExistingAdapters; - if (!SelectDriver( - Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams, &DevInfoExistingAdapters, &ExistingAdapters)) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to select adapter %u driver", Adapter->DevInfoData.DevInst); + SW_DEVICE_CREATE_INFO CreateInfo = { .cbSize = sizeof(CreateInfo), + .pszInstanceId = InstanceIdStr, + .pszzHardwareIds = Hwids, + .pszzCompatibleIds = Hwids, + .CapabilityFlags = + SWDeviceCapabilitiesSilentInstall | SWDeviceCapabilitiesDriverRequired, + .pszDeviceDescription = TunnelTypeName }; + DEVPROPERTY DeviceProperties[] = { + { .CompKey = { .Key = DEVPKEY_WireGuard_Name, .Store = DEVPROP_STORE_SYSTEM }, + .Type = DEVPROP_TYPE_STRING, + .Buffer = (WCHAR *)Name, + .BufferSize = (ULONG)((wcslen(Name) + 1) * sizeof(*Name)) }, + { .CompKey = { .Key = DEVPKEY_Device_FriendlyName, .Store = DEVPROP_STORE_SYSTEM }, + .Type = DEVPROP_TYPE_STRING, + .Buffer = TunnelTypeName, + .BufferSize = (ULONG)((wcslen(TunnelTypeName) + 1) * sizeof(*TunnelTypeName)) }, + { .CompKey = { .Key = DEVPKEY_Device_DeviceDesc, .Store = DEVPROP_STORE_SYSTEM }, + .Type = DEVPROP_TYPE_STRING, + .Buffer = TunnelTypeName, + .BufferSize = (ULONG)((wcslen(TunnelTypeName) + 1) * sizeof(*TunnelTypeName)) } + }; + SW_DEVICE_CREATE_CTX CreateContext = { .DeviceInstanceId = Adapter->DevInstanceID, + .Triggered = CreateEventW(NULL, FALSE, FALSE, NULL) }; + if (!CreateContext.Triggered) + { + LastError = LOG_LAST_ERROR(L"Failed to create event trigger"); goto cleanupAdapter; } - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) + if (IsWindows7) { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to take %s pool mutex", Pool); - goto cleanupDriverInfoList; + if (!CreateAdapterWin7(Adapter, Name, TunnelTypeName)) + { + LastError = GetLastError(); + goto cleanupCreateContext; + } + goto resumeAfterInstanceId; } - if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, Adapter->DevInfo, &Adapter->DevInfoData)) + HRet = SwDeviceCreate( + WIREGUARD_HWID, + RootNodeName, + &CreateInfo, + _countof(DeviceProperties), + DeviceProperties, + DeviceCreateCallback, + &CreateContext, + &Adapter->SwDevice); + if (FAILED(HRet)) { - LastError = LOG_LAST_ERROR(L"Failed to register adapter %u device", Adapter->DevInfoData.DevInst); - goto cleanupDevice; + LastError = LOG_ERROR(HRet, L"Failed to initiate device creation"); + goto cleanupCreateContext; } - if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, Adapter->DevInfo, &Adapter->DevInfoData)) - LOG_LAST_ERROR(L"Failed to register adapter %u coinstallers", Adapter->DevInfoData.DevInst); - if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, Adapter->DevInfo, &Adapter->DevInfoData)) - LOG_LAST_ERROR(L"Failed to install adapter %u interfaces", Adapter->DevInfoData.DevInst); - if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, Adapter->DevInfo, &Adapter->DevInfoData)) + if (WaitForSingleObject(CreateContext.Triggered, INFINITE) != WAIT_OBJECT_0) { - LastError = LOG_LAST_ERROR(L"Failed to install adapter %u device", Adapter->DevInfoData.DevInst); - goto cleanupDevice; + LastError = LOG_LAST_ERROR(L"Failed to wait for device creation trigger"); + goto cleanupCreateContext; } - - if (CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData)) + if (FAILED(CreateContext.CreateResult)) { - LastError = ERROR_PNP_REBOOT_REQUIRED; - goto cleanupDevice; + LastError = LOG_ERROR(CreateContext.CreateResult, L"Failed to create device"); + goto cleanupCreateContext; } - if (!SetupDiSetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_WireGuard_Pool, - DEVPROP_TYPE_STRING, -#pragma warning(suppress : 4090) - (const BYTE *)Pool, - (DWORD)((wcslen(Pool) + 1) * sizeof(*Pool)), - 0)) +resumeAfterInstanceId: + Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + if (Adapter->DevInfo == INVALID_HANDLE_VALUE) { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u pool", Adapter->DevInfoData.DevInst); - goto cleanupDevice; + Adapter->DevInfo = NULL; + LastError = LOG_LAST_ERROR(L"Failed to make device list"); + goto cleanupCreateContext; } - if (!SetupDiSetDeviceRegistryPropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - SPDRP_DEVICEDESC, - (const BYTE *)PoolDeviceTypeName, - (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(*PoolDeviceTypeName)))) + Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); + if (!SetupDiOpenDeviceInfoW( + Adapter->DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &Adapter->DevInfoData)) { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u description", Adapter->DevInfoData.DevInst); - goto cleanupDevice; + LastError = LOG_LAST_ERROR(L"Failed to open device instance ID %s", Adapter->DevInstanceID); + SetupDiDestroyDeviceInfoList(Adapter->DevInfo); + Adapter->DevInfo = NULL; + goto cleanupCreateContext; } - if (!WaitForInterface(Adapter->DevInfo, &Adapter->DevInfoData)) + if (!WaitForInterface(Adapter->DevInstanceID)) { DEVPROPTYPE PropertyType = 0; NTSTATUS NtStatus = 0; @@ -1729,131 +762,73 @@ WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) LastError = RtlNtStatusToDosError(NtStatus); if (LastError == ERROR_SUCCESS) LastError = ERROR_DEVICE_NOT_AVAILABLE; - LOG_ERROR(LastError, L"Failed to setup adapter (problem code: 0x%x, ntstatus: 0x%x)", ProblemCode, NtStatus); - goto cleanupDevice; + LOG_ERROR(LastError, L"Failed to setup adapter (problem code: 0x%X, ntstatus: 0x%X)", ProblemCode, NtStatus); + goto cleanupCreateContext; } - if (!PopulateAdapterData(Adapter, Pool)) + if (!PopulateAdapterData(Adapter)) { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); - goto cleanupDevice; + LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to populate adapter data"); + goto cleanupCreateContext; } - if (!WireGuardSetAdapterName(Adapter, Name)) + if (!NciSetAdapterName(&Adapter->CfgInstanceID, Name)) { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to set adapter name %s", Name); - goto cleanupDevice; + LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to set adapter name \"%s\"", Name); + goto cleanupCreateContext; } - if (!EnsureDeviceObject(Adapter->DevInstanceID)) - { - LastError = LOG_LAST_ERROR(L"Device object file did not appear"); - goto cleanupDevice; - } - LastError = ERROR_SUCCESS; + if (IsWindows7) + CreateAdapterPostWin7(Adapter, TunnelTypeName); -cleanupDevice: - if (LastError != ERROR_SUCCESS) - { - SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_REMOVE }, - .Scope = DI_REMOVEDEVICE_GLOBAL }; - if (SetupDiSetClassInstallParamsW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &RemoveDeviceParams.ClassInstallHeader, - sizeof(RemoveDeviceParams))) - SetupDiCallClassInstaller(DIF_REMOVE, Adapter->DevInfo, &Adapter->DevInfoData); - } - NamespaceReleaseMutex(Mutex); -cleanupDriverInfoList: - SelectDriverDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); - SetupDiDestroyDriverInfoList(Adapter->DevInfo, &Adapter->DevInfoData, SPDIT_COMPATDRIVER); +cleanupCreateContext: + CloseHandle(CreateContext.Triggered); cleanupInstanceIdFile: DeleteFileW(InstanceIdInf); -cleanupInstanceIdMutex: - NamespaceReleaseMutex(InstanceIdMutex); cleanupAdapter: if (LastError != ERROR_SUCCESS) - WireGuardFreeAdapter(Adapter); + { + WireGuardCloseAdapter(Adapter); + Adapter = NULL; + } +cleanupDriverInstall: + DriverInstallDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); +cleanupDeviceInstallationMutex: + NamespaceReleaseMutex(DeviceInstallationMutex); +cleanup: + QueueUpOrphanedDeviceCleanupRoutine(); return RET_ERROR(Adapter, LastError); } _Use_decl_annotations_ -BOOL WINAPI -WireGuardDeleteAdapter(WIREGUARD_ADAPTER *Adapter) +WIREGUARD_ADAPTER_HANDLE WINAPI +WireGuardOpenAdapter(LPCWSTR Name) { - WireGuardSetAdapterLogging(Adapter, WIREGUARD_ADAPTER_LOG_OFF); - -#ifdef MAYBE_WOW64 - if (NativeMachine != IMAGE_FILE_PROCESS) - return DeleteAdapterViaRundll32(Adapter); -#endif - DWORD LastError = ERROR_SUCCESS; - HANDLE Mutex = NamespaceTakePoolMutex(Adapter->Pool); - if (!Mutex) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to take %s pool mutex", Adapter->Pool); - goto cleanup; - } + WIREGUARD_ADAPTER *Adapter = NULL; - SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; - if (!SetupDiGetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) - { - LastError = LOG_LAST_ERROR( - L"Failed to retrieve adapter %u device installation parameters", Adapter->DevInfoData.DevInst); - goto cleanupMutex; - } - DevInstallParams.Flags |= DI_QUIETINSTALL; - if (!SetupDiSetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) + HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex(); + if (!DeviceInstallationMutex) { - LastError = - LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", Adapter->DevInfoData.DevInst); - goto cleanupMutex; + LastError = LOG_LAST_ERROR(L"Failed to take device installation mutex"); + goto cleanup; } - SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_REMOVE }, - .Scope = DI_REMOVEDEVICE_GLOBAL }; - if ((!SetupDiSetClassInstallParamsW( - Adapter->DevInfo, &Adapter->DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_REMOVE, Adapter->DevInfo, &Adapter->DevInfoData)) && - GetLastError() != ERROR_NO_SUCH_DEVINST) - LastError = LOG_LAST_ERROR(L"Failed to remove adapter %u", Adapter->DevInfoData.DevInst); - - if (CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData)) - LastError = LastError == ERROR_SUCCESS ? ERROR_SUCCESS_REBOOT_REQUIRED : ERROR_FAIL_REBOOT_REQUIRED; - -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - return RET_ERROR(TRUE, LastError); -} + Adapter = Zalloc(sizeof(*Adapter)); + if (!Adapter) + goto cleanupDeviceInstallationMutex; -static _Return_type_success_(return != FALSE) -BOOL -DeleteAllOurAdapters(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired) -{ - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to take %s pool mutex", Pool); - return FALSE; - } - DWORD LastError = ERROR_SUCCESS; - HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WIREGUARD_ENUMERATOR, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) { LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); - goto cleanupMutex; + goto cleanupAdapter; } - SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_REMOVE }, - .Scope = DI_REMOVEDEVICE_GLOBAL }; - for (DWORD EnumIndex = 0;; ++EnumIndex) + + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + BOOL Found = FALSE; + for (DWORD EnumIndex = 0; !Found; ++EnumIndex) { - SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) @@ -1861,138 +836,101 @@ DeleteAllOurAdapters(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired) continue; } - if (!IsOurAdapter(DevInfo, &DevInfoData) || !IsPoolMember(Pool, DevInfo, &DevInfoData)) - continue; - - LOG(WIREGUARD_LOG_INFO, L"Removing adapter %u", DevInfoData.DevInst); - if ((!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) && - GetLastError() != ERROR_NO_SUCH_DEVINST) - { - LOG_LAST_ERROR(L"Failed to remove adapter %u", DevInfoData.DevInst); - LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); - } - *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); + DEVPROPTYPE PropType; + WCHAR OtherName[MAX_ADAPTER_NAME]; + Found = SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_WireGuard_Name, + &PropType, + (PBYTE)OtherName, + MAX_ADAPTER_NAME * sizeof(OtherName[0]), + NULL, + 0) && + PropType == DEVPROP_TYPE_STRING && !_wcsicmp(Name, OtherName); } - SetupDiDestroyDeviceInfoList(DevInfo); -cleanupMutex: - NamespaceReleaseMutex(Mutex); - return RET_ERROR(TRUE, LastError); -} - -_Use_decl_annotations_ -BOOL WINAPI -WireGuardDeletePoolDriver(LPCWSTR Pool) -{ - DWORD LastError = ERROR_SUCCESS; -#ifdef MAYBE_WOW64 - if (NativeMachine != IMAGE_FILE_PROCESS) + if (!Found) { - LastError = DeletePoolDriverViaRundll32(Pool) ? ERROR_SUCCESS : GetLastError(); - goto cleanup; + LastError = LOG_ERROR(ERROR_NOT_FOUND, L"Failed to find matching adapter name"); + goto cleanupDevInfo; } -#endif - - BOOL RebootRequired = FALSE; - if (!DeleteAllOurAdapters(Pool, &RebootRequired)) + DWORD RequiredChars = _countof(Adapter->DevInstanceID); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, Adapter->DevInstanceID, RequiredChars, &RequiredChars)) { - LastError = GetLastError(); - goto cleanup; + LastError = LOG_LAST_ERROR(L"Failed to get adapter instance ID"); + goto cleanupDevInfo; } - - HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); - if (!DriverInstallationLock) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to take driver installation mutex"); - goto cleanup; - } - HDEVINFO DeviceInfoSet = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, 0); - if (!DeviceInfoSet) - { - LastError = LOG_LAST_ERROR(L"Failed to get adapter information"); - goto cleanupDriverInstallationLock; - } - if (!SetupDiBuildDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER)) + Adapter->DevInfo = DevInfo; + Adapter->DevInfoData = DevInfoData; + BOOL Ret = WaitForInterface(Adapter->DevInstanceID) && PopulateAdapterData(Adapter); + Adapter->DevInfo = NULL; + if (!Ret) { - LastError = LOG_LAST_ERROR(L"Failed building driver info list"); - goto cleanupDeviceInfoSet; + LastError = LOG_LAST_ERROR(L"Failed to populate adapter"); + goto cleanupDevInfo; } - for (DWORD EnumIndex = 0;; ++EnumIndex) + +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanupAdapter: + if (LastError != ERROR_SUCCESS) { - SP_DRVINFO_DATA_W DriverInfo = { .cbSize = sizeof(DriverInfo) }; - if (!SetupDiEnumDriverInfoW(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER, EnumIndex, &DriverInfo)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } - SP_DRVINFO_DETAIL_DATA_W *DriverDetail = GetAdapterDrvInfoDetail(DeviceInfoSet, NULL, &DriverInfo); - if (!DriverDetail) - continue; - if (!_wcsicmp(DriverDetail->HardwareID, WIREGUARD_HWID)) - { - LPCWSTR Path = PathFindFileNameW(DriverDetail->InfFileName); - LOG(WIREGUARD_LOG_INFO, L"Removing driver %s", Path); - if (!SetupUninstallOEMInfW(Path, 0, NULL)) - { - LOG_LAST_ERROR(L"Unable to remove driver %s", Path); - LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); - } - } - Free(DriverDetail); + WireGuardCloseAdapter(Adapter); + Adapter = NULL; } - if (RebootRequired) - LastError = LastError == ERROR_SUCCESS ? ERROR_SUCCESS_REBOOT_REQUIRED : ERROR_FAIL_REBOOT_REQUIRED; - SetupDiDestroyDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER); -cleanupDeviceInfoSet: - SetupDiDestroyDeviceInfoList(DeviceInfoSet); -cleanupDriverInstallationLock: - NamespaceReleaseMutex(DriverInstallationLock); +cleanupDeviceInstallationMutex: + NamespaceReleaseMutex(DeviceInstallationMutex); cleanup: - return RET_ERROR(TRUE, LastError); + QueueUpOrphanedDeviceCleanupRoutine(); + return RET_ERROR(Adapter, LastError); +} + +_Use_decl_annotations_ +BOOL +AdapterRemoveInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) +{ +#ifdef MAYBE_WOW64 + if (NativeMachine != IMAGE_FILE_PROCESS) + return RemoveInstanceViaRundll32(DevInfo, DevInfoData); +#endif + + SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_REMOVE }, + .Scope = DI_REMOVEDEVICE_GLOBAL }; + return SetupDiSetClassInstallParamsW( + DevInfo, DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) && + SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, DevInfoData); } _Use_decl_annotations_ -BOOL WINAPI -WireGuardEnumAdapters(LPCWSTR Pool, WIREGUARD_ENUM_CALLBACK Func, LPARAM Param) +BOOL +AdapterEnableInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - DWORD LastError = ERROR_SUCCESS; - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to take %s pool mutex", Pool); - goto cleanup; - } - HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (DevInfo == INVALID_HANDLE_VALUE) - { - LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); - goto cleanupMutex; - } - BOOL Continue = TRUE; - for (DWORD EnumIndex = 0; Continue; ++EnumIndex) - { - WIREGUARD_ADAPTER Adapter = { .DevInfo = DevInfo, .DevInfoData.cbSize = sizeof(Adapter.DevInfoData) }; - if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &Adapter.DevInfoData)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } +#ifdef MAYBE_WOW64 + if (NativeMachine != IMAGE_FILE_PROCESS) + return EnableInstanceViaRundll32(DevInfo, DevInfoData); +#endif - if (!IsOurAdapter(DevInfo, &Adapter.DevInfoData) || !IsPoolMember(Pool, DevInfo, &Adapter.DevInfoData)) - continue; + SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_PROPERTYCHANGE }, + .StateChange = DICS_ENABLE, + .Scope = DICS_FLAG_GLOBAL }; + return SetupDiSetClassInstallParamsW(DevInfo, DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) && + SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, DevInfoData); +} - if (!PopulateAdapterData(&Adapter, Pool)) - { - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to populate adapter %u data", Adapter.DevInfoData.DevInst); - break; - } - Continue = Func(&Adapter, Param); - } - SetupDiDestroyDeviceInfoList(DevInfo); -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - return RET_ERROR(TRUE, LastError); +_Use_decl_annotations_ +BOOL +AdapterDisableInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) +{ +#ifdef MAYBE_WOW64 + if (NativeMachine != IMAGE_FILE_PROCESS) + return DisableInstanceViaRundll32(DevInfo, DevInfoData); +#endif + SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_PROPERTYCHANGE }, + .StateChange = DICS_DISABLE, + .Scope = DICS_FLAG_GLOBAL }; + return SetupDiSetClassInstallParamsW(DevInfo, DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) && + SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, DevInfoData); } diff --git a/api/adapter.h b/api/adapter.h index 3ae88c0..75358c2 100644 --- a/api/adapter.h +++ b/api/adapter.h @@ -12,29 +12,29 @@ #define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ #define WIREGUARD_HWID L"WireGuard" +#define WIREGUARD_ENUMERATOR (IsWindows7 ? L"ROOT\\" WIREGUARD_HWID : L"SWD\\" WIREGUARD_HWID) + +extern const DEVPROPKEY DEVPKEY_WireGuard_Name; + +typedef struct HSWDEVICE__ *HSWDEVICE; /** * WireGuard adapter descriptor. */ typedef struct _WIREGUARD_ADAPTER { + HSWDEVICE SwDevice; HDEVINFO DevInfo; SP_DEVINFO_DATA DevInfoData; + WCHAR *InterfaceFilename; GUID CfgInstanceID; WCHAR DevInstanceID[MAX_INSTANCE_ID]; DWORD LuidIndex; DWORD IfType; DWORD IfIndex; - WCHAR Pool[WIREGUARD_MAX_POOL]; HANDLE LogThread; DWORD LogState; } WIREGUARD_ADAPTER; - -/** - * @copydoc WIREGUARD_FREE_ADAPTER_FUNC - */ -WIREGUARD_FREE_ADAPTER_FUNC WireGuardFreeAdapter; - /** * @copydoc WIREGUARD_CREATE_ADAPTER_FUNC */ @@ -46,19 +46,9 @@ WIREGUARD_CREATE_ADAPTER_FUNC WireGuardCreateAdapter; WIREGUARD_OPEN_ADAPTER_FUNC WireGuardOpenAdapter; /** - * @copydoc WIREGUARD_DELETE_ADAPTER_FUNC - */ -WIREGUARD_DELETE_ADAPTER_FUNC WireGuardDeleteAdapter; - -/** - * @copydoc WIREGUARD_ENUM_ADAPTERS_FUNC - */ -WIREGUARD_ENUM_ADAPTERS_FUNC WireGuardEnumAdapters; - -/** - * @copydoc WIREGUARD_DELETE_POOL_DRIVER_FUNC + * @copydoc WIREGUARD_CLOSE_ADAPTER_FUNC */ -WIREGUARD_DELETE_POOL_DRIVER_FUNC WireGuardDeletePoolDriver; +WIREGUARD_CLOSE_ADAPTER_FUNC WireGuardCloseAdapter; /** * @copydoc WIREGUARD_GET_ADAPTER_LUID_FUNC @@ -66,21 +56,6 @@ WIREGUARD_DELETE_POOL_DRIVER_FUNC WireGuardDeletePoolDriver; WIREGUARD_GET_ADAPTER_LUID_FUNC WireGuardGetAdapterLUID; /** - * @copydoc WIREGUARD_GET_ADAPTER_NAME_FUNC - */ -WIREGUARD_GET_ADAPTER_NAME_FUNC WireGuardGetAdapterName; - -/** - * @copydoc WIREGUARD_SET_ADAPTER_NAME_FUNC - */ -WIREGUARD_SET_ADAPTER_NAME_FUNC WireGuardSetAdapterName; - -/** - * @copydoc WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC - */ -WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC WireGuardGetRunningDriverVersion; - -/** * Returns a handle to the adapter device object. * * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter. @@ -94,18 +69,66 @@ HANDLE WINAPI AdapterOpenDeviceObject(_In_ const WIREGUARD_ADAPTER *Adapter); /** - * Returns an adapter object based on a devnode instance ID. - * - * @param Pool Pool name of adapter object to be opened. + * Returns the device object file name for an adapter instance ID. * - * @param DevInstanceID Instance ID of devnode for opening adapter. + * @param InstanceID The device instance ID of the adapter. * - * @return If the function succeeds, the return value is adapter object.. - * If the function fails, the return value is NULL. To get extended error - * information, call GetLastError. + * @return If the function succeeds, the return value is the filename of the device object, which + * must be freed with Free(). If the function fails, the return value is INVALID_HANDLE_VALUE. + * To get extended error information, call GetLastError. */ _Must_inspect_result_ _Return_type_success_(return != NULL) _Post_maybenull_ -WIREGUARD_ADAPTER * -AdapterOpenFromDevInstanceId(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR DevInstanceID); +LPWSTR +AdapterGetDeviceObjectFileName(_In_z_ LPCWSTR InstanceId); + +/** + * Cleans up adapters with no attached process. + */ +VOID AdapterCleanupOrphanedDevices(VOID); + +/** + * Removes the specified device instance. + * + * @param DevInfo Device info handle from SetupAPI. + * @param DevInfoData Device info data specifying which device. + * + * @return If the function succeeds, the return value is TRUE. If the + * function fails, the return value is FALSE. To get extended + * error information, call GetLastError. + */ + +_Return_type_success_(return != FALSE) +BOOL +AdapterRemoveInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); + +/** + * Enables the specified device instance. + * + * @param DevInfo Device info handle from SetupAPI. + * @param DevInfoData Device info data specifying which device. + * + * @return If the function succeeds, the return value is TRUE. If the + * function fails, the return value is FALSE. To get extended + * error information, call GetLastError. + */ + +_Return_type_success_(return != FALSE) +BOOL +AdapterEnableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); + +/** + * Disables the specified device instance. + * + * @param DevInfo Device info handle from SetupAPI. + * @param DevInfoData Device info data specifying which device. + * + * @return If the function succeeds, the return value is TRUE. If the + * function fails, the return value is FALSE. To get extended + * error information, call GetLastError. + */ + +_Return_type_success_(return != FALSE) +BOOL +AdapterDisableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); diff --git a/api/adapter_win7.h b/api/adapter_win7.h new file mode 100644 index 0000000..abb89e6 --- /dev/null +++ b/api/adapter_win7.h @@ -0,0 +1,310 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +static const DEVPROPKEY DEVPKEY_WireGuard_OwningProcess = { + { 0x65726957, 0x7547, 0x7261, { 0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73 } }, + DEVPROPID_FIRST_USABLE + 3 +}; + +typedef struct _OWNING_PROCESS +{ + DWORD ProcessId; + FILETIME CreationTime; +} OWNING_PROCESS; + +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +WaitForInterfaceWin7(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ LPCWSTR DevInstanceId) +{ + ULONG Status, Number; + DWORD ValType, Zero; + WCHAR *FileName = NULL; + HKEY Key = INVALID_HANDLE_VALUE; + BOOLEAN Ret = FALSE; + for (int i = 0; i < 1500; ++i) + { + if (i) + Sleep(10); + if (Key == INVALID_HANDLE_VALUE) + { + Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + if (Key == INVALID_HANDLE_VALUE) + continue; + } + _Analysis_assume_(Key); + if (!FileName) + FileName = AdapterGetDeviceObjectFileName(DevInstanceId); + Zero = 0; + if (FileName && RegQueryValueExW(Key, L"NetCfgInstanceId", NULL, &ValType, NULL, &Zero) != ERROR_MORE_DATA && + CM_Get_DevNode_Status(&Status, &Number, DevInfoData->DevInst, 0) == CR_SUCCESS && + !(Status & DN_HAS_PROBLEM) && !Number) + { + Ret = TRUE; + break; + } + } + if (Key != INVALID_HANDLE_VALUE) + RegCloseKey(Key); + Free(FileName); + return Ret; +} + +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +CreateAdapterWin7(_Inout_ WIREGUARD_ADAPTER *Adapter, _In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelTypeName) +{ + DWORD LastError = ERROR_SUCCESS; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to create empty device information set"); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + +#ifdef MAYBE_WOW64 + if (NativeMachine != IMAGE_FILE_PROCESS) + { + if (!CreateInstanceWin7ViaRundll32(Adapter->DevInstanceID)) + { + LastError = LOG_LAST_ERROR(L"Failed to create device instance"); + goto cleanup; + } + if (!SetupDiOpenDeviceInfoW(DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + goto resumeAfterInstance; + } +#endif + + if (!SetupDiCreateDeviceInfoW( + DevInfo, WIREGUARD_HWID, &GUID_DEVCLASS_NET, TunnelTypeName, NULL, DICD_GENERATE_ID, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to create new device information element"); + goto cleanupDevInfo; + } + SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; + if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = LOG_LAST_ERROR(L"Failed to retrieve adapter device installation parameters"); + goto cleanupDevInfo; + } + DevInstallParams.Flags |= DI_QUIETINSTALL; + if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = LOG_LAST_ERROR(L"Failed to set adapter device installation parameters"); + goto cleanupDevInfo; + } + if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to select adapter device"); + goto cleanupDevInfo; + } + static const WCHAR Hwids[_countof(WIREGUARD_HWID) + 1 /*Multi-string terminator*/] = WIREGUARD_HWID; + if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) + { + LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID"); + goto cleanupDevInfo; + } + if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER)) + { + LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list"); + goto cleanupDevInfo; + } + SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; + if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) || + !SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData)) + { + LastError = LOG_ERROR(ERROR_DRIVER_INSTALL_BLOCKED, L"Failed to select a driver"); + goto cleanupDriverInfo; + } + + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to register adapter device"); + goto cleanupDevInfo; + } + if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData)) + LOG_LAST_ERROR(L"Failed to register adapter coinstallers"); + if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData)) + LOG_LAST_ERROR(L"Failed to install adapter interfaces"); + if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to install adapter device"); + goto cleanupDevice; + } + +#ifdef MAYBE_WOW64 +resumeAfterInstance:; +#endif + + OWNING_PROCESS OwningProcess = { .ProcessId = GetCurrentProcessId() }; + FILETIME Unused; + if (!GetProcessTimes(GetCurrentProcess(), &OwningProcess.CreationTime, &Unused, &Unused, &Unused)) + { + LastError = LOG_LAST_ERROR(L"Failed to get process creation time"); + goto cleanupDevice; + } + + if (!SetupDiSetDeviceRegistryPropertyW( + DevInfo, + &DevInfoData, + SPDRP_FRIENDLYNAME, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) || + !SetupDiSetDeviceRegistryPropertyW( + DevInfo, + &DevInfoData, + SPDRP_DEVICEDESC, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) || + !SetupDiSetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_WireGuard_Name, + DEVPROP_TYPE_STRING, + (PBYTE)Name, + (DWORD)((wcslen(Name) + 1) * sizeof(Name[0])), + 0) || + !SetupDiSetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_WireGuard_OwningProcess, + DEVPROP_TYPE_BINARY, + (PBYTE)&OwningProcess, + sizeof(OwningProcess), + 0)) + { + LastError = LOG_LAST_ERROR(L"Failed to set device properties"); + goto cleanupDevice; + } + + DWORD RequiredChars = _countof(Adapter->DevInstanceID); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, Adapter->DevInstanceID, RequiredChars, &RequiredChars)) + { + LastError = LOG_LAST_ERROR(L"Failed to get adapter instance ID"); + goto cleanupDevice; + } + + if (!WaitForInterfaceWin7(DevInfo, &DevInfoData, Adapter->DevInstanceID)) + { + DEVPROPTYPE PropertyType = 0; + INT32 ProblemCode = 0; + if (!SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Device_ProblemCode, + &PropertyType, + (PBYTE)&ProblemCode, + sizeof(ProblemCode), + NULL, + 0) || + (PropertyType != DEVPROP_TYPE_INT32 && PropertyType != DEVPROP_TYPE_UINT32)) + ProblemCode = 0; + LastError = LOG_ERROR( + ERROR_DEVICE_REINITIALIZATION_NEEDED, L"Failed to setup adapter (problem code: 0x%x)", ProblemCode); + goto cleanupDevice; + } + +cleanupDevice: + if (LastError != ERROR_SUCCESS) + AdapterRemoveInstance(DevInfo, &DevInfoData); +cleanupDriverInfo: + SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + return RET_ERROR(TRUE, LastError); +} + +static VOID +CreateAdapterPostWin7(_Inout_ WIREGUARD_ADAPTER *Adapter, _In_z_ LPCWSTR TunnelTypeName) +{ + SetupDiSetDeviceRegistryPropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + SPDRP_FRIENDLYNAME, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))); + SetupDiSetDeviceRegistryPropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + SPDRP_DEVICEDESC, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))); +} + +static BOOL +ProcessIsStale(_In_ OWNING_PROCESS *OwningProcess) +{ + HANDLE Process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, OwningProcess->ProcessId); + if (!Process) + return TRUE; + FILETIME CreationTime, Unused; + BOOL Ret = GetProcessTimes(Process, &CreationTime, &Unused, &Unused, &Unused); + CloseHandle(Process); + if (!Ret) + return FALSE; + return !!memcmp(&CreationTime, &OwningProcess->CreationTime, sizeof(CreationTime)); +} + +VOID AdapterCleanupOrphanedDevicesWin7(VOID) +{ + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WIREGUARD_ENUMERATOR, NULL, 0, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + if (GetLastError() != ERROR_INVALID_DATA) + LOG_LAST_ERROR(L"Failed to get adapters"); + return; + } + + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + + OWNING_PROCESS OwningProcess; + DEVPROPTYPE PropType; + if (SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_WireGuard_OwningProcess, + &PropType, + (PBYTE)&OwningProcess, + sizeof(OwningProcess), + NULL, + 0) && + PropType == DEVPROP_TYPE_BINARY && !ProcessIsStale(&OwningProcess)) + continue; + + WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; + SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_WireGuard_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + if (!AdapterRemoveInstance(DevInfo, &DevInfoData)) + { + LOG_LAST_ERROR(L"Failed to remove orphaned adapter \"%s\"", Name); + continue; + } + LOG(WIREGUARD_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name); + } + SetupDiDestroyDeviceInfoList(DevInfo); +}
\ No newline at end of file diff --git a/api/api.vcxproj b/api/api.vcxproj index 0c75dc8..13d3a85 100644 --- a/api/api.vcxproj +++ b/api/api.vcxproj @@ -18,24 +18,25 @@ <ClCompile> <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Platform)'=='Win32'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <PreprocessorDefinitions Condition="'$(Platform)'=='x64'">ACCEPT_WOW64;MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Platform)'=='x64'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <PreprocessorDefinitions Condition="'$(Platform)'=='ARM64'">ACCEPT_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Platform)'=='ARM64'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions> <DisableSpecificWarnings>4100;4201;$(DisableSpecificWarnings)</DisableSpecificWarnings> <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <ResourceCompile> <AdditionalIncludeDirectories>..\$(Configuration)\$(WireGuardPlatform);..\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\arm64\wireguard.dll')">BUILT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\amd64\wireguard.dll')">BUILT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\arm64\driver\wireguard.sys') And Exists('..\$(Configuration)\arm64\setupapihost.dll')">BUILT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\amd64\driver\wireguard.sys') And Exists('..\$(Configuration)\amd64\setupapihost.dll')">BUILT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Platform)'=='Win32'">WANT_ARM64_WOW64;WANT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Platform)'=='x64'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Link> - <DelayLoadDLLs>advapi32.dll;api-ms-win-devices-query-l1-1-0.dll;bcrypt.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll</DelayLoadDLLs> - <AdditionalDependencies>Bcrypt.lib;Cfgmgr32.lib;Iphlpapi.lib;onecore.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies> + <DelayLoadDLLs>advapi32.dll;api-ms-win-devices-query-l1-1-0.dll;api-ms-win-devices-swdevice-l1-1-0.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shlwapi.dll;version.dll</DelayLoadDLLs> + <DelayLoadDLLs Condition="'$(Platform)'!='ARM64'">shell32.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <AdditionalDependencies>Cfgmgr32.lib;Iphlpapi.lib;onecore.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;swdevice.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies> <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> <SubSystem>Windows</SubSystem> </Link> @@ -48,8 +49,10 @@ <None Include="nci.def" /> </ItemGroup> <ItemGroup> + <ClInclude Include="adapter_win7.h" /> <ClInclude Include="main.h" /> <ClInclude Include="adapter.h" /> + <ClInclude Include="driver.h" /> <ClInclude Include="logger.h" /> <ClInclude Include="namespace.h" /> <ClInclude Include="nci.h" /> @@ -62,6 +65,7 @@ <ItemGroup> <ClCompile Include="main.c" /> <ClCompile Include="adapter.c" /> + <ClCompile Include="driver.c" /> <ClCompile Include="logger.c" /> <ClCompile Include="namespace.c" /> <ClCompile Include="registry.c" /> diff --git a/api/api.vcxproj.filters b/api/api.vcxproj.filters index f6bf8fa..1eb9c40 100644 --- a/api/api.vcxproj.filters +++ b/api/api.vcxproj.filters @@ -58,6 +58,12 @@ <ClInclude Include="rundll32.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="driver.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="adapter_win7.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="namespace.c"> @@ -66,9 +72,6 @@ <ClCompile Include="rundll32.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="registry.c"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="logger.c"> <Filter>Source Files</Filter> </ClCompile> @@ -84,5 +87,11 @@ <ClCompile Include="main.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="registry.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> </Project>
\ No newline at end of file diff --git a/api/driver.c b/api/driver.c new file mode 100644 index 0000000..05756d4 --- /dev/null +++ b/api/driver.c @@ -0,0 +1,752 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +#include <Windows.h> +#include <winternl.h> +#include <cfgmgr32.h> +#include <SetupAPI.h> +#include <devguid.h> +#include <ndisguid.h> +#include <Shlwapi.h> +#include <shellapi.h> +#include <wchar.h> + +#include "driver.h" +#include "../driver/ioctl.h" +#include "adapter.h" +#include "logger.h" +#include "namespace.h" +#include "resource.h" +#include "registry.h" +#include "ntdll.h" +#include "rundll32.h" +#include "wireguard-inf.h" + +#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ + +struct _SP_DEVINFO_DATA_LIST +{ + SP_DEVINFO_DATA Data; + VOID *Configuration; + DWORD ConfigurationBytes; + WIREGUARD_ADAPTER_STATE AdapterState; + struct _SP_DEVINFO_DATA_LIST *Next; +}; + +_Must_inspect_result_ +static _Return_type_success_(return != INVALID_HANDLE_VALUE) +HANDLE +OpenDeviceObject(_In_z_ LPCWSTR InstanceId) +{ + WIREGUARD_ADAPTER Adapter = { .InterfaceFilename = AdapterGetDeviceObjectFileName(InstanceId) }; + if (!Adapter.InterfaceFilename) + return INVALID_HANDLE_VALUE; + HANDLE Handle = AdapterOpenDeviceObject(&Adapter); + Free(Adapter.InterfaceFilename); + return Handle; +} + +static _Return_type_success_(return != FALSE) +BOOL +SnapshotConfigurationAndState( + _In_ HDEVINFO DevInfo, + _In_ SP_DEVINFO_DATA *DevInfoData, + _Out_ VOID **Configuration, + _Out_ DWORD *ConfigurationBytes, + _Out_ WIREGUARD_ADAPTER_STATE *State) +{ + DEVPROPTYPE PropType; + WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; + SetupDiGetDevicePropertyW( + DevInfo, + DevInfoData, + &DEVPKEY_WireGuard_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + + DWORD LastError = ERROR_SUCCESS; + DWORD RequiredBytes; + if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) || + (LastError = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) + { + LOG_ERROR(LastError, L"Failed to query adapter \"%s\" instance ID size", Name); + return FALSE; + } + LastError = ERROR_SUCCESS; + LPWSTR InstanceId = ZallocArray(RequiredBytes, sizeof(*InstanceId)); + if (!InstanceId) + return FALSE; + if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes)) + { + LastError = LOG_LAST_ERROR(L"Failed to get adapter \"%s\" instance ID", Name); + goto cleanupInstanceId; + } + HANDLE NdisHandle = OpenDeviceObject(InstanceId); + if (NdisHandle == INVALID_HANDLE_VALUE) + { + LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to get adapter \"%s\" object", Name); + goto cleanupInstanceId; + } + WG_IOCTL_ADAPTER_STATE Op = WG_IOCTL_ADAPTER_STATE_QUERY; + if (!DeviceIoControl( + NdisHandle, WG_IOCTL_SET_ADAPTER_STATE, &Op, sizeof(Op), State, sizeof(*State), &RequiredBytes, NULL)) + { + LastError = LOG_LAST_ERROR(L"Failed to query adapter state on adapter \"%s\"", Name); + goto cleanupHandle; + } + for (RequiredBytes = 512;; RequiredBytes = *ConfigurationBytes) + { + *Configuration = Alloc(RequiredBytes); + if (!*Configuration) + { + LastError = + LOG_LAST_ERROR(L"Failed to allocate %u bytes for configuration on adapter \"%s\"", RequiredBytes, Name); + goto cleanupHandle; + } + if (DeviceIoControl(NdisHandle, WG_IOCTL_GET, NULL, 0, *Configuration, RequiredBytes, ConfigurationBytes, NULL)) + break; + Free(*Configuration); + *Configuration = NULL; + if (GetLastError() != ERROR_MORE_DATA) + { + LastError = LOG_LAST_ERROR(L"Failed to query configuration on adapter \"%s\"", Name); + goto cleanupHandle; + } + } +cleanupHandle: + CloseHandle(NdisHandle); +cleanupInstanceId: + Free(InstanceId); + return RET_ERROR(TRUE, LastError); +} + +static _Return_type_success_(return != FALSE) +BOOL +RestoreConfigurationAndState( + _In_ HDEVINFO DevInfo, + _In_ SP_DEVINFO_DATA *DevInfoData, + _In_ VOID *Configuration, + _In_ DWORD ConfigurationBytes, + _In_ WIREGUARD_ADAPTER_STATE State) +{ + DEVPROPTYPE PropType; + WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; + SetupDiGetDevicePropertyW( + DevInfo, + DevInfoData, + &DEVPKEY_WireGuard_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + + DWORD LastError = ERROR_SUCCESS; + DWORD RequiredBytes; + if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) || + (LastError = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) + { + LOG_ERROR(LastError, L"Failed to query adapter \"%s\" instance ID size", Name); + return FALSE; + } + LastError = ERROR_SUCCESS; + LPWSTR InstanceId = ZallocArray(RequiredBytes, sizeof(*InstanceId)); + if (!InstanceId) + return FALSE; + if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes)) + { + LastError = LOG_LAST_ERROR(L"Failed to get adapter \"%s\" instance ID", Name); + goto cleanupInstanceId; + } + HANDLE NdisHandle = OpenDeviceObject(InstanceId); + if (NdisHandle == INVALID_HANDLE_VALUE) + { + LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to get adapter \"%s\" object", Name); + goto cleanupInstanceId; + } + if (!DeviceIoControl(NdisHandle, WG_IOCTL_SET, NULL, 0, Configuration, ConfigurationBytes, &RequiredBytes, NULL)) + { + LastError = LOG_LAST_ERROR(L"Failed to set configuration on adapter \"%s\"", Name); + goto cleanupHandle; + } + if (!DeviceIoControl(NdisHandle, WG_IOCTL_SET_ADAPTER_STATE, &State, sizeof(State), NULL, 0, &RequiredBytes, NULL)) + { + LastError = LOG_LAST_ERROR(L"Failed to set adapter state on adapter \"%s\"", Name); + goto cleanupHandle; + } +cleanupHandle: + CloseHandle(NdisHandle); +cleanupInstanceId: + Free(InstanceId); + return RET_ERROR(TRUE, LastError); +} + +static _Return_type_success_(return != FALSE) +BOOL +DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters) +{ + DWORD LastError = ERROR_SUCCESS; + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + SP_DEVINFO_DATA_LIST *DeviceNode = Zalloc(sizeof(*DeviceNode)); + if (!DeviceNode) + return FALSE; + DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA); + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + { + Free(DeviceNode); + break; + } + goto cleanupDeviceNode; + } + + DEVPROPTYPE PropType; + WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; + SetupDiGetDevicePropertyW( + DevInfo, + &DeviceNode->Data, + &DEVPKEY_WireGuard_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + + ULONG Status, ProblemCode; + if (CM_Get_DevNode_Status(&Status, &ProblemCode, DeviceNode->Data.DevInst, 0) != CR_SUCCESS || + ((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED)) + goto cleanupDeviceNode; + + LOG(WIREGUARD_LOG_INFO, L"Snapshotting configuration of adapter \"%s\"", Name); + if (!SnapshotConfigurationAndState( + DevInfo, + &DeviceNode->Data, + &DeviceNode->Configuration, + &DeviceNode->ConfigurationBytes, + &DeviceNode->AdapterState)) + LOG(WIREGUARD_LOG_WARN, L"Failed to snapshot configuration of adapter \"%s\"", Name); + + LOG(WIREGUARD_LOG_INFO, L"Disabling adapter \"%s\"", Name); + if (!AdapterDisableInstance(DevInfo, &DeviceNode->Data)) + { + LOG_LAST_ERROR(L"Failed to disable adapter \"%s\"", Name); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); + goto cleanupDeviceNode; + } + + DeviceNode->Next = *DisabledAdapters; + *DisabledAdapters = DeviceNode; + continue; + + cleanupDeviceNode: + Free(DeviceNode); + } + return RET_ERROR(TRUE, LastError); +} + +static _Return_type_success_(return != FALSE) +BOOL +EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable) +{ + DWORD LastError = ERROR_SUCCESS; + for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next) + { + DEVPROPTYPE PropType; + WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; + SetupDiGetDevicePropertyW( + DevInfo, + &DeviceNode->Data, + &DEVPKEY_WireGuard_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + + LOG(WIREGUARD_LOG_INFO, L"Enabling adapter \"%s\"", Name); + if (!AdapterEnableInstance(DevInfo, &DeviceNode->Data)) + { + LOG_LAST_ERROR(L"Failed to enable adapter \"%s\"", Name); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); + } + LOG(WIREGUARD_LOG_INFO, L"Restoring configuration of adapter \"%s\"", Name); + if (!RestoreConfigurationAndState( + DevInfo, + &DeviceNode->Data, + DeviceNode->Configuration, + DeviceNode->ConfigurationBytes, + DeviceNode->AdapterState)) + LOG(WIREGUARD_LOG_WARN, L"Failed to restore configuration of adapter \"%s\"", Name); + } + return RET_ERROR(TRUE, LastError); +} + +static BOOL +IsNewer( + _In_ const FILETIME *DriverDate1, + _In_ DWORDLONG DriverVersion1, + _In_ const FILETIME *DriverDate2, + _In_ DWORDLONG DriverVersion2) +{ + if (DriverDate1->dwHighDateTime > DriverDate2->dwHighDateTime) + return TRUE; + if (DriverDate1->dwHighDateTime < DriverDate2->dwHighDateTime) + return FALSE; + + if (DriverDate1->dwLowDateTime > DriverDate2->dwLowDateTime) + return TRUE; + if (DriverDate1->dwLowDateTime < DriverDate2->dwLowDateTime) + return FALSE; + + if (DriverVersion1 > DriverVersion2) + return TRUE; + if (DriverVersion1 < DriverVersion2) + return FALSE; + + return FALSE; +} + +static _Return_type_success_(return != 0) +DWORD +VersionOfFile(_In_z_ LPCWSTR Filename) +{ + DWORD Zero; + DWORD Len = GetFileVersionInfoSizeW(Filename, &Zero); + if (!Len) + { + LOG_LAST_ERROR(L"Failed to query %s version info size", Filename); + return 0; + } + VOID *VersionInfo = Alloc(Len); + if (!VersionInfo) + return 0; + DWORD LastError = ERROR_SUCCESS, Version = 0; + VS_FIXEDFILEINFO *FixedInfo; + UINT FixedInfoLen = sizeof(*FixedInfo); + if (!GetFileVersionInfoW(Filename, 0, Len, VersionInfo)) + { + LastError = LOG_LAST_ERROR(L"Failed to get %s version info", Filename); + goto out; + } + if (!VerQueryValueW(VersionInfo, L"\\", &FixedInfo, &FixedInfoLen)) + { + LastError = LOG_LAST_ERROR(L"Failed to get %s version info root", Filename); + goto out; + } + Version = FixedInfo->dwFileVersionMS; + if (!Version) + { + LOG(WIREGUARD_LOG_WARN, L"Determined version of %s, but was v0.0, so returning failure", Filename); + LastError = ERROR_VERSION_PARSE_ERROR; + } +out: + Free(VersionInfo); + return RET_ERROR(Version, LastError); +} + +static DWORD WINAPI +MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion) +{ + PRTL_PROCESS_MODULES Modules; + ULONG BufferSize = 128 * 1024; + for (;;) + { + Modules = Alloc(BufferSize); + if (!Modules) + return 0; + NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize); + if (NT_SUCCESS(Status)) + break; + Free(Modules); + if (Status == STATUS_INFO_LENGTH_MISMATCH) + continue; + LOG(WIREGUARD_LOG_ERR, L"Failed to enumerate drivers (status: 0x%x)", Status); + SetLastError(RtlNtStatusToDosError(Status)); + return 0; + } + DWORD LastError = ERROR_SUCCESS, Version = 0; + for (ULONG i = Modules->NumberOfModules; i-- > 0;) + { + LPCSTR NtPath = (LPCSTR)Modules->Modules[i].FullPathName; + if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wireguard.sys")) + { + if (ReturnOneIfRunningInsteadOfVersion) + { + Version = 1; + goto cleanupModules; + } + WCHAR FilePath[MAX_PATH * 3 + 15]; + if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1) + continue; + Version = VersionOfFile(FilePath); + if (!Version) + LastError = GetLastError(); + goto cleanupModules; + } + } + LastError = ERROR_FILE_NOT_FOUND; +cleanupModules: + Free(Modules); + return RET_ERROR(Version, LastError); +} + +_Use_decl_annotations_ +DWORD WINAPI WireGuardGetRunningDriverVersion(VOID) +{ + return MaybeGetRunningDriverVersion(FALSE); +} + +static BOOL EnsureWireGuardUnloaded(VOID) +{ + BOOL Loaded; + for (int i = 0; (Loaded = MaybeGetRunningDriverVersion(TRUE) != 0) != FALSE && i < 300; ++i) + Sleep(50); + return !Loaded; +} + +_Use_decl_annotations_ +VOID +DriverInstallDeferredCleanup(HDEVINFO DevInfoExistingAdapters, SP_DEVINFO_DATA_LIST *ExistingAdapters) +{ + if (ExistingAdapters) + { + EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters); + while (ExistingAdapters) + { + SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; + Free(ExistingAdapters->Configuration); + Free(ExistingAdapters); + ExistingAdapters = Next; + } + } + if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE) + SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters); +} + +_Use_decl_annotations_ +BOOL +DriverInstall(HDEVINFO *DevInfoExistingAdaptersForCleanup, SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup) +{ + static const FILETIME OurDriverDate = WIREGUARD_INF_FILETIME; + static const DWORDLONG OurDriverVersion = WIREGUARD_INF_VERSION; + HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); + if (!DriverInstallationLock) + { + LOG(WIREGUARD_LOG_ERR, L"Failed to take driver installation mutex"); + return FALSE; + } + DWORD LastError = ERROR_SUCCESS; + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to create empty device information set"); + goto cleanupDriverInstallationLock; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiCreateDeviceInfoW( + DevInfo, WIREGUARD_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to create new device information element"); + goto cleanupDevInfo; + } + static const WCHAR Hwids[_countof(WIREGUARD_HWID) + 1 /*Multi-string terminator*/] = WIREGUARD_HWID; + if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) + { + LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID"); + goto cleanupDevInfo; + } + if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER)) + { + LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list"); + goto cleanupDevInfo; + } + FILETIME DriverDate = { 0 }; + DWORDLONG DriverVersion = 0; + HDEVINFO DevInfoExistingAdapters = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL; + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; + if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + if (IsNewer(&OurDriverDate, OurDriverVersion, &DrvInfoData.DriverDate, DrvInfoData.DriverVersion)) + { + if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE) + { + DevInfoExistingAdapters = SetupDiGetClassDevsExW( + &GUID_DEVCLASS_NET, WIREGUARD_ENUMERATOR, NULL, DIGCF_PRESENT, NULL, NULL, NULL); + if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); + SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); + goto cleanupExistingAdapters; + } + _Analysis_assume_(DevInfoExistingAdapters != NULL); + DisableAllOurAdapters(DevInfoExistingAdapters, &ExistingAdapters); + LOG(WIREGUARD_LOG_INFO, L"Waiting for existing driver to unload from kernel"); + if (!EnsureWireGuardUnloaded()) + LOG(WIREGUARD_LOG_WARN, + L"Failed to unload existing driver, which means a reboot will likely be required"); + } + LOG(WIREGUARD_LOG_INFO, + L"Removing existing driver %u.%u", + (DWORD)((DrvInfoData.DriverVersion & 0xffff000000000000) >> 48), + (DWORD)((DrvInfoData.DriverVersion & 0x0000ffff00000000) >> 32)); + BYTE LargeBuffer[0x2000]; + DWORD Size = sizeof(LargeBuffer); + SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer; + DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); + if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size)) + { + LOG(WIREGUARD_LOG_WARN, L"Failed getting adapter driver info detail"); + continue; + } + LPWSTR InfFileName = PathFindFileNameW(DrvInfoDetailData->InfFileName); + if (!SetupUninstallOEMInfW(InfFileName, SUOI_FORCEDELETE, NULL)) + LOG_LAST_ERROR(L"Unable to remove existing driver %s", InfFileName); + continue; + } + if (!IsNewer(&DrvInfoData.DriverDate, DrvInfoData.DriverVersion, &DriverDate, DriverVersion)) + continue; + DriverDate = DrvInfoData.DriverDate; + DriverVersion = DrvInfoData.DriverVersion; + } + SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); + + if (DriverVersion) + { + LOG(WIREGUARD_LOG_INFO, + L"Using existing driver %u.%u", + (DWORD)((DriverVersion & 0xffff000000000000) >> 48), + (DWORD)((DriverVersion & 0x0000ffff00000000) >> 32)); + LastError = ERROR_SUCCESS; + goto cleanupExistingAdapters; + } + + LOG(WIREGUARD_LOG_INFO, + L"Installing driver %u.%u", + (DWORD)((OurDriverVersion & 0xffff000000000000) >> 48), + (DWORD)((OurDriverVersion & 0x0000ffff00000000) >> 32)); + WCHAR RandomTempSubDirectory[MAX_PATH]; + if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory)) + { + LastError = LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory); + goto cleanupExistingAdapters; + } + + WCHAR CatPath[MAX_PATH] = { 0 }; + WCHAR SysPath[MAX_PATH] = { 0 }; + WCHAR InfPath[MAX_PATH] = { 0 }; + WCHAR DownlevelShimPath[MAX_PATH] = { 0 }; + if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wireguard.cat") || + !PathCombineW(SysPath, RandomTempSubDirectory, L"wireguard.sys") || + !PathCombineW(InfPath, RandomTempSubDirectory, L"wireguard.inf")) + { + LastError = ERROR_BUFFER_OVERFLOW; + goto cleanupDirectory; + } + + WCHAR *CatSource, *SysSource, *InfSource; + if (NativeMachine == IMAGE_FILE_PROCESS) + { + CatSource = L"wireguard.cat"; + SysSource = L"wireguard.sys"; + InfSource = L"wireguard.inf"; + } + else if (NativeMachine == IMAGE_FILE_MACHINE_AMD64) + { + CatSource = L"wireguard-amd64.cat"; + SysSource = L"wireguard-amd64.sys"; + InfSource = L"wireguard-amd64.inf"; + } + else if (NativeMachine == IMAGE_FILE_MACHINE_ARM64) + { + CatSource = L"wireguard-arm64.cat"; + SysSource = L"wireguard-arm64.sys"; + InfSource = L"wireguard-arm64.inf"; + } + else + { + LastError = LOG_ERROR(ERROR_NOT_SUPPORTED, L"Unsupported platform 0x%x", NativeMachine); + goto cleanupDirectory; + } + + LOG(WIREGUARD_LOG_INFO, L"Extracting driver"); + if (!ResourceCopyToFile(CatPath, CatSource) || !ResourceCopyToFile(SysPath, SysSource) || + !ResourceCopyToFile(InfPath, InfSource)) + { + LastError = LOG_LAST_ERROR(L"Failed to extract driver"); + goto cleanupDelete; + } + + WCHAR *WintrustKeyOriginalValue = NULL; + HKEY WintrustKey = NULL; + if (!IsWindows10) + { + LOG(WIREGUARD_LOG_INFO, L"Shimming downlevel driver loader"); + if (!PathCombineW(DownlevelShimPath, RandomTempSubDirectory, L"downlevelshim.dll")) + { + DownlevelShimPath[0] = L'\0'; + LastError = ERROR_BUFFER_OVERFLOW; + goto cleanupDelete; + } + if (!ResourceCopyToFile(DownlevelShimPath, L"downlevelshim.dll")) + { + LastError = LOG_LAST_ERROR(L"Failed to extract downlevel shim"); + goto cleanupDelete; + } + LastError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Cryptography\\Providers\\Trust\\FinalPolicy\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}", + 0, + KEY_QUERY_VALUE | KEY_SET_VALUE, + &WintrustKey); + if (LastError != ERROR_SUCCESS) + { + LOG_ERROR(LastError, L"Failed to open Wintrust FinalPolicy key"); + goto cleanupDelete; + } + WintrustKeyOriginalValue = RegistryQueryString(WintrustKey, L"$DLL", TRUE); + if (!WintrustKeyOriginalValue) + { + LastError = LOG_LAST_ERROR(L"Failed to read current Wintrust FinalPolicy key"); + goto cleanupWintrustKey; + } + LastError = RegSetValueExW( + WintrustKey, + L"$DLL", + 0, + REG_SZ, + (BYTE *)DownlevelShimPath, + (DWORD)((wcslen(DownlevelShimPath) + 1) * sizeof(DownlevelShimPath[0]))); + if (LastError != ERROR_SUCCESS) + { + LOG_ERROR(LastError, L"Failed to set Wintrust FinalPolicy key"); + goto cleanupWintrustChangedKey; + } + } + + LOG(WIREGUARD_LOG_INFO, L"Installing driver"); + if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_NONE, 0, NULL, 0, NULL, NULL)) + LastError = LOG_LAST_ERROR(L"Could not install driver %s to store", InfPath); + +cleanupWintrustChangedKey: + if (WintrustKeyOriginalValue) + RegSetValueExW( + WintrustKey, + L"$DLL", + 0, + REG_SZ, + (BYTE *)WintrustKeyOriginalValue, + (DWORD)((wcslen(WintrustKeyOriginalValue) + 1) * sizeof(WintrustKeyOriginalValue[0]))); +cleanupWintrustKey: + if (WintrustKey) + RegCloseKey(WintrustKey); + if (WintrustKeyOriginalValue) + Free(WintrustKeyOriginalValue); +cleanupDelete: + DeleteFileW(CatPath); + DeleteFileW(SysPath); + DeleteFileW(InfPath); + if (DownlevelShimPath[0]) + DeleteFileW(DownlevelShimPath); +cleanupDirectory: + RemoveDirectoryW(RandomTempSubDirectory); +cleanupExistingAdapters: + if (LastError == ERROR_SUCCESS) + { + *DevInfoExistingAdaptersForCleanup = DevInfoExistingAdapters; + *ExistingAdaptersForCleanup = ExistingAdapters; + } + else + DriverInstallDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanupDriverInstallationLock: + NamespaceReleaseMutex(DriverInstallationLock); + return RET_ERROR(TRUE, LastError); +} + +_Use_decl_annotations_ +BOOL WINAPI WireGuardDeleteDriver(VOID) +{ + DWORD LastError = ERROR_SUCCESS; + + AdapterCleanupOrphanedDevices(); + + HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); + if (!DriverInstallationLock) + { + LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to take driver installation mutex"); + goto cleanup; + } + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to create empty device information set"); + goto cleanupDriverInstallationLock; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiCreateDeviceInfoW( + DevInfo, WIREGUARD_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to create new device information element"); + goto cleanupDevInfo; + } + static const WCHAR Hwids[_countof(WIREGUARD_HWID) + 1 /*Multi-string terminator*/] = WIREGUARD_HWID; + if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) + { + LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID"); + goto cleanupDevInfo; + } + if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER)) + { + LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list"); + goto cleanupDevInfo; + } + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; + if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + BYTE LargeBuffer[0x2000]; + DWORD Size = sizeof(LargeBuffer); + SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer; + DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); + if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size)) + { + LOG(WIREGUARD_LOG_WARN, L"Failed getting adapter driver info detail"); + continue; + } + LPCWSTR Path = PathFindFileNameW(DrvInfoDetailData->InfFileName); + LOG(WIREGUARD_LOG_INFO, L"Removing driver %s", Path); + if (!SetupUninstallOEMInfW(Path, 0, NULL)) + { + LOG_LAST_ERROR(L"Unable to remove driver %s", Path); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); + } + } + SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanupDriverInstallationLock: + NamespaceReleaseMutex(DriverInstallationLock); +cleanup: + return RET_ERROR(TRUE, LastError); +} diff --git a/api/driver.h b/api/driver.h new file mode 100644 index 0000000..ff1b781 --- /dev/null +++ b/api/driver.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +#pragma once + +#include "wireguard.h" +#include <Windows.h> +#include <SetupAPI.h> + +#define WIREGUARD_HWID L"WireGuard" + +typedef struct _SP_DEVINFO_DATA_LIST SP_DEVINFO_DATA_LIST; + +VOID +DriverInstallDeferredCleanup(_In_ HDEVINFO DevInfoExistingAdapters, _In_opt_ SP_DEVINFO_DATA_LIST *ExistingAdapters); + +_Must_inspect_result_ +_Return_type_success_(return != FALSE) +BOOL +DriverInstall( + _Out_ HDEVINFO *DevInfoExistingAdaptersForCleanup, + _Out_ SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup); + +/** + * @copydoc WIREGUARD_DELETE_DRIVER_FUNC + */ +WIREGUARD_DELETE_DRIVER_FUNC WireGuardDeleteDriver; + +/** + * @copydoc WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC + */ +WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC WireGuardGetRunningDriverVersion; diff --git a/api/exports.def b/api/exports.def index e9879bb..891228c 100644 --- a/api/exports.def +++ b/api/exports.def @@ -1,18 +1,14 @@ LIBRARY wireguard.dll EXPORTS WireGuardCreateAdapter - WireGuardDeleteAdapter - WireGuardDeletePoolDriver - WireGuardEnumAdapters - WireGuardFreeAdapter WireGuardOpenAdapter + WireGuardCloseAdapter WireGuardGetAdapterLUID - WireGuardGetAdapterName WireGuardGetAdapterState WireGuardGetConfiguration WireGuardGetRunningDriverVersion + WireGuardDeleteDriver WireGuardSetAdapterLogging - WireGuardSetAdapterName WireGuardSetAdapterState WireGuardSetConfiguration WireGuardSetLogger @@ -21,7 +21,13 @@ HANDLE ModuleHeap; SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) }; BOOL IsLocalSystem; USHORT NativeMachine = IMAGE_FILE_PROCESS; -BOOL IsWindows10, IsWindows7; + +#if NTDDI_VERSION == NTDDI_WIN7 +BOOL IsWindows7; +#endif +#if NTDDI_VERSION < NTDDI_WIN10 +BOOL IsWindows10; +#endif static FARPROC WINAPI DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) @@ -74,8 +80,13 @@ static void EnvInit(VOID) { DWORD MajorVersion, MinorVersion; RtlGetNtVersionNumbers(&MajorVersion, &MinorVersion, NULL); - IsWindows10 = MajorVersion >= 10; + +#if NTDDI_VERSION == NTDDI_WIN7 IsWindows7 = MajorVersion == 6 && MinorVersion == 1; +#endif +#if NTDDI_VERSION < NTDDI_WIN10 + IsWindows10 = MajorVersion >= 10; +#endif #ifdef MAYBE_WOW64 typedef BOOL(WINAPI * IsWow64Process2_t)( @@ -24,4 +24,15 @@ extern HANDLE ModuleHeap; extern SECURITY_ATTRIBUTES SecurityAttributes; extern BOOL IsLocalSystem; extern USHORT NativeMachine; -extern BOOL IsWindows10, IsWindows7;
\ No newline at end of file + +#if NTDDI_VERSION > NTDDI_WIN7 +# define IsWindows7 FALSE +#else +extern BOOL IsWindows7; +#endif + +#if NTDDI_VERSION >= NTDDI_WIN10 +# define IsWindows10 TRUE +#else +extern BOOL IsWindows10; +#endif
\ No newline at end of file diff --git a/api/namespace.c b/api/namespace.c index 8230a0a..9c05b41 100644 --- a/api/namespace.c +++ b/api/namespace.c @@ -9,7 +9,6 @@ #include <Windows.h> #include <winternl.h> -#include <bcrypt.h> #include <winefs.h> #include <wchar.h> #include <stdlib.h> @@ -17,32 +16,6 @@ static HANDLE PrivateNamespace = NULL; static HANDLE BoundaryDescriptor = NULL; static CRITICAL_SECTION Initializing; -static BCRYPT_ALG_HANDLE AlgProvider; - -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -LPWSTR -NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ LPCWSTR Source) -{ - int Len = NormalizeString(NormForm, Source, -1, NULL, 0); - for (;;) - { - LPWSTR Str = AllocArray(Len, sizeof(*Str)); - if (!Str) - return NULL; - Len = NormalizeString(NormForm, Source, -1, Str, Len); - if (Len > 0) - return Str; - Free(Str); - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - { - LOG_LAST_ERROR(L"Failed: %s", Source); - return NULL; - } - Len = -Len; - } -} static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(VOID) @@ -56,27 +29,19 @@ BOOL NamespaceRuntimeInit(VOID) return TRUE; } - NTSTATUS Status; - if (!BCRYPT_SUCCESS(Status = BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0))) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to open algorithm provider (status: 0x%x)", Status); - LastError = RtlNtStatusToDosError(Status); - goto cleanupLeaveCriticalSection; - } - BYTE Sid[MAX_SID_SIZE]; DWORD SidSize = sizeof(Sid); if (!CreateWellKnownSid(IsLocalSystem ? WinLocalSystemSid : WinBuiltinAdministratorsSid, NULL, Sid, &SidSize)) { LastError = LOG_LAST_ERROR(L"Failed to create SID"); - goto cleanupBCryptCloseAlgorithmProvider; + goto cleanupLeaveCriticalSection; } BoundaryDescriptor = CreateBoundaryDescriptorW(L"WireGuard", 0); if (!BoundaryDescriptor) { LastError = LOG_LAST_ERROR(L"Failed to create boundary descriptor"); - goto cleanupBCryptCloseAlgorithmProvider; + goto cleanupLeaveCriticalSection; } if (!AddSIDToBoundaryDescriptor(&BoundaryDescriptor, Sid)) { @@ -106,8 +71,6 @@ BOOL NamespaceRuntimeInit(VOID) cleanupBoundaryDescriptor: DeleteBoundaryDescriptor(BoundaryDescriptor); -cleanupBCryptCloseAlgorithmProvider: - BCryptCloseAlgorithmProvider(AlgProvider, 0); cleanupLeaveCriticalSection: LeaveCriticalSection(&Initializing); SetLastError(LastError); @@ -116,81 +79,6 @@ cleanupLeaveCriticalSection: _Use_decl_annotations_ HANDLE -NamespaceTakePoolMutex(LPCWSTR Pool) -{ - if (!NamespaceRuntimeInit()) - return NULL; - - BCRYPT_HASH_HANDLE Sha256 = NULL; - NTSTATUS Status; - if (!BCRYPT_SUCCESS(Status = BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0))) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to create hash (status: 0x%x)", Status); - SetLastError(RtlNtStatusToDosError(Status)); - return NULL; - } - DWORD LastError; - static const WCHAR mutex_label[] = L"WireGuard Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com"; - if (!BCRYPT_SUCCESS( - Status = BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0))) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status); - LastError = RtlNtStatusToDosError(Status); - goto cleanupSha256; - } - LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool); - if (!PoolNorm) - { - LastError = GetLastError(); - goto cleanupSha256; - } - if (!BCRYPT_SUCCESS( - Status = BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0))) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status); - LastError = RtlNtStatusToDosError(Status); - goto cleanupPoolNorm; - } - BYTE Hash[32]; - if (!BCRYPT_SUCCESS(Status = BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0))) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to calculate hash (status: 0x%x)", Status); - LastError = RtlNtStatusToDosError(Status); - goto cleanupPoolNorm; - } - static const WCHAR MutexNamePrefix[] = L"WireGuard\\WireGuard-Name-Mutex-"; - WCHAR MutexName[_countof(MutexNamePrefix) + sizeof(Hash) * 2]; - memcpy(MutexName, MutexNamePrefix, sizeof(MutexNamePrefix)); - for (size_t i = 0; i < sizeof(Hash); ++i) - swprintf_s(&MutexName[_countof(MutexNamePrefix) - 1 + i * 2], 3, L"%02x", Hash[i]); - HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName); - if (!Mutex) - { - LastError = LOG_LAST_ERROR(L"Failed to create mutex %s", MutexName); - goto cleanupPoolNorm; - } - DWORD Result = WaitForSingleObject(Mutex, INFINITE); - switch (Result) - { - case WAIT_OBJECT_0: - case WAIT_ABANDONED: - Free(PoolNorm); - BCryptDestroyHash(Sha256); - return Mutex; - } - LOG(WIREGUARD_LOG_ERR, L"Failed to get mutex %s (status: 0x%x)", MutexName, Result); - LastError = ERROR_GEN_FAILURE; - CloseHandle(Mutex); -cleanupPoolNorm: - Free(PoolNorm); -cleanupSha256: - BCryptDestroyHash(Sha256); - SetLastError(LastError); - return NULL; -} - -_Use_decl_annotations_ -HANDLE NamespaceTakeDriverInstallationMutex(VOID) { if (!NamespaceRuntimeInit()) @@ -216,11 +104,11 @@ NamespaceTakeDriverInstallationMutex(VOID) _Use_decl_annotations_ HANDLE -NamespaceTakeInstanceIdMutex(VOID) +NamespaceTakeDeviceInstallationMutex(VOID) { if (!NamespaceRuntimeInit()) return NULL; - HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"WireGuard\\WireGuard-InstanceId-Mutex"); + HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"WireGuard\\WireGuard-Device-Installation-Mutex"); if (!Mutex) { LOG_LAST_ERROR(L"Failed to create mutex"); @@ -257,7 +145,6 @@ VOID NamespaceDone(VOID) EnterCriticalSection(&Initializing); if (PrivateNamespace) { - BCryptCloseAlgorithmProvider(AlgProvider, 0); ClosePrivateNamespace(PrivateNamespace, 0); DeleteBoundaryDescriptor(BoundaryDescriptor); PrivateNamespace = NULL; diff --git a/api/namespace.h b/api/namespace.h index 2aa2b0e..a0397be 100644 --- a/api/namespace.h +++ b/api/namespace.h @@ -12,13 +12,6 @@ _Return_type_success_(return != NULL) _Post_maybenull_ _Acquires_lock_(_Curr_) HANDLE -NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool); - -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -_Acquires_lock_(_Curr_) -HANDLE NamespaceTakeDriverInstallationMutex(VOID); _Must_inspect_result_ @@ -26,7 +19,7 @@ _Return_type_success_(return != NULL) _Post_maybenull_ _Acquires_lock_(_Curr_) HANDLE -NamespaceTakeInstanceIdMutex(VOID); +NamespaceTakeDeviceInstallationMutex(VOID); _Releases_lock_(Mutex) VOID diff --git a/api/registry.c b/api/registry.c index 245d72f..58aa7a0 100644 --- a/api/registry.c +++ b/api/registry.c @@ -56,48 +56,6 @@ RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType) } } -_Use_decl_annotations_ -BOOL -RegistryGetMultiString(PZZWSTR *Buf, DWORD Len, DWORD ValueType) -{ - if (ValueType == REG_MULTI_SZ) - { - for (size_t i = 0;; i += wcsnlen(*Buf + i, Len - i) + 1) - { - if (i > Len) - { - /* Missing string and list terminators. */ - PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 2, sizeof(*BufZ)); - if (!BufZ) - return FALSE; - *Buf = BufZ; - return TRUE; - } - if (i == Len) - { - /* Missing list terminator. */ - PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ)); - if (!BufZ) - return FALSE; - *Buf = BufZ; - return TRUE; - } - if (!(*Buf)[i]) - return TRUE; - } - } - - /* Sanitize REG_SZ/REG_EXPAND_SZ and append a list terminator to make a multi-string. */ - if (!RegistryGetString(Buf, Len, ValueType)) - return FALSE; - Len = (DWORD)wcslen(*Buf) + 1; - PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(WCHAR)); - if (!BufZ) - return FALSE; - *Buf = BufZ; - return TRUE; -} - _Must_inspect_result_ static _Return_type_success_(return != NULL) _Post_maybenull_ diff --git a/api/registry.h b/api/registry.h index 9f9429d..4ded9a6 100644 --- a/api/registry.h +++ b/api/registry.h @@ -33,25 +33,6 @@ BOOL RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType); /** - * Validates and/or sanitizes multi-string value read from registry. - * - * @param Buf On input, it contains a pointer to pointer where the data is stored. The data must be allocated - * using HeapAlloc(ModuleHeap, 0). On output, it contains a pointer to pointer where the sanitized - * data is stored. It must be released with HeapFree(ModuleHeap, 0, *Buf) after use. - * - * @param Len Length of data string in wide characters. - * - * @param ValueType Type of data. Must be one of REG_MULTI_SZ, REG_SZ or REG_EXPAND_SZ. - * - * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To - * get extended error information, call GetLastError. - */ -_Must_inspect_result_ -_Return_type_success_(return != FALSE) -BOOL -RegistryGetMultiString(_Inout_ PZZWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType); - -/** * Reads string value from registry key. * * @param Key Handle of the registry key to read from. Must be opened with read access. diff --git a/api/resources.rc b/api/resources.rc index 0c283c5..2a5c4dc 100644 --- a/api/resources.rc +++ b/api/resources.rc @@ -16,16 +16,22 @@ downlevelshim.dll RCDATA "downlevelshim.dll" #if defined(WANT_AMD64_WOW64) # if defined(BUILT_AMD64_WOW64) -wireguard-amd64.dll RCDATA "amd64\\wireguard.dll" +wireguard-amd64.cat RCDATA "amd64\\driver\\wireguard.cat" +wireguard-amd64.inf RCDATA "amd64\\driver\\wireguard.inf" +wireguard-amd64.sys RCDATA "amd64\\driver\\wireguard.sys" +setupapihost-amd64.dll RCDATA "amd64\\setupapihost.dll" # else -# pragma message("AMD64 wireguard.dll was not built, so this will not work from WOW64") +# pragma message("AMD64 wireguard.sys was not built, so this will not work from WOW64") # endif #endif #if defined(WANT_ARM64_WOW64) # if defined(BUILT_ARM64_WOW64) -wireguard-arm64.dll RCDATA "arm64\\wireguard.dll" +wireguard-arm64.cat RCDATA "arm64\\driver\\wireguard.cat" +wireguard-arm64.inf RCDATA "arm64\\driver\\wireguard.inf" +wireguard-arm64.sys RCDATA "arm64\\driver\\wireguard.sys" +setupapihost-arm64.dll RCDATA "arm64\\setupapihost.dll" # else -# pragma message("ARM64 wireguard.dll was not built, so this will not work from WOW64") +# pragma message("ARM64 wireguard.sys was not built, so this will not work from WOW64") # endif #endif diff --git a/api/rundll32.c b/api/rundll32.c index b4fe912..cdc5412 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -15,131 +15,6 @@ #include <objbase.h> #include <assert.h> -#ifdef ACCEPT_WOW64 - -# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) - -static DWORD -WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...) -{ - LPWSTR FormattedMessage = NULL; - DWORD Size; - va_list Arguments; - va_start(Arguments, Template); - DWORD Len = FormatMessageW( - FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - Template, - 0, - 0, - (VOID *)&FormattedMessage, - 0, - &Arguments); - if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size))) - WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL); - else - Size = 0; - LocalFree(FormattedMessage); - va_end(Arguments); - return Size / sizeof(*FormattedMessage); -} - -static VOID CALLBACK -ConsoleLogger(_In_ WIREGUARD_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ LPCWSTR LogLine) -{ - LPCWSTR Template; - switch (Level) - { - case WIREGUARD_LOG_INFO: - Template = L"[+ %1!I64u!] %2\n"; - break; - case WIREGUARD_LOG_WARN: - Template = L"[- %1!I64u!] %2\n"; - break; - case WIREGUARD_LOG_ERR: - Template = L"[! %1!I64u!] %2\n"; - break; - default: - return; - } - WriteFormatted(STD_ERROR_HANDLE, Template, Timestamp, LogLine); -} - -VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WireGuardSetLogger(ConsoleLogger); - - if (Argc < 4) - goto cleanup; - if (wcslen(Argv[2]) >= WIREGUARD_MAX_POOL) - goto cleanup; - if (wcslen(Argv[3]) >= MAX_ADAPTER_NAME) - goto cleanup; - GUID RequestedGUID; - if (Argc > 4 && FAILED(CLSIDFromString(Argv[4], &RequestedGUID))) - goto cleanup; - - WIREGUARD_ADAPTER *Adapter = - WireGuardCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL); - DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError(); - WriteFormatted( - STD_OUTPUT_HANDLE, L"%1!X! %2!s!", LastError, Adapter ? Adapter->DevInstanceID : L"\"\""); - if (Adapter) - WireGuardFreeAdapter(Adapter); - -cleanup: - LocalFree(Argv); -} - -VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WireGuardSetLogger(ConsoleLogger); - - if (Argc < 3) - goto cleanup; - - DWORD LastError; - WIREGUARD_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]); - if (!Adapter) - { - LastError = GetLastError(); - goto write; - } - LastError = WireGuardDeleteAdapter(Adapter) ? ERROR_SUCCESS : GetLastError(); - WireGuardFreeAdapter(Adapter); -write: - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); - -cleanup: - LocalFree(Argv); -} - -VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WireGuardSetLogger(ConsoleLogger); - - if (Argc < 2) - goto cleanup; - - DWORD LastError = WireGuardDeletePoolDriver(Argv[2]) ? ERROR_SUCCESS : GetLastError(); - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); - -cleanup: - LocalFree(Argv); -} -#endif - #ifdef MAYBE_WOW64 _Return_type_success_(return != FALSE) @@ -311,7 +186,7 @@ ExecuteRunDll32( return FALSE; } WCHAR DllPath[MAX_PATH] = { 0 }; - if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wireguard.dll")) + if (!PathCombineW(DllPath, RandomTempSubDirectory, L"setupapihost.dll")) { LastError = ERROR_BUFFER_OVERFLOW; goto cleanupDirectory; @@ -320,10 +195,10 @@ ExecuteRunDll32( switch (NativeMachine) { case IMAGE_FILE_MACHINE_AMD64: - WireGuardDllResourceName = L"wireguard-amd64.dll"; + WireGuardDllResourceName = L"setupapihost-amd64.dll"; break; case IMAGE_FILE_MACHINE_ARM64: - WireGuardDllResourceName = L"wireguard-arm64.dll"; + WireGuardDllResourceName = L"setupapihost-arm64.dll"; break; default: LOG(WIREGUARD_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine); @@ -412,9 +287,9 @@ cleanupThreads: WaitForSingleObject(ThreadStdout, INFINITE); DWORD ThreadResult; if (!GetExitCodeThread(ThreadStdout, &ThreadResult)) - LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); + LastError = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); else if (ThreadResult != ERROR_SUCCESS) - LOG_ERROR(LastError, L"Failed to read process output"); + LastError = LOG_ERROR(ThreadResult, L"Failed to read process output"); CloseHandle(ThreadStdout); } cleanupPipes: @@ -430,126 +305,94 @@ cleanupDirectory: return RET_ERROR(TRUE, LastError); } -_Use_decl_annotations_ -WIREGUARD_ADAPTER * -CreateAdapterViaRundll32(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) +static _Return_type_success_(return != FALSE) +BOOL +InvokeClassInstaller(_In_ LPCWSTR Action, _In_ LPCWSTR Function, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - LOG(WIREGUARD_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = NULL; - if (RequestedGUID) + LOG(WIREGUARD_LOG_INFO, L"Spawning native process to %s instance", Action); + + WCHAR InstanceId[MAX_INSTANCE_ID]; + DWORD RequiredChars = _countof(InstanceId); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredChars, &RequiredChars)) { - WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; - if (StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr))) - Arguments = ArgvToCommandLineW(3, Pool, Name, RequestedGUIDStr); + LOG_LAST_ERROR(L"Failed to get adapter instance ID"); + return FALSE; } - else - Arguments = ArgvToCommandLineW(2, Pool, Name); + LPWSTR Arguments = ArgvToCommandLineW(1, InstanceId); if (!Arguments) { - LOG(WIREGUARD_LOG_ERR, L"Command line too long"); - SetLastError(ERROR_INVALID_PARAMETER); - return NULL; + SetLastError(LOG_ERROR(ERROR_INVALID_PARAMETER, L"Command line too long")); + return FALSE; } - WIREGUARD_ADAPTER *Adapter = NULL; DWORD LastError; - WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1]; - if (!ExecuteRunDll32(L"CreateAdapter", Arguments, Response, _countof(Response))) + WCHAR Response[8 + 1]; + if (!ExecuteRunDll32(Function, Arguments, Response, _countof(Response))) { - LastError = GetLastError(); - LOG(WIREGUARD_LOG_ERR, L"Error executing worker process: %s", Arguments); + LastError = LOG_LAST_ERROR(L"Error executing worker process: %s", Arguments); goto cleanupArguments; } int Argc; LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 2) + if (Argc < 1) { - LOG(WIREGUARD_LOG_ERR, L"Incomplete response: %s", Response); - LastError = ERROR_INVALID_PARAMETER; + LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response); goto cleanupArgv; } LastError = wcstoul(Argv[0], NULL, 16); - if (LastError == ERROR_SUCCESS && (Adapter = AdapterOpenFromDevInstanceId(Pool, Argv[1])) == NULL) - { - LOG(WIREGUARD_LOG_ERR, L"Failed to get adapter %s", Argv[1]); - LastError = ERROR_FILE_NOT_FOUND; - } cleanupArgv: LocalFree(Argv); cleanupArguments: Free(Arguments); - SetLastError(LastError); - return Adapter; + return RET_ERROR(TRUE, LastError); } _Use_decl_annotations_ BOOL -DeleteAdapterViaRundll32(const WIREGUARD_ADAPTER *Adapter) +RemoveInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - LOG(WIREGUARD_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = ArgvToCommandLineW(2, Adapter->Pool, Adapter->DevInstanceID); - if (!Arguments) - { - LOG(WIREGUARD_LOG_ERR, L"Command line too long"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - WCHAR Response[8 + 1 + 8 + 1]; - DWORD LastError; - if (!ExecuteRunDll32(L"DeleteAdapter", Arguments, Response, _countof(Response))) - { - LastError = GetLastError(); - LOG(WIREGUARD_LOG_ERR, L"Error executing worker process: %s", Arguments); - goto cleanupArguments; - } - int Argc; - LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 1) - { - LOG(WIREGUARD_LOG_ERR, L"Incomplete response: %s", Response); - LastError = ERROR_INVALID_PARAMETER; - goto cleanupArgv; - } - LastError = wcstoul(Argv[0], NULL, 16); -cleanupArgv: - LocalFree(Argv); -cleanupArguments: - Free(Arguments); - return RET_ERROR(TRUE, LastError); + return InvokeClassInstaller(L"remove", L"RemoveInstance", DevInfo, DevInfoData); } _Use_decl_annotations_ BOOL -DeletePoolDriverViaRundll32(LPCWSTR Pool) +EnableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - LOG(WIREGUARD_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = ArgvToCommandLineW(1, Pool); - if (!Arguments) - { - LOG(WIREGUARD_LOG_ERR, L"Command line too long"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - WCHAR Response[8 + 1 + 8 + 1]; + return InvokeClassInstaller(L"enable", L"EnableInstance", DevInfo, DevInfoData); +} + +_Use_decl_annotations_ +BOOL +DisableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) +{ + return InvokeClassInstaller(L"disable", L"DisableInstance", DevInfo, DevInfoData); +} + +_Use_decl_annotations_ +BOOL +CreateInstanceWin7ViaRundll32(LPWSTR InstanceId) +{ + LOG(WIREGUARD_LOG_INFO, L"Spawning native process to create instance"); + DWORD LastError; - if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response))) + WCHAR Response[MAX_INSTANCE_ID + 1]; + if (!ExecuteRunDll32(L"CreateInstanceWin7", L"", Response, _countof(Response))) { - LastError = GetLastError(); - LOG(WIREGUARD_LOG_ERR, L"Error executing worker process: %s", Arguments); - goto cleanupArguments; + LastError = LOG_LAST_ERROR(L"Error executing worker process"); + goto cleanup; } int Argc; LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 1) + if (Argc < 2) { - LOG(WIREGUARD_LOG_ERR, L"Incomplete response: %s", Response); - LastError = ERROR_INVALID_PARAMETER; + LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response); goto cleanupArgv; } LastError = wcstoul(Argv[0], NULL, 16); + if (LastError == ERROR_SUCCESS) + wcsncpy_s(InstanceId, MAX_INSTANCE_ID, Argv[1], _TRUNCATE); cleanupArgv: LocalFree(Argv); -cleanupArguments: - Free(Arguments); +cleanup: return RET_ERROR(TRUE, LastError); } #endif diff --git a/api/rundll32.h b/api/rundll32.h index 2b0e0a4..030419c 100644 --- a/api/rundll32.h +++ b/api/rundll32.h @@ -5,21 +5,22 @@ #pragma once +#include <Windows.h> +#include <SetupAPI.h> #include "adapter.h" -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -WIREGUARD_ADAPTER * -CreateAdapterViaRundll32( - _In_z_ LPCWSTR Pool, - _In_z_ LPCWSTR Name, - _In_opt_ const GUID *RequestedGUID); +_Return_type_success_(return != FALSE) +BOOL +RemoveInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); + +_Return_type_success_(return != FALSE) +BOOL +EnableInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); _Return_type_success_(return != FALSE) BOOL -DeleteAdapterViaRundll32(_In_ const WIREGUARD_ADAPTER *Adapter); +DisableInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); _Return_type_success_(return != FALSE) BOOL -DeletePoolDriverViaRundll32(_In_z_ LPCWSTR Pool); +CreateInstanceWin7ViaRundll32(_Out_writes_z_(MAX_INSTANCE_ID) LPWSTR InstanceId);
\ No newline at end of file diff --git a/api/wireguard.h b/api/wireguard.h index 27477e9..d60cbd2 100644 --- a/api/wireguard.h +++ b/api/wireguard.h @@ -39,147 +39,70 @@ extern "C" { typedef struct _WIREGUARD_ADAPTER *WIREGUARD_ADAPTER_HANDLE; /** - * Maximum pool name length including zero terminator - */ -#define WIREGUARD_MAX_POOL 256 - -/** * Creates a new WireGuard adapter. * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WIREGUARD_MAX_POOL-1 characters. - * * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1 * characters. * + * @param TunelType Name of the adapter tunnel type. Zero-terminated string of up to MAX_ADAPTER_NAME-1 + * characters. + * * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically. * If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is * created for each new adapter. It is called "requested" GUID because the API it uses is * completely undocumented, and so there could be minor interesting complications with its usage. * - * @return If the function succeeds, the return value is the adapter handle. Must be released with WireGuardFreeAdapter. - * If the function fails, the return value is NULL. To get extended error information, call GetLastError. + * @return If the function succeeds, the return value is the adapter handle. Must be released with + * WireGuardCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call + * GetLastError. */ typedef _Must_inspect_result_ _Return_type_success_(return != NULL) _Post_maybenull_ WIREGUARD_ADAPTER_HANDLE(WINAPI WIREGUARD_CREATE_ADAPTER_FUNC) -(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name, _In_opt_ const GUID *RequestedGUID); +(_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID); /** * Opens an existing WireGuard adapter. * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WIREGUARD_MAX_POOL-1 characters. - * - * @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters. + * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1 + * characters. * - * @return If the function succeeds, the return value is adapter handle. Must be released with WireGuardFreeAdapter. If - * the function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors - * include the following: ERROR_FILE_NOT_FOUND if adapter with given name is not found; ERROR_ALREADY_EXISTS if adapter - * is found but not a WireGuard-class or not a member of the pool + * @return If the function succeeds, the return value is the adapter handle. Must be released with + * WireGuardCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call + * GetLastError. */ typedef _Must_inspect_result_ _Return_type_success_(return != NULL) _Post_maybenull_ -WIREGUARD_ADAPTER_HANDLE(WINAPI WIREGUARD_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name); - -/** - * Deletes a WireGuard adapter. - * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter. - * - * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To - * get extended error information, call GetLastError. - */ -typedef _Return_type_success_(return != FALSE) -BOOL(WINAPI WIREGUARD_DELETE_ADAPTER_FUNC) -(_In_ WIREGUARD_ADAPTER_HANDLE Adapter); - -/** - * Called by WireGuardEnumAdapters for each adapter in the pool. - * - * @param Adapter Adapter handle, which will be freed when this function returns. - * - * @param Param An application-defined value passed to the WireGuardEnumAdapters. - * - * @return Non-zero to continue iterating adapters; zero to stop. - */ -typedef BOOL(CALLBACK *WIREGUARD_ENUM_CALLBACK)(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_ LPARAM Param); - -/** - * Enumerates all WireGuard adapters. - * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WIREGUARD_MAX_POOL-1 characters. - * - * @param Callback Callback function. To continue enumeration, the callback function must return TRUE; to stop - * enumeration, it must return FALSE. - * - * @param Param An application-defined value to be passed to the callback function. - * - * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To - * get extended error information, call GetLastError. - */ -typedef _Return_type_success_(return != FALSE) -BOOL(WINAPI WIREGUARD_ENUM_ADAPTERS_FUNC) -(_In_z_ LPCWSTR Pool, _In_ WIREGUARD_ENUM_CALLBACK Callback, _In_ LPARAM Param); +WIREGUARD_ADAPTER_HANDLE(WINAPI WIREGUARD_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name); /** - * Releases WireGuard adapter resources. + * Releases WireGuard adapter resources and, if adapter was created with WireGuardCreateAdapter, removes adapter. * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter. + * @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter. */ -typedef VOID(WINAPI WIREGUARD_FREE_ADAPTER_FUNC)(_In_opt_ WIREGUARD_ADAPTER_HANDLE Adapter); +typedef VOID(WINAPI WIREGUARD_CLOSE_ADAPTER_FUNC)(_In_opt_ WIREGUARD_ADAPTER_HANDLE Adapter); /** - * Deletes all WireGuard adapters in a pool and if there are no more adapters in any other pools, also removes WireGuard - * from the driver store, usually called by uninstallers. - * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WIREGUARD_MAX_POOL-1 characters. + * Deletes the WireGuard driver if there are no more adapters in use. * * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * get extended error information, call GetLastError. */ typedef _Return_type_success_(return != FALSE) -BOOL(WINAPI WIREGUARD_DELETE_POOL_DRIVER_FUNC)(_In_z_ LPCWSTR Pool); +BOOL(WINAPI WIREGUARD_DELETE_DRIVER_FUNC)(VOID); /** * Returns the LUID of the adapter. * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter + * @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter * * @param Luid Pointer to LUID to receive adapter LUID. */ typedef VOID(WINAPI WIREGUARD_GET_ADAPTER_LUID_FUNC)(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid); /** - * Returns the name of the WireGuard adapter. - * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter - * - * @param Name Pointer to a string to receive adapter name - * - * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To - * get extended error information, call GetLastError. - */ -typedef _Must_inspect_result_ -_Return_type_success_(return != FALSE) -BOOL(WINAPI WIREGUARD_GET_ADAPTER_NAME_FUNC) -(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _Out_writes_z_(MAX_ADAPTER_NAME) LPWSTR Name); - -/** - * Sets name of the WireGuard adapter. - * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter - * - * @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters. - * - * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To - * get extended error information, call GetLastError. - */ -typedef _Return_type_success_(return != FALSE) -BOOL(WINAPI WIREGUARD_SET_ADAPTER_NAME_FUNC) -(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_reads_or_z_(MAX_ADAPTER_NAME) LPCWSTR Name); - -/** * Determines the version of the WireGuard driver currently loaded. * * @return If the function succeeds, the return value is the version number. If the function fails, the return value is @@ -235,7 +158,7 @@ typedef enum /** * Sets whether and how the adapter logs to the logger previously set up with WireGuardSetLoggerFunc. * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter + * @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter * * @param LogState Adapter logging state. * @@ -258,7 +181,7 @@ typedef enum /** * Sets the adapter state of the WireGuard adapter. Note: sockets are owned by the process that sets the state to up. * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter + * @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter * * @param State Adapter state. * @@ -272,7 +195,7 @@ BOOL(WINAPI WIREGUARD_SET_ADAPTER_STATE_FUNC) /** * Gets the adapter state of the WireGuard adapter. * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter + * @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter * * @param State Pointer to adapter state. * @@ -345,7 +268,7 @@ struct ALIGNED(8) _WIREGUARD_INTERFACE /** * Sets the configuration of the WireGuard adapter. * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter + * @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter * * @param Config Configuration for the adapter. * @@ -361,7 +284,7 @@ BOOL(WINAPI WIREGUARD_SET_CONFIGURATION_FUNC) /** * Gets the configuration of the WireGuard adapter. * - * @param Adapter Adapter handle obtained with WireGuardOpenAdapter or WireGuardCreateAdapter + * @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter * * @param Config Configuration for the adapter. * diff --git a/example/example.c b/example/example.c index 23ef91f..b0cb642 100644 --- a/example/example.c +++ b/example/example.c @@ -18,15 +18,11 @@ #include "wireguard.h"
static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter;
-static WIREGUARD_DELETE_ADAPTER_FUNC *WireGuardDeleteAdapter;
-static WIREGUARD_DELETE_POOL_DRIVER_FUNC *WireGuardDeletePoolDriver;
-static WIREGUARD_ENUM_ADAPTERS_FUNC *WireGuardEnumAdapters;
-static WIREGUARD_FREE_ADAPTER_FUNC *WireGuardFreeAdapter;
static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter;
+static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter;
static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID;
-static WIREGUARD_GET_ADAPTER_NAME_FUNC *WireGuardGetAdapterName;
-static WIREGUARD_SET_ADAPTER_NAME_FUNC *WireGuardSetAdapterName;
static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion;
+static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver;
static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger;
static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging;
static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState;
@@ -43,15 +39,11 @@ InitializeWireGuardNT(void) return NULL;
#define X(Name, Type) ((Name = (Type *)GetProcAddress(WireGuardDll, #Name)) == NULL)
if (X(WireGuardCreateAdapter, WIREGUARD_CREATE_ADAPTER_FUNC) ||
- X(WireGuardDeleteAdapter, WIREGUARD_DELETE_ADAPTER_FUNC) ||
- X(WireGuardDeletePoolDriver, WIREGUARD_DELETE_POOL_DRIVER_FUNC) ||
- X(WireGuardEnumAdapters, WIREGUARD_ENUM_ADAPTERS_FUNC) ||
- X(WireGuardFreeAdapter, WIREGUARD_FREE_ADAPTER_FUNC) || X(WireGuardOpenAdapter, WIREGUARD_OPEN_ADAPTER_FUNC) ||
+ X(WireGuardOpenAdapter, WIREGUARD_OPEN_ADAPTER_FUNC) ||
+ X(WireGuardCloseAdapter, WIREGUARD_CLOSE_ADAPTER_FUNC) ||
X(WireGuardGetAdapterLUID, WIREGUARD_GET_ADAPTER_LUID_FUNC) ||
- X(WireGuardGetAdapterName, WIREGUARD_GET_ADAPTER_NAME_FUNC) ||
- X(WireGuardSetAdapterName, WIREGUARD_SET_ADAPTER_NAME_FUNC) ||
X(WireGuardGetRunningDriverVersion, WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC) ||
- X(WireGuardSetLogger, WIREGUARD_SET_LOGGER_FUNC) ||
+ X(WireGuardDeleteDriver, WIREGUARD_DELETE_DRIVER_FUNC) || X(WireGuardSetLogger, WIREGUARD_SET_LOGGER_FUNC) ||
X(WireGuardSetAdapterLogging, WIREGUARD_SET_ADAPTER_LOGGING_FUNC) ||
X(WireGuardGetAdapterState, WIREGUARD_GET_ADAPTER_STATE_FUNC) ||
X(WireGuardSetAdapterState, WIREGUARD_SET_ADAPTER_STATE_FUNC) ||
@@ -228,15 +220,6 @@ CtrlHandler(_In_ DWORD CtrlType) return FALSE;
}
-static BOOL CALLBACK
-PrintAdapter(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_ LPARAM Param)
-{
- WCHAR szAdapterName[MAX_ADAPTER_NAME];
- if (WireGuardGetAdapterName(Adapter, szAdapterName))
- Log(WIREGUARD_LOG_INFO, L"Existing WireGuard adapter: %s", szAdapterName);
- return TRUE;
-}
-
_Return_type_success_(return != FALSE)
static BOOL
TalkToDemoServer(
@@ -295,7 +278,6 @@ int __cdecl main(void) }
WireGuardSetLogger(ConsoleLogger);
Log(WIREGUARD_LOG_INFO, L"WireGuardNT library loaded");
- WireGuardEnumAdapters(L"Example", PrintAdapter, 0);
struct
{
@@ -370,15 +352,7 @@ int __cdecl main(void) }
GUID ExampleGuid = { 0xdeadc001, 0xbeef, 0xbabe, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
- WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(L"Example", L"Demo");
- if (Adapter && !WireGuardDeleteAdapter(Adapter))
- {
- LastError = GetLastError();
- LogError(L"Failed to delete already existing adapter", LastError);
- goto cleanupQuit;
- }
- WireGuardFreeAdapter(Adapter);
- Adapter = WireGuardCreateAdapter(L"Example", L"Demo", &ExampleGuid);
+ WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"Demo", L"Example", &ExampleGuid);
if (!Adapter)
{
LastError = GetLastError();
@@ -466,8 +440,7 @@ int __cdecl main(void) } while (WaitForSingleObject(QuitEvent, 1000) == WAIT_TIMEOUT);
cleanupAdapter:
- WireGuardDeleteAdapter(Adapter);
- WireGuardFreeAdapter(Adapter);
+ WireGuardCloseAdapter(Adapter);
cleanupQuit:
SetConsoleCtrlHandler(CtrlHandler, FALSE);
CloseHandle(QuitEvent);
diff --git a/setupapihost/host.c b/setupapihost/host.c new file mode 100644 index 0000000..6f643fd --- /dev/null +++ b/setupapihost/host.c @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +#include <windows.h> +#include <delayimp.h> +#include <setupapi.h> +#include <shellapi.h> +#include <intsafe.h> +#include <stdlib.h> + +#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) + +static FARPROC WINAPI +DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) +{ + if (dliNotify != dliNotePreLoadLibrary) + return NULL; + HMODULE Library = LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!Library) + abort(); + return (FARPROC)Library; +} + +const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook; + +static DWORD +WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...) +{ + LPWSTR FormattedMessage = NULL; + DWORD Size; + va_list Arguments; + va_start(Arguments, Template); + DWORD Len = FormatMessageW( + FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + Template, + 0, + 0, + (VOID *)&FormattedMessage, + 0, + &Arguments); + if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size))) + WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL); + else + Size = 0; + LocalFree(FormattedMessage); + va_end(Arguments); + return Size / sizeof(*FormattedMessage); +} + +VOID __stdcall RemoveInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + + if (Argc < 3) + goto cleanup; + WCHAR *InstanceId = Argv[2]; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_REMOVE }, + .Scope = DI_REMOVEDEVICE_GLOBAL }; + if (!SetupDiSetClassInstallParamsW( + DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) || + !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + LocalFree(Argv); + + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); +} + +VOID __stdcall EnableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + + if (Argc < 3) + goto cleanup; + WCHAR *InstanceId = Argv[2]; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_PROPERTYCHANGE }, + .StateChange = DICS_ENABLE, + .Scope = DICS_FLAG_GLOBAL }; + if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || + !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + LocalFree(Argv); + + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); +} + +VOID __stdcall DisableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + + if (Argc < 3) + goto cleanup; + WCHAR *InstanceId = Argv[2]; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_PROPERTYCHANGE }, + .StateChange = DICS_DISABLE, + .Scope = DICS_FLAG_GLOBAL }; + if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || + !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + LocalFree(Argv); + + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); +} + +#if NTDDI_VERSION == NTDDI_WIN7 +#include "host_win7.h" +#endif diff --git a/setupapihost/host_win7.h b/setupapihost/host_win7.h new file mode 100644 index 0000000..4350533 --- /dev/null +++ b/setupapihost/host_win7.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +#include <devguid.h> + +#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ +#define WIREGUARD_HWID L"WireGuard" + +VOID __stdcall CreateInstanceWin7(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + WCHAR InstanceId[MAX_INSTANCE_ID] = { 0 }; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiCreateDeviceInfoW( + DevInfo, WIREGUARD_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; + if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + DevInstallParams.Flags |= DI_QUIETINSTALL; + if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + static const WCHAR Hwids[_countof(WIREGUARD_HWID) + 1 /*Multi-string terminator*/] = WIREGUARD_HWID; + if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; + if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) || + !SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData)) + { + LastError = GetLastError(); + goto cleanupDriverInfo; + } + + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData); + SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData); + if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevice; + } + DWORD RequiredChars = _countof(InstanceId); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, InstanceId, RequiredChars, &RequiredChars)) + { + LastError = GetLastError(); + goto cleanupDevice; + } + +cleanupDevice: + if (LastError != ERROR_SUCCESS) + { + SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_REMOVE }, + .Scope = DI_REMOVEDEVICE_GLOBAL }; + if (SetupDiSetClassInstallParamsW( + DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams))) + SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData); + } +cleanupDriverInfo: + SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!s!", LastError, LastError == ERROR_SUCCESS ? InstanceId : L"\"\""); +} diff --git a/setupapihost/setupapihost.vcxproj b/setupapihost/setupapihost.vcxproj new file mode 100644 index 0000000..80b1e60 --- /dev/null +++ b/setupapihost/setupapihost.vcxproj @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="Globals"> + <ProjectGuid>{91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}</ProjectGuid> + <RootNamespace>setupapihost</RootNamespace> + <ProjectName>setupapihost</ProjectName> + </PropertyGroup> + <PropertyGroup Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + </PropertyGroup> + <Import Project="..\wireguard-nt.props" /> + <PropertyGroup> + <TargetName>setupapihost</TargetName> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions> + <DisableSpecificWarnings>4100;4201;$(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <DelayLoadDLLs>setupapi.dll;shell32.dll</DelayLoadDLLs> + <AdditionalDependencies>Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <SubSystem>Windows</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="host.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="host_win7.h" /> + </ItemGroup> + <Import Project="..\wireguard-nt.props.user" Condition="exists('..\wireguard-nt.props.user')" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets" /> +</Project>
\ No newline at end of file diff --git a/wireguard-nt.proj b/wireguard-nt.proj index e8d4e4f..222c660 100644 --- a/wireguard-nt.proj +++ b/wireguard-nt.proj @@ -69,21 +69,21 @@ <Target Name="Dll-x86" Outputs="$(Configuration)\x86\wireguard.dll" DependsOnTargets="Dll-amd64;Dll-arm64"> - <MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Win32" /> + <MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Win32" /> </Target> <Target Name="Dll-amd64" Outputs="$(Configuration)\amd64\wireguard.dll" DependsOnTargets="Dll-arm64"> - <MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=x64" /> + <MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=x64" /> </Target> <Target Name="Dll-arm" Outputs="$(Configuration)\arm\wireguard.dll" DependsOnTargets="Dll-arm64"> - <MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM" /> + <MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM" /> </Target> <Target Name="Dll-arm64" Outputs="$(Configuration)\arm64\wireguard.dll"> - <MSBuild Projects="downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM64" /> + <MSBuild Projects="setupapihost\setupapihost.vcxproj;downlevelshim\downlevelshim.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM64" /> </Target> <!-- diff --git a/wireguard-nt.sln b/wireguard-nt.sln index 0841074..989a683 100644 --- a/wireguard-nt.sln +++ b/wireguard-nt.sln @@ -8,10 +8,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api", "api\api.vcxproj", "{ ProjectSection(ProjectDependencies) = postProject {8B282C8F-5870-44C3-9A2A-B9091F4E9F68} = {8B282C8F-5870-44C3-9A2A-B9091F4E9F68} {E22CA58F-DEA5-48DC-BCF5-12075AD9BB82} = {E22CA58F-DEA5-48DC-BCF5-12075AD9BB82} + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33} = {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver\driver.vcxproj", "{8B282C8F-5870-44C3-9A2A-B9091F4E9F68}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setupapihost", "setupapihost\setupapihost.vcxproj", "{91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "downlevelshim", "downlevelshim\downlevelshim.vcxproj", "{E22CA58F-DEA5-48DC-BCF5-12075AD9BB82}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3A98F138-EE02-4488-B856-B3C48500BEA8}" @@ -82,6 +85,22 @@ Global {8B282C8F-5870-44C3-9A2A-B9091F4E9F68}.Release|arm64.Build.0 = Release|ARM64 {8B282C8F-5870-44C3-9A2A-B9091F4E9F68}.Release|x86.ActiveCfg = Release|Win32 {8B282C8F-5870-44C3-9A2A-B9091F4E9F68}.Release|x86.Build.0 = Release|Win32 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|amd64.ActiveCfg = Debug|x64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|amd64.Build.0 = Debug|x64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|arm.ActiveCfg = Debug|ARM + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|arm.Build.0 = Debug|ARM + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|arm64.ActiveCfg = Debug|ARM64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|arm64.Build.0 = Debug|ARM64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|x86.ActiveCfg = Debug|Win32 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Debug|x86.Build.0 = Debug|Win32 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|amd64.ActiveCfg = Release|x64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|amd64.Build.0 = Release|x64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|arm.ActiveCfg = Release|ARM + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|arm.Build.0 = Release|ARM + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|arm64.ActiveCfg = Release|ARM64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|arm64.Build.0 = Release|ARM64 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|x86.ActiveCfg = Release|Win32 + {91F6BAF4-6CA1-4F33-A1BE-EFBA4E978B33}.Release|x86.Build.0 = Release|Win32 {E22CA58F-DEA5-48DC-BCF5-12075AD9BB82}.Debug|amd64.ActiveCfg = Debug|x64 {E22CA58F-DEA5-48DC-BCF5-12075AD9BB82}.Debug|amd64.Build.0 = Debug|x64 {E22CA58F-DEA5-48DC-BCF5-12075AD9BB82}.Debug|arm.ActiveCfg = Debug|ARM |