aboutsummaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2021-10-11 23:21:31 -0600
committerJason A. Donenfeld <Jason@zx2c4.com>2021-10-12 18:54:20 +0000
commit544fdaaf8fb970d9657a59c1fc4c4569de4f2d3e (patch)
tree715e49e1f325bf7795face50ff84936b05ab86e2 /api
parentproj: remove SDV and DVL support (diff)
downloadwintun-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.c2225
-rw-r--r--api/adapter.h128
-rw-r--r--api/adapter_win7.h351
-rw-r--r--api/api.vcxproj18
-rw-r--r--api/api.vcxproj.filters17
-rw-r--r--api/driver.c587
-rw-r--r--api/driver.h34
-rw-r--r--api/exports.def8
-rw-r--r--api/logger.c47
-rw-r--r--api/logger.h47
-rw-r--r--api/main.c19
-rw-r--r--api/main.h13
-rw-r--r--api/namespace.c108
-rw-r--r--api/namespace.h4
-rw-r--r--api/ntdll.h1
-rw-r--r--api/registry.c241
-rw-r--r--api/registry.h81
-rw-r--r--api/resources.rc14
-rw-r--r--api/rundll32.c321
-rw-r--r--api/rundll32.h25
-rw-r--r--api/session.c14
-rw-r--r--api/wintun.h192
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
+}
diff --git a/api/main.c b/api/main.c
index 294f35d..28937fa 100644
--- a/api/main.c
+++ b/api/main.c
@@ -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:
diff --git a/api/main.h b/api/main.h
index 5d3ebb1..04ba7dd 100644
--- a/api/main.h
+++ b/api/main.h
@@ -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
}