diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-10-11 23:21:31 -0600 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-10-12 18:54:20 +0000 |
commit | 544fdaaf8fb970d9657a59c1fc4c4569de4f2d3e (patch) | |
tree | 715e49e1f325bf7795face50ff84936b05ab86e2 /api | |
parent | proj: remove SDV and DVL support (diff) | |
download | wintun-544fdaaf8fb970d9657a59c1fc4c4569de4f2d3e.tar.xz wintun-544fdaaf8fb970d9657a59c1fc4c4569de4f2d3e.zip |
api: rewrite based on SwDevice
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'api')
-rw-r--r-- | api/adapter.c | 2225 | ||||
-rw-r--r-- | api/adapter.h | 128 | ||||
-rw-r--r-- | api/adapter_win7.h | 351 | ||||
-rw-r--r-- | api/api.vcxproj | 18 | ||||
-rw-r--r-- | api/api.vcxproj.filters | 17 | ||||
-rw-r--r-- | api/driver.c | 587 | ||||
-rw-r--r-- | api/driver.h | 34 | ||||
-rw-r--r-- | api/exports.def | 8 | ||||
-rw-r--r-- | api/logger.c | 47 | ||||
-rw-r--r-- | api/logger.h | 47 | ||||
-rw-r--r-- | api/main.c | 19 | ||||
-rw-r--r-- | api/main.h | 13 | ||||
-rw-r--r-- | api/namespace.c | 108 | ||||
-rw-r--r-- | api/namespace.h | 4 | ||||
-rw-r--r-- | api/ntdll.h | 1 | ||||
-rw-r--r-- | api/registry.c | 241 | ||||
-rw-r--r-- | api/registry.h | 81 | ||||
-rw-r--r-- | api/resources.rc | 14 | ||||
-rw-r--r-- | api/rundll32.c | 321 | ||||
-rw-r--r-- | api/rundll32.h | 25 | ||||
-rw-r--r-- | api/session.c | 14 | ||||
-rw-r--r-- | api/wintun.h | 192 |
22 files changed, 1977 insertions, 2518 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); } diff --git a/api/adapter.h b/api/adapter.h index 5f468b0..ec84d70 100644 --- a/api/adapter.h +++ b/api/adapter.h @@ -12,97 +12,141 @@ #define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ #define WINTUN_HWID L"Wintun" +#define WINTUN_ENUMERATOR (IsWindows7 ? L"ROOT\\" WINTUN_HWID : L"SWD\\" WINTUN_HWID) + +extern const DEVPROPKEY DEVPKEY_Wintun_Name; + +typedef struct HSWDEVICE__ *HSWDEVICE; /** * Wintun adapter descriptor. */ typedef struct _WINTUN_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[WINTUN_MAX_POOL]; } WINTUN_ADAPTER; - -/** - * @copydoc WINTUN_FREE_ADAPTER_FUNC - */ -WINTUN_FREE_ADAPTER_FUNC_IMPL WintunFreeAdapter; - /** * @copydoc WINTUN_CREATE_ADAPTER_FUNC */ -WINTUN_CREATE_ADAPTER_FUNC_IMPL WintunCreateAdapter; +WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter; /** * @copydoc WINTUN_OPEN_ADAPTER_FUNC */ -WINTUN_OPEN_ADAPTER_FUNC_IMPL WintunOpenAdapter; +WINTUN_OPEN_ADAPTER_FUNC WintunOpenAdapter; /** - * @copydoc WINTUN_DELETE_ADAPTER_FUNC + * @copydoc WINTUN_CLOSE_ADAPTER_FUNC */ -WINTUN_DELETE_ADAPTER_FUNC_IMPL WintunDeleteAdapter; +WINTUN_CLOSE_ADAPTER_FUNC WintunCloseAdapter; /** - * @copydoc WINTUN_ENUM_ADAPTERS_FUNC + * @copydoc WINTUN_GET_ADAPTER_LUID_FUNC */ -WINTUN_ENUM_ADAPTERS_FUNC_IMPL WintunEnumAdapters; +WINTUN_GET_ADAPTER_LUID_FUNC WintunGetAdapterLUID; /** - * @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC + * Returns a handle to the adapter device object. + * + * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. + * + * @return If the function succeeds, the return value is adapter device object handle. + * If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error + * information, call GetLastError. */ -WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL WintunDeletePoolDriver; +_Return_type_success_(return != INVALID_HANDLE_VALUE) +HANDLE WINAPI +AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter); /** - * @copydoc WINTUN_GET_ADAPTER_LUID_FUNC + * Returns the device object file name for an adapter instance ID. + * + * @param InstanceID The device instance ID of the adapter. + * + * @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. */ -WINTUN_GET_ADAPTER_LUID_FUNC_IMPL WintunGetAdapterLUID; +_Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +LPWSTR +AdapterGetDeviceObjectFileName(_In_z_ LPCWSTR InstanceId); /** - * @copydoc WINTUN_GET_ADAPTER_NAME_FUNC + * Cleans up adapters with no attached process. */ -WINTUN_GET_ADAPTER_NAME_FUNC_IMPL WintunGetAdapterName; +VOID AdapterCleanupOrphanedDevices(VOID); /** - * @copydoc WINTUN_SET_ADAPTER_NAME_FUNC + * Cleans up adapters that use the old enumerator. */ -WINTUN_SET_ADAPTER_NAME_FUNC_IMPL WintunSetAdapterName; +VOID AdapterCleanupLegacyDevices(VOID); /** - * @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC + * 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. */ -WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL WintunGetRunningDriverVersion; + +_Return_type_success_(return != FALSE) +BOOL +AdapterRemoveInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); /** - * Returns a handle to the adapter device object. + * Enables the specified device instance. * - * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. + * @param DevInfo Device info handle from SetupAPI. + * @param DevInfoData Device info data specifying which device. * - * @return If the function succeeds, the return value is adapter device object handle. - * If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error - * information, call GetLastError. + * @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 != INVALID_HANDLE_VALUE) -HANDLE WINAPI -AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter); + +_Return_type_success_(return != FALSE) +BOOL +AdapterEnableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); + /** - * Returns an adapter object based on a devnode instance ID. + * Disables the specified device instance. * - * @param Pool Pool name of adapter object to be opened. + * @param DevInfo Device info handle from SetupAPI. + * @param DevInfoData Device info data specifying which device. * - * @param DevInstanceID Instance ID of devnode for opening adapter. + * @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); + +/** + * Force closes all device handles of the specified device instance. * - * @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. + * @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. */ -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -WINTUN_ADAPTER * -AdapterOpenFromDevInstanceId(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR DevInstanceID); + +_Return_type_success_(return != FALSE) +BOOL +AdapterForceCloseHandles(_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..affbd09 --- /dev/null +++ b/api/adapter_win7.h @@ -0,0 +1,351 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +static const DEVPROPKEY DEVPKEY_Wintun_OwningProcess = { + { 0x3361c968, 0x2f2e, 0x4660, { 0xb4, 0x7e, 0x69, 0x9c, 0xdc, 0x4c, 0x32, 0xb9 } }, + 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; + HANDLE FileHandle = INVALID_HANDLE_VALUE; + BOOLEAN Ret = FALSE; + for (DWORD Tries = 0; Tries < 1500; ++Tries) + { + if (Tries) + Sleep(10); + if (Key == INVALID_HANDLE_VALUE) + Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + if (!FileName) + FileName = AdapterGetDeviceObjectFileName(DevInstanceId); + if (FileName && FileHandle == INVALID_HANDLE_VALUE) + FileHandle = CreateFileW( + FileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + 0, + NULL); + Zero = 0; + if (FileName && FileHandle != INVALID_HANDLE_VALUE && Key != INVALID_HANDLE_VALUE && Key && + 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 && Key) + RegCloseKey(Key); + if (FileHandle != INVALID_HANDLE_VALUE) + CloseHandle(FileHandle); + Free(FileName); + return Ret; +} + +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +CreateAdapterWin7(_Inout_ WINTUN_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, WINTUN_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(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_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_Wintun_Name, + DEVPROP_TYPE_STRING, + (PBYTE)Name, + (DWORD)((wcslen(Name) + 1) * sizeof(Name[0])), + 0) || + !SetupDiSetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Wintun_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_ WINTUN_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, WINTUN_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_Wintun_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_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); +} + +VOID AdapterCleanupLegacyDevices(VOID) +{ + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"ROOT\\NET", NULL, 0, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + 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; + } + WCHAR HardwareIDs[0x400] = { 0 }; + DWORD ValueType, Size = sizeof(HardwareIDs) - sizeof(HardwareIDs[0]); + if (!SetupDiGetDeviceRegistryPropertyW( + DevInfo, &DevInfoData, SPDRP_HARDWAREID, &ValueType, (PBYTE)HardwareIDs, Size, &Size) || + Size > sizeof(HardwareIDs) - sizeof(HardwareIDs[0])) + continue; + Size /= sizeof(HardwareIDs[0]); + for (WCHAR *P = HardwareIDs; P < HardwareIDs + Size; P += wcslen(P) + 1) + { + if (!_wcsicmp(P, WINTUN_HWID)) + { + AdapterRemoveInstance(DevInfo, &DevInfoData); + break; + } + } + } + SetupDiDestroyDeviceInfoList(DevInfo); +}
\ No newline at end of file diff --git a/api/api.vcxproj b/api/api.vcxproj index 2155ef5..d0d0dcb 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)\$(WintunPlatform);..\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\arm64\wintun.dll')">BUILT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\amd64\wintun.dll')">BUILT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\arm64\driver\wintun.sys') And Exists('..\$(Configuration)\arm64\setupapihost.dll')">BUILT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\amd64\driver\wintun.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;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;$(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" /> @@ -88,4 +92,4 @@ <Target Name="CleanNci"> <Delete Files="$(IntDir)nci.obj;$(IntDir)nci.lib" /> </Target> -</Project>
\ No newline at end of file +</Project> diff --git a/api/api.vcxproj.filters b/api/api.vcxproj.filters index 1a31cf2..5fb8b10 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 +</Project> diff --git a/api/driver.c b/api/driver.c new file mode 100644 index 0000000..3fb4909 --- /dev/null +++ b/api/driver.c @@ -0,0 +1,587 @@ +/* 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 "adapter.h" +#include "logger.h" +#include "namespace.h" +#include "resource.h" +#include "registry.h" +#include "ntdll.h" +#include "rundll32.h" +#include "wintun-inf.h" + +#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ + +struct _SP_DEVINFO_DATA_LIST +{ + SP_DEVINFO_DATA Data; + struct _SP_DEVINFO_DATA_LIST *Next; +}; + +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_Wintun_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(WINTUN_LOG_INFO, L"Force closing adapter \"%s\" open handles", Name); + if (!AdapterForceCloseHandles(DevInfo, &DeviceNode->Data)) + LOG(WINTUN_LOG_WARN, L"Failed to force close adapter \"%s\" open handles", Name); + + LOG(WINTUN_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_Wintun_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + + LOG(WINTUN_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(); + } + } + 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(WINTUN_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(WINTUN_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], "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; + } + } + LastError = ERROR_FILE_NOT_FOUND; +cleanupModules: + Free(Modules); + return RET_ERROR(Version, LastError); +} + +_Use_decl_annotations_ +DWORD WINAPI WintunGetRunningDriverVersion(VOID) +{ + return MaybeGetRunningDriverVersion(FALSE); +} + +static BOOL EnsureWintunUnloaded(VOID) +{ + BOOL Loaded; + for (DWORD Tries = 0; Tries < 1500; ++Tries) + { + if (Tries) + Sleep(50); + Loaded = MaybeGetRunningDriverVersion(TRUE) != 0; + if (!Loaded) + break; + } + 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); + 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 = 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 = 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, WINTUN_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(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_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, WINTUN_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(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)); + 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(WINTUN_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(WINTUN_LOG_INFO, + L"Using existing driver %u.%u", + (DWORD)((DriverVersion & 0xffff000000000000) >> 48), + (DWORD)((DriverVersion & 0x0000ffff00000000) >> 32)); + LastError = ERROR_SUCCESS; + goto cleanupExistingAdapters; + } + + 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; + } + + 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")) + { + LastError = ERROR_BUFFER_OVERFLOW; + goto cleanupDirectory; + } + + WCHAR *CatSource, *SysSource, *InfSource; + if (NativeMachine == IMAGE_FILE_PROCESS) + { + CatSource = L"wintun.cat"; + SysSource = L"wintun.sys"; + InfSource = L"wintun.inf"; + } + else if (NativeMachine == IMAGE_FILE_MACHINE_AMD64) + { + CatSource = L"wintun-amd64.cat"; + SysSource = L"wintun-amd64.sys"; + InfSource = L"wintun-amd64.inf"; + } + else if (NativeMachine == IMAGE_FILE_MACHINE_ARM64) + { + CatSource = L"wintun-arm64.cat"; + SysSource = L"wintun-arm64.sys"; + InfSource = L"wintun-arm64.inf"; + } + else + { + LastError = LOG_ERROR(ERROR_NOT_SUPPORTED, L"Unsupported platform 0x%x", NativeMachine); + goto cleanupDirectory; + } + + LOG(WINTUN_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(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"); + 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 WintunDeleteDriver(VOID) +{ + DWORD LastError = ERROR_SUCCESS; + + AdapterCleanupOrphanedDevices(); + + HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); + if (!DriverInstallationLock) + { + LastError = LOG(WINTUN_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, WINTUN_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(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_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(WINTUN_LOG_WARN, L"Failed getting adapter driver info detail"); + continue; + } + LPCWSTR Path = PathFindFileNameW(DrvInfoDetailData->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(); + } + } + 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..dae4e9b --- /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 "wintun.h" +#include <Windows.h> +#include <SetupAPI.h> + +#define WINTUN_HWID L"Wintun" + +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 WINTUN_DELETE_DRIVER_FUNC + */ +WINTUN_DELETE_DRIVER_FUNC WintunDeleteDriver; + +/** + * @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC + */ +WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC WintunGetRunningDriverVersion; diff --git a/api/exports.def b/api/exports.def index 3539ad8..c12db57 100644 --- a/api/exports.def +++ b/api/exports.def @@ -2,19 +2,15 @@ LIBRARY wintun.dll EXPORTS WintunAllocateSendPacket WintunCreateAdapter - WintunDeleteAdapter - WintunDeletePoolDriver WintunEndSession - WintunEnumAdapters - WintunFreeAdapter WintunOpenAdapter + WintunCloseAdapter WintunGetAdapterLUID - WintunGetAdapterName WintunGetReadWaitEvent WintunGetRunningDriverVersion WintunReceivePacket WintunReleaseReceivePacket WintunSendPacket - WintunSetAdapterName + WintunDeleteDriver WintunSetLogger WintunStartSession diff --git a/api/logger.c b/api/logger.c index 71dff5b..94ce525 100644 --- a/api/logger.c +++ b/api/logger.c @@ -7,18 +7,26 @@ #include "adapter.h" #include "ntdll.h" #include <Windows.h> +#include <iphlpapi.h> #include <winternl.h> #include <wchar.h> #include <stdlib.h> static BOOL CALLBACK -NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine) +NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ LPCWSTR LogLine) { return TRUE; } WINTUN_LOGGER_CALLBACK Logger = NopLogger; +static DWORD64 Now(VOID) +{ + LARGE_INTEGER Timestamp; + NtQuerySystemTime(&Timestamp); + return Timestamp.QuadPart; +} + _Use_decl_annotations_ VOID WINAPI WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger) @@ -37,41 +45,30 @@ StrTruncate(_Inout_count_(StrChars) LPWSTR Str, _In_ SIZE_T StrChars) _Use_decl_annotations_ DWORD -LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR LogLine) +LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR LogLine) { DWORD LastError = GetLastError(); - if (Function) - { - WCHAR Combined[0x400]; - if (_snwprintf_s(Combined, _countof(Combined), _TRUNCATE, L"%s: %s", Function, LogLine) == -1) - StrTruncate(Combined, _countof(Combined)); - Logger(Level, Combined); - } - else - Logger(Level, LogLine); + Logger(Level, Now(), LogLine); SetLastError(LastError); return LastError; } _Use_decl_annotations_ DWORD -LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR Format, va_list Args) +LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Format, va_list Args) { DWORD LastError = GetLastError(); WCHAR LogLine[0x400]; if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1) StrTruncate(LogLine, _countof(LogLine)); - if (Function) - LoggerLog(Level, Function, LogLine); - else - Logger(Level, LogLine); + Logger(Level, Now(), LogLine); SetLastError(LastError); return LastError; } _Use_decl_annotations_ DWORD -LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix) +LoggerError(DWORD Error, LPCWSTR Prefix) { LPWSTR SystemMessage = NULL, FormattedMessage = NULL; FormatMessageW( @@ -85,14 +82,14 @@ LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix) FormatMessageW( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_MAX_WIDTH_MASK, - SystemMessage ? L"%4: %1: %3(Code 0x%2!08X!)" : L"%4: %1: Code 0x%2!08X!", + SystemMessage ? L"%1: %3(Code 0x%2!08X!)" : L"%1: Code 0x%2!08X!", 0, 0, (VOID *)&FormattedMessage, 0, - (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function }); + (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage }); if (FormattedMessage) - Logger(WINTUN_LOG_ERR, FormattedMessage); + Logger(WINTUN_LOG_ERR, Now(), FormattedMessage); LocalFree(FormattedMessage); LocalFree(SystemMessage); return Error; @@ -100,12 +97,12 @@ LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix) _Use_decl_annotations_ DWORD -LoggerErrorV(DWORD Error, LPCWSTR Function, LPCWSTR Format, va_list Args) +LoggerErrorV(DWORD Error, LPCWSTR Format, va_list Args) { - WCHAR Prefix[0x400]; - if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1) - StrTruncate(Prefix, _countof(Prefix)); - return LoggerError(Error, Function, Prefix); + WCHAR LogLine[0x400]; + if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1) + StrTruncate(LogLine, _countof(LogLine)); + return LoggerError(Error, LogLine); } _Use_decl_annotations_ diff --git a/api/logger.h b/api/logger.h index 72853cc..d83839e 100644 --- a/api/logger.h +++ b/api/logger.h @@ -18,71 +18,63 @@ extern WINTUN_LOGGER_CALLBACK Logger; /** * @copydoc WINTUN_SET_LOGGER_FUNC */ -WINTUN_SET_LOGGER_FUNC_IMPL WintunSetLogger; +WINTUN_SET_LOGGER_FUNC WintunSetLogger; _Post_equals_last_error_ DWORD -LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR LogLine); +LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine); _Post_equals_last_error_ DWORD -LoggerLogV( - _In_ WINTUN_LOGGER_LEVEL Level, - _In_z_ LPCWSTR Function, - _In_z_ _Printf_format_string_ LPCWSTR Format, - _In_ va_list Args); +LoggerLogV(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args); _Post_equals_last_error_ static inline DWORD -LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) +LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) { va_list Args; va_start(Args, Format); - DWORD LastError = LoggerLogV(Level, Function, Format, Args); + DWORD LastError = LoggerLogV(Level, Format, Args); va_end(Args); return LastError; } _Post_equals_last_error_ DWORD -LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR Prefix); +LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Prefix); _Post_equals_last_error_ DWORD -LoggerErrorV( - _In_ DWORD Error, - _In_z_ LPCWSTR Function, - _In_z_ _Printf_format_string_ LPCWSTR Format, - _In_ va_list Args); +LoggerErrorV(_In_ DWORD Error, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args); _Post_equals_last_error_ static inline DWORD -LoggerErrorFmt(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) +LoggerErrorFmt(_In_ DWORD Error, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) { va_list Args; va_start(Args, Format); - DWORD LastError = LoggerErrorV(Error, Function, Format, Args); + DWORD LastError = LoggerErrorV(Error, Format, Args); va_end(Args); return LastError; } _Post_equals_last_error_ static inline DWORD -LoggerLastErrorV(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args) +LoggerLastErrorV(_In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args) { DWORD LastError = GetLastError(); - LoggerErrorV(LastError, Function, Format, Args); + LoggerErrorV(LastError, Format, Args); SetLastError(LastError); return LastError; } _Post_equals_last_error_ static inline DWORD -LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) +LoggerLastErrorFmt(_In_z_ _Printf_format_string_ LPCWSTR Format, ...) { va_list Args; va_start(Args, Format); - DWORD LastError = LoggerLastErrorV(Function, Format, Args); + DWORD LastError = LoggerLastErrorV(Format, Args); va_end(Args); return LastError; } @@ -90,11 +82,9 @@ LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWST VOID LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path); -#define __L(x) L##x -#define _L(x) __L(x) -#define LOG(lvl, msg, ...) (LoggerLogFmt((lvl), _L(__FUNCTION__), msg, __VA_ARGS__)) -#define LOG_ERROR(err, msg, ...) (LoggerErrorFmt((err), _L(__FUNCTION__), msg, __VA_ARGS__)) -#define LOG_LAST_ERROR(msg, ...) (LoggerLastErrorFmt(_L(__FUNCTION__), msg, __VA_ARGS__)) +#define LOG(lvl, msg, ...) (LoggerLogFmt((lvl), msg, __VA_ARGS__)) +#define LOG_ERROR(err, msg, ...) (LoggerErrorFmt((err), msg, __VA_ARGS__)) +#define LOG_LAST_ERROR(msg, ...) (LoggerLastErrorFmt(msg, __VA_ARGS__)) #define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0)) @@ -130,6 +120,9 @@ LoggerReAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _Frees_ptr_opt_ LPVOID } return Data; } + +#define __L(x) L##x +#define _L(x) __L(x) #define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size) #define ReAlloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), 0, Mem, Size) #define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size) @@ -179,4 +172,4 @@ Free(_Frees_ptr_opt_ VOID *Ptr) DWORD LastError = GetLastError(); HeapFree(ModuleHeap, 0, Ptr); SetLastError(LastError); -}
\ No newline at end of file +} @@ -21,7 +21,13 @@ HANDLE ModuleHeap; SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) }; BOOL IsLocalSystem; USHORT NativeMachine = IMAGE_FILE_PROCESS; + +#if NTDDI_VERSION == NTDDI_WIN7 +BOOL IsWindows7; +#endif +#if NTDDI_VERSION < NTDDI_WIN10 BOOL IsWindows10; +#endif static FARPROC WINAPI DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) @@ -70,11 +76,17 @@ cleanupProcessToken: return Ret; } -static VOID EnvInit(VOID) +static void EnvInit(VOID) { - DWORD MajorVersion; - RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL); + DWORD MajorVersion, MinorVersion; + RtlGetNtVersionNumbers(&MajorVersion, &MinorVersion, NULL); + +#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)( @@ -110,6 +122,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) } EnvInit(); NamespaceInit(); + AdapterCleanupLegacyDevices(); break; case DLL_PROCESS_DETACH: @@ -24,4 +24,15 @@ extern HANDLE ModuleHeap; extern SECURITY_ATTRIBUTES SecurityAttributes; extern BOOL IsLocalSystem; extern USHORT NativeMachine; -extern BOOL IsWindows10;
\ 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 760dc6f..3248edb 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(WINTUN_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"Wintun", 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,86 +79,36 @@ cleanupLeaveCriticalSection: _Use_decl_annotations_ HANDLE -NamespaceTakePoolMutex(LPCWSTR Pool) +NamespaceTakeDriverInstallationMutex(VOID) { if (!NamespaceRuntimeInit()) return NULL; - - BCRYPT_HASH_HANDLE Sha256 = NULL; - NTSTATUS Status; - if (!BCRYPT_SUCCESS(Status = BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0))) - { - LOG(WINTUN_LOG_ERR, L"Failed to create hash (status: 0x%x)", Status); - SetLastError(RtlNtStatusToDosError(Status)); - return NULL; - } - DWORD LastError; - static const WCHAR mutex_label[] = L"Wintun 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(WINTUN_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(WINTUN_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(WINTUN_LOG_ERR, L"Failed to calculate hash (status: 0x%x)", Status); - LastError = RtlNtStatusToDosError(Status); - goto cleanupPoolNorm; - } - static const WCHAR MutexNamePrefix[] = L"Wintun\\Wintun-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); + HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex"); if (!Mutex) { - LastError = LOG_LAST_ERROR(L"Failed to create mutex %s", MutexName); - goto cleanupPoolNorm; + LOG_LAST_ERROR(L"Failed to create mutex"); + return NULL; } DWORD Result = WaitForSingleObject(Mutex, INFINITE); switch (Result) { case WAIT_OBJECT_0: case WAIT_ABANDONED: - Free(PoolNorm); - BCryptDestroyHash(Sha256); return Mutex; } - LOG(WINTUN_LOG_ERR, L"Failed to get mutex %s (status: 0x%x)", MutexName, Result); - LastError = ERROR_GEN_FAILURE; + LOG(WINTUN_LOG_ERR, L"Failed to get mutex (status: 0x%x)", Result); CloseHandle(Mutex); -cleanupPoolNorm: - Free(PoolNorm); -cleanupSha256: - BCryptDestroyHash(Sha256); - SetLastError(LastError); + SetLastError(ERROR_GEN_FAILURE); return NULL; } _Use_decl_annotations_ HANDLE -NamespaceTakeDriverInstallationMutex(VOID) +NamespaceTakeDeviceInstallationMutex(VOID) { if (!NamespaceRuntimeInit()) return NULL; - HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex"); + HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Device-Installation-Mutex"); if (!Mutex) { LOG_LAST_ERROR(L"Failed to create mutex"); @@ -232,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 cbd9100..a0397be 100644 --- a/api/namespace.h +++ b/api/namespace.h @@ -12,14 +12,14 @@ _Return_type_success_(return != NULL) _Post_maybenull_ _Acquires_lock_(_Curr_) HANDLE -NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool); +NamespaceTakeDriverInstallationMutex(VOID); _Must_inspect_result_ _Return_type_success_(return != NULL) _Post_maybenull_ _Acquires_lock_(_Curr_) HANDLE -NamespaceTakeDriverInstallationMutex(VOID); +NamespaceTakeDeviceInstallationMutex(VOID); _Releases_lock_(Mutex) VOID diff --git a/api/ntdll.h b/api/ntdll.h index 3782a30..2eb2786 100644 --- a/api/ntdll.h +++ b/api/ntdll.h @@ -39,7 +39,6 @@ typedef struct _KEY_NAME_INFORMATION } KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION; #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) // TODO: #include <ntstatus.h> instead of this -#define STATUS_PNP_DEVICE_CONFIGURATION_PENDING ((NTSTATUS)0xC0000495L) /* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista * when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers. diff --git a/api/registry.c b/api/registry.c index d385d86..4f1001c 100644 --- a/api/registry.c +++ b/api/registry.c @@ -10,100 +10,6 @@ #include <stdlib.h> #include <strsafe.h> -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -HKEY -OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) -{ - DWORD LastError; - LPWSTR PathNext = wcschr(Path, L'\\'); - if (PathNext) - *PathNext = 0; - - HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!Event) - { - LOG_LAST_ERROR(L"Failed to create event"); - return NULL; - } - for (;;) - { - LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE); - if (LastError != ERROR_SUCCESS) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); - break; - } - - HKEY Subkey; - LastError = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey); - if (LastError == ERROR_SUCCESS) - { - if (PathNext) - { - HKEY KeyOut = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline); - if (KeyOut) - { - RegCloseKey(Subkey); - CloseHandle(Event); - return KeyOut; - } - LastError = GetLastError(); - break; - } - else - { - CloseHandle(Event); - return Subkey; - } - } - if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to open registry key %.*s\\%s", MAX_REG_PATH, RegPath, Path); - break; - } - - LONGLONG TimeLeft = Deadline - GetTickCount64(); - if (TimeLeft < 0) - TimeLeft = 0; - DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft); - if (Result != WAIT_OBJECT_0) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG(WINTUN_LOG_ERR, - L"Timeout waiting for registry key %.*s\\%s (status: 0x%x)", - MAX_REG_PATH, - RegPath, - Path, - Result); - break; - } - } - CloseHandle(Event); - SetLastError(LastError); - return NULL; -} - -_Use_decl_annotations_ -HKEY -RegistryOpenKeyWait(HKEY Key, LPCWSTR Path, DWORD Access, DWORD Timeout) -{ - WCHAR Buf[MAX_REG_PATH]; - if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE) - { - LOG(WINTUN_LOG_ERR, L"Registry path too long: %s", Path); - SetLastError(ERROR_INVALID_PARAMETER); - return NULL; - } - return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout); -} - _Use_decl_annotations_ BOOL RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType) @@ -150,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_ @@ -257,59 +121,6 @@ RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log) } _Use_decl_annotations_ -LPWSTR -RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout) -{ - DWORD LastError; - ULONGLONG Deadline = GetTickCount64() + Timeout; - HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!Event) - { - LOG_LAST_ERROR(L"Failed to create event"); - return NULL; - } - for (;;) - { - LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); - if (LastError != ERROR_SUCCESS) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); - break; - } - LPWSTR Value = RegistryQueryString(Key, Name, FALSE); - if (Value) - { - CloseHandle(Event); - return Value; - } - LastError = GetLastError(); - if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) - break; - LONGLONG TimeLeft = Deadline - GetTickCount64(); - if (TimeLeft < 0) - TimeLeft = 0; - DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft); - if (Result != WAIT_OBJECT_0) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG(WINTUN_LOG_ERR, - L"Timeout waiting for registry value %.*s\\%s (status: 0x%x)", - MAX_REG_PATH, - RegPath, - Name, - Result); - break; - } - } - CloseHandle(Event); - SetLastError(LastError); - return NULL; -} - -_Use_decl_annotations_ BOOL RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log) { @@ -344,55 +155,3 @@ RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log) } return TRUE; } - -_Use_decl_annotations_ -BOOL -RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value) -{ - DWORD LastError; - ULONGLONG Deadline = GetTickCount64() + Timeout; - HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!Event) - { - LOG_LAST_ERROR(L"Failed to create event"); - return FALSE; - } - for (;;) - { - LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); - if (LastError != ERROR_SUCCESS) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); - break; - } - if (RegistryQueryDWORD(Key, Name, Value, FALSE)) - { - CloseHandle(Event); - return TRUE; - } - LastError = GetLastError(); - if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) - break; - LONGLONG TimeLeft = Deadline - GetTickCount64(); - if (TimeLeft < 0) - TimeLeft = 0; - DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft); - if (Result != WAIT_OBJECT_0) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG(WINTUN_LOG_ERR, - L"Timeout waiting registry value %.*s\\%s (status: 0x%x)", - MAX_REG_PATH, - RegPath, - Name, - Result); - break; - } - } - CloseHandle(Event); - SetLastError(LastError); - return FALSE; -} diff --git a/api/registry.h b/api/registry.h index 7a366b0..6beed2f 100644 --- a/api/registry.h +++ b/api/registry.h @@ -13,26 +13,6 @@ https://support.microsoft.com/en-us/help/256986/windows-registry-information-for-advanced-users */ /** - * Opens the specified registry key. It waits for the registry key to become available. - * - * @param Key Handle of the parent registry key. Must be opened with notify access. - * - * @param Path Subpath of the registry key to open. Zero-terminated string of up to MAX_REG_PATH-1 characters. - * - * @param Access A mask that specifies the desired access rights to the key to be opened. - * - * @param Timeout Timeout to wait for the value in milliseconds. - * - * @return Key handle on success. If the function fails, the return value is zero. To get extended error information, - * call GetLastError. - */ -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -HKEY -RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ LPCWSTR Path, _In_ DWORD Access, _In_ DWORD Timeout); - -/** * Validates and/or sanitizes 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 @@ -53,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. @@ -97,27 +58,6 @@ LPWSTR RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ BOOL Log); /** - * Reads string value from registry key. It waits for the registry value to become available. - * - * @param Key Handle of the registry key to read from. Must be opened with read and notify access. - * - * @param Name Name of the value to read. - * - * @param Timeout Timeout to wait for the value in milliseconds. - * - * @return Registry value. If the value type is REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings(). If - * the value type is REG_MULTI_SZ, only the first string from the multi-string is returned. The string must be - * released with HeapFree(ModuleHeap, 0, Value) after use. If the function fails, the return value is zero. To - * get extended error information, call GetLastError. Possible errors include the following: - * ERROR_INVALID_DATATYPE when the registry value is not a string - */ -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -LPWSTR -RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout); - -/** * Reads a 32-bit DWORD value from registry key. * * @param Key Handle of the registry key to read from. Must be opened with read access. @@ -137,24 +77,3 @@ _Must_inspect_result_ _Return_type_success_(return != FALSE) BOOL RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log); - -/** - * Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available. - * - * @param Key Handle of the registry key to read from. Must be opened with read access. - * - * @param Name Name of the value to read. - * - * @param Timeout Timeout to wait for the value in milliseconds. - * - * @param Value Pointer to DWORD to retrieve registry value. - * - * @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. Possible errors include the following: - * ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type; - * ERROR_INVALID_DATA when registry value size is not 4 bytes - */ -_Must_inspect_result_ -_Return_type_success_(return != FALSE) -BOOL -RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value); diff --git a/api/resources.rc b/api/resources.rc index 822ed3f..ca0aacd 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) -wintun-amd64.dll RCDATA "amd64\\wintun.dll" +wintun-amd64.cat RCDATA "amd64\\driver\\wintun.cat" +wintun-amd64.inf RCDATA "amd64\\driver\\wintun.inf" +wintun-amd64.sys RCDATA "amd64\\driver\\wintun.sys" +setupapihost-amd64.dll RCDATA "amd64\\setupapihost.dll" # else -# pragma message("AMD64 wintun.dll was not built, so this will not work from WOW64") +# pragma message("AMD64 wintun.sys was not built, so this will not work from WOW64") # endif #endif #if defined(WANT_ARM64_WOW64) # if defined(BUILT_ARM64_WOW64) -wintun-arm64.dll RCDATA "arm64\\wintun.dll" +wintun-arm64.cat RCDATA "arm64\\driver\\wintun.cat" +wintun-arm64.inf RCDATA "arm64\\driver\\wintun.inf" +wintun-arm64.sys RCDATA "arm64\\driver\\wintun.sys" +setupapihost-arm64.dll RCDATA "arm64\\setupapihost.dll" # else -# pragma message("ARM64 wintun.dll was not built, so this will not work from WOW64") +# pragma message("ARM64 wintun.sys was not built, so this will not work from WOW64") # endif #endif diff --git a/api/rundll32.c b/api/rundll32.c index 37d4387..6bdc7c9 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -15,134 +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_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine) -{ - LPCWSTR Template; - switch (Level) - { - case WINTUN_LOG_INFO: - Template = L"[+] %1\n"; - break; - case WINTUN_LOG_WARN: - Template = L"[-] %1\n"; - break; - case WINTUN_LOG_ERR: - Template = L"[!] %1\n"; - break; - default: - return; - } - WriteFormatted(STD_ERROR_HANDLE, Template, LogLine); -} - -VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WintunSetLogger(ConsoleLogger); - - if (Argc < 4) - goto cleanup; - if (wcslen(Argv[2]) >= WINTUN_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; - - BOOL RebootRequired; - WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired); - DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError(); - WriteFormatted( - STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"\"\"", RebootRequired); - if (Adapter) - WintunFreeAdapter(Adapter); - -cleanup: - LocalFree(Argv); -} - -VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WintunSetLogger(ConsoleLogger); - - if (Argc < 4) - goto cleanup; - - DWORD LastError; - BOOL RebootRequired = FALSE; - WINTUN_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]); - if (!Adapter) - { - LastError = GetLastError(); - goto write; - } - BOOL ForceCloseSessions = wcstoul(Argv[4], NULL, 10); - LastError = WintunDeleteAdapter(Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); - WintunFreeAdapter(Adapter); -write: - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); - -cleanup: - LocalFree(Argv); -} - -VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WintunSetLogger(ConsoleLogger); - - if (Argc < 2) - goto cleanup; - - BOOL RebootRequired; - DWORD LastError = WintunDeletePoolDriver(Argv[2], &RebootRequired) ? ERROR_SUCCESS : GetLastError(); - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); - -cleanup: - LocalFree(Argv); -} -#endif - #ifdef MAYBE_WOW64 _Return_type_success_(return != FALSE) @@ -265,52 +137,23 @@ ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State) static DWORD WINAPI ProcessStderr(_In_ HANDLE Stderr) { - enum - { - OnNone, - OnLevelStart, - OnLevel, - OnLevelEnd, - OnSpace, - OnMsg - } State = OnNone; - WCHAR Msg[0x200]; - DWORD Count = 0; - WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO; + WCHAR Msg[0x200], Buf[0x220], LevelRune; + DWORD64 Timestamp; + DWORD SizeRead; + WINTUN_LOGGER_LEVEL Level; for (;;) { - WCHAR Buf[0x200]; - DWORD SizeRead; - if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL)) + if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL) || !SizeRead) return ERROR_SUCCESS; if (SizeRead % sizeof(*Buf)) return ERROR_INVALID_DATA; - SizeRead /= sizeof(*Buf); - for (DWORD i = 0; i < SizeRead; ++i) - { - WCHAR c = Buf[i]; - if (State == OnNone && c == L'[') - State = OnLevelStart; - else if ( - State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') || - (Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!'))) - State = OnLevelEnd; - else if (State == OnLevelEnd && c == L']') - State = OnSpace; - else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n') - { - if (Count < _countof(Msg) - 1) - Msg[Count++] = c; - State = OnMsg; - } - else if (State == OnMsg && c == L'\n') - { - Msg[Count] = 0; - LoggerLog(Level, NULL, Msg); - State = OnNone; - Count = 0; - } - } + Msg[0] = Buf[SizeRead / sizeof(*Buf) - 1] = L'\0'; + if (swscanf_s(Buf, L"[%c %I64u] %[^\n]", &LevelRune, 1, &Timestamp, Msg, (DWORD)_countof(Msg)) != 3 || !Msg[0]) + return ERROR_INVALID_DATA; + if (!((Level = WINTUN_LOG_INFO, LevelRune == L'+') || (Level = WINTUN_LOG_WARN, LevelRune == L'-') || + (Level = WINTUN_LOG_ERR, LevelRune == L'!'))) + return ERROR_INVALID_DATA; + Logger(Level, Timestamp, Msg); } } @@ -343,7 +186,7 @@ ExecuteRunDll32( return FALSE; } WCHAR DllPath[MAX_PATH] = { 0 }; - if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll")) + if (!PathCombineW(DllPath, RandomTempSubDirectory, L"setupapihost.dll")) { LastError = ERROR_BUFFER_OVERFLOW; goto cleanupDirectory; @@ -352,10 +195,10 @@ ExecuteRunDll32( switch (NativeMachine) { case IMAGE_FILE_MACHINE_AMD64: - WintunDllResourceName = L"wintun-amd64.dll"; + WintunDllResourceName = L"setupapihost-amd64.dll"; break; case IMAGE_FILE_MACHINE_ARM64: - WintunDllResourceName = L"wintun-arm64.dll"; + WintunDllResourceName = L"setupapihost-arm64.dll"; break; default: LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine); @@ -444,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: @@ -462,132 +305,94 @@ cleanupDirectory: return RET_ERROR(TRUE, LastError); } -_Use_decl_annotations_ -WINTUN_ADAPTER * -CreateAdapterViaRundll32(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired) +static _Return_type_success_(return != FALSE) +BOOL +InvokeClassInstaller(_In_ LPCWSTR Action, _In_ LPCWSTR Function, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = NULL; - if (RequestedGUID) + LOG(WINTUN_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(WINTUN_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; } - WINTUN_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(WINTUN_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 < 3) + if (Argc < 1) { - LOG(WINTUN_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(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]); - LastError = ERROR_FILE_NOT_FOUND; - } - if (wcstoul(Argv[2], NULL, 16)) - *RebootRequired = TRUE; cleanupArgv: LocalFree(Argv); cleanupArguments: Free(Arguments); - SetLastError(LastError); - return Adapter; + return RET_ERROR(TRUE, LastError); } _Use_decl_annotations_ BOOL -DeleteAdapterViaRundll32(const WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired) +RemoveInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = ArgvToCommandLineW(3, Adapter->Pool, Adapter->DevInstanceID, ForceCloseSessions ? L"1" : L"0"); - if (!Arguments) - { - LOG(WINTUN_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(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); - goto cleanupArguments; - } - int Argc; - LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 2) - { - LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response); - LastError = ERROR_INVALID_PARAMETER; - goto cleanupArgv; - } - LastError = wcstoul(Argv[0], NULL, 16); - if (wcstoul(Argv[1], NULL, 16)) - *RebootRequired = TRUE; -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, BOOL *RebootRequired) +EnableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = ArgvToCommandLineW(1, Pool); - if (!Arguments) - { - LOG(WINTUN_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(WINTUN_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(WINTUN_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 < 2) { - LOG(WINTUN_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 (wcstoul(Argv[1], NULL, 16)) - *RebootRequired = TRUE; + 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 1cd3cae..030419c 100644 --- a/api/rundll32.h +++ b/api/rundll32.h @@ -5,25 +5,22 @@ #pragma once +#include <Windows.h> +#include <SetupAPI.h> #include "adapter.h" -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -WINTUN_ADAPTER * -CreateAdapterViaRundll32( - _In_z_ LPCWSTR Pool, - _In_z_ LPCWSTR Name, - _In_opt_ const GUID *RequestedGUID, - _Inout_ BOOL *RebootRequired); +_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 WINTUN_ADAPTER *Adapter, - _In_ BOOL ForceCloseSessions, - _Inout_ BOOL *RebootRequired); +DisableInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); _Return_type_success_(return != FALSE) BOOL -DeletePoolDriverViaRundll32(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired); +CreateInstanceWin7ViaRundll32(_Out_writes_z_(MAX_INSTANCE_ID) LPWSTR InstanceId);
\ No newline at end of file diff --git a/api/session.c b/api/session.c index d620411..ab96c64 100644 --- a/api/session.c +++ b/api/session.c @@ -70,7 +70,7 @@ typedef struct _TUN_SESSION HANDLE Handle; } TUN_SESSION; -WINTUN_START_SESSION_FUNC_IMPL WintunStartSession; +WINTUN_START_SESSION_FUNC WintunStartSession; _Use_decl_annotations_ TUN_SESSION *WINAPI WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity) @@ -146,7 +146,7 @@ cleanup: return NULL; } -WINTUN_END_SESSION_FUNC_IMPL WintunEndSession; +WINTUN_END_SESSION_FUNC WintunEndSession; _Use_decl_annotations_ VOID WINAPI WintunEndSession(TUN_SESSION *Session) @@ -160,7 +160,7 @@ WintunEndSession(TUN_SESSION *Session) Free(Session); } -WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL WintunGetReadWaitEvent; +WINTUN_GET_READ_WAIT_EVENT_FUNC WintunGetReadWaitEvent; _Use_decl_annotations_ HANDLE WINAPI WintunGetReadWaitEvent(TUN_SESSION *Session) @@ -168,7 +168,7 @@ WintunGetReadWaitEvent(TUN_SESSION *Session) return Session->Descriptor.Send.TailMoved; } -WINTUN_RECEIVE_PACKET_FUNC_IMPL WintunReceivePacket; +WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket; _Use_decl_annotations_ BYTE *WINAPI WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize) @@ -221,7 +221,7 @@ cleanup: return NULL; } -WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL WintunReleaseReceivePacket; +WINTUN_RELEASE_RECEIVE_PACKET_FUNC WintunReleaseReceivePacket; _Use_decl_annotations_ VOID WINAPI WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet) @@ -242,7 +242,7 @@ WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet) LeaveCriticalSection(&Session->Send.Lock); } -WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL WintunAllocateSendPacket; +WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket; _Use_decl_annotations_ BYTE *WINAPI WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize) @@ -280,7 +280,7 @@ cleanup: return NULL; } -WINTUN_SEND_PACKET_FUNC_IMPL WintunSendPacket; +WINTUN_SEND_PACKET_FUNC WintunSendPacket; _Use_decl_annotations_ VOID WINAPI WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet) diff --git a/api/wintun.h b/api/wintun.h index 9464a96..ff1223a 100644 --- a/api/wintun.h +++ b/api/wintun.h @@ -5,176 +5,102 @@ #pragma once +#include <winsock2.h> #include <windows.h> #include <ipexport.h> #include <ifdef.h> +#include <ws2ipdef.h> #ifdef __cplusplus extern "C" { #endif +#ifndef ALIGNED +# if defined(_MSC_VER) +# define ALIGNED(n) __declspec(align(n)) +# elif defined(__GNUC__) +# define ALIGNED(n) __attribute__((aligned(n))) +# else +# error "Unable to define ALIGNED" +# endif +#endif + +/* MinGW is missing this one, unfortunately. */ +#ifndef _Post_maybenull_ +# define _Post_maybenull_ +#endif + +#pragma warning(push) +#pragma warning(disable : 4324) /* structure was padded due to alignment specifier */ + /** * A handle representing Wintun adapter */ typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE; /** - * Maximum pool name length including zero terminator - */ -#define WINTUN_MAX_POOL 256 - -/** * Creates a new Wintun adapter. * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_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. * - * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. - * - * @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. 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 + * WintunCloseAdapter. 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_ -WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC_IMPL) -(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name, _In_opt_ const GUID *RequestedGUID, _Out_opt_ BOOL *RebootRequired); -typedef WINTUN_CREATE_ADAPTER_FUNC_IMPL *WINTUN_CREATE_ADAPTER_FUNC; +WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC) +(_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID); /** * Opens an existing Wintun adapter. * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_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 WintunFreeAdapter. 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 Wintun-class or not a member of the pool + * @return If the function succeeds, the return value is the adapter handle. Must be released with + * WintunCloseAdapter. 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_ -WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name); -typedef WINTUN_OPEN_ADAPTER_FUNC_IMPL *WINTUN_OPEN_ADAPTER_FUNC; - -/** - * Deletes a Wintun adapter. - * - * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. - * - * @param ForceCloseSessions Force close adapter handles that may be in use by other processes. Only set this to TRUE - * with extreme care, as this is resource intensive and may put processes into an undefined - * or unpredictable state. Most users should set this to FALSE. - * - * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. - * - * @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 WINTUN_DELETE_ADAPTER_FUNC_IMPL) -(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired); -typedef WINTUN_DELETE_ADAPTER_FUNC_IMPL *WINTUN_DELETE_ADAPTER_FUNC; - -/** - * Called by WintunEnumAdapters 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 WintunEnumAdapters. - * - * @return Non-zero to continue iterating adapters; zero to stop. - */ -typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ LPARAM Param); - -/** - * Enumerates all Wintun adapters. - * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_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 WINTUN_ENUM_ADAPTERS_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param); -typedef WINTUN_ENUM_ADAPTERS_FUNC_IMPL *WINTUN_ENUM_ADAPTERS_FUNC; +WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name); /** - * Releases Wintun adapter resources. + * Releases Wintun adapter resources and, if adapter was created with WintunCreateAdapter, removes adapter. * - * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. + * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter. */ -typedef VOID(WINAPI WINTUN_FREE_ADAPTER_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter); -typedef WINTUN_FREE_ADAPTER_FUNC_IMPL *WINTUN_FREE_ADAPTER_FUNC; +typedef VOID(WINAPI WINTUN_CLOSE_ADAPTER_FUNC)(_In_opt_ WINTUN_ADAPTER_HANDLE Adapter); /** - * Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun - * from the driver store, usually called by uninstallers. - * - * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters. - * - * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. + * Deletes the Wintun 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 WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _Out_opt_ BOOL *RebootRequired); -typedef WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL *WINTUN_DELETE_POOL_DRIVER_FUNC; +BOOL(WINAPI WINTUN_DELETE_DRIVER_FUNC)(VOID); /** * Returns the LUID of the adapter. * - * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter + * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter * * @param Luid Pointer to LUID to receive adapter LUID. */ -typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid); -typedef WINTUN_GET_ADAPTER_LUID_FUNC_IMPL *WINTUN_GET_ADAPTER_LUID_FUNC; - -/** - * Returns the name of the Wintun adapter. - * - * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter - * - * @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 WINTUN_GET_ADAPTER_NAME_FUNC_IMPL) -(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_writes_z_(MAX_ADAPTER_NAME) LPWSTR Name); -typedef WINTUN_GET_ADAPTER_NAME_FUNC_IMPL *WINTUN_GET_ADAPTER_NAME_FUNC; - -/** - * Sets name of the Wintun adapter. - * - * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter - * - * @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 WINTUN_SET_ADAPTER_NAME_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ LPCWSTR Name); -typedef WINTUN_SET_ADAPTER_NAME_FUNC_IMPL *WINTUN_SET_ADAPTER_NAME_FUNC; +typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid); /** * Determines the version of the Wintun driver currently loaded. @@ -184,8 +110,7 @@ typedef WINTUN_SET_ADAPTER_NAME_FUNC_IMPL *WINTUN_SET_ADAPTER_NAME_FUNC; * ERROR_FILE_NOT_FOUND Wintun not loaded */ typedef _Return_type_success_(return != 0) -DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL)(VOID); -typedef WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC; +DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(VOID); /** * Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK. @@ -202,9 +127,14 @@ typedef enum * * @param Level Message level. * + * @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC. + * * @param Message Message text. */ -typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Message); +typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)( + _In_ WINTUN_LOGGER_LEVEL Level, + _In_ DWORD64 Timestamp, + _In_z_ LPCWSTR Message); /** * Sets logger callback function. @@ -213,8 +143,7 @@ typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _ * threads concurrently. Should the logging require serialization, you must handle serialization in * NewLogger. Set to NULL to disable. */ -typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC_IMPL)(_In_ WINTUN_LOGGER_CALLBACK NewLogger); -typedef WINTUN_SET_LOGGER_FUNC_IMPL *WINTUN_SET_LOGGER_FUNC; +typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger); /** * Minimum ring capacity. @@ -245,16 +174,14 @@ typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE; typedef _Must_inspect_result_ _Return_type_success_(return != NULL) _Post_maybenull_ -WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); -typedef WINTUN_START_SESSION_FUNC_IMPL *WINTUN_START_SESSION_FUNC; +WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); /** * Ends Wintun session. * * @param Session Wintun session handle obtained with WintunStartSession */ -typedef VOID(WINAPI WINTUN_END_SESSION_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session); -typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC; +typedef VOID(WINAPI WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session); /** * Gets Wintun session's read-wait event handle. @@ -266,8 +193,7 @@ typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC; * load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call * CloseHandle on this event - it is managed by the session. */ -typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session); -typedef WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL *WINTUN_GET_READ_WAIT_EVENT_FUNC; +typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session); /** * Maximum IP packet size @@ -293,8 +219,7 @@ typedef _Must_inspect_result_ _Return_type_success_(return != NULL) _Post_maybenull_ _Post_writable_byte_size_(*PacketSize) -BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize); -typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC; +BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize); /** * Releases internal buffer after the received packet has been processed by the client. This function is thread-safe. @@ -304,8 +229,7 @@ typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC; * @param Packet Packet obtained with WintunReceivePacket */ typedef VOID( - WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); -typedef WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RELEASE_RECEIVE_PACKET_FUNC; + WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); /** * Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send @@ -326,8 +250,7 @@ typedef _Must_inspect_result_ _Return_type_success_(return != NULL) _Post_maybenull_ _Post_writable_byte_size_(PacketSize) -BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize); -typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC; +BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize); /** * Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket @@ -338,8 +261,9 @@ typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC; * * @param Packet Packet obtained with WintunAllocateSendPacket */ -typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); -typedef WINTUN_SEND_PACKET_FUNC_IMPL *WINTUN_SEND_PACKET_FUNC; +typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); + +#pragma warning(pop) #ifdef __cplusplus } |