api: internal reorganization

Gather adapter management in adapter.h/.c (formerly devmgmt.h/.c) and
unify HwID tests.

Use "Namespace" namespace in all functions from namespace.h/.c.

Fix char strings in LOG_...

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-10-15 11:32:06 +02:00 committed by Jason A. Donenfeld
parent 78b7a01eb3
commit 16a9737578
12 changed files with 424 additions and 444 deletions

View File

@ -10,6 +10,56 @@
static _locale_t Locale; static _locale_t Locale;
/**
* Retrieves driver information detail for a device information set or a particular device information element in the
* device information set.
*
* @param DevInfo A handle to the device information set that contains a device information element that
* represents the device for which to retrieve driver information.
*
* @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo.
*
* @param DrvInfoData A pointer to a structure that specifies the driver information element that represents the
* driver for which to retrieve details.
*
* @param DrvInfoDetailData A pointer to a structure that receives detailed information about the specified driver.
* Must be released with HeapFree(GetProcessHeap(), 0, *DrvInfoDetailData) after use.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
WINTUN_STATUS
AdapterGetDrvInfoDetail(
_In_ HDEVINFO DevInfo,
_In_opt_ SP_DEVINFO_DATA *DevInfoData,
_In_ SP_DRVINFO_DATA_W *DrvInfoData,
_Out_ SP_DRVINFO_DETAIL_DATA_W **DrvInfoDetailData)
{
HANDLE Heap = GetProcessHeap();
DWORD Size = sizeof(SP_DRVINFO_DETAIL_DATA_W) + 0x100;
DWORD Result;
for (;;)
{
*DrvInfoDetailData = HeapAlloc(Heap, 0, Size);
if (!*DrvInfoDetailData)
{
Result = ERROR_OUTOFMEMORY;
goto out;
}
(*DrvInfoDetailData)->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
if (SetupDiGetDriverInfoDetailW(DevInfo, DevInfoData, DrvInfoData, *DrvInfoDetailData, Size, &Size))
return ERROR_SUCCESS;
Result = GetLastError();
HeapFree(Heap, 0, *DrvInfoDetailData);
if (Result != ERROR_INSUFFICIENT_BUFFER)
{
LOG_ERROR(L"Failed", Result);
goto out;
}
}
out:
return Result;
}
/** /**
* Retrieves a specified Plug and Play device property. * Retrieves a specified Plug and Play device property.
* *
@ -140,19 +190,273 @@ GetDeviceRegistryMultiString(
} }
/** /**
* Tests if any of the hardware IDs match ours. * Tests if any of device compatible hardware IDs match ours.
* *
* @param Hwids Multi-string containing a list of hardware IDs. * @param DevInfo A handle to the device information set that contains a device information element that
* represents the device.
* *
* @return TRUE on match; FALSE otherwise. * @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/ */
static BOOL static WINTUN_STATUS
IsOurHardwareID(_In_z_ WCHAR *Hwids) IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _Out_ BOOL *IsOur)
{ {
for (; Hwids[0]; Hwids += wcslen(Hwids) + 1) WCHAR *Hwids;
if (!_wcsicmp(Hwids, WINTUN_HWID)) DWORD Result = GetDeviceRegistryMultiString(DevInfo, DevInfoData, SPDRP_HARDWAREID, &Hwids);
return TRUE; if (Result != ERROR_SUCCESS)
return FALSE; return LOG_ERROR(L"Failed to query hardware ID", Result);
*IsOur = DriverIsOurHardwareID(Hwids);
return ERROR_SUCCESS;
}
/**
* Returns a handle to the adapter device object.
*
* @param InstanceId Adapter device instance ID.
*
* @param Handle Pointer to receive the adapter device object handle. Must be released with CloseHandle.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
static WINTUN_STATUS
GetDeviceObject(_In_opt_z_ const WCHAR *InstanceId, _Out_ HANDLE *Handle)
{
HANDLE Heap = GetProcessHeap();
ULONG InterfacesLen;
DWORD Result = CM_Get_Device_Interface_List_SizeW(
&InterfacesLen, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (Result != CR_SUCCESS)
{
LOG(WINTUN_LOG_ERR, L"Failed to get device associated device instances size");
return ERROR_GEN_FAILURE;
}
WCHAR *Interfaces = HeapAlloc(Heap, 0, InterfacesLen * sizeof(WCHAR));
if (!Interfaces)
return ERROR_OUTOFMEMORY;
Result = CM_Get_Device_Interface_ListW(
(GUID *)&GUID_DEVINTERFACE_NET,
(DEVINSTID_W)InstanceId,
Interfaces,
InterfacesLen,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (Result != CR_SUCCESS)
{
LOG(WINTUN_LOG_ERR, L"Failed to get device associated device instances");
Result = ERROR_GEN_FAILURE;
goto cleanupBuf;
}
*Handle = CreateFileW(
Interfaces,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL);
Result = *Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR(L"Failed to connect to device");
cleanupBuf:
HeapFree(Heap, 0, Interfaces);
return Result;
}
#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
/**
* Closes all client handles to the Wintun adapter.
*
* @param DevInfo A handle to the device information set that contains a device information element that
* represents the device.
*
* @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
static WINTUN_STATUS
ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData)
{
DWORD Result = ERROR_SUCCESS;
DWORD RequiredBytes;
if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) ||
(Result = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
return LOG_ERROR(L"Failed to query device instance ID size", Result);
HANDLE Heap = GetProcessHeap();
WCHAR *InstanceId = HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(*InstanceId) * RequiredBytes);
if (!InstanceId)
return ERROR_OUTOFMEMORY;
if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes))
{
Result = LOG_LAST_ERROR(L"Failed to get device instance ID");
goto out;
}
HANDLE NdisHandle;
Result = GetDeviceObject(InstanceId, &NdisHandle);
if (Result != ERROR_SUCCESS)
{
LOG_ERROR(L"Failed to get adapter device object", Result);
goto out;
}
Result = DeviceIoControl(NdisHandle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL)
? ERROR_SUCCESS
: LOG_LAST_ERROR(L"Failed to perform ioctl");
CloseHandle(NdisHandle);
out:
HeapFree(Heap, 0, InstanceId);
return Result;
}
/**
* Disables all Wintun adapters.
*
* @param DevInfo A handle to the device information set.
*
* @param DisabledAdapters Output list of disabled adapters. The adapters disabled are inserted in the list head.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
WINTUN_STATUS
AdapterDisableAllOurs(_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 Result = ERROR_SUCCESS;
HANDLE Heap = GetProcessHeap();
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
SP_DEVINFO_DATA_LIST *DeviceNode = HeapAlloc(Heap, 0, sizeof(SP_DEVINFO_DATA_LIST));
if (!DeviceNode)
return ERROR_OUTOFMEMORY;
DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
{
HeapFree(Heap, 0, DeviceNode);
break;
}
goto cleanupDeviceInfoData;
}
BOOL IsOur;
if (IsOurAdapter(DevInfo, &DeviceNode->Data, &IsOur) != ERROR_SUCCESS || !IsOur)
goto cleanupDeviceInfoData;
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 cleanupDeviceInfoData;
LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter");
if (ForceCloseWintunAdapterHandle(DevInfo, &DeviceNode->Data) != ERROR_SUCCESS)
LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles");
Sleep(200);
LOG(WINTUN_LOG_INFO, L"Disabling existing adapter");
if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data))
{
LOG_LAST_ERROR(L"Unable to disable existing adapter");
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
goto cleanupDeviceInfoData;
}
DeviceNode->Next = *DisabledAdapters;
*DisabledAdapters = DeviceNode;
continue;
cleanupDeviceInfoData:
HeapFree(Heap, 0, &DeviceNode->Data);
}
return Result;
}
/**
* Enables all adapters.
*
* @param DevInfo A handle to the device information set.
*
* @param AdaptersToEnable Input list of adapters to enable.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
WINTUN_STATUS
AdapterEnableAll(_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 Result = ERROR_SUCCESS;
for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next)
{
LOG(WINTUN_LOG_INFO, L"Enabling existing adapter");
if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data))
{
LOG_LAST_ERROR(L"Unable to enable existing adapter");
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
}
}
return Result;
}
/**
* Removes all Wintun adapters.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
WINTUN_STATUS
AdapterDeleteAllOurs()
{
DWORD Result = ERROR_SUCCESS;
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE)
return LOG_LAST_ERROR(L"Failed to get present class devices");
SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
.InstallFunction = DIF_REMOVE },
.Scope = DI_REMOVEDEVICE_GLOBAL };
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) };
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
continue;
}
BOOL IsOur;
if (IsOurAdapter(DevInfo, &DevInfoData, &IsOur) != ERROR_SUCCESS || !IsOur)
continue;
LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter");
if (ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS)
LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles");
Sleep(200);
LOG(WINTUN_LOG_INFO, L"Removing existing adapter");
if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData))
{
LOG_LAST_ERROR(L"Unable to remove existing adapter");
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
}
}
SetupDiDestroyDeviceInfoList(DevInfo);
return Result;
}
void
AdapterInit()
{
Locale = _wcreate_locale(LC_ALL, L"");
}
void
AdapterCleanup()
{
_free_locale(Locale);
} }
/** /**
@ -528,7 +832,7 @@ WintunGetAdapter(
_Out_ WINTUN_ADAPTER **Adapter) _Out_ WINTUN_ADAPTER **Adapter)
{ {
DWORD Result; DWORD Result;
HANDLE Mutex = TakeNameMutex(Pool); HANDLE Mutex = NamespaceTakeMutex(Pool);
if (!Mutex) if (!Mutex)
return ERROR_INVALID_HANDLE; return ERROR_INVALID_HANDLE;
@ -539,7 +843,6 @@ WintunGetAdapter(
goto cleanupMutex; goto cleanupMutex;
} }
HANDLE Heap = GetProcessHeap();
for (DWORD EnumIndex = 0;; ++EnumIndex) for (DWORD EnumIndex = 0;; ++EnumIndex)
{ {
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) };
@ -566,25 +869,17 @@ WintunGetAdapter(
continue; continue;
} }
/* Check the Hardware ID to make sure it's a real Wintun device. This avoids doing slow operations on non-Wintun /* Check the Hardware ID to make sure it's a real Wintun device. */
* devices. */ BOOL IsOur;
WCHAR *Hwids; Result = IsOurAdapter(DevInfo, &DevInfoData, &IsOur);
Result = GetDeviceRegistryMultiString(DevInfo, &DevInfoData, SPDRP_HARDWAREID, &Hwids);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
{ {
LOG_ERROR(L"Failed to query hardware ID", Result); LOG_ERROR(L"Failed to determine hardware ID", Result);
goto cleanupDevInfo; goto cleanupDevInfo;
} }
if (!IsOurHardwareID(Hwids)) if (!IsOur)
{
HeapFree(Heap, 0, Hwids);
Result = ERROR_ALREADY_EXISTS;
goto cleanupDevInfo;
}
HeapFree(Heap, 0, Hwids);
if (!DriverIsWintunAdapter(DevInfo, &DevInfoData))
{ {
LOG_ERROR(L"Foreign adapter with the same name exists", Result);
Result = ERROR_ALREADY_EXISTS; Result = ERROR_ALREADY_EXISTS;
goto cleanupDevInfo; goto cleanupDevInfo;
} }
@ -598,6 +893,7 @@ WintunGetAdapter(
} }
if (!IsMember) if (!IsMember)
{ {
LOG_ERROR(L"Wintun adapter with the same name exists in another pool", Result);
Result = ERROR_ALREADY_EXISTS; Result = ERROR_ALREADY_EXISTS;
goto cleanupDevInfo; goto cleanupDevInfo;
} }
@ -612,7 +908,7 @@ WintunGetAdapter(
cleanupDevInfo: cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo); SetupDiDestroyDeviceInfoList(DevInfo);
cleanupMutex: cleanupMutex:
ReleaseNameMutex(Mutex); NamespaceReleaseMutex(Mutex);
return Result; return Result;
} }
@ -739,8 +1035,7 @@ WintunGetAdapterLUID(_In_ const WINTUN_ADAPTER *Adapter, _Out_ LUID *Luid)
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunGetAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle) WintunGetAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle)
{ {
*Handle = DriverGetAdapterDeviceObject(Adapter->DevInstanceID); return GetDeviceObject(Adapter->DevInstanceID, Handle);
return *Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : GetLastError();
} }
/** /**
@ -797,7 +1092,7 @@ WintunCreateAdapter(
_Inout_ BOOL *RebootRequired) _Inout_ BOOL *RebootRequired)
{ {
DWORD Result; DWORD Result;
HANDLE Mutex = TakeNameMutex(Pool); HANDLE Mutex = NamespaceTakeMutex(Pool);
if (!Mutex) if (!Mutex)
return ERROR_INVALID_HANDLE; return ERROR_INVALID_HANDLE;
@ -862,12 +1157,10 @@ WintunCreateAdapter(
if (!IsNewer(&DrvInfoData, &DriverDate, DriverVersion)) if (!IsNewer(&DrvInfoData, &DriverDate, DriverVersion))
continue; continue;
SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = DriverGetDrvInfoDetail(DevInfo, &DevInfoData, &DrvInfoData); SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData;
if (!DrvInfoDetailData) if (AdapterGetDrvInfoDetail(DevInfo, &DevInfoData, &DrvInfoData, &DrvInfoDetailData) != ERROR_SUCCESS)
continue; continue;
if ((DrvInfoDetailData->CompatIDsOffset <= 1 || _wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_HWID)) && if (!DriverIsOurDrvInfoDetail(DrvInfoDetailData))
(!DrvInfoDetailData->CompatIDsLength ||
!IsOurHardwareID(DrvInfoDetailData->HardwareID + DrvInfoDetailData->CompatIDsOffset)))
{ {
HeapFree(Heap, 0, DrvInfoDetailData); HeapFree(Heap, 0, DrvInfoDetailData);
continue; continue;
@ -1021,7 +1314,7 @@ WintunCreateAdapter(
goto cleanupTcpipAdapterRegKey; goto cleanupTcpipAdapterRegKey;
} }
const static DWORD EnableDeadGWDetect = 0; static const DWORD EnableDeadGWDetect = 0;
Result = RegSetKeyValueW( Result = RegSetKeyValueW(
TcpipInterfaceRegKey, NULL, L"EnableDeadGWDetect", REG_DWORD, &EnableDeadGWDetect, sizeof(EnableDeadGWDetect)); TcpipInterfaceRegKey, NULL, L"EnableDeadGWDetect", REG_DWORD, &EnableDeadGWDetect, sizeof(EnableDeadGWDetect));
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
@ -1055,7 +1348,7 @@ cleanupDriverInfoList:
cleanupDevInfo: cleanupDevInfo:
SetupDiDestroyDeviceInfoList(DevInfo); SetupDiDestroyDeviceInfoList(DevInfo);
cleanupMutex: cleanupMutex:
ReleaseNameMutex(Mutex); NamespaceReleaseMutex(Mutex);
return Result; return Result;
} }
@ -1111,10 +1404,10 @@ WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequ
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunEnumAdapters(_In_z_count_c_(MAX_POOL) const WCHAR *Pool, _In_ WINTUN_ENUM_FUNC Func, _In_ LPARAM Param) WintunEnumAdapters(_In_z_count_c_(MAX_POOL) const WCHAR *Pool, _In_ WINTUN_ENUM_FUNC Func, _In_ LPARAM Param)
{ {
DWORD Result; HANDLE Mutex = NamespaceTakeMutex(Pool);
HANDLE Mutex = TakeNameMutex(Pool);
if (!Mutex) if (!Mutex)
return ERROR_INVALID_HANDLE; return ERROR_INVALID_HANDLE;
DWORD Result = ERROR_SUCCESS;
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE) if (DevInfo == INVALID_HANDLE_VALUE)
{ {
@ -1122,36 +1415,25 @@ WintunEnumAdapters(_In_z_count_c_(MAX_POOL) const WCHAR *Pool, _In_ WINTUN_ENUM_
goto cleanupMutex; goto cleanupMutex;
} }
HANDLE Heap = GetProcessHeap(); HANDLE Heap = GetProcessHeap();
for (DWORD EnumIndex = 0;; ++EnumIndex) BOOL Continue = TRUE;
for (DWORD EnumIndex = 0; Continue; ++EnumIndex)
{ {
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) };
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
{ {
if (GetLastError() == ERROR_NO_MORE_ITEMS) if (GetLastError() == ERROR_NO_MORE_ITEMS)
{
Result = ERROR_SUCCESS;
break; break;
}
continue; continue;
} }
/* Check the Hardware ID to make sure it's a real Wintun device. This avoids doing slow operations on non-Wintun BOOL IsOur;
* devices. */ Result = IsOurAdapter(DevInfo, &DevInfoData, &IsOur);
WCHAR *Hwids;
Result = GetDeviceRegistryMultiString(DevInfo, &DevInfoData, SPDRP_HARDWAREID, &Hwids);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
{ {
LOG_ERROR(L"Failed to query hardware ID", Result); LOG_ERROR(L"Failed to determine hardware ID", Result);
break; break;
} }
if (!IsOurHardwareID(Hwids)) if (!IsOur)
{
HeapFree(Heap, 0, Hwids);
continue;
}
HeapFree(Heap, 0, Hwids);
if (!DriverIsWintunAdapter(DevInfo, &DevInfoData))
continue; continue;
BOOL IsMember; BOOL IsMember;
@ -1171,28 +1453,11 @@ WintunEnumAdapters(_In_z_count_c_(MAX_POOL) const WCHAR *Pool, _In_ WINTUN_ENUM_
LOG_ERROR(L"Failed to create adapter data", Result); LOG_ERROR(L"Failed to create adapter data", Result);
break; break;
} }
if (Func(Adapter, Param)) Continue = Func(Adapter, Param);
HeapFree(Heap, 0, Adapter); HeapFree(Heap, 0, Adapter);
else
{
HeapFree(Heap, 0, Adapter);
break;
}
} }
SetupDiDestroyDeviceInfoList(DevInfo); SetupDiDestroyDeviceInfoList(DevInfo);
cleanupMutex: cleanupMutex:
ReleaseNameMutex(Mutex); NamespaceReleaseMutex(Mutex);
return Result; return Result;
} }
void
DevmgmtInit()
{
Locale = _wcreate_locale(LC_ALL, L"");
}
void
DevmgmtCleanup()
{
_free_locale(Locale);
}

View File

@ -6,11 +6,40 @@
#pragma once #pragma once
#include "api.h" #include "api.h"
#include <SetupAPI.h>
#include <IPExport.h> #include <IPExport.h>
#define MAX_POOL 256 #define MAX_POOL 256
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ #define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
typedef struct _SP_DEVINFO_DATA_LIST
{
SP_DEVINFO_DATA Data;
struct _SP_DEVINFO_DATA_LIST *Next;
} SP_DEVINFO_DATA_LIST;
WINTUN_STATUS
AdapterGetDrvInfoDetail(
_In_ HDEVINFO DevInfo,
_In_opt_ SP_DEVINFO_DATA *DevInfoData,
_In_ SP_DRVINFO_DATA_W *DrvInfoData,
_Out_ SP_DRVINFO_DETAIL_DATA_W **DrvInfoDetailData);
WINTUN_STATUS
AdapterDisableAllOurs(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters);
WINTUN_STATUS
AdapterEnableAll(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable);
WINTUN_STATUS
AdapterDeleteAllOurs();
void
AdapterInit();
void
AdapterCleanup();
typedef struct _WINTUN_ADAPTER typedef struct _WINTUN_ADAPTER
{ {
GUID CfgInstanceID; GUID CfgInstanceID;
@ -59,9 +88,3 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_FUNC)(_In_ const WINTUN_ADAPTER *Adapter, _In
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunEnumAdapters(_In_z_count_c_(MAX_POOL) const WCHAR *Pool, _In_ WINTUN_ENUM_FUNC Func, _In_ LPARAM Param); WintunEnumAdapters(_In_z_count_c_(MAX_POOL) const WCHAR *Pool, _In_ WINTUN_ENUM_FUNC Func, _In_ LPARAM Param);
void
DevmgmtInit();
void
DevmgmtCleanup();

View File

@ -67,15 +67,15 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
ResourceModule = hinstDLL; ResourceModule = hinstDLL;
AdapterInit();
NamespaceInit(); NamespaceInit();
NciInit(); NciInit();
DevmgmtInit();
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
DevmgmtCleanup();
NciCleanup(); NciCleanup();
NamespaceCleanup(); NamespaceCleanup();
AdapterCleanup();
break; break;
} }
return TRUE; return TRUE;

View File

@ -190,7 +190,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="api.h" /> <ClInclude Include="api.h" />
<ClInclude Include="devmgmt.h" /> <ClInclude Include="adapter.h" />
<ClInclude Include="driver.h" /> <ClInclude Include="driver.h" />
<ClInclude Include="logger.h" /> <ClInclude Include="logger.h" />
<ClInclude Include="namespace.h" /> <ClInclude Include="namespace.h" />
@ -201,7 +201,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="api.c" /> <ClCompile Include="api.c" />
<ClCompile Include="devmgmt.c" /> <ClCompile Include="adapter.c" />
<ClCompile Include="driver.c" /> <ClCompile Include="driver.c" />
<ClCompile Include="logger.c" /> <ClCompile Include="logger.c" />
<ClCompile Include="namespace.c" /> <ClCompile Include="namespace.c" />

View File

@ -40,9 +40,6 @@
<ClInclude Include="registry.h"> <ClInclude Include="registry.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="devmgmt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="logger.h"> <ClInclude Include="logger.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -52,6 +49,9 @@
<ClInclude Include="driver.h"> <ClInclude Include="driver.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="adapter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="api.c"> <ClCompile Include="api.c">
@ -60,9 +60,6 @@
<ClCompile Include="namespace.c"> <ClCompile Include="namespace.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="devmgmt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="nci.c"> <ClCompile Include="nci.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -84,5 +81,8 @@
<ClCompile Include="driver.c"> <ClCompile Include="driver.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="adapter.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -7,153 +7,35 @@
#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ #pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
typedef struct _SP_DEVINFO_DATA_LIST
{
SP_DEVINFO_DATA Data;
struct _SP_DEVINFO_DATA_LIST *Next;
} SP_DEVINFO_DATA_LIST;
/** /**
* Retrieves driver information detail for a device information set or a particular device information element in the * Tests if any of the hardware IDs match ours.
* device information set.
* *
* @param DevInfo A handle to the device information set that contains a device information element that * @param Hwids Multi-string containing a list of hardware IDs.
* represents the device for which to retrieve driver information.
* *
* @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo. * @return TRUE on match; FALSE otherwise.
*
* @param DrvInfoData A pointer to a structure that specifies the driver information element that represents the
* driver for which to retrieve details.
*
* @param DrvInfoDetailData A pointer to a structure that receives detailed information about the specified driver.
* Must be released with HeapFree(GetProcessHeap(), 0, *DrvInfoDetailData) after use.
*
* @return non-zero on success; zero otherwise - use GetLastError().
*/
_Return_type_success_(return != NULL) SP_DRVINFO_DETAIL_DATA_W *DriverGetDrvInfoDetail(
_In_ HDEVINFO DevInfo,
_In_opt_ SP_DEVINFO_DATA *DevInfoData,
_In_ SP_DRVINFO_DATA_W *DrvInfoData)
{
HANDLE Heap = GetProcessHeap();
DWORD Size = sizeof(SP_DRVINFO_DETAIL_DATA_W) + 0x100;
DWORD Result;
for (;;)
{
SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = HeapAlloc(Heap, 0, Size);
if (!DrvInfoDetailData)
{
Result = ERROR_OUTOFMEMORY;
goto out;
}
DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
if (SetupDiGetDriverInfoDetailW(DevInfo, DevInfoData, DrvInfoData, DrvInfoDetailData, Size, &Size))
return DrvInfoDetailData;
Result = GetLastError();
HeapFree(Heap, 0, DrvInfoDetailData);
if (Result != ERROR_INSUFFICIENT_BUFFER)
{
LOG_ERROR(L"Failed", Result);
goto out;
}
}
out:
SetLastError(Result);
return NULL;
}
/**
* Checks if the device (i.e. network adapter) is using Wintun driver.
*
* @param DevInfo A handle to the device information set that contains a device information element that
* represents the device.
*
* @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo.
*
* @return non-zero when using Wintun driver; zero when not or error - use GetLastError().
*/ */
BOOL BOOL
DriverIsWintunAdapter(_In_ HDEVINFO DevInfo, _In_opt_ SP_DEVINFO_DATA *DevInfoData) DriverIsOurHardwareID(_In_z_ const WCHAR *Hwids)
{ {
BOOL Found = FALSE; for (; Hwids[0]; Hwids += wcslen(Hwids) + 1)
if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER)) if (!_wcsicmp(Hwids, WINTUN_HWID))
{ return TRUE;
LOG_LAST_ERROR(L"Failed to build list of drivers");
return FALSE; return FALSE;
}
HANDLE Heap = GetProcessHeap();
for (DWORD EnumIndex = 0; !Found; ++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 = DriverGetDrvInfoDetail(DevInfo, DevInfoData, &DrvInfoData);
if (!DrvInfoDetailData)
continue;
Found = !_wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_HWID);
HeapFree(Heap, 0, DrvInfoDetailData);
}
SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER);
SetLastError(ERROR_SUCCESS);
return Found;
} }
/** /**
* Returns a handle to the adapter device object. * Tests if hardware ID or any of the compatible IDs match ours.
* *
* @param InstanceId Adapter device instance ID. * @param DrvInfoDetailData Detailed information about a particular driver information structure.
* *
* @return device handle on success; INVALID_HANDLE_VALUE otherwise - use GetLastError(). * @return TRUE on match; FALSE otherwise.
*/ */
_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE BOOL
DriverGetAdapterDeviceObject(_In_opt_z_ const WCHAR *InstanceId) DriverIsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData)
{ {
HANDLE Heap = GetProcessHeap(); return DrvInfoDetailData->CompatIDsOffset > 1 && !_wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_HWID) ||
ULONG InterfacesLen; DrvInfoDetailData->CompatIDsLength &&
HANDLE Handle = INVALID_HANDLE_VALUE; DriverIsOurHardwareID(DrvInfoDetailData->HardwareID + DrvInfoDetailData->CompatIDsOffset);
DWORD Result = CM_Get_Device_Interface_List_SizeW(
&InterfacesLen, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (Result != CR_SUCCESS)
{
LOG(WINTUN_LOG_ERR, L"Failed to get device associated device instances size");
SetLastError(ERROR_GEN_FAILURE);
return INVALID_HANDLE_VALUE;
}
WCHAR *Interfaces = HeapAlloc(Heap, 0, InterfacesLen * sizeof(WCHAR));
if (!Interfaces)
{
SetLastError(ERROR_OUTOFMEMORY);
return INVALID_HANDLE_VALUE;
}
Result = CM_Get_Device_Interface_ListW(
(GUID *)&GUID_DEVINTERFACE_NET,
(DEVINSTID_W)InstanceId,
Interfaces,
InterfacesLen,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (Result != CR_SUCCESS)
{
LOG(WINTUN_LOG_ERR, L"Failed to get device associated device instances");
Result = ERROR_GEN_FAILURE;
goto cleanupBuf;
}
Handle = CreateFileW(
Interfaces,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL);
Result = Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR(L"Failed to connect to device");
cleanupBuf:
HeapFree(Heap, 0, Interfaces);
SetLastError(Result);
return Handle;
} }
#if defined(HAVE_EV) || defined(HAVE_WHQL) #if defined(HAVE_EV) || defined(HAVE_WHQL)
@ -405,7 +287,7 @@ InstallCertificate(_In_z_ const WCHAR *SignedResource)
DWORD SizeResource; DWORD SizeResource;
DWORD Result = ResourceGetAddress(SignedResource, &LockedResource, &SizeResource); DWORD Result = ResourceGetAddress(SignedResource, &LockedResource, &SizeResource);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
return LOG_ERROR("Failed to locate resource", Result); return LOG_ERROR(L"Failed to locate resource", Result);
const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = (BYTE *)LockedResource }; const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = (BYTE *)LockedResource };
HCERTSTORE QueriedStore; HCERTSTORE QueriedStore;
if (!CryptQueryObject( if (!CryptQueryObject(
@ -420,7 +302,7 @@ InstallCertificate(_In_z_ const WCHAR *SignedResource)
&QueriedStore, &QueriedStore,
0, 0,
NULL)) NULL))
return LOG_LAST_ERROR("Failed to find certificate"); return LOG_LAST_ERROR(L"Failed to find certificate");
HCERTSTORE TrustedStore = HCERTSTORE TrustedStore =
CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"TrustedPublisher"); CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"TrustedPublisher");
if (!TrustedStore) if (!TrustedStore)
@ -576,11 +458,14 @@ static WINTUN_STATUS RemoveDriver(VOID)
break; break;
continue; continue;
} }
SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = DriverGetDrvInfoDetail(DevInfo, NULL, &DrvInfoData); SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData;
if (!DrvInfoDetailData) if (AdapterGetDrvInfoDetail(DevInfo, NULL, &DrvInfoData, &DrvInfoDetailData) != ERROR_SUCCESS)
continue; continue;
if (!_wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_HWID)) if (!DriverIsOurDrvInfoDetail(DrvInfoDetailData))
{ {
HeapFree(Heap, 0, DrvInfoDetailData);
continue;
}
PathStripPathW(DrvInfoDetailData->InfFileName); PathStripPathW(DrvInfoDetailData->InfFileName);
LOG(WINTUN_LOG_INFO, L"Removing existing driver"); LOG(WINTUN_LOG_INFO, L"Removing existing driver");
if (!SetupUninstallOEMInfW(DrvInfoDetailData->InfFileName, SUOI_FORCEDELETE, NULL)) if (!SetupUninstallOEMInfW(DrvInfoDetailData->InfFileName, SUOI_FORCEDELETE, NULL))
@ -588,7 +473,6 @@ static WINTUN_STATUS RemoveDriver(VOID)
LOG_LAST_ERROR(L"Unable to remove existing driver"); LOG_LAST_ERROR(L"Unable to remove existing driver");
Result = Result != ERROR_SUCCESS ? Result : GetLastError(); Result = Result != ERROR_SUCCESS ? Result : GetLastError();
} }
}
HeapFree(Heap, 0, DrvInfoDetailData); HeapFree(Heap, 0, DrvInfoDetailData);
} }
SetupDiDestroyDriverInfoList(DevInfo, NULL, SPDIT_CLASSDRIVER); SetupDiDestroyDriverInfoList(DevInfo, NULL, SPDIT_CLASSDRIVER);
@ -597,189 +481,6 @@ cleanupDeviceInfoSet:
return Result; return Result;
} }
# define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
/**
* Closes all client handles to the Wintun adapter.
*
* @param DevInfo A handle to the device information set that contains a device information element that
* represents the device.
*
* @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
static WINTUN_STATUS
ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData)
{
DWORD Result = ERROR_SUCCESS;
DWORD RequiredBytes;
if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) ||
(Result = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
return LOG_ERROR(L"Failed to query device instance ID size", Result);
HANDLE Heap = GetProcessHeap();
WCHAR *InstanceId = HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(*InstanceId) * RequiredBytes);
if (!InstanceId)
return ERROR_OUTOFMEMORY;
if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes))
{
Result = LOG_LAST_ERROR(L"Failed to get device instance ID");
goto out;
}
HANDLE NdisHandle = DriverGetAdapterDeviceObject(InstanceId);
if (NdisHandle == INVALID_HANDLE_VALUE)
{
Result = GetLastError();
goto out;
}
Result = DeviceIoControl(NdisHandle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL)
? ERROR_SUCCESS
: LOG_LAST_ERROR(L"Failed to perform ioctl");
CloseHandle(NdisHandle);
out:
HeapFree(Heap, 0, InstanceId);
return Result;
}
/**
* Disables Wintun adapters.
*
* @param DevInfo A handle to the device information set.
*
* @param DisabledAdapters Output list of disabled adapters. The adapters disabled are inserted in the list head.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
static WINTUN_STATUS
DisableWintunAdapters(_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 Result = ERROR_SUCCESS;
HANDLE Heap = GetProcessHeap();
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
SP_DEVINFO_DATA_LIST *DeviceNode = HeapAlloc(Heap, 0, sizeof(SP_DEVINFO_DATA_LIST));
if (!DeviceNode)
return ERROR_OUTOFMEMORY;
DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
{
HeapFree(Heap, 0, DeviceNode);
break;
}
goto cleanupDeviceInfoData;
}
if (!DriverIsWintunAdapter(DevInfo, &DeviceNode->Data))
goto cleanupDeviceInfoData;
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 cleanupDeviceInfoData;
LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter");
if (ForceCloseWintunAdapterHandle(DevInfo, &DeviceNode->Data) != ERROR_SUCCESS)
LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles");
Sleep(200);
LOG(WINTUN_LOG_INFO, L"Disabling existing adapter");
if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data))
{
LOG_LAST_ERROR(L"Unable to disable existing adapter");
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
goto cleanupDeviceInfoData;
}
DeviceNode->Next = *DisabledAdapters;
*DisabledAdapters = DeviceNode;
continue;
cleanupDeviceInfoData:
HeapFree(Heap, 0, &DeviceNode->Data);
}
return Result;
}
/**
* Removes all Wintun adapters.
*
* @param DevInfo A handle to the device information set.
*
* @param DisabledAdapters Output list of disabled adapters.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
static WINTUN_STATUS
RemoveWintunAdapters(_In_ HDEVINFO DevInfo)
{
SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
.InstallFunction = DIF_REMOVE },
.Scope = DI_REMOVEDEVICE_GLOBAL };
DWORD Result = ERROR_SUCCESS;
for (DWORD EnumIndex = 0;; ++EnumIndex)
{
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) };
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
continue;
}
if (!DriverIsWintunAdapter(DevInfo, &DevInfoData))
continue;
LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter");
if (ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS)
LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles");
Sleep(200);
LOG(WINTUN_LOG_INFO, L"Removing existing adapter");
if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData))
{
LOG_LAST_ERROR(L"Unable to remove existing adapter");
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
}
}
return Result;
}
/**
* Enables Wintun adapters.
*
* @param DevInfo A handle to the device information set.
*
* @param AdaptersToEnable Input list of adapters to enable.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/
static WINTUN_STATUS
EnableWintunAdapters(_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 Result = ERROR_SUCCESS;
for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next)
{
LOG(WINTUN_LOG_INFO, L"Enabling existing adapter");
if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data))
{
LOG_LAST_ERROR(L"Unable to enable existing adapter");
Result = Result != ERROR_SUCCESS ? Result : GetLastError();
}
}
return Result;
}
/** /**
* Installs or updates Wintun driver. * Installs or updates Wintun driver.
* *
@ -794,7 +495,7 @@ WINTUN_STATUS DriverInstallOrUpdate(VOID)
SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL; SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
if (IsDriverLoaded()) if (IsDriverLoaded())
{ {
DisableWintunAdapters(DevInfo, &ExistingAdapters); AdapterDisableAllOurs(DevInfo, &ExistingAdapters);
LOG(WINTUN_LOG_INFO, L"Waiting for driver to unload from kernel"); LOG(WINTUN_LOG_INFO, L"Waiting for driver to unload from kernel");
if (!EnsureDriverUnloaded()) if (!EnsureDriverUnloaded())
LOG(WINTUN_LOG_WARN, L"Unable to unload driver, which means a reboot will likely be required"); LOG(WINTUN_LOG_WARN, L"Unable to unload driver, which means a reboot will likely be required");
@ -815,7 +516,7 @@ WINTUN_STATUS DriverInstallOrUpdate(VOID)
cleanupAdapters:; cleanupAdapters:;
if (ExistingAdapters) if (ExistingAdapters)
{ {
EnableWintunAdapters(DevInfo, ExistingAdapters); AdapterEnableAll(DevInfo, ExistingAdapters);
while (ExistingAdapters) while (ExistingAdapters)
{ {
SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
@ -834,10 +535,7 @@ cleanupAdapters:;
*/ */
WINTUN_STATUS DriverUninstall(VOID) WINTUN_STATUS DriverUninstall(VOID)
{ {
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); AdapterDeleteAllOurs();
if (DevInfo == INVALID_HANDLE_VALUE)
return LOG_LAST_ERROR(L"Failed to get present class devices");
RemoveWintunAdapters(DevInfo);
DWORD Result = RemoveDriver(); DWORD Result = RemoveDriver();
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
LOG_ERROR(L"Failed to uninstall driver", Result); LOG_ERROR(L"Failed to uninstall driver", Result);

View File

@ -7,20 +7,14 @@
#include "api.h" #include "api.h"
#include <Windows.h> #include <Windows.h>
#include <SetupAPI.h>
#define WINTUN_HWID L"Wintun" #define WINTUN_HWID L"Wintun"
_Return_type_success_(return != NULL) SP_DRVINFO_DETAIL_DATA_W *DriverGetDrvInfoDetail( BOOL
_In_ HDEVINFO DevInfo, DriverIsOurHardwareID(_In_z_ const WCHAR *Hwids);
_In_opt_ SP_DEVINFO_DATA *DevInfoData,
_In_ SP_DRVINFO_DATA_W *DrvInfoData);
BOOL BOOL
DriverIsWintunAdapter(_In_ HDEVINFO DevInfo, _In_opt_ SP_DEVINFO_DATA *DevInfoData); DriverIsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData);
_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE
DriverGetAdapterDeviceObject(_In_opt_z_ const WCHAR *InstanceId);
#if defined(HAVE_EV) || defined(HAVE_WHQL) #if defined(HAVE_EV) || defined(HAVE_WHQL)

View File

@ -122,7 +122,7 @@ cleanupLeaveCriticalSection:
_Check_return_ _Check_return_
HANDLE HANDLE
TakeNameMutex(_In_z_ const WCHAR *Pool) NamespaceTakeMutex(_In_z_ const WCHAR *Pool)
{ {
HANDLE Mutex = NULL; HANDLE Mutex = NULL;
@ -171,7 +171,7 @@ cleanupSha256:
} }
void void
ReleaseNameMutex(_In_ HANDLE Mutex) NamespaceReleaseMutex(_In_ HANDLE Mutex)
{ {
ReleaseMutex(Mutex); ReleaseMutex(Mutex);
CloseHandle(Mutex); CloseHandle(Mutex);

View File

@ -9,10 +9,10 @@
_Check_return_ _Check_return_
HANDLE HANDLE
TakeNameMutex(_In_z_ const WCHAR *Pool); NamespaceTakeMutex(_In_z_ const WCHAR *Pool);
void void
ReleaseNameMutex(_In_ HANDLE Mutex); NamespaceReleaseMutex(_In_ HANDLE Mutex);
void void
NamespaceInit(); NamespaceInit();

View File

@ -5,8 +5,8 @@
#pragma once #pragma once
#include "adapter.h"
#include "api.h" #include "api.h"
#include "devmgmt.h"
#include "driver.h" #include "driver.h"
#include "logger.h" #include "logger.h"
#include "namespace.h" #include "namespace.h"

View File

@ -49,7 +49,7 @@ OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGL
TimeLeft = 0; TimeLeft = 0;
if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0) if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
{ {
LOG(WINTUN_LOG_ERR, "Timeout waiting"); LOG(WINTUN_LOG_ERR, L"Timeout waiting");
break; break;
} }
} }
@ -349,7 +349,7 @@ RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD
TimeLeft = 0; TimeLeft = 0;
if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0) if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
{ {
LOG(WINTUN_LOG_ERR, "Timeout waiting"); LOG(WINTUN_LOG_ERR, L"Timeout waiting");
break; break;
} }
} }
@ -427,7 +427,7 @@ RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD T
TimeLeft = 0; TimeLeft = 0;
if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0) if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
{ {
LOG(WINTUN_LOG_ERR, "Timeout waiting"); LOG(WINTUN_LOG_ERR, L"Timeout waiting");
break; break;
} }
} }

View File

@ -58,7 +58,7 @@ ResourceCopyToFile(
DWORD SizeResource; DWORD SizeResource;
DWORD Result = ResourceGetAddress(ResourceName, &LockedResource, &SizeResource); DWORD Result = ResourceGetAddress(ResourceName, &LockedResource, &SizeResource);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
return LOG_ERROR("Failed to locate resource", Result); return LOG_ERROR(L"Failed to locate resource", Result);
HANDLE DestinationHandle = CreateFileW( HANDLE DestinationHandle = CreateFileW(
DestinationPath, DestinationPath,
GENERIC_WRITE, GENERIC_WRITE,