diff options
author | 2021-10-11 23:21:31 -0600 | |
---|---|---|
committer | 2021-10-12 18:54:20 +0000 | |
commit | 544fdaaf8fb970d9657a59c1fc4c4569de4f2d3e (patch) | |
tree | 715e49e1f325bf7795face50ff84936b05ab86e2 /api/adapter.c | |
parent | proj: remove SDV and DVL support (diff) | |
download | wintun-544fdaa.tar.xz wintun-544fdaa.zip |
api: rewrite based on SwDevice
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'api/adapter.c')
-rw-r--r-- | api/adapter.c | 2225 |
1 files changed, 662 insertions, 1563 deletions
diff --git a/api/adapter.c b/api/adapter.c index f0a90e5..b71032a 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -3,469 +3,55 @@ * 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 <devioctl.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> -#include <devioctl.h> + +/* We pretend we're Windows 8, and then hack around the limitation in Windows 7 below. */ +#if NTDDI_VERSION == NTDDI_WIN7 +# 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 "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 "wintun-inf.h" +#include "registry.h" +#include "adapter_win7.h" #pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ -#define WAIT_FOR_REGISTRY_TIMEOUT 10000 /* ms */ -#define MAX_POOL_DEVICE_TYPE (WINTUN_MAX_POOL + 8) /* Should accommodate a pool name with " Tunnel" appended */ - -static const DEVPROPKEY DEVPKEY_Wintun_Pool = { - { 0xaba51201, 0xdf7a, 0x3a38, { 0x0a, 0xd9, 0x90, 0x64, 0x42, 0xd2, 0x71, 0xae } }, - DEVPROPID_FIRST_USABLE + 0 -}; - -static const DEVPROPKEY DEVPKEY_Wintun_Name = { +const DEVPROPKEY DEVPKEY_Wintun_Name = { { 0x3361c968, 0x2f2e, 0x4660, { 0xb4, 0x7e, 0x69, 0x9c, 0xdc, 0x4c, 0x32, 0xb9 } }, DEVPROPID_FIRST_USABLE + 1 }; -typedef struct _SP_DEVINFO_DATA_LIST -{ - SP_DEVINFO_DATA Data; - 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(WINTUN_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(WINTUN_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, WINTUN_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; -} - -#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) - -static _Return_type_success_(return != FALSE) -BOOL -ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) -{ - 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(WINTUN_LOG_ERR, L"Failed to get adapter %u object", DevInfoData->DevInst); - goto cleanupInstanceId; - } - if (DeviceIoControl(NdisHandle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL)) - { - LastError = ERROR_SUCCESS; - Sleep(200); - } - else if (GetLastError() == ERROR_NOTHING_TO_TERMINATE) - LastError = ERROR_SUCCESS; - else - LastError = LOG_LAST_ERROR(L"Failed to perform ioctl on adapter %u", DevInfoData->DevInst); - 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(WINTUN_LOG_INFO, L"Force closing all adapter %u open handles", DeviceNode->Data.DevInst); - if (!ForceCloseWintunAdapterHandle(DevInfo, &DeviceNode->Data)) - LOG(WINTUN_LOG_WARN, L"Failed to force close adapter %u handles", DeviceNode->Data.DevInst); - - LOG(WINTUN_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(WINTUN_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(); - } - } - 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(WINTUN_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_Wintun_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_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR Pool) +PopulateAdapterData(_Inout_ WINTUN_ADAPTER *Adapter) { DWORD LastError = ERROR_SUCCESS; @@ -474,7 +60,7 @@ PopulateAdapterData(_Inout_ WINTUN_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; } @@ -512,18 +98,10 @@ PopulateAdapterData(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR Pool) goto cleanupKey; } - DWORD Size; - if (!SetupDiGetDeviceInstanceIdW( - Adapter->DevInfo, &Adapter->DevInfoData, Adapter->DevInstanceID, _countof(Adapter->DevInstanceID), &Size)) + Adapter->InterfaceFilename = AdapterGetDeviceObjectFileName(Adapter->DevInstanceID); + if (!Adapter->InterfaceFilename) { - 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) - { - LOG(WINTUN_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; } @@ -532,38 +110,150 @@ 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, WINTUN_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_Wintun_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(WINTUN_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name); + } + SetupDiDestroyDeviceInfoList(DevInfo); +cleanupDeviceInstallationMutex: + NamespaceReleaseMutex(DeviceInstallationMutex); +} + _Use_decl_annotations_ VOID WINAPI -WintunFreeAdapter(WINTUN_ADAPTER *Adapter) +WintunCloseAdapter(WINTUN_ADAPTER *Adapter) { if (!Adapter) return; + Free(Adapter->InterfaceFilename); if (Adapter->DevInfo) + AdapterForceCloseHandles(Adapter->DevInfo, &Adapter->DevInfoData); + 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 -WintunGetAdapterName(WINTUN_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_Wintun_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, WINTUN_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_Wintun_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_ @@ -587,36 +277,20 @@ ConvertInterfaceAliasToGuid(_In_z_ LPCWSTR Name, _Out_ GUID *Guid) return TRUE; } -_Use_decl_annotations_ -BOOL WINAPI -WintunSetAdapterName(WINTUN_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(WINTUN_LOG_ERR, L"Adapter name too long: %s", Name); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (!SetupDiSetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_Wintun_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; @@ -627,8 +301,7 @@ WintunSetAdapterName(WINTUN_ADAPTER *Adapter, LPCWSTR Name) WCHAR Proposal[MAX_ADAPTER_NAME]; if (_snwprintf_s(Proposal, _countof(Proposal), _TRUNCATE, L"%s %d", Name, j + 1) == -1) { - LOG(WINTUN_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) @@ -636,9 +309,11 @@ WintunSetAdapterName(WINTUN_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; } @@ -650,142 +325,19 @@ WintunSetAdapterName(WINTUN_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(WINTUN_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_Wintun_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_ -WINTUN_ADAPTER_HANDLE WINAPI -WintunOpenAdapter(LPCWSTR Pool, LPCWSTR Name) -{ - WINTUN_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); - if (!Adapter) - return FALSE; - - DWORD LastError = ERROR_SUCCESS; - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) - { - LastError = LOG(WINTUN_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 (!WintunGetAdapterName(Adapter, Name2)) - continue; - if (_wcsicmp(Name, Name2)) - continue; - - /* Check the Hardware ID to make sure it's a real Wintun device. */ - if (!IsOurAdapter(Adapter->DevInfo, &Adapter->DevInfoData)) - { - LOG(WINTUN_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(WINTUN_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(WINTUN_LOG_ERR, L"Failed to get adapter %u pool membership", Adapter->DevInfoData.DevInst); - goto cleanupMutex; - } - } - - if (!PopulateAdapterData(Adapter, Pool)) - { - LastError = LOG(WINTUN_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. */ - WintunSetAdapterName(Adapter, Name); - - LastError = ERROR_SUCCESS; - goto cleanupMutex; - } - LastError = ERROR_FILE_NOT_FOUND; -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - if (LastError != ERROR_SUCCESS) - WintunFreeAdapter(Adapter); - return RET_ERROR(Adapter, LastError); -} - -_Use_decl_annotations_ VOID WINAPI WintunGetAdapterLUID(WINTUN_ADAPTER *Adapter, NET_LUID *Luid) { @@ -798,1092 +350,639 @@ _Use_decl_annotations_ HANDLE WINAPI AdapterOpenDeviceObject(const WINTUN_ADAPTER *Adapter) { - return OpenDeviceObject(Adapter->DevInstanceID); -} - -static BOOL -IsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData) -{ - if (DrvInfoDetailData->CompatIDsOffset > 1 && !_wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_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; -} - -_Must_inspect_result_ -static _Return_type_success_(return != FALSE) -BOOL -GetTcpipAdapterRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path) -{ - WCHAR Guid[MAX_GUID_STRING_LEN]; - if (_snwprintf_s( - Path, - MAX_REG_PATH, - _TRUNCATE, - L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%.*s", - StringFromGUID2(&Adapter->CfgInstanceID, Guid, _countof(Guid)), - Guid) == -1) - { - LOG(WINTUN_LOG_ERR, L"Registry path too long"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - return TRUE; + 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; } -_Must_inspect_result_ -static _Return_type_success_(return != FALSE) -BOOL -GetTcpipInterfaceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path) +_Use_decl_annotations_ +LPWSTR +AdapterGetDeviceObjectFileName(LPCWSTR InstanceId) { - HKEY TcpipAdapterRegKey; - WCHAR TcpipAdapterRegPath[MAX_REG_PATH]; - if (!GetTcpipAdapterRegPath(Adapter, TcpipAdapterRegPath)) - return FALSE; - DWORD LastError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TcpipAdapterRegPath, 0, KEY_QUERY_VALUE, &TcpipAdapterRegKey); + 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 open registry key %s", TcpipAdapterRegPath)); - return FALSE; - } - LPWSTR Paths = RegistryQueryString(TcpipAdapterRegKey, L"IpConfig", TRUE); - if (!Paths) - { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %s\\IpConfig", TcpipAdapterRegPath); - goto cleanupTcpipAdapterRegKey; - } - if (!Paths[0]) - { - LOG(WINTUN_LOG_ERR, L"%s\\IpConfig is empty", TcpipAdapterRegPath); - LastError = ERROR_INVALID_DATA; - goto cleanupPaths; - } - if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"SYSTEM\\CurrentControlSet\\Services\\%s", Paths) == -1) - { - LOG(WINTUN_LOG_ERR, L"Registry path too long: %s", Paths); - LastError = ERROR_INVALID_PARAMETER; - goto cleanupPaths; - } -cleanupPaths: - Free(Paths); -cleanupTcpipAdapterRegKey: - RegCloseKey(TcpipAdapterRegKey); - return RET_ERROR(TRUE, LastError); -} - -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(WINTUN_LOG_WARN, L"Determined version of %s, but was v0.0, so returning failure", Filename); - LastError = ERROR_VERSION_PARSE_ERROR; + SetLastError(LOG_ERROR(LastError, L"Failed to query adapter %s associated instances size", InstanceId)); + return NULL; } -out: - Free(VersionInfo); - return RET_ERROR(Version, LastError); -} - -static DWORD WINAPI -MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion) -{ - PRTL_PROCESS_MODULES Modules; - ULONG BufferSize = 128 * 1024; - for (;;) + 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) { - 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(WINTUN_LOG_ERR, L"Failed to enumerate drivers (status: 0x%x)", Status); - SetLastError(RtlNtStatusToDosError(Status)); - return 0; + LOG_ERROR(LastError, L"Failed to get adapter %s associated instances", InstanceId); + Free(Interfaces); + SetLastError(LastError); + return NULL; } - DWORD LastError = ERROR_SUCCESS, Version = 0; - for (ULONG i = Modules->NumberOfModules; i-- > 0;) + if (!Interfaces[0]) { - LPCSTR NtPath = (LPCSTR)Modules->Modules[i].FullPathName; - if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wintun.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; - } + Free(Interfaces); + SetLastError(ERROR_DEVICE_NOT_AVAILABLE); + return NULL; } - LastError = ERROR_FILE_NOT_FOUND; -cleanupModules: - Free(Modules); - return RET_ERROR(Version, LastError); -} - -_Use_decl_annotations_ -DWORD WINAPI WintunGetRunningDriverVersion(VOID) -{ - return MaybeGetRunningDriverVersion(FALSE); + return Interfaces; } -static BOOL EnsureWintunUnloaded(VOID) +typedef struct _WAIT_FOR_INTERFACE_CTX { - BOOL Loaded; - for (int i = 0; (Loaded = MaybeGetRunningDriverVersion(TRUE) != 0) != FALSE && i < 300; ++i) - Sleep(50); - return !Loaded; -} + HANDLE Event; + DWORD LastError; +} WAIT_FOR_INTERFACE_CTX; -static VOID -SelectDriverDeferredCleanup(_In_ HDEVINFO DevInfoExistingAdapters, _In_opt_ SP_DEVINFO_DATA_LIST *ExistingAdapters) +static VOID WINAPI +WaitForInterfaceCallback( + _In_ HDEVQUERY DevQuery, + _Inout_ PVOID Context, + _In_ const DEV_QUERY_RESULT_ACTION_DATA *ActionData) { - if (ExistingAdapters) + WAIT_FOR_INTERFACE_CTX *Ctx = Context; + Ctx->LastError = ERROR_SUCCESS; + if (ActionData->Action == DevQueryResultStateChange) { - EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters); - while (ExistingAdapters) - { - SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; - Free(ExistingAdapters); - ExistingAdapters = Next; - } + if (ActionData->Data.State != DevQueryStateAborted) + return; + Ctx->LastError = ERROR_DEVICE_NOT_AVAILABLE; } - if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE) - SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters); + else if (ActionData->Action == DevQueryResultRemove) + return; + SetEvent(Ctx->Event); } _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) +WaitForInterface(_In_ WCHAR *InstanceId) { - static const FILETIME OurDriverDate = WINTUN_INF_FILETIME; - static const DWORDLONG OurDriverVersion = WINTUN_INF_VERSION; - HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); - if (!DriverInstallationLock) - { - LOG(WINTUN_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(WINTUN_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(WINTUN_LOG_INFO, L"Waiting for existing driver to unload from kernel"); - if (!EnsureWintunUnloaded()) - LOG(WINTUN_LOG_WARN, - L"Failed to unload existing driver, which means a reboot will likely be required"); - } - LOG(WINTUN_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(WINTUN_LOG_INFO, - L"Using existing driver %u.%u", - (DWORD)((DriverVersion & 0xffff000000000000) >> 48), - (DWORD)((DriverVersion & 0x0000ffff00000000) >> 32)); - LastError = ERROR_SUCCESS; - DestroyDriverInfoListOnCleanup = FALSE; - goto cleanupExistingAdapters; - } + if (IsWindows7) + return TRUE; - LOG(WINTUN_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; + 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, + .Property.CompKey.Store = DEVPROP_STORE_SYSTEM, + .Property.Type = DEVPROP_TYPE_STRING, + .Property.Buffer = InstanceId, + .Property.BufferSize = + (ULONG)((wcslen(InstanceId) + 1) * sizeof(InstanceId[0])) }, + { .Operator = DEVPROP_OPERATOR_EQUALS, + .Property.CompKey.Key = DEVPKEY_DeviceInterface_Enabled, + .Property.CompKey.Store = DEVPROP_STORE_SYSTEM, + .Property.Type = DEVPROP_TYPE_BOOLEAN, + .Property.Buffer = (PVOID)&DevPropTrue, + .Property.BufferSize = sizeof(DevPropTrue) }, + { .Operator = DEVPROP_OPERATOR_EQUALS, + .Property.CompKey.Key = DEVPKEY_DeviceInterface_ClassGuid, + .Property.CompKey.Store = DEVPROP_STORE_SYSTEM, + .Property.Type = DEVPROP_TYPE_GUID, + .Property.Buffer = (PVOID)&GUID_DEVINTERFACE_NET, + .Property.BufferSize = sizeof(GUID_DEVINTERFACE_NET) } }; + WAIT_FOR_INTERFACE_CTX Ctx = { .Event = CreateEventW(NULL, FALSE, FALSE, NULL) }; + if (!Ctx.Event) + { + LastError = LOG_LAST_ERROR(L"Failed to create event"); + goto cleanup; } - - 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"wintun.cat") || - !PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") || - !PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf")) + HDEVQUERY Query; + HRESULT HRet = DevCreateObjectQuery( + DevObjectTypeDeviceInterface, + DevQueryFlagUpdateResults, + 0, + NULL, + _countof(Filters), + Filters, + WaitForInterfaceCallback, + &Ctx, + &Query); + if (FAILED(HRet)) { - LastError = ERROR_BUFFER_OVERFLOW; - goto cleanupDirectory; + LastError = LOG_ERROR(HRet, L"Failed to create device query"); + goto cleanupEvent; } - - LOG(WINTUN_LOG_INFO, L"Extracting driver"); - if (!ResourceCopyToFile(CatPath, L"wintun.cat") || !ResourceCopyToFile(SysPath, L"wintun.sys") || - !ResourceCopyToFile(InfPath, L"wintun.inf")) + LastError = WaitForSingleObject(Ctx.Event, 15000); + if (LastError != WAIT_OBJECT_0) { - LastError = LOG_LAST_ERROR(L"Failed to extract driver"); - goto cleanupDelete; + if (LastError == WAIT_FAILED) + LastError = LOG_LAST_ERROR(L"Failed to wait for device query"); + else + LastError = LOG_ERROR(LastError, L"Timed out waiting for device query"); + goto cleanupQuery; } + LastError = Ctx.LastError; + if (LastError != ERROR_SUCCESS) + LastError = LOG_ERROR(LastError, L"Failed to get enabled device"); +cleanupQuery: + DevCloseObjectQuery(Query); +cleanupEvent: + CloseHandle(Ctx.Event); +cleanup: + return RET_ERROR(TRUE, LastError); +} - WCHAR *WintrustKeyOriginalValue = NULL; - HKEY WintrustKey = NULL; - if (!IsWindows10) - { - LOG(WINTUN_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(WINTUN_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); +typedef struct _SW_DEVICE_CREATE_CTX +{ + HRESULT CreateResult; + WCHAR *DeviceInstanceId; + HANDLE Triggered; +} SW_DEVICE_CREATE_CTX; - SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER); - DestroyDriverInfoListOnCleanup = FALSE; - DevInstallParams->Flags |= DI_ENUMSINGLEINF; - if (wcsncpy_s(DevInstallParams->DriverPath, _countof(DevInstallParams->DriverPath), InfStorePath, _TRUNCATE) == - STRUNCATE) - { - LOG(WINTUN_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); +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_ -WINTUN_ADAPTER * -AdapterOpenFromDevInstanceId(LPCWSTR Pool, LPCWSTR DevInstanceID) +WINTUN_ADAPTER_HANDLE WINAPI +WintunCreateAdapter(LPCWSTR Name, LPCWSTR TunnelType, const GUID *RequestedGUID) { - WINTUN_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); - if (!Adapter) - return FALSE; - DWORD LastError = ERROR_SUCCESS; - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) + WINTUN_ADAPTER *Adapter = NULL; + + HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex(); + if (!DeviceInstallationMutex) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Pool); + LastError = LOG_LAST_ERROR(L"Failed to take device installation mutex"); goto cleanup; } - Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, 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); - if (!SetupDiOpenDeviceInfoW(Adapter->DevInfo, DevInstanceID, NULL, 0, &Adapter->DevInfoData)) - { - LastError = LOG_LAST_ERROR(L"Failed to open device instance ID %s", DevInstanceID); - goto cleanupMutex; - } - if (!PopulateAdapterData(Adapter, Pool)) + + HDEVINFO DevInfoExistingAdapters; + SP_DEVINFO_DATA_LIST *ExistingAdapters; + if (!DriverInstall(&DevInfoExistingAdapters, &ExistingAdapters)) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); - goto cleanupMutex; + LastError = GetLastError(); + goto cleanupDeviceInstallationMutex; } -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - if (LastError != ERROR_SUCCESS) - WintunFreeAdapter(Adapter); - return RET_ERROR(Adapter, LastError); -} -_Use_decl_annotations_ -WINTUN_ADAPTER_HANDLE WINAPI -WintunCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired) -{ - BOOL DummyRebootRequired; - if (!RebootRequired) - RebootRequired = &DummyRebootRequired; - *RebootRequired = FALSE; - -#ifdef MAYBE_WOW64 - if (NativeMachine != IMAGE_FILE_PROCESS) - return CreateAdapterViaRundll32(Pool, Name, RequestedGUID, RebootRequired); -#endif - - DWORD LastError = ERROR_SUCCESS; LOG(WINTUN_LOG_INFO, L"Creating adapter"); - if (!IsWindows10) - RequestedGUID = NULL; - - WINTUN_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); + Adapter = Zalloc(sizeof(*Adapter)); if (!Adapter) - return NULL; + goto cleanupDriverInstall; - Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); - if (Adapter->DevInfo == INVALID_HANDLE_VALUE) + 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 create empty device information set"); + LastError = ERROR_BUFFER_OVERFLOW; goto cleanupAdapter; } - WCHAR ClassName[MAX_CLASS_NAME_LEN]; - if (!SetupDiClassNameFromGuidExW(&GUID_DEVCLASS_NET, ClassName, _countof(ClassName), NULL, NULL, NULL)) + + 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 class name associated with class GUID"); + LastError = LOG_ERROR(CM_MapCrToWin32Err(ConfigRet, ERROR_GEN_FAILURE), L"Failed to get root node name"); goto cleanupAdapter; } - WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; - if (!GetPoolDeviceTypeName(Pool, PoolDeviceTypeName)) + 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 = GetLastError(); + LastError = LOG_ERROR(HRet, L"Failed to convert GUID"); goto cleanupAdapter; } - Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); - if (!SetupDiCreateDeviceInfoW( - Adapter->DevInfo, - ClassName, - &GUID_DEVCLASS_NET, - PoolDeviceTypeName, - NULL, - DICD_GENERATE_ID, - &Adapter->DevInfoData)) + 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 new device information element"); + LastError = LOG_LAST_ERROR(L"Failed to create event trigger"); goto cleanupAdapter; } - SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; - if (!SetupDiGetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) + + if (IsWindows7) { - LastError = LOG_LAST_ERROR( - L"Failed to retrieve adapter %u device installation parameters", Adapter->DevInfoData.DevInst); - goto cleanupAdapter; + if (!CreateAdapterWin7(Adapter, Name, TunnelTypeName)) + { + LastError = GetLastError(); + goto cleanupCreateContext; + } + goto skipSwDevice; } - DevInstallParams.Flags |= DI_QUIETINSTALL; - if (!SetupDiSetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) + if (!IsWindows10) + goto skipStub; + + SW_DEVICE_CREATE_INFO StubCreateInfo = { .cbSize = sizeof(StubCreateInfo), + .pszInstanceId = InstanceIdStr, + .pszzHardwareIds = L"", + .CapabilityFlags = + SWDeviceCapabilitiesSilentInstall | SWDeviceCapabilitiesDriverRequired, + .pszDeviceDescription = TunnelTypeName }; + DEVPROPERTY StubDeviceProperties[] = { { .CompKey = { .Key = DEVPKEY_Device_ClassGuid, + .Store = DEVPROP_STORE_SYSTEM }, + .Type = DEVPROP_TYPE_GUID, + .Buffer = (PVOID)&GUID_DEVCLASS_NET, + .BufferSize = sizeof(GUID_DEVCLASS_NET) } }; + HRet = SwDeviceCreate( + WINTUN_HWID, + RootNodeName, + &StubCreateInfo, + _countof(StubDeviceProperties), + StubDeviceProperties, + DeviceCreateCallback, + &CreateContext, + &Adapter->SwDevice); + if (FAILED(HRet)) + { + LastError = LOG_ERROR(HRet, L"Failed to initiate stub device creation"); + goto cleanupCreateContext; + } + if (WaitForSingleObject(CreateContext.Triggered, INFINITE) != WAIT_OBJECT_0) + { + LastError = LOG_LAST_ERROR(L"Failed to wait for stub device creation trigger"); + goto cleanupCreateContext; + } + if (FAILED(CreateContext.CreateResult)) + { + LastError = LOG_ERROR(CreateContext.CreateResult, L"Failed to create stub device"); + goto cleanupCreateContext; + } + DEVINST DevInst; + CONFIGRET CRet = CM_Locate_DevNodeW(&DevInst, Adapter->DevInstanceID, CM_LOCATE_DEVNODE_PHANTOM); + if (CRet != CR_SUCCESS) { LastError = - LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", Adapter->DevInfoData.DevInst); - goto cleanupAdapter; + LOG_ERROR(CM_MapCrToWin32Err(CRet, ERROR_DEVICE_ENUMERATION_ERROR), L"Failed to make stub device list"); + goto cleanupCreateContext; } - if (!SetupDiSetSelectedDevice(Adapter->DevInfo, &Adapter->DevInfoData)) + HKEY DriverKey; + CRet = CM_Open_DevNode_Key(DevInst, KEY_SET_VALUE, 0, RegDisposition_OpenAlways, &DriverKey, CM_REGISTRY_SOFTWARE); + if (CRet != CR_SUCCESS) { - LastError = LOG_LAST_ERROR(L"Failed to select adapter %u device", Adapter->DevInfoData.DevInst); - goto cleanupAdapter; + LastError = + LOG_ERROR(CM_MapCrToWin32Err(CRet, ERROR_PNP_REGISTRY_ERROR), L"Failed to create software registry key"); + goto cleanupCreateContext; } - static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID; - if (!SetupDiSetDeviceRegistryPropertyW( - Adapter->DevInfo, &Adapter->DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) + LastError = + RegSetValueExW(DriverKey, L"SuggestedInstanceId", 0, REG_BINARY, (const BYTE *)&InstanceId, sizeof(InstanceId)); + RegCloseKey(DriverKey); + if (LastError != ERROR_SUCCESS) { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u hardware ID", Adapter->DevInfoData.DevInst); - goto cleanupAdapter; + LastError = LOG_ERROR(LastError, L"Failed to set SuggestedInstanceId to %s", InstanceIdStr); + goto cleanupCreateContext; } + SwDeviceClose(Adapter->SwDevice); + Adapter->SwDevice = NULL; - HDEVINFO DevInfoExistingAdapters; - SP_DEVINFO_DATA_LIST *ExistingAdapters; - if (!SelectDriver( - Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams, &DevInfoExistingAdapters, &ExistingAdapters)) +skipStub:; + static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID; + SW_DEVICE_CREATE_INFO CreateInfo = { .cbSize = sizeof(CreateInfo), + .pszInstanceId = InstanceIdStr, + .pszzHardwareIds = Hwids, + .CapabilityFlags = + SWDeviceCapabilitiesSilentInstall | SWDeviceCapabilitiesDriverRequired, + .pszDeviceDescription = TunnelTypeName }; + DEVPROPERTY DeviceProperties[] = { + { .CompKey = { .Key = DEVPKEY_Wintun_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)) } + }; + + HRet = SwDeviceCreate( + WINTUN_HWID, + RootNodeName, + &CreateInfo, + _countof(DeviceProperties), + DeviceProperties, + DeviceCreateCallback, + &CreateContext, + &Adapter->SwDevice); + if (FAILED(HRet)) + { + LastError = LOG_ERROR(HRet, L"Failed to initiate device creation"); + goto cleanupCreateContext; + } + if (WaitForSingleObject(CreateContext.Triggered, INFINITE) != WAIT_OBJECT_0) + { + LastError = LOG_LAST_ERROR(L"Failed to wait for device creation trigger"); + goto cleanupCreateContext; + } + if (FAILED(CreateContext.CreateResult)) + { + LastError = LOG_ERROR(CreateContext.CreateResult, L"Failed to create device"); + goto cleanupCreateContext; + } + + if (!WaitForInterface(Adapter->DevInstanceID)) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to select adapter %u driver", Adapter->DevInfoData.DevInst); - goto cleanupAdapter; + LastError = GetLastError(); + DEVPROPTYPE PropertyType = 0; + NTSTATUS NtStatus = 0; + INT32 ProblemCode = 0; + Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + if (Adapter->DevInfo == INVALID_HANDLE_VALUE) + { + Adapter->DevInfo = NULL; + goto cleanupCreateContext; + } + Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); + if (!SetupDiOpenDeviceInfoW( + Adapter->DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &Adapter->DevInfoData)) + { + SetupDiDestroyDeviceInfoList(Adapter->DevInfo); + Adapter->DevInfo = NULL; + goto cleanupCreateContext; + } + if (!SetupDiGetDevicePropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + &DEVPKEY_Device_ProblemStatus, + &PropertyType, + (PBYTE)&NtStatus, + sizeof(NtStatus), + NULL, + 0) || + PropertyType != DEVPROP_TYPE_NTSTATUS) + NtStatus = 0; + if (!SetupDiGetDevicePropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + &DEVPKEY_Device_ProblemCode, + &PropertyType, + (PBYTE)&ProblemCode, + sizeof(ProblemCode), + NULL, + 0) || + (PropertyType != DEVPROP_TYPE_INT32 && PropertyType != DEVPROP_TYPE_UINT32)) + ProblemCode = 0; + 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 cleanupCreateContext; } - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) +skipSwDevice: + Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (Adapter->DevInfo == INVALID_HANDLE_VALUE) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Pool); - goto cleanupDriverInfoList; + Adapter->DevInfo = NULL; + LastError = LOG_LAST_ERROR(L"Failed to make device list"); + goto cleanupCreateContext; } - - if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, Adapter->DevInfo, &Adapter->DevInfoData)) + 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 register adapter %u device", 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 (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, Adapter->DevInfo, &Adapter->DevInfoData)) - LOG_LAST_ERROR(L"Failed to register adapter %u coinstallers", Adapter->DevInfoData.DevInst); - HKEY NetDevRegKey = INVALID_HANDLE_VALUE; - const int PollTimeout = 50 /* ms */; - for (int i = 0; NetDevRegKey == INVALID_HANDLE_VALUE && i < WAIT_FOR_REGISTRY_TIMEOUT / PollTimeout; ++i) - { - if (i) - Sleep(PollTimeout); - NetDevRegKey = SetupDiOpenDevRegKey( - Adapter->DevInfo, - &Adapter->DevInfoData, - DICS_FLAG_GLOBAL, - 0, - DIREG_DRV, - KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY); - } - if (NetDevRegKey == INVALID_HANDLE_VALUE) + if (!PopulateAdapterData(Adapter)) { - LastError = - LOG_LAST_ERROR(L"Failed to open adapter %u device-specific registry key", Adapter->DevInfoData.DevInst); - goto cleanupDevice; + LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter data"); + goto cleanupCreateContext; } - if (RequestedGUID) + + if (!NciSetAdapterName(&Adapter->CfgInstanceID, Name)) { - LastError = RegSetValueExW( - NetDevRegKey, L"SuggestedInstanceId", 0, REG_BINARY, (const BYTE *)RequestedGUID, sizeof(*RequestedGUID)); - if (LastError != ERROR_SUCCESS) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); - LOG_ERROR(LastError, L"Failed to set %.*s\\SuggestedInstanceId", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; - } + LastError = LOG(WINTUN_LOG_ERR, L"Failed to set adapter name \"%s\"", Name); + goto cleanupCreateContext; } - if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, Adapter->DevInfo, &Adapter->DevInfoData)) - LOG_LAST_ERROR(L"Failed to install adapter %u interfaces", Adapter->DevInfoData.DevInst); + if (IsWindows7) + CreateAdapterPostWin7(Adapter, TunnelTypeName); - if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, Adapter->DevInfo, &Adapter->DevInfoData)) - { - LastError = LOG_LAST_ERROR(L"Failed to install adapter %u device", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; - } - *RebootRequired = *RebootRequired || CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData); - - if (!SetupDiSetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_Wintun_Pool, - DEVPROP_TYPE_STRING, -#pragma warning(suppress : 4090) - (const BYTE *)Pool, - (DWORD)((wcslen(Pool) + 1) * sizeof(*Pool)), - 0)) - { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u pool", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; - } - if (!SetupDiSetDeviceRegistryPropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - SPDRP_DEVICEDESC, - (const BYTE *)PoolDeviceTypeName, - (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(*PoolDeviceTypeName)))) +cleanupCreateContext: + CloseHandle(CreateContext.Triggered); +cleanupAdapter: + if (LastError != ERROR_SUCCESS) { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u description", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; + WintunCloseAdapter(Adapter); + Adapter = NULL; } +cleanupDriverInstall: + DriverInstallDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); +cleanupDeviceInstallationMutex: + NamespaceReleaseMutex(DeviceInstallationMutex); +cleanup: + QueueUpOrphanedDeviceCleanupRoutine(); + return RET_ERROR(Adapter, LastError); +} - /* DIF_INSTALLDEVICE returns almost immediately, while the device installation continues in the background. It might - * take a while, before all registry keys and values are populated. */ - LPWSTR DummyStr = RegistryQueryStringWait(NetDevRegKey, L"NetCfgInstanceId", WAIT_FOR_REGISTRY_TIMEOUT); - if (!DummyStr) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); - LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\NetCfgInstanceId", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; - } - Free(DummyStr); - DWORD DummyDWORD; - if (!RegistryQueryDWORDWait(NetDevRegKey, L"NetLuidIndex", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD)) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); - LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\NetLuidIndex", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; - } - if (!RegistryQueryDWORDWait(NetDevRegKey, L"*IfType", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD)) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); - LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\*IfType", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; - } +_Use_decl_annotations_ +WINTUN_ADAPTER_HANDLE WINAPI +WintunOpenAdapter(LPCWSTR Name) +{ + DWORD LastError = ERROR_SUCCESS; + WINTUN_ADAPTER *Adapter = NULL; - if (!PopulateAdapterData(Adapter, Pool)) + HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex(); + if (!DeviceInstallationMutex) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; + LastError = LOG_LAST_ERROR(L"Failed to take device installation mutex"); + goto cleanup; } - HKEY TcpipAdapterRegKey; - WCHAR TcpipAdapterRegPath[MAX_REG_PATH]; - if (!GetTcpipAdapterRegPath(Adapter, TcpipAdapterRegPath)) - { - LastError = GetLastError(); - goto cleanupAdapter; - } - TcpipAdapterRegKey = RegistryOpenKeyWait( - HKEY_LOCAL_MACHINE, TcpipAdapterRegPath, KEY_QUERY_VALUE | KEY_NOTIFY, WAIT_FOR_REGISTRY_TIMEOUT); - if (!TcpipAdapterRegKey) + Adapter = Zalloc(sizeof(*Adapter)); + if (!Adapter) + goto cleanupDeviceInstallationMutex; + + HDEVINFO DevInfo = + SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, DIGCF_PRESENT, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) { - LastError = LOG( - WINTUN_LOG_ERR, L"Failed to open adapter-specific TCP/IP interface registry key %s", TcpipAdapterRegPath); + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); goto cleanupAdapter; } - DummyStr = RegistryQueryStringWait(TcpipAdapterRegKey, L"IpConfig", WAIT_FOR_REGISTRY_TIMEOUT); - if (!DummyStr) - { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %s\\IpConfig", TcpipAdapterRegPath); - goto cleanupTcpipAdapterRegKey; - } - Free(DummyStr); - WCHAR TcpipInterfaceRegPath[MAX_REG_PATH]; - if (!GetTcpipInterfaceRegPath(Adapter, TcpipInterfaceRegPath)) - { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to determine interface-specific TCP/IP network registry key path"); - goto cleanupTcpipAdapterRegKey; - } - for (int Tries = 0; Tries < 300; ++Tries) + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + BOOL Found = FALSE; + for (DWORD EnumIndex = 0; !Found; ++EnumIndex) { - HKEY TcpipInterfaceRegKey = RegistryOpenKeyWait( - HKEY_LOCAL_MACHINE, TcpipInterfaceRegPath, KEY_QUERY_VALUE | KEY_SET_VALUE, WAIT_FOR_REGISTRY_TIMEOUT); - if (!TcpipInterfaceRegKey) + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) { - LastError = - LOG(WINTUN_LOG_ERR, - L"Failed to open interface-specific TCP/IP network registry key %s", - TcpipInterfaceRegPath); - goto cleanupTcpipAdapterRegKey; + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; } - static const DWORD EnableDeadGWDetect = 0; - LastError = RegSetKeyValueW( - TcpipInterfaceRegKey, - NULL, - L"EnableDeadGWDetect", - REG_DWORD, - &EnableDeadGWDetect, - sizeof(EnableDeadGWDetect)); - RegCloseKey(TcpipInterfaceRegKey); - if (LastError == ERROR_SUCCESS) - break; - if (LastError != ERROR_TRANSACTION_NOT_ACTIVE) - { - LOG_ERROR(LastError, L"Failed to set %s\\EnableDeadGWDetect", TcpipInterfaceRegPath); - goto cleanupTcpipAdapterRegKey; - } - Sleep(10); + DEVPROPTYPE PropType; + WCHAR OtherName[MAX_ADAPTER_NAME]; + Found = SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Wintun_Name, + &PropType, + (PBYTE)OtherName, + MAX_ADAPTER_NAME * sizeof(OtherName[0]), + NULL, + 0) && + PropType == DEVPROP_TYPE_STRING && !_wcsicmp(Name, OtherName); } - - if (!WintunSetAdapterName(Adapter, Name)) + if (!Found) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to set adapter name %s", Name); - goto cleanupTcpipAdapterRegKey; + LastError = LOG_ERROR(ERROR_NOT_FOUND, L"Failed to find matching adapter name"); + goto cleanupDevInfo; } - - for (int Tries = 0; Tries < 1000; ++Tries) + DWORD RequiredChars = _countof(Adapter->DevInstanceID); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, Adapter->DevInstanceID, RequiredChars, &RequiredChars)) { - DEVPROPTYPE PropertyType; - NTSTATUS ProblemStatus; - if (SetupDiGetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_Device_ProblemStatus, - &PropertyType, - (PBYTE)&ProblemStatus, - sizeof(ProblemStatus), - NULL, - 0) && - PropertyType == DEVPROP_TYPE_NTSTATUS) - { - if (ProblemStatus != STATUS_PNP_DEVICE_CONFIGURATION_PENDING || Tries == 999) - { - INT32 ProblemCode; - if (!SetupDiGetDevicePropertyW( - Adapter->DevInfo, - &Adapter->DevInfoData, - &DEVPKEY_Device_ProblemCode, - &PropertyType, - (PBYTE)&ProblemCode, - sizeof(ProblemCode), - NULL, - 0) || - PropertyType != DEVPROP_TYPE_INT32) - ProblemCode = 0; - LastError = RtlNtStatusToDosError(ProblemStatus); - if (LastError == ERROR_SUCCESS) - LastError = ERROR_NOT_READY; - LOG_ERROR(LastError, L"Failed to setup adapter (code: 0x%x, status: 0x%x)", ProblemCode, ProblemStatus); - goto cleanupTcpipAdapterRegKey; - } - Sleep(10); - } - else - break; + LastError = LOG_LAST_ERROR(L"Failed to get adapter instance ID"); + goto cleanupDevInfo; } - if (!EnsureDeviceObject(Adapter->DevInstanceID)) + Adapter->DevInfo = DevInfo; + Adapter->DevInfoData = DevInfoData; + BOOL Ret = WaitForInterface(Adapter->DevInstanceID) && PopulateAdapterData(Adapter); + Adapter->DevInfo = NULL; + if (!Ret) { - LastError = LOG_LAST_ERROR(L"Device object file did not appear"); - goto cleanupTcpipAdapterRegKey; + LastError = LOG_LAST_ERROR(L"Failed to populate adapter"); + goto cleanupDevInfo; } - LastError = ERROR_SUCCESS; -cleanupTcpipAdapterRegKey: - RegCloseKey(TcpipAdapterRegKey); -cleanupNetDevRegKey: - RegCloseKey(NetDevRegKey); -cleanupDevice: +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanupAdapter: 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)) - *RebootRequired = *RebootRequired || CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData); + WintunCloseAdapter(Adapter); + Adapter = NULL; } - NamespaceReleaseMutex(Mutex); -cleanupDriverInfoList: - SelectDriverDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); - SetupDiDestroyDriverInfoList(Adapter->DevInfo, &Adapter->DevInfoData, SPDIT_COMPATDRIVER); -cleanupAdapter: - if (LastError != ERROR_SUCCESS) - WintunFreeAdapter(Adapter); +cleanupDeviceInstallationMutex: + NamespaceReleaseMutex(DeviceInstallationMutex); +cleanup: + QueueUpOrphanedDeviceCleanupRoutine(); return RET_ERROR(Adapter, LastError); } +#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) + _Use_decl_annotations_ -BOOL WINAPI -WintunDeleteAdapter(WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired) +BOOL +AdapterForceCloseHandles(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - BOOL DummyRebootRequired; - if (!RebootRequired) - RebootRequired = &DummyRebootRequired; - *RebootRequired = FALSE; -#ifdef MAYBE_WOW64 - if (NativeMachine != IMAGE_FILE_PROCESS) - return DeleteAdapterViaRundll32(Adapter, ForceCloseSessions, RebootRequired); -#endif - DWORD LastError = ERROR_SUCCESS; - HANDLE Mutex = NamespaceTakePoolMutex(Adapter->Pool); - if (!Mutex) - { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Adapter->Pool); - goto cleanup; - } - - SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; - if (!SetupDiGetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) + WCHAR InstanceId[MAX_INSTANCE_ID]; + DWORD RequiredChars = _countof(InstanceId); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredChars, &RequiredChars)) { - LastError = LOG_LAST_ERROR( - L"Failed to retrieve adapter %u device installation parameters", Adapter->DevInfoData.DevInst); - goto cleanupMutex; + LOG_LAST_ERROR(L"Failed to get adapter instance ID"); + return FALSE; } - DevInstallParams.Flags |= DI_QUIETINSTALL; - if (!SetupDiSetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) + WINTUN_ADAPTER Adapter = { .InterfaceFilename = AdapterGetDeviceObjectFileName(InstanceId) }; + if (!Adapter.InterfaceFilename) { - LastError = - LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", Adapter->DevInfoData.DevInst); - goto cleanupMutex; - } - - if (ForceCloseSessions && !ForceCloseWintunAdapterHandle(Adapter->DevInfo, &Adapter->DevInfoData)) - LOG(WINTUN_LOG_WARN, L"Failed to force close adapter %u handles", Adapter->DevInfoData.DevInst); - - 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); - - *RebootRequired = *RebootRequired || CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData); - -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - return RET_ERROR(TRUE, LastError); -} - -static _Return_type_success_(return != FALSE) -BOOL -DeleteAllOurAdapters(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired) -{ - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) - { - LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Pool); + LOG_LAST_ERROR(L"Failed to get adapter file name"); return FALSE; } - DWORD LastError = ERROR_SUCCESS; - HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (DevInfo == INVALID_HANDLE_VALUE) + HANDLE Handle = AdapterOpenDeviceObject(&Adapter); + Free(Adapter.InterfaceFilename); + if (Handle == INVALID_HANDLE_VALUE) { - LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); - goto cleanupMutex; + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get adapter file object"); + return FALSE; } - SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_REMOVE }, - .Scope = DI_REMOVEDEVICE_GLOBAL }; - for (DWORD EnumIndex = 0;; ++EnumIndex) + DWORD RequiredBytes; + if (DeviceIoControl(Handle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL)) { - SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; - if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } - - if (!IsOurAdapter(DevInfo, &DevInfoData) || !IsPoolMember(Pool, DevInfo, &DevInfoData)) - continue; - - LOG(WINTUN_LOG_INFO, L"Force closing all adapter %u open handles", DevInfoData.DevInst); - if (!ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData)) - LOG(WINTUN_LOG_WARN, L"Failed to force close adapter %u handles", DevInfoData.DevInst); - - LOG(WINTUN_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); + LastError = ERROR_SUCCESS; + Sleep(200); } - SetupDiDestroyDeviceInfoList(DevInfo); -cleanupMutex: - NamespaceReleaseMutex(Mutex); + else if (GetLastError() == ERROR_NOTHING_TO_TERMINATE) + LastError = ERROR_SUCCESS; + else + LastError = LOG_LAST_ERROR(L"Failed to perform force close ioctl"); + CloseHandle(Handle); return RET_ERROR(TRUE, LastError); } _Use_decl_annotations_ -BOOL WINAPI -WintunDeletePoolDriver(LPCWSTR Pool, BOOL *RebootRequired) +BOOL +AdapterRemoveInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - BOOL DummyRebootRequired; - if (!RebootRequired) - RebootRequired = &DummyRebootRequired; - *RebootRequired = FALSE; - - DWORD LastError = ERROR_SUCCESS; #ifdef MAYBE_WOW64 if (NativeMachine != IMAGE_FILE_PROCESS) - { - LastError = DeletePoolDriverViaRundll32(Pool, RebootRequired) ? ERROR_SUCCESS : GetLastError(); - goto cleanup; - } + return RemoveInstanceViaRundll32(DevInfo, DevInfoData); #endif - if (!DeleteAllOurAdapters(Pool, RebootRequired)) - { - LastError = GetLastError(); - goto cleanup; - } - - HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); - if (!DriverInstallationLock) - { - LastError = LOG(WINTUN_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)) - { - LastError = LOG_LAST_ERROR(L"Failed building driver info list"); - goto cleanupDeviceInfoSet; - } - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - 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, WINTUN_HWID)) - { - LPCWSTR Path = PathFindFileNameW(DriverDetail->InfFileName); - LOG(WINTUN_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); - } - SetupDiDestroyDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER); -cleanupDeviceInfoSet: - SetupDiDestroyDeviceInfoList(DeviceInfoSet); -cleanupDriverInstallationLock: - NamespaceReleaseMutex(DriverInstallationLock); -cleanup: - return RET_ERROR(TRUE, LastError); + 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 -WintunEnumAdapters(LPCWSTR Pool, WINTUN_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(WINTUN_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) - { - WINTUN_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(WINTUN_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); } |