2020-07-07 15:42:39 +02:00
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright ( C ) 2018 - 2020 WireGuard LLC . All Rights Reserved .
*/
2020-10-31 11:55:26 +01:00
# include "adapter.h"
# include "elevate.h"
# include "entry.h"
# include "logger.h"
# include "namespace.h"
# include "nci.h"
2020-11-03 15:28:17 +01:00
# include "ntdll.h"
2020-10-31 11:55:26 +01:00
# include "registry.h"
# include "resource.h"
2020-11-03 17:06:20 +01:00
# include "wintun-inf.h"
2020-10-31 11:55:26 +01:00
# include <Windows.h>
# include <winternl.h>
2020-10-31 18:13:36 +01:00
# define _NTDEF_ /* TODO: figure out how to include ntsecapi and winternal together without requiring this */
2020-10-31 11:55:26 +01:00
# include <cfgmgr32.h>
# include <devguid.h>
# include <iphlpapi.h>
# include <ndisguid.h>
# include <newdev.h>
# include <NTSecAPI.h>
# include <SetupAPI.h>
# include <Shlwapi.h>
# include <wchar.h>
2020-11-02 13:52:47 +01:00
# 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>
2020-07-07 15:42:39 +02:00
2020-10-15 15:54:37 +02:00
# pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
2020-10-31 08:53:32 +01:00
# define WAIT_FOR_REGISTRY_TIMEOUT 10000 /* ms */
# define MAX_POOL_DEVICE_TYPE (WINTUN_MAX_POOL + 8) /* Should accommodate a pool name with " Tunnel" appended */
2020-10-16 13:30:51 +02:00
# if defined(_M_IX86)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386
# elif defined(_M_AMD64)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64
# elif defined(_M_ARM)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT
# elif defined(_M_ARM64)
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64
# else
# error Unsupported architecture
# endif
2020-07-07 15:42:39 +02:00
2020-11-02 16:28:51 +01:00
typedef struct _SP_DEVINFO_DATA_LIST
{
SP_DEVINFO_DATA Data ;
struct _SP_DEVINFO_DATA_LIST * Next ;
} SP_DEVINFO_DATA_LIST ;
2020-10-16 13:30:51 +02:00
static USHORT NativeMachine = IMAGE_FILE_PROCESS ;
2020-07-28 12:30:12 +02:00
2020-11-02 16:28:51 +01:00
static WINTUN_STATUS
GetAdapterDrvInfoDetail (
2020-10-15 11:32:06 +02:00
_In_ HDEVINFO DevInfo ,
_In_opt_ SP_DEVINFO_DATA * DevInfoData ,
_In_ SP_DRVINFO_DATA_W * DrvInfoData ,
_Out_ SP_DRVINFO_DETAIL_DATA_W * * DrvInfoDetailData )
{
DWORD Size = sizeof ( SP_DRVINFO_DETAIL_DATA_W ) + 0x100 ;
for ( ; ; )
{
2020-10-30 13:08:57 +01:00
SP_DRVINFO_DETAIL_DATA_W * p = HeapAlloc ( ModuleHeap , 0 , Size ) ;
if ( ! p )
2020-10-15 12:38:05 +02:00
return LOG ( WINTUN_LOG_ERR , L " Out of memory " ) , ERROR_OUTOFMEMORY ;
2020-10-30 13:08:57 +01:00
p - > cbSize = sizeof ( SP_DRVINFO_DETAIL_DATA_W ) ;
if ( SetupDiGetDriverInfoDetailW ( DevInfo , DevInfoData , DrvInfoData , p , Size , & Size ) )
{
* DrvInfoDetailData = p ;
2020-10-15 11:32:06 +02:00
return ERROR_SUCCESS ;
2020-10-30 13:08:57 +01:00
}
2020-10-15 12:38:05 +02:00
DWORD Result = GetLastError ( ) ;
2020-10-30 13:08:57 +01:00
HeapFree ( ModuleHeap , 0 , p ) ;
2020-10-15 11:32:06 +02:00
if ( Result ! = ERROR_INSUFFICIENT_BUFFER )
2020-10-15 12:38:05 +02:00
return LOG_ERROR ( L " Failed " , Result ) ;
2020-10-15 11:32:06 +02:00
}
}
2020-07-21 16:43:34 +02:00
static WINTUN_STATUS
2020-07-21 11:11:14 +02:00
GetDeviceRegistryProperty (
2020-07-07 15:42:39 +02:00
_In_ HDEVINFO DevInfo ,
_In_ SP_DEVINFO_DATA * DevInfoData ,
_In_ DWORD Property ,
2020-07-24 08:29:33 +02:00
_Out_opt_ DWORD * ValueType ,
_Out_ void * * Buf ,
_Inout_ DWORD * BufLen )
2020-07-07 15:42:39 +02:00
{
for ( ; ; )
{
2020-10-30 13:08:57 +01:00
BYTE * p = HeapAlloc ( ModuleHeap , 0 , * BufLen ) ;
if ( ! p )
2020-10-15 12:38:05 +02:00
return LOG ( WINTUN_LOG_ERR , L " Out of memory " ) , ERROR_OUTOFMEMORY ;
2020-10-30 13:08:57 +01:00
if ( SetupDiGetDeviceRegistryPropertyW ( DevInfo , DevInfoData , Property , ValueType , p , * BufLen , BufLen ) )
{
* Buf = p ;
2020-07-24 08:29:33 +02:00
return ERROR_SUCCESS ;
2020-10-30 13:08:57 +01:00
}
2020-07-24 08:29:33 +02:00
DWORD Result = GetLastError ( ) ;
2020-10-30 13:08:57 +01:00
HeapFree ( ModuleHeap , 0 , p ) ;
2020-07-24 08:29:33 +02:00
if ( Result ! = ERROR_INSUFFICIENT_BUFFER )
2020-10-14 13:04:29 +02:00
return LOG_ERROR ( L " Querying property failed " , Result ) ;
2020-07-07 15:42:39 +02:00
}
}
2020-07-21 16:43:34 +02:00
static WINTUN_STATUS
2020-07-21 11:11:14 +02:00
GetDeviceRegistryString (
2020-07-07 15:42:39 +02:00
_In_ HDEVINFO DevInfo ,
_In_ SP_DEVINFO_DATA * DevInfoData ,
_In_ DWORD Property ,
2020-07-24 08:29:33 +02:00
_Out_ WCHAR * * Buf )
2020-07-07 15:42:39 +02:00
{
2020-07-24 08:29:33 +02:00
DWORD Result , ValueType , Size = 256 * sizeof ( WCHAR ) ;
Result = GetDeviceRegistryProperty ( DevInfo , DevInfoData , Property , & ValueType , Buf , & Size ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
return Result ;
switch ( ValueType )
{
case REG_SZ :
case REG_EXPAND_SZ :
2020-07-21 16:38:00 +02:00
case REG_MULTI_SZ :
2020-07-24 08:29:33 +02:00
Result = RegistryGetString ( Buf , Size / sizeof ( WCHAR ) , ValueType ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , * Buf ) ;
2020-07-07 15:42:39 +02:00
return Result ;
default :
2020-10-14 13:04:29 +02:00
LOG ( WINTUN_LOG_ERR , L " Property is not a string " ) ;
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , * Buf ) ;
2020-07-07 15:42:39 +02:00
return ERROR_INVALID_DATATYPE ;
}
}
2020-07-21 16:43:34 +02:00
static WINTUN_STATUS
2020-07-21 11:11:14 +02:00
GetDeviceRegistryMultiString (
2020-07-07 15:42:39 +02:00
_In_ HDEVINFO DevInfo ,
_In_ SP_DEVINFO_DATA * DevInfoData ,
_In_ DWORD Property ,
2020-07-24 08:29:33 +02:00
_Out_ WCHAR * * Buf )
2020-07-07 15:42:39 +02:00
{
2020-07-24 08:29:33 +02:00
DWORD Result , ValueType , Size = 256 * sizeof ( WCHAR ) ;
Result = GetDeviceRegistryProperty ( DevInfo , DevInfoData , Property , & ValueType , Buf , & Size ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
return Result ;
switch ( ValueType )
{
case REG_SZ :
case REG_EXPAND_SZ :
case REG_MULTI_SZ :
2020-07-24 08:29:33 +02:00
Result = RegistryGetMultiString ( Buf , Size / sizeof ( WCHAR ) , ValueType ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , * Buf ) ;
2020-07-07 15:42:39 +02:00
return Result ;
default :
2020-10-14 13:04:29 +02:00
LOG ( WINTUN_LOG_ERR , L " Property is not a string " ) ;
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , * Buf ) ;
2020-07-07 15:42:39 +02:00
return ERROR_INVALID_DATATYPE ;
}
}
2020-10-30 09:53:09 +01:00
static BOOL
IsOurHardwareID ( _In_z_ const WCHAR * Hwids )
{
for ( ; Hwids [ 0 ] ; Hwids + = wcslen ( Hwids ) + 1 )
if ( ! _wcsicmp ( Hwids , WINTUN_HWID ) )
return TRUE ;
return FALSE ;
}
2020-10-15 11:32:06 +02:00
static WINTUN_STATUS
2020-10-16 15:51:50 +02:00
IsOurAdapter ( _In_ HDEVINFO DevInfo , _In_ SP_DEVINFO_DATA * DevInfoData , _Out_ BOOL * IsOurs )
2020-07-21 18:19:15 +02:00
{
2020-10-15 11:32:06 +02:00
WCHAR * Hwids ;
DWORD Result = GetDeviceRegistryMultiString ( DevInfo , DevInfoData , SPDRP_HARDWAREID , & Hwids ) ;
if ( Result ! = ERROR_SUCCESS )
2020-11-02 11:52:54 +01:00
return LOG ( WINTUN_LOG_ERR , L " Failed to get hardware ID " ) , Result ;
2020-10-30 09:53:09 +01:00
* IsOurs = IsOurHardwareID ( Hwids ) ;
2020-10-15 11:32:06 +02:00
return ERROR_SUCCESS ;
}
static WINTUN_STATUS
GetDeviceObject ( _In_opt_z_ const WCHAR * InstanceId , _Out_ HANDLE * Handle )
{
ULONG InterfacesLen ;
2020-11-02 16:28:51 +01:00
DWORD Result = 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 ) ;
2020-11-02 00:13:55 +01:00
if ( Result ! = ERROR_SUCCESS )
return LOG_ERROR ( L " Failed to query associated instances size " , Result ) ;
2020-10-24 22:12:47 +02:00
WCHAR * Interfaces = HeapAlloc ( ModuleHeap , 0 , InterfacesLen * sizeof ( WCHAR ) ) ;
2020-10-15 11:32:06 +02:00
if ( ! Interfaces )
2020-10-15 12:38:05 +02:00
return LOG ( WINTUN_LOG_ERR , L " Out of memory " ) , ERROR_OUTOFMEMORY ;
2020-11-02 16:28:51 +01:00
Result = 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 ) ;
2020-11-02 00:13:55 +01:00
if ( Result ! = ERROR_SUCCESS )
2020-10-15 11:32:06 +02:00
{
2020-11-02 00:13:55 +01:00
LOG_ERROR ( L " Failed to get associated instances " , Result ) ;
2020-10-15 11:32:06 +02:00
goto cleanupBuf ;
}
* Handle = CreateFileW (
Interfaces ,
GENERIC_READ | GENERIC_WRITE ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
NULL ,
OPEN_EXISTING ,
0 ,
NULL ) ;
2020-11-02 11:52:54 +01:00
Result = * Handle ! = INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR ( L " Failed to connect to adapter " ) ;
2020-10-15 11:32:06 +02:00
cleanupBuf :
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , Interfaces ) ;
2020-10-15 11:32:06 +02:00
return Result ;
}
# define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
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 )
2020-11-02 11:52:54 +01:00
return LOG_ERROR ( L " Failed to query instance ID size " , Result ) ;
2020-10-24 22:12:47 +02:00
WCHAR * InstanceId = HeapAlloc ( ModuleHeap , HEAP_ZERO_MEMORY , sizeof ( * InstanceId ) * RequiredBytes ) ;
2020-10-15 11:32:06 +02:00
if ( ! InstanceId )
2020-10-15 12:38:05 +02:00
return LOG ( WINTUN_LOG_ERR , L " Out of memory " ) , ERROR_OUTOFMEMORY ;
2020-10-15 11:32:06 +02:00
if ( ! SetupDiGetDeviceInstanceIdW ( DevInfo , DevInfoData , InstanceId , RequiredBytes , & RequiredBytes ) )
{
2020-11-02 11:52:54 +01:00
Result = LOG_LAST_ERROR ( L " Failed to get instance ID " ) ;
2020-10-15 11:32:06 +02:00
goto out ;
}
HANDLE NdisHandle ;
Result = GetDeviceObject ( InstanceId , & NdisHandle ) ;
if ( Result ! = ERROR_SUCCESS )
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get adapter object " ) ;
2020-10-15 11:32:06 +02:00
goto out ;
}
2020-10-30 14:21:13 +01:00
if ( DeviceIoControl ( NdisHandle , TUN_IOCTL_FORCE_CLOSE_HANDLES , NULL , 0 , NULL , 0 , & RequiredBytes , NULL ) )
{
Result = ERROR_SUCCESS ;
Sleep ( 200 ) ;
}
else if ( GetLastError ( ) = = ERROR_NOTHING_TO_TERMINATE )
Result = ERROR_SUCCESS ;
else
Result = LOG_LAST_ERROR ( L " Failed to perform ioctl " ) ;
2020-10-15 11:32:06 +02:00
CloseHandle ( NdisHandle ) ;
out :
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , InstanceId ) ;
2020-10-15 11:32:06 +02:00
return Result ;
}
2020-11-02 16:28:51 +01:00
static WINTUN_STATUS
DisableAllOurAdapters ( _In_ HDEVINFO DevInfo , _Inout_ SP_DEVINFO_DATA_LIST * * DisabledAdapters )
2020-10-15 11:32:06 +02:00
{
SP_PROPCHANGE_PARAMS Params = { . ClassInstallHeader = { . cbSize = sizeof ( SP_CLASSINSTALL_HEADER ) ,
. InstallFunction = DIF_PROPERTYCHANGE } ,
. StateChange = DICS_DISABLE ,
. Scope = DICS_FLAG_GLOBAL } ;
DWORD Result = ERROR_SUCCESS ;
for ( DWORD EnumIndex = 0 ; ; + + EnumIndex )
{
2020-10-24 22:12:47 +02:00
SP_DEVINFO_DATA_LIST * DeviceNode = HeapAlloc ( ModuleHeap , 0 , sizeof ( SP_DEVINFO_DATA_LIST ) ) ;
2020-10-15 11:32:06 +02:00
if ( ! DeviceNode )
2020-10-15 12:38:05 +02:00
return LOG ( WINTUN_LOG_ERR , L " Out of memory " ) , ERROR_OUTOFMEMORY ;
2020-10-15 11:32:06 +02:00
DeviceNode - > Data . cbSize = sizeof ( SP_DEVINFO_DATA ) ;
if ( ! SetupDiEnumDeviceInfo ( DevInfo , EnumIndex , & DeviceNode - > Data ) )
{
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
{
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , DeviceNode ) ;
2020-10-15 11:32:06 +02:00
break ;
}
2020-11-02 23:21:16 +01:00
goto cleanupDeviceNode ;
2020-10-15 11:32:06 +02:00
}
2020-10-16 15:51:50 +02:00
BOOL IsOurs ;
if ( IsOurAdapter ( DevInfo , & DeviceNode - > Data , & IsOurs ) ! = ERROR_SUCCESS | | ! IsOurs )
2020-11-02 23:21:16 +01:00
goto cleanupDeviceNode ;
2020-10-15 11:32:06 +02:00
ULONG Status , ProblemCode ;
if ( CM_Get_DevNode_Status ( & Status , & ProblemCode , DeviceNode - > Data . DevInst , 0 ) ! = CR_SUCCESS | |
( ( Status & DN_HAS_PROBLEM ) & & ProblemCode = = CM_PROB_DISABLED ) )
2020-11-02 23:21:16 +01:00
goto cleanupDeviceNode ;
2020-10-15 11:32:06 +02:00
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 " ) ;
LOG ( WINTUN_LOG_INFO , L " Disabling existing adapter " ) ;
if ( ! SetupDiSetClassInstallParamsW ( DevInfo , & DeviceNode - > Data , & Params . ClassInstallHeader , sizeof ( Params ) ) | |
! SetupDiCallClassInstaller ( DIF_PROPERTYCHANGE , DevInfo , & DeviceNode - > Data ) )
{
2020-11-02 11:52:54 +01:00
LOG_LAST_ERROR ( L " Failed to disable existing adapter " ) ;
2020-10-15 11:32:06 +02:00
Result = Result ! = ERROR_SUCCESS ? Result : GetLastError ( ) ;
2020-11-02 23:21:16 +01:00
goto cleanupDeviceNode ;
2020-10-15 11:32:06 +02:00
}
DeviceNode - > Next = * DisabledAdapters ;
* DisabledAdapters = DeviceNode ;
continue ;
2020-11-02 23:21:16 +01:00
cleanupDeviceNode :
HeapFree ( ModuleHeap , 0 , DeviceNode ) ;
2020-10-15 11:32:06 +02:00
}
return Result ;
}
2020-11-02 16:28:51 +01:00
static WINTUN_STATUS
EnableAllOurAdapters ( _In_ HDEVINFO DevInfo , _In_ SP_DEVINFO_DATA_LIST * AdaptersToEnable )
2020-10-15 11:32:06 +02:00
{
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 ) )
{
2020-11-02 11:52:54 +01:00
LOG_LAST_ERROR ( L " Failed to enable existing adapter " ) ;
2020-10-15 11:32:06 +02:00
Result = Result ! = ERROR_SUCCESS ? Result : GetLastError ( ) ;
}
}
return Result ;
}
void
2020-10-30 06:03:21 +01:00
AdapterInit ( void )
2020-10-15 11:32:06 +02:00
{
2020-11-03 02:09:00 +01:00
if ( ! MAYBE_WOW64 )
return ;
2020-10-16 13:30:51 +02:00
typedef BOOL ( WINAPI * IsWow64Process2_t ) (
_In_ HANDLE hProcess , _Out_ USHORT * pProcessMachine , _Out_opt_ USHORT * pNativeMachine ) ;
HANDLE Kernel32 ;
IsWow64Process2_t IsWow64Process2 ;
USHORT ProcessMachine ;
if ( ( Kernel32 = GetModuleHandleW ( L " kernel32.dll " ) ) = = NULL | |
( IsWow64Process2 = ( IsWow64Process2_t ) GetProcAddress ( Kernel32 , " IsWow64Process2 " ) ) = = NULL | |
! IsWow64Process2 ( GetCurrentProcess ( ) , & ProcessMachine , & NativeMachine ) )
{
BOOL IsWoW64 ;
NativeMachine =
IsWow64Process ( GetCurrentProcess ( ) , & IsWoW64 ) & & IsWoW64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_PROCESS ;
}
2020-10-15 11:32:06 +02:00
}
2020-07-21 18:19:15 +02:00
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 ) )
2020-10-13 19:40:52 +02:00
{
2020-10-14 13:04:29 +02:00
LOG_LAST_ERROR ( L " Retrieving device installation parameters failed " ) ;
2020-07-21 18:19:15 +02:00
return FALSE ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 18:19:15 +02:00
return ( DevInstallParams . Flags & ( DI_NEEDREBOOT | DI_NEEDRESTART ) ) ! = 0 ;
}
static WINTUN_STATUS
SetQuietInstall ( _In_ HDEVINFO DevInfo , _In_ SP_DEVINFO_DATA * DevInfoData )
{
SP_DEVINSTALL_PARAMS_W DevInstallParams = { . cbSize = sizeof ( SP_DEVINSTALL_PARAMS_W ) } ;
if ( ! SetupDiGetDeviceInstallParamsW ( DevInfo , DevInfoData , & DevInstallParams ) )
2020-10-14 13:04:29 +02:00
return LOG_LAST_ERROR ( L " Retrieving device installation parameters failed " ) ;
2020-07-21 18:19:15 +02:00
DevInstallParams . Flags | = DI_QUIETINSTALL ;
if ( ! SetupDiSetDeviceInstallParamsW ( DevInfo , DevInfoData , & DevInstallParams ) )
2020-10-14 13:04:29 +02:00
return LOG_LAST_ERROR ( L " Setting device installation parameters failed " ) ;
2020-07-21 18:19:15 +02:00
return ERROR_SUCCESS ;
}
2020-07-21 16:43:34 +02:00
static WINTUN_STATUS
2020-07-21 16:38:00 +02:00
GetNetCfgInstanceId ( _In_ HDEVINFO DevInfo , _In_ SP_DEVINFO_DATA * DevInfoData , _Out_ GUID * CfgInstanceID )
{
HKEY Key = SetupDiOpenDevRegKey ( DevInfo , DevInfoData , DICS_FLAG_GLOBAL , 0 , DIREG_DRV , KEY_QUERY_VALUE ) ;
if ( Key = = INVALID_HANDLE_VALUE )
2020-10-14 13:04:29 +02:00
return LOG_LAST_ERROR ( L " Opening device registry key failed " ) ;
2020-07-21 18:19:15 +02:00
WCHAR * ValueStr ;
2020-10-23 22:04:40 +02:00
DWORD Result = RegistryQueryString ( Key , L " NetCfgInstanceId " , & ValueStr , TRUE ) ;
2020-07-21 16:38:00 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get NetCfgInstanceId " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupKey ;
2020-10-13 19:40:52 +02:00
}
if ( FAILED ( CLSIDFromString ( ValueStr , CfgInstanceID ) ) )
{
2020-10-14 13:04:29 +02:00
LOG ( WINTUN_LOG_ERR , L " NetCfgInstanceId is not a GUID " ) ;
2020-10-13 19:40:52 +02:00
Result = ERROR_INVALID_DATA ;
}
else
Result = ERROR_SUCCESS ;
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , ValueStr ) ;
2020-07-21 16:38:00 +02:00
cleanupKey :
RegCloseKey ( Key ) ;
return Result ;
}
2020-07-21 18:19:15 +02:00
static WINTUN_STATUS
GetDevInfoData ( _In_ const GUID * CfgInstanceID , _Out_ HDEVINFO * DevInfo , _Out_ SP_DEVINFO_DATA * DevInfoData )
{
2020-10-13 19:40:52 +02:00
* DevInfo = SetupDiGetClassDevsExW ( & GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL ) ;
2020-07-21 18:19:15 +02:00
if ( ! * DevInfo )
2020-11-02 11:52:54 +01:00
return LOG_LAST_ERROR ( L " Failed to get present adapters " ) ;
2020-10-13 19:40:52 +02:00
for ( DWORD EnumIndex = 0 ; ; + + EnumIndex )
2020-07-21 18:19:15 +02:00
{
DevInfoData - > cbSize = sizeof ( SP_DEVINFO_DATA ) ;
2020-10-13 19:40:52 +02:00
if ( ! SetupDiEnumDeviceInfo ( * DevInfo , EnumIndex , DevInfoData ) )
2020-07-21 18:19:15 +02:00
{
2020-07-24 08:29:33 +02:00
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
2020-07-21 18:19:15 +02:00
break ;
continue ;
}
GUID CfgInstanceID2 ;
2020-07-24 08:29:33 +02:00
if ( GetNetCfgInstanceId ( * DevInfo , DevInfoData , & CfgInstanceID2 ) = = ERROR_SUCCESS & &
! memcmp ( CfgInstanceID , & CfgInstanceID2 , sizeof ( GUID ) ) )
return ERROR_SUCCESS ;
2020-07-21 18:19:15 +02:00
}
SetupDiDestroyDeviceInfoList ( * DevInfo ) ;
2020-07-24 08:26:20 +02:00
return ERROR_FILE_NOT_FOUND ;
2020-07-21 18:19:15 +02:00
}
static void
2020-10-30 06:12:42 +01:00
RemoveNumberedSuffix ( _Inout_z_ WCHAR * Name )
2020-07-21 18:19:15 +02:00
{
2020-10-30 06:12:42 +01:00
for ( size_t i = wcslen ( Name ) ; i - - ; )
2020-07-21 18:19:15 +02:00
{
2020-10-30 06:12:42 +01:00
if ( ( Name [ i ] < L ' 0 ' | | Name [ i ] > L ' 9 ' ) & & ! iswspace ( Name [ i ] ) )
2020-07-21 18:19:15 +02:00
return ;
2020-10-30 06:12:42 +01:00
Name [ i ] = 0 ;
2020-07-21 18:19:15 +02:00
}
}
2020-10-30 06:51:24 +01:00
static WINTUN_STATUS
2020-10-31 18:13:36 +01:00
GetPoolDeviceTypeName ( _In_z_ const WCHAR * Pool , _Out_cap_c_ ( MAX_POOL_DEVICE_TYPE ) WCHAR * Name )
2020-07-21 18:19:15 +02:00
{
2020-10-31 18:13:36 +01:00
if ( _snwprintf_s ( Name , MAX_POOL_DEVICE_TYPE , _TRUNCATE , L " %s Tunnel " , Pool ) = = - 1 )
2020-10-30 06:51:24 +01:00
return LOG ( WINTUN_LOG_ERR , L " Pool name too long " ) , ERROR_INVALID_PARAMETER ;
return ERROR_SUCCESS ;
2020-07-21 18:19:15 +02:00
}
static WINTUN_STATUS
2020-10-31 18:13:36 +01:00
IsPoolMember ( _In_z_ const WCHAR * Pool , _In_ HDEVINFO DevInfo , _In_ SP_DEVINFO_DATA * DevInfoData , _Out_ BOOL * IsMember )
2020-07-21 18:19:15 +02:00
{
WCHAR * DeviceDesc , * FriendlyName ;
DWORD Result = GetDeviceRegistryString ( DevInfo , DevInfoData , SPDRP_DEVICEDESC , & DeviceDesc ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get adapter description " ) ;
2020-07-21 18:19:15 +02:00
return Result ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 18:19:15 +02:00
Result = GetDeviceRegistryString ( DevInfo , DevInfoData , SPDRP_FRIENDLYNAME , & FriendlyName ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get adapter friendly name " ) ;
2020-07-21 18:19:15 +02:00
goto cleanupDeviceDesc ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 18:19:15 +02:00
WCHAR PoolDeviceTypeName [ MAX_POOL_DEVICE_TYPE ] ;
2020-10-30 06:51:24 +01:00
Result = GetPoolDeviceTypeName ( Pool , PoolDeviceTypeName ) ;
if ( Result ! = ERROR_SUCCESS )
goto cleanupFriendlyName ;
2020-10-30 06:06:06 +01:00
if ( ! _wcsicmp ( FriendlyName , PoolDeviceTypeName ) | | ! _wcsicmp ( DeviceDesc , PoolDeviceTypeName ) )
2020-07-21 18:19:15 +02:00
{
* IsMember = TRUE ;
goto cleanupFriendlyName ;
}
2020-10-30 06:12:42 +01:00
RemoveNumberedSuffix ( FriendlyName ) ;
RemoveNumberedSuffix ( DeviceDesc ) ;
2020-10-30 06:06:06 +01:00
if ( ! _wcsicmp ( FriendlyName , PoolDeviceTypeName ) | | ! _wcsicmp ( DeviceDesc , PoolDeviceTypeName ) )
2020-07-21 18:19:15 +02:00
{
* IsMember = TRUE ;
goto cleanupFriendlyName ;
}
* IsMember = FALSE ;
cleanupFriendlyName :
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , FriendlyName ) ;
2020-07-21 18:19:15 +02:00
cleanupDeviceDesc :
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , DeviceDesc ) ;
2020-07-21 18:19:15 +02:00
return Result ;
}
2020-07-21 16:43:34 +02:00
static WINTUN_STATUS
2020-07-21 16:38:00 +02:00
CreateAdapterData (
2020-10-31 18:13:36 +01:00
_In_z_ const WCHAR * Pool ,
2020-07-07 15:42:39 +02:00
_In_ HDEVINFO DevInfo ,
_In_ SP_DEVINFO_DATA * DevInfoData ,
2020-07-21 16:38:00 +02:00
_Out_ WINTUN_ADAPTER * * Adapter )
2020-07-07 15:42:39 +02:00
{
DWORD Result ;
/* Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\<class>\<id> registry key. */
HKEY Key = SetupDiOpenDevRegKey ( DevInfo , DevInfoData , DICS_FLAG_GLOBAL , 0 , DIREG_DRV , KEY_QUERY_VALUE ) ;
if ( Key = = INVALID_HANDLE_VALUE )
2020-10-14 13:04:29 +02:00
return LOG_LAST_ERROR ( L " Opening device registry key failed " ) ;
2020-07-07 15:42:39 +02:00
2020-10-30 13:08:57 +01:00
WINTUN_ADAPTER * a = HeapAlloc ( ModuleHeap , 0 , sizeof ( WINTUN_ADAPTER ) ) ;
if ( ! a )
2020-07-21 16:38:00 +02:00
{
2020-10-15 12:38:05 +02:00
LOG ( WINTUN_LOG_ERR , L " Out of memory " ) ;
2020-07-21 16:38:00 +02:00
Result = ERROR_OUTOFMEMORY ;
goto cleanupKey ;
}
2020-07-07 15:42:39 +02:00
/* Read the NetCfgInstanceId value and convert to GUID. */
2020-07-21 18:19:15 +02:00
WCHAR * ValueStr ;
2020-10-23 22:04:40 +02:00
Result = RegistryQueryString ( Key , L " NetCfgInstanceId " , & ValueStr , TRUE ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get NetCfgInstanceId " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupAdapter ;
2020-10-13 19:40:52 +02:00
}
2020-10-30 13:08:57 +01:00
if ( FAILED ( CLSIDFromString ( ValueStr , & a - > CfgInstanceID ) ) )
2020-07-07 15:42:39 +02:00
{
2020-10-14 13:04:29 +02:00
LOG ( WINTUN_LOG_ERR , L " NetCfgInstanceId is not a GUID " ) ;
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , ValueStr ) ;
2020-07-07 15:42:39 +02:00
Result = ERROR_INVALID_DATA ;
2020-07-21 16:38:00 +02:00
goto cleanupAdapter ;
2020-07-07 15:42:39 +02:00
}
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , ValueStr ) ;
2020-07-07 15:42:39 +02:00
/* Read the NetLuidIndex value. */
2020-10-30 13:08:57 +01:00
Result = RegistryQueryDWORD ( Key , L " NetLuidIndex " , & a - > LuidIndex , TRUE ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get NetLuidIndex " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupAdapter ;
2020-10-13 19:40:52 +02:00
}
2020-07-07 15:42:39 +02:00
/* Read the NetLuidIndex value. */
2020-10-30 13:08:57 +01:00
Result = RegistryQueryDWORD ( Key , L " *IfType " , & a - > IfType , TRUE ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get *IfType " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupAdapter ;
2020-10-13 19:40:52 +02:00
}
2020-07-07 15:42:39 +02:00
DWORD Size ;
2020-10-30 13:08:57 +01:00
if ( ! SetupDiGetDeviceInstanceIdW ( DevInfo , DevInfoData , a - > DevInstanceID , _countof ( a - > DevInstanceID ) , & Size ) )
2020-07-07 15:42:39 +02:00
{
2020-11-02 11:52:54 +01:00
Result = LOG_LAST_ERROR ( L " Failed to get instance ID " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupAdapter ;
2020-07-07 15:42:39 +02:00
}
2020-10-30 13:08:57 +01:00
if ( wcsncpy_s ( a - > Pool , _countof ( a - > Pool ) , Pool , _TRUNCATE ) = = STRUNCATE )
2020-10-30 06:51:24 +01:00
{
LOG ( WINTUN_LOG_ERR , L " Pool name too long " ) ;
Result = ERROR_INVALID_PARAMETER ;
goto cleanupAdapter ;
}
2020-10-30 13:08:57 +01:00
* Adapter = a ;
2020-07-07 15:42:39 +02:00
Result = ERROR_SUCCESS ;
2020-07-21 16:38:00 +02:00
cleanupAdapter :
if ( Result ! = ERROR_SUCCESS )
2020-10-30 13:08:57 +01:00
HeapFree ( ModuleHeap , 0 , a ) ;
2020-07-07 15:42:39 +02:00
cleanupKey :
RegCloseKey ( Key ) ;
return Result ;
}
2020-10-30 06:51:24 +01:00
static WINTUN_STATUS
2020-07-24 08:10:00 +02:00
GetDeviceRegPath ( _In_ const WINTUN_ADAPTER * Adapter , _Out_cap_c_ ( MAX_REG_PATH ) WCHAR * Path )
2020-07-21 16:38:00 +02:00
{
2020-10-30 06:51:24 +01:00
if ( _snwprintf_s (
Path ,
MAX_REG_PATH ,
_TRUNCATE ,
L " SYSTEM \\ CurrentControlSet \\ Enum \\ %.*s " ,
MAX_INSTANCE_ID ,
Adapter - > DevInstanceID ) = = - 1 )
return LOG ( WINTUN_LOG_ERR , L " Registry path too long " ) , ERROR_INVALID_PARAMETER ;
return ERROR_SUCCESS ;
2020-07-21 16:38:00 +02:00
}
2020-07-21 18:19:15 +02:00
void WINAPI
2020-07-07 15:42:39 +02:00
WintunFreeAdapter ( _In_ WINTUN_ADAPTER * Adapter )
{
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , Adapter ) ;
2020-07-07 15:42:39 +02:00
}
2020-07-21 16:43:34 +02:00
WINTUN_STATUS WINAPI
2020-10-31 18:13:36 +01:00
WintunGetAdapter ( _In_z_ const WCHAR * Pool , _In_z_ const WCHAR * Name , _Out_ WINTUN_ADAPTER * * Adapter )
2020-07-07 15:42:39 +02:00
{
2020-10-30 12:25:24 +01:00
if ( ! ElevateToSystem ( ) )
2020-11-03 02:24:32 +01:00
return LOG_LAST_ERROR ( L " Failed to impersonate SYSTEM user " ) ;
2020-07-07 15:42:39 +02:00
DWORD Result ;
2020-11-02 12:07:05 +01:00
HANDLE Mutex = NamespaceTakePoolMutex ( Pool ) ;
2020-07-07 15:42:39 +02:00
if ( ! Mutex )
2020-10-30 12:25:24 +01:00
{
Result = ERROR_INVALID_HANDLE ;
goto cleanupToken ;
}
2020-07-07 15:42:39 +02:00
2020-10-13 19:40:52 +02:00
HDEVINFO DevInfo = SetupDiGetClassDevsExW ( & GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL ) ;
2020-07-07 15:42:39 +02:00
if ( DevInfo = = INVALID_HANDLE_VALUE )
{
2020-11-02 11:52:54 +01:00
Result = LOG_LAST_ERROR ( L " Failed to get present adapters " ) ;
2020-07-07 15:42:39 +02:00
goto cleanupMutex ;
}
2020-10-13 19:40:52 +02:00
for ( DWORD EnumIndex = 0 ; ; + + EnumIndex )
2020-07-07 15:42:39 +02:00
{
SP_DEVINFO_DATA DevInfoData = { . cbSize = sizeof ( SP_DEVINFO_DATA ) } ;
2020-10-13 19:40:52 +02:00
if ( ! SetupDiEnumDeviceInfo ( DevInfo , EnumIndex , & DevInfoData ) )
2020-07-07 15:42:39 +02:00
{
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
break ;
continue ;
}
GUID CfgInstanceID ;
2020-07-24 08:29:33 +02:00
if ( GetNetCfgInstanceId ( DevInfo , & DevInfoData , & CfgInstanceID ) ! = ERROR_SUCCESS )
2020-07-07 15:42:39 +02:00
continue ;
/* TODO: is there a better way than comparing ifnames? */
2020-07-28 12:38:17 +02:00
WCHAR Name2 [ MAX_ADAPTER_NAME ] ;
2020-07-21 16:38:00 +02:00
if ( NciGetConnectionName ( & CfgInstanceID , Name2 , sizeof ( Name2 ) , NULL ) ! = ERROR_SUCCESS )
2020-07-07 15:42:39 +02:00
continue ;
2020-07-21 16:38:00 +02:00
Name2 [ _countof ( Name2 ) - 1 ] = 0 ;
2020-10-30 06:06:06 +01:00
if ( _wcsicmp ( Name , Name2 ) )
2020-07-28 12:38:17 +02:00
{
2020-10-30 06:12:42 +01:00
RemoveNumberedSuffix ( Name2 ) ;
2020-10-30 06:06:06 +01:00
if ( _wcsicmp ( Name , Name2 ) )
2020-07-28 12:38:17 +02:00
continue ;
}
2020-07-07 15:42:39 +02:00
2020-10-15 11:32:06 +02:00
/* Check the Hardware ID to make sure it's a real Wintun device. */
2020-10-16 15:51:50 +02:00
BOOL IsOurs ;
Result = IsOurAdapter ( DevInfo , & DevInfoData , & IsOurs ) ;
2020-07-07 15:42:39 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get hardware ID " ) ;
2020-07-07 15:42:39 +02:00
goto cleanupDevInfo ;
}
2020-10-16 15:51:50 +02:00
if ( ! IsOurs )
2020-07-07 15:42:39 +02:00
{
2020-10-15 12:21:55 +02:00
LOG ( WINTUN_LOG_ERR , L " Foreign adapter with the same name exists " ) ;
2020-07-07 15:42:39 +02:00
Result = ERROR_ALREADY_EXISTS ;
goto cleanupDevInfo ;
}
BOOL IsMember ;
Result = IsPoolMember ( Pool , DevInfo , & DevInfoData , & IsMember ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get pool membership " ) ;
2020-07-07 15:42:39 +02:00
goto cleanupDevInfo ;
2020-10-13 19:40:52 +02:00
}
2020-07-07 15:42:39 +02:00
if ( ! IsMember )
{
2020-10-15 12:21:55 +02:00
LOG ( WINTUN_LOG_ERR , L " Wintun adapter with the same name exists in another pool " ) ;
2020-07-07 15:42:39 +02:00
Result = ERROR_ALREADY_EXISTS ;
goto cleanupDevInfo ;
}
2020-07-21 18:19:15 +02:00
Result = CreateAdapterData ( Pool , DevInfo , & DevInfoData , Adapter ) ;
2020-10-13 19:40:52 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-15 12:21:55 +02:00
LOG ( WINTUN_LOG_ERR , L " Failed to create adapter data " ) ;
2020-10-13 19:40:52 +02:00
2020-07-21 16:38:00 +02:00
goto cleanupDevInfo ;
}
Result = ERROR_FILE_NOT_FOUND ;
cleanupDevInfo :
SetupDiDestroyDeviceInfoList ( DevInfo ) ;
cleanupMutex :
2020-10-15 11:32:06 +02:00
NamespaceReleaseMutex ( Mutex ) ;
2020-10-30 12:25:24 +01:00
cleanupToken :
RevertToSelf ( ) ;
2020-07-21 16:38:00 +02:00
return Result ;
}
2020-07-21 16:43:34 +02:00
WINTUN_STATUS WINAPI
2020-07-21 18:19:15 +02:00
WintunGetAdapterName ( _In_ const WINTUN_ADAPTER * Adapter , _Out_cap_c_ ( MAX_ADAPTER_NAME ) WCHAR * Name )
2020-07-21 16:38:00 +02:00
{
return NciGetConnectionName ( & Adapter - > CfgInstanceID , Name , MAX_ADAPTER_NAME * sizeof ( WCHAR ) , NULL ) ;
}
2020-07-21 16:43:34 +02:00
static WINTUN_STATUS
2020-07-21 18:19:15 +02:00
ConvertInterfaceAliasToGuid ( _In_z_ const WCHAR * Name , _Out_ GUID * Guid )
2020-07-21 16:38:00 +02:00
{
NET_LUID Luid ;
2020-07-21 18:19:15 +02:00
DWORD Result = ConvertInterfaceAliasToLuid ( Name , & Luid ) ;
2020-07-21 16:38:00 +02:00
if ( Result ! = NO_ERROR )
2020-10-14 13:04:29 +02:00
return LOG_ERROR ( L " Failed convert interface alias name to the locally unique identifier " , Result ) ;
2020-07-21 16:38:00 +02:00
return ConvertInterfaceLuidToGuid ( & Luid , Guid ) ;
}
2020-07-21 16:43:34 +02:00
WINTUN_STATUS WINAPI
2020-10-31 18:13:36 +01:00
WintunSetAdapterName ( _In_ const WINTUN_ADAPTER * Adapter , _In_z_ const WCHAR * Name )
2020-07-21 16:38:00 +02:00
{
DWORD Result ;
const int MaxSuffix = 1000 ;
WCHAR AvailableName [ MAX_ADAPTER_NAME ] ;
2020-10-30 06:51:24 +01:00
if ( wcsncpy_s ( AvailableName , _countof ( AvailableName ) , Name , _TRUNCATE ) = = STRUNCATE )
2020-10-31 18:13:36 +01:00
return LOG ( WINTUN_LOG_ERR , L " Adapter name too long " ) , ERROR_INVALID_PARAMETER ;
2020-07-21 16:38:00 +02:00
for ( int i = 0 ; ; + + i )
{
Result = NciSetConnectionName ( & Adapter - > CfgInstanceID , AvailableName ) ;
if ( Result = = ERROR_DUP_NAME )
2020-07-07 15:42:39 +02:00
{
2020-07-21 16:38:00 +02:00
GUID Guid2 ;
2020-07-21 18:19:15 +02:00
DWORD Result2 = ConvertInterfaceAliasToGuid ( AvailableName , & Guid2 ) ;
2020-07-21 16:38:00 +02:00
if ( Result2 = = ERROR_SUCCESS )
{
for ( int j = 0 ; j < MaxSuffix ; + + j )
{
WCHAR Proposal [ MAX_ADAPTER_NAME ] ;
2020-10-31 18:13:36 +01:00
if ( _snwprintf_s ( Proposal , _countof ( Proposal ) , _TRUNCATE , L " %s %d " , Name , j + 1 ) = = - 1 )
return LOG ( WINTUN_LOG_ERR , L " Adapter name too long " ) , ERROR_INVALID_PARAMETER ;
2020-07-21 16:38:00 +02:00
if ( _wcsnicmp ( Proposal , AvailableName , MAX_ADAPTER_NAME ) = = 0 )
continue ;
Result2 = NciSetConnectionName ( & Guid2 , Proposal ) ;
if ( Result2 = = ERROR_DUP_NAME )
continue ;
if ( Result2 = = ERROR_SUCCESS )
{
Result = NciSetConnectionName ( & Adapter - > CfgInstanceID , AvailableName ) ;
if ( Result = = ERROR_SUCCESS )
break ;
}
break ;
}
}
2020-07-07 15:42:39 +02:00
}
2020-07-21 16:38:00 +02:00
if ( Result = = ERROR_SUCCESS )
break ;
2020-10-30 06:57:56 +01:00
if ( i > = MaxSuffix | | Result ! = ERROR_DUP_NAME )
2020-10-14 13:04:29 +02:00
return LOG_ERROR ( L " Setting adapter name failed " , Result ) ;
2020-10-31 18:13:36 +01:00
if ( _snwprintf_s ( AvailableName , _countof ( AvailableName ) , _TRUNCATE , L " %s %d " , Name , i + 1 ) = = - 1 )
return LOG ( WINTUN_LOG_ERR , L " Adapter name too long " ) , ERROR_INVALID_PARAMETER ;
2020-07-21 16:38:00 +02:00
}
/* TODO: This should use NetSetup2 so that it doesn't get unset. */
HKEY DeviceRegKey ;
2020-07-24 08:10:00 +02:00
WCHAR DeviceRegPath [ MAX_REG_PATH ] ;
2020-10-30 06:51:24 +01:00
Result = GetDeviceRegPath ( Adapter , DeviceRegPath ) ;
if ( Result ! = ERROR_SUCCESS )
return Result ;
2020-07-21 16:38:00 +02:00
Result = RegOpenKeyExW ( HKEY_LOCAL_MACHINE , DeviceRegPath , 0 , KEY_SET_VALUE , & DeviceRegKey ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-14 13:04:29 +02:00
return LOG_ERROR ( L " Failed to open registry key " , Result ) ;
2020-07-21 16:38:00 +02:00
WCHAR PoolDeviceTypeName [ MAX_POOL_DEVICE_TYPE ] ;
2020-10-30 06:51:24 +01:00
Result = GetPoolDeviceTypeName ( Adapter - > Pool , PoolDeviceTypeName ) ;
if ( Result ! = ERROR_SUCCESS )
goto cleanupDeviceRegKey ;
2020-07-21 16:38:00 +02:00
Result = RegSetKeyValueW (
DeviceRegKey ,
NULL ,
L " FriendlyName " ,
REG_SZ ,
PoolDeviceTypeName ,
( DWORD ) ( ( wcslen ( PoolDeviceTypeName ) + 1 ) * sizeof ( WCHAR ) ) ) ;
2020-10-30 06:51:24 +01:00
cleanupDeviceRegKey :
2020-07-21 16:38:00 +02:00
RegCloseKey ( DeviceRegKey ) ;
return Result ;
}
void WINAPI
2020-11-02 18:34:49 +01:00
WintunGetAdapterLUID ( _In_ const WINTUN_ADAPTER * Adapter , _Out_ NET_LUID * Luid )
2020-07-21 16:38:00 +02:00
{
2020-11-02 18:34:49 +01:00
Luid - > Info . Reserved = 0 ;
Luid - > Info . NetLuidIndex = Adapter - > LuidIndex ;
Luid - > Info . IfType = Adapter - > IfType ;
2020-07-21 16:38:00 +02:00
}
2020-07-21 16:43:34 +02:00
WINTUN_STATUS WINAPI
2020-11-03 12:31:49 +01:00
WintunOpenAdapterDeviceObject ( _In_ const WINTUN_ADAPTER * Adapter , _Out_ HANDLE * Handle )
2020-07-21 16:38:00 +02:00
{
2020-10-15 11:32:06 +02:00
return GetDeviceObject ( Adapter - > DevInstanceID , Handle ) ;
2020-07-21 16:38:00 +02:00
}
2020-10-15 15:54:37 +02:00
static BOOL
2020-10-30 06:03:21 +01:00
HaveWHQL ( void )
2020-10-15 15:54:37 +02:00
{
2020-11-03 02:09:00 +01:00
if ( HAVE_WHQL )
{
DWORD MajorVersion ;
RtlGetNtVersionNumbers ( & MajorVersion , NULL , NULL ) ;
return MajorVersion > = 10 ;
}
2020-10-30 08:17:33 +01:00
return FALSE ;
2020-10-15 15:54:37 +02:00
}
static WINTUN_STATUS
InstallCertificate ( _In_z_ const WCHAR * SignedResource )
{
LOG ( WINTUN_LOG_INFO , L " Trusting code signing certificate " ) ;
2020-10-17 15:12:20 +02:00
const void * LockedResource ;
2020-10-15 15:54:37 +02:00
DWORD SizeResource ;
DWORD Result = ResourceGetAddress ( SignedResource , & LockedResource , & SizeResource ) ;
if ( Result ! = ERROR_SUCCESS )
return LOG ( WINTUN_LOG_ERR , L " Failed to locate resource " ) , Result ;
const CERT_BLOB CertBlob = { . cbData = SizeResource , . pbData = ( BYTE * ) LockedResource } ;
HCERTSTORE QueriedStore ;
if ( ! CryptQueryObject (
CERT_QUERY_OBJECT_BLOB ,
& CertBlob ,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED ,
CERT_QUERY_FORMAT_FLAG_ALL ,
0 ,
0 ,
0 ,
0 ,
& QueriedStore ,
0 ,
NULL ) )
return LOG_LAST_ERROR ( L " Failed to find certificate " ) ;
HCERTSTORE TrustedStore =
CertOpenStore ( CERT_STORE_PROV_SYSTEM , 0 , 0 , CERT_SYSTEM_STORE_LOCAL_MACHINE , L " TrustedPublisher " ) ;
if ( ! TrustedStore )
{
Result = LOG_LAST_ERROR ( L " Failed to open store " ) ;
goto cleanupQueriedStore ;
}
LPSTR CodeSigningOid [ ] = { szOID_PKIX_KP_CODE_SIGNING } ;
CERT_ENHKEY_USAGE EnhancedUsage = { . cUsageIdentifier = 1 , . rgpszUsageIdentifier = CodeSigningOid } ;
for ( const CERT_CONTEXT * CertContext = NULL ; ( CertContext = CertFindCertificateInStore (
QueriedStore ,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG ,
CERT_FIND_ENHKEY_USAGE ,
& EnhancedUsage ,
CertContext ) ) ! = NULL ; )
{
CERT_EXTENSION * Ext = CertFindExtension (
szOID_BASIC_CONSTRAINTS2 , CertContext - > pCertInfo - > cExtension , CertContext - > pCertInfo - > rgExtension ) ;
CERT_BASIC_CONSTRAINTS2_INFO Constraints ;
DWORD Size = sizeof ( Constraints ) ;
if ( Ext & &
CryptDecodeObjectEx (
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
szOID_BASIC_CONSTRAINTS2 ,
Ext - > Value . pbData ,
Ext - > Value . cbData ,
0 ,
NULL ,
& Constraints ,
& Size ) & &
! Constraints . fCA )
if ( ! CertAddCertificateContextToStore ( TrustedStore , CertContext , CERT_STORE_ADD_REPLACE_EXISTING , NULL ) )
{
LOG_LAST_ERROR ( L " Failed to add certificate to store " ) ;
Result = Result ! = ERROR_SUCCESS ? Result : GetLastError ( ) ;
}
}
CertCloseStore ( TrustedStore , 0 ) ;
cleanupQueriedStore :
CertCloseStore ( QueriedStore , 0 ) ;
return Result ;
}
2020-10-30 09:53:09 +01:00
static BOOL
IsOurDrvInfoDetail ( _In_ const SP_DRVINFO_DETAIL_DATA_W * DrvInfoDetailData )
{
2020-11-03 09:47:42 +01:00
if ( DrvInfoDetailData - > CompatIDsOffset > 1 & & ! _wcsicmp ( DrvInfoDetailData - > HardwareID , WINTUN_HWID ) )
return TRUE ;
if ( DrvInfoDetailData - > CompatIDsLength & &
IsOurHardwareID ( DrvInfoDetailData - > HardwareID + DrvInfoDetailData - > CompatIDsOffset ) )
return TRUE ;
return FALSE ;
2020-10-30 09:53:09 +01:00
}
2020-10-16 15:20:49 +02:00
static BOOL
2020-11-02 16:28:51 +01:00
IsNewer (
_In_ const FILETIME * DriverDate1 ,
_In_ DWORDLONG DriverVersion1 ,
_In_ const FILETIME * DriverDate2 ,
_In_ DWORDLONG DriverVersion2 )
2020-10-16 15:20:49 +02:00
{
2020-11-02 16:28:51 +01:00
if ( DriverDate1 - > dwHighDateTime > DriverDate2 - > dwHighDateTime )
2020-10-16 15:20:49 +02:00
return TRUE ;
2020-11-02 16:28:51 +01:00
if ( DriverDate1 - > dwHighDateTime < DriverDate2 - > dwHighDateTime )
2020-10-16 15:20:49 +02:00
return FALSE ;
2020-11-02 16:28:51 +01:00
if ( DriverDate1 - > dwLowDateTime > DriverDate2 - > dwLowDateTime )
2020-10-16 15:20:49 +02:00
return TRUE ;
2020-11-02 16:28:51 +01:00
if ( DriverDate1 - > dwLowDateTime < DriverDate2 - > dwLowDateTime )
2020-10-16 15:20:49 +02:00
return FALSE ;
2020-11-02 16:28:51 +01:00
if ( DriverVersion1 > DriverVersion2 )
2020-10-16 15:20:49 +02:00
return TRUE ;
2020-11-02 16:28:51 +01:00
if ( DriverVersion1 < DriverVersion2 )
2020-10-16 15:20:49 +02:00
return FALSE ;
return FALSE ;
}
2020-10-30 06:51:24 +01:00
static DWORD
2020-10-16 15:20:49 +02:00
GetTcpipAdapterRegPath ( _In_ const WINTUN_ADAPTER * Adapter , _Out_cap_c_ ( MAX_REG_PATH ) WCHAR * Path )
{
WCHAR Guid [ MAX_GUID_STRING_LEN ] ;
2020-10-30 06:51:24 +01:00
if ( _snwprintf_s (
Path ,
MAX_REG_PATH ,
_TRUNCATE ,
L " SYSTEM \\ CurrentControlSet \\ Services \\ Tcpip \\ Parameters \\ Adapters \\ %.*s " ,
StringFromGUID2 ( & Adapter - > CfgInstanceID , Guid , _countof ( Guid ) ) ,
Guid ) = = - 1 )
return LOG ( WINTUN_LOG_ERR , L " Registry path too long " ) , ERROR_INVALID_PARAMETER ;
return ERROR_SUCCESS ;
2020-10-16 15:20:49 +02:00
}
static WINTUN_STATUS
GetTcpipInterfaceRegPath ( _In_ const WINTUN_ADAPTER * Adapter , _Out_cap_c_ ( MAX_REG_PATH ) WCHAR * Path )
{
DWORD Result ;
HKEY TcpipAdapterRegKey ;
WCHAR TcpipAdapterRegPath [ MAX_REG_PATH ] ;
2020-10-30 06:51:24 +01:00
Result = GetTcpipAdapterRegPath ( Adapter , TcpipAdapterRegPath ) ;
if ( Result ! = ERROR_SUCCESS )
return Result ;
2020-10-16 15:20:49 +02:00
Result = RegOpenKeyExW ( HKEY_LOCAL_MACHINE , TcpipAdapterRegPath , 0 , KEY_QUERY_VALUE , & TcpipAdapterRegKey ) ;
if ( Result ! = ERROR_SUCCESS )
return LOG_ERROR ( L " Failed to open registry key " , Result ) ;
WCHAR * Paths ;
2020-10-23 22:04:40 +02:00
Result = RegistryQueryString ( TcpipAdapterRegKey , L " IpConfig " , & Paths , TRUE ) ;
2020-10-16 15:20:49 +02:00
if ( Result ! = ERROR_SUCCESS )
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get IpConfig " ) ;
2020-10-16 15:20:49 +02:00
goto cleanupTcpipAdapterRegKey ;
}
if ( ! Paths [ 0 ] )
{
LOG ( WINTUN_LOG_ERR , L " IpConfig is empty " ) ;
Result = ERROR_INVALID_DATA ;
goto cleanupPaths ;
}
2020-10-30 06:51:24 +01:00
if ( _snwprintf_s ( Path , MAX_REG_PATH , _TRUNCATE , L " SYSTEM \\ CurrentControlSet \\ Services \\ %s " , Paths ) = = - 1 )
{
LOG ( WINTUN_LOG_ERR , L " Registry path too long " ) ;
Result = ERROR_INVALID_PARAMETER ;
goto cleanupPaths ;
}
Result = ERROR_SUCCESS ;
2020-10-16 15:20:49 +02:00
cleanupPaths :
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , Paths ) ;
2020-10-16 15:20:49 +02:00
cleanupTcpipAdapterRegKey :
RegCloseKey ( TcpipAdapterRegKey ) ;
return Result ;
}
2020-11-03 11:00:53 +01:00
static DWORD
2020-11-02 16:28:51 +01:00
VersionOfFile ( _In_z_ const WCHAR * Filename )
2020-10-30 18:20:57 +01:00
{
2020-11-03 11:00:53 +01:00
DWORD Version = 0 ;
2020-10-30 18:20:57 +01:00
DWORD Zero ;
DWORD Len = GetFileVersionInfoSizeW ( Filename , & Zero ) ;
if ( ! Len )
2020-11-02 11:52:54 +01:00
return LOG_LAST_ERROR ( L " Failed to query version info size " ) , Version ;
2020-10-30 18:20:57 +01:00
VOID * VersionInfo = HeapAlloc ( ModuleHeap , 0 , Len ) ;
if ( ! VersionInfo )
{
LOG ( WINTUN_LOG_ERR , L " Out of memory " ) ;
return Version ;
}
VS_FIXEDFILEINFO * FixedInfo ;
UINT FixedInfoLen = sizeof ( * FixedInfo ) ;
if ( ! GetFileVersionInfoW ( Filename , 0 , Len , VersionInfo ) )
{
LOG_LAST_ERROR ( L " Failed to get version info " ) ;
goto out ;
}
if ( ! VerQueryValueW ( VersionInfo , L " \\ " , & FixedInfo , & FixedInfoLen ) )
{
2020-11-02 11:52:54 +01:00
LOG_LAST_ERROR ( L " Failed to get version info root " ) ;
2020-10-30 18:20:57 +01:00
goto out ;
}
2020-11-03 11:00:53 +01:00
Version = FixedInfo - > dwFileVersionMS ;
2020-10-30 18:20:57 +01:00
out :
HeapFree ( ModuleHeap , 0 , VersionInfo ) ;
return Version ;
}
2020-10-15 15:54:37 +02:00
static WINTUN_STATUS
2020-11-02 16:28:51 +01:00
CreateTemporaryDirectory ( _Out_cap_c_ ( MAX_PATH ) WCHAR * RandomTempSubDirectory )
2020-07-21 16:38:00 +02:00
{
2020-11-02 16:28:51 +01:00
WCHAR WindowsDirectory [ MAX_PATH ] ;
if ( ! GetWindowsDirectoryW ( WindowsDirectory , _countof ( WindowsDirectory ) ) )
return LOG_LAST_ERROR ( L " Failed to get Windows folder " ) ;
WCHAR WindowsTempDirectory [ MAX_PATH ] ;
if ( ! PathCombineW ( WindowsTempDirectory , WindowsDirectory , L " Temp " ) )
return ERROR_BUFFER_OVERFLOW ;
UCHAR RandomBytes [ 32 ] = { 0 } ;
# pragma warning(suppress : 6387)
if ( ! RtlGenRandom ( RandomBytes , sizeof ( RandomBytes ) ) )
return LOG_LAST_ERROR ( L " Failed to generate random " ) ;
WCHAR RandomSubDirectory [ sizeof ( RandomBytes ) * 2 + 1 ] ;
for ( int i = 0 ; i < sizeof ( RandomBytes ) ; + + i )
swprintf_s ( & RandomSubDirectory [ i * 2 ] , 3 , L " %02x " , RandomBytes [ i ] ) ;
if ( ! PathCombineW ( RandomTempSubDirectory , WindowsTempDirectory , RandomSubDirectory ) )
return ERROR_BUFFER_OVERFLOW ;
if ( ! CreateDirectoryW ( RandomTempSubDirectory , & SecurityAttributes ) )
return LOG_LAST_ERROR ( L " Failed to create temporary folder " ) ;
return ERROR_SUCCESS ;
}
2020-07-21 16:38:00 +02:00
2020-11-03 11:00:53 +01:00
DWORD
2020-11-02 16:28:51 +01:00
WintunGetVersion ( void )
{
2020-11-03 11:00:53 +01:00
DWORD Version = 0 ;
2020-11-02 16:28:51 +01:00
PRTL_PROCESS_MODULES Modules ;
ULONG BufferSize = 128 * 1024 ;
for ( ; ; )
2020-10-31 18:13:36 +01:00
{
2020-11-02 16:28:51 +01:00
Modules = HeapAlloc ( ModuleHeap , 0 , BufferSize ) ;
if ( ! Modules )
{
LOG ( WINTUN_LOG_ERR , L " Out of memory " ) ;
return Version ;
}
NTSTATUS Status = NtQuerySystemInformation ( SystemModuleInformation , Modules , BufferSize , & BufferSize ) ;
if ( NT_SUCCESS ( Status ) )
break ;
HeapFree ( ModuleHeap , 0 , Modules ) ;
if ( Status = = STATUS_INFO_LENGTH_MISMATCH )
continue ;
LOG ( WINTUN_LOG_ERR , L " Failed to enumerate drivers " ) ;
return Version ;
2020-10-31 18:13:36 +01:00
}
2020-11-02 16:28:51 +01:00
for ( ULONG i = Modules - > NumberOfModules ; i - - > 0 ; )
2020-10-15 15:54:37 +02:00
{
2020-11-02 16:28:51 +01:00
const char * NtPath = ( const char * ) Modules - > Modules [ i ] . FullPathName ;
if ( ! _stricmp ( & NtPath [ Modules - > Modules [ i ] . OffsetToFileName ] , " wintun.sys " ) )
{
WCHAR FilePath [ MAX_PATH * 3 + 15 ] ;
if ( _snwprintf_s ( FilePath , _countof ( FilePath ) , _TRUNCATE , L " \\ \\ ? \\ GLOBALROOT%S " , NtPath ) = = - 1 )
continue ;
Version = VersionOfFile ( FilePath ) ;
goto out ;
}
2020-10-15 15:54:37 +02:00
}
2020-11-02 16:28:51 +01:00
out :
HeapFree ( ModuleHeap , 0 , Modules ) ;
return Version ;
}
2020-07-21 16:38:00 +02:00
2020-11-02 16:28:51 +01:00
static BOOL
EnsureWintunUnloaded ( void )
{
BOOL Loaded ;
for ( int i = 0 ; ( Loaded = WintunGetVersion ( ) ! = 0 ) ! = FALSE & & i < 300 ; + + i )
Sleep ( 50 ) ;
return ! Loaded ;
}
2020-07-21 16:38:00 +02:00
2020-11-02 16:28:51 +01:00
static WINTUN_STATUS
SelectDriver (
_In_ HDEVINFO DevInfo ,
_In_opt_ SP_DEVINFO_DATA * DevInfoData ,
_Inout_ SP_DEVINSTALL_PARAMS_W * DevInstallParams ,
_Inout_ BOOL * RebootRequired )
{
2020-11-03 17:06:20 +01:00
static const FILETIME OurDriverDate = WINTUN_INF_FILETIME ;
static const DWORDLONG OurDriverVersion = WINTUN_INF_VERSION ;
2020-11-02 16:28:51 +01:00
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex ( ) ;
if ( ! DriverInstallationLock )
return LOG_LAST_ERROR ( L " Failed to take driver installation mutex " ) ;
2020-11-03 17:06:20 +01:00
DWORD Result = ERROR_SUCCESS ;
2020-11-02 16:28:51 +01:00
if ( ! SetupDiBuildDriverInfoList ( DevInfo , DevInfoData , SPDIT_COMPATDRIVER ) )
2020-07-21 16:38:00 +02:00
{
2020-10-14 13:04:29 +02:00
Result = LOG_LAST_ERROR ( L " Failed building driver info list " ) ;
2020-11-02 16:28:51 +01:00
goto cleanupDriverInstallationLock ;
2020-07-21 16:38:00 +02:00
}
2020-11-03 10:34:37 +01:00
BOOL DestroyDriverInfoListOnCleanup = TRUE ;
2020-11-02 16:28:51 +01:00
FILETIME DriverDate = { 0 } ;
2020-07-21 16:38:00 +02:00
DWORDLONG DriverVersion = 0 ;
2020-11-02 16:28:51 +01:00
HDEVINFO DevInfoExistingAdapters = INVALID_HANDLE_VALUE ;
SP_DEVINFO_DATA_LIST * ExistingAdapters = NULL ;
for ( DWORD EnumIndex = 0 ; ; + + EnumIndex )
2020-07-21 16:38:00 +02:00
{
2020-10-13 19:40:52 +02:00
SP_DRVINFO_DATA_W DrvInfoData = { . cbSize = sizeof ( SP_DRVINFO_DATA_W ) } ;
2020-11-02 16:28:51 +01:00
if ( ! SetupDiEnumDriverInfoW ( DevInfo , DevInfoData , SPDIT_COMPATDRIVER , EnumIndex , & DrvInfoData ) )
2020-07-21 16:38:00 +02:00
{
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
break ;
continue ;
}
2020-10-15 11:32:06 +02:00
SP_DRVINFO_DETAIL_DATA_W * DrvInfoDetailData ;
2020-11-02 16:28:51 +01:00
if ( GetAdapterDrvInfoDetail ( DevInfo , DevInfoData , & DrvInfoData , & DrvInfoDetailData ) ! = ERROR_SUCCESS )
2020-10-15 12:21:55 +02:00
{
LOG ( WINTUN_LOG_WARN , L " Failed getting driver info detail " ) ;
2020-07-21 16:38:00 +02:00
continue ;
2020-10-15 12:21:55 +02:00
}
2020-10-30 09:53:09 +01:00
if ( ! IsOurDrvInfoDetail ( DrvInfoDetailData ) )
2020-11-02 16:28:51 +01:00
goto next ;
if ( IsNewer ( & OurDriverDate , OurDriverVersion , & DrvInfoData . DriverDate , DrvInfoData . DriverVersion ) )
2020-07-21 16:38:00 +02:00
{
2020-11-02 16:28:51 +01:00
if ( DevInfoExistingAdapters = = INVALID_HANDLE_VALUE )
{
DevInfoExistingAdapters =
SetupDiGetClassDevsExW ( & GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL ) ;
if ( DevInfoExistingAdapters = = INVALID_HANDLE_VALUE )
{
Result = LOG_LAST_ERROR ( L " Failed to get present adapters " ) ;
2020-11-03 10:34:37 +01:00
HeapFree ( ModuleHeap , 0 , DrvInfoDetailData ) ;
goto cleanupExistingAdapters ;
2020-11-02 16:28:51 +01:00
}
_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 , TEXT ( " Removing existing driver " ) ) ;
if ( ! SetupUninstallOEMInfW ( PathFindFileNameW ( DrvInfoDetailData - > InfFileName ) , SUOI_FORCEDELETE , NULL ) )
LOG_LAST_ERROR ( TEXT ( " Unable to remove existing driver " ) ) ;
goto next ;
}
if ( ! IsNewer ( & DrvInfoData . DriverDate , DrvInfoData . DriverVersion , & DriverDate , DriverVersion ) )
goto next ;
if ( ! SetupDiSetSelectedDriverW ( DevInfo , DevInfoData , & DrvInfoData ) )
{
LOG_ERROR ( L " Failed to select driver " , GetLastError ( ) ) ;
goto next ;
2020-07-21 16:38:00 +02:00
}
2020-10-13 19:40:52 +02:00
DriverDate = DrvInfoData . DriverDate ;
DriverVersion = DrvInfoData . DriverVersion ;
2020-11-02 16:28:51 +01:00
next :
HeapFree ( ModuleHeap , 0 , DrvInfoDetailData ) ;
2020-07-21 16:38:00 +02:00
}
2020-11-02 16:28:51 +01:00
if ( DriverVersion )
2020-11-03 10:34:37 +01:00
{
DestroyDriverInfoListOnCleanup = FALSE ;
2020-11-02 16:28:51 +01:00
goto cleanupExistingAdapters ;
2020-11-03 10:34:37 +01:00
}
2020-07-21 16:38:00 +02:00
2020-11-02 16:28:51 +01:00
WCHAR RandomTempSubDirectory [ MAX_PATH ] ;
if ( ( Result = CreateTemporaryDirectory ( RandomTempSubDirectory ) ) ! = ERROR_SUCCESS )
2020-07-21 16:38:00 +02:00
{
2020-11-02 16:28:51 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to create temporary folder " ) ;
goto cleanupExistingAdapters ;
2020-07-21 16:38:00 +02:00
}
2020-11-02 16:28:51 +01:00
WCHAR CatPath [ MAX_PATH ] = { 0 } ;
WCHAR SysPath [ MAX_PATH ] = { 0 } ;
WCHAR InfPath [ MAX_PATH ] = { 0 } ;
if ( ! PathCombineW ( CatPath , RandomTempSubDirectory , L " wintun.cat " ) | |
! PathCombineW ( SysPath , RandomTempSubDirectory , L " wintun.sys " ) | |
! PathCombineW ( InfPath , RandomTempSubDirectory , L " wintun.inf " ) )
2020-07-21 16:38:00 +02:00
{
2020-11-02 16:28:51 +01:00
Result = ERROR_BUFFER_OVERFLOW ;
goto cleanupDirectory ;
}
BOOL UseWHQL = HaveWHQL ( ) ;
if ( ! UseWHQL & & ( Result = InstallCertificate ( L " wintun.cat " ) ) ! = ERROR_SUCCESS )
LOG ( WINTUN_LOG_WARN , L " Failed to install code signing certificate " ) ;
LOG ( WINTUN_LOG_INFO , L " Extracting driver " ) ;
if ( ( Result = ResourceCopyToFile ( CatPath , UseWHQL ? L " wintun-whql.cat " : L " wintun.cat " ) ) ! = ERROR_SUCCESS | |
( Result = ResourceCopyToFile ( SysPath , UseWHQL ? L " wintun-whql.sys " : L " wintun.sys " ) ) ! = ERROR_SUCCESS | |
( Result = ResourceCopyToFile ( InfPath , UseWHQL ? L " wintun-whql.inf " : L " wintun.inf " ) ) ! = ERROR_SUCCESS )
{
LOG ( WINTUN_LOG_ERR , L " Failed to extract driver " ) ;
goto cleanupDelete ;
}
LOG ( WINTUN_LOG_INFO , L " Installing driver " ) ;
WCHAR InfStorePath [ MAX_PATH ] ;
if ( ! SetupCopyOEMInfW ( InfPath , NULL , SPOST_NONE , 0 , InfStorePath , MAX_PATH , NULL , NULL ) )
{
Result = LOG_LAST_ERROR ( L " Could not install driver to store " ) ;
goto cleanupDelete ;
}
_Analysis_assume_nullterminated_ ( InfStorePath ) ;
BOOL UpdateRebootRequired = FALSE ;
if ( ExistingAdapters & &
! UpdateDriverForPlugAndPlayDevicesW (
NULL , WINTUN_HWID , InfStorePath , INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE , & UpdateRebootRequired ) )
LOG ( WINTUN_LOG_WARN , L " Could not update existing adapters " ) ;
* RebootRequired = * RebootRequired | | UpdateRebootRequired ;
SetupDiDestroyDriverInfoList ( DevInfo , DevInfoData , SPDIT_COMPATDRIVER ) ;
2020-11-03 10:34:37 +01:00
DestroyDriverInfoListOnCleanup = FALSE ;
2020-11-02 16:28:51 +01:00
DevInstallParams - > Flags | = DI_ENUMSINGLEINF ;
if ( wcsncpy_s ( DevInstallParams - > DriverPath , _countof ( DevInstallParams - > DriverPath ) , InfStorePath , _TRUNCATE ) = =
STRUNCATE )
{
LOG ( WINTUN_LOG_ERR , L " Inf path too long " ) ;
Result = ERROR_INVALID_PARAMETER ;
goto cleanupDelete ;
}
if ( ! SetupDiSetDeviceInstallParamsW ( DevInfo , DevInfoData , DevInstallParams ) )
{
Result = LOG_LAST_ERROR ( L " Setting device installation parameters failed " ) ;
goto cleanupDelete ;
}
if ( ! SetupDiBuildDriverInfoList ( DevInfo , DevInfoData , SPDIT_COMPATDRIVER ) )
{
Result = LOG_LAST_ERROR ( L " Failed rebuilding driver info list " ) ;
goto cleanupDelete ;
}
2020-11-03 10:34:37 +01:00
DestroyDriverInfoListOnCleanup = TRUE ;
2020-11-02 16:28:51 +01:00
SP_DRVINFO_DATA_W DrvInfoData = { . cbSize = sizeof ( SP_DRVINFO_DATA_W ) } ;
if ( ! SetupDiEnumDriverInfoW ( DevInfo , DevInfoData , SPDIT_COMPATDRIVER , 0 , & DrvInfoData ) )
{
Result = LOG_LAST_ERROR ( L " Failed to get driver " ) ;
goto cleanupDelete ;
}
if ( ! SetupDiSetSelectedDriverW ( DevInfo , DevInfoData , & DrvInfoData ) )
{
Result = LOG_LAST_ERROR ( L " Failed to set driver " ) ;
goto cleanupDelete ;
}
Result = ERROR_SUCCESS ;
2020-11-03 10:34:37 +01:00
DestroyDriverInfoListOnCleanup = FALSE ;
2020-11-02 16:28:51 +01:00
cleanupDelete :
DeleteFileW ( CatPath ) ;
DeleteFileW ( SysPath ) ;
DeleteFileW ( InfPath ) ;
cleanupDirectory :
RemoveDirectoryW ( RandomTempSubDirectory ) ;
cleanupExistingAdapters :
if ( ExistingAdapters )
{
EnableAllOurAdapters ( DevInfoExistingAdapters , ExistingAdapters ) ;
while ( ExistingAdapters )
{
SP_DEVINFO_DATA_LIST * Next = ExistingAdapters - > Next ;
HeapFree ( ModuleHeap , 0 , ExistingAdapters ) ;
ExistingAdapters = Next ;
}
}
if ( DevInfoExistingAdapters ! = INVALID_HANDLE_VALUE )
SetupDiDestroyDeviceInfoList ( DevInfoExistingAdapters ) ;
2020-11-03 10:34:37 +01:00
if ( DestroyDriverInfoListOnCleanup )
2020-11-02 16:28:51 +01:00
SetupDiDestroyDriverInfoList ( DevInfo , DevInfoData , SPDIT_COMPATDRIVER ) ;
cleanupDriverInstallationLock :
NamespaceReleaseMutex ( DriverInstallationLock ) ;
return Result ;
}
static WINTUN_STATUS
CreateAdapter (
_In_z_ const WCHAR * Pool ,
_In_z_ const WCHAR * Name ,
_In_opt_ const GUID * RequestedGUID ,
_Out_ WINTUN_ADAPTER * * Adapter ,
_Inout_ BOOL * RebootRequired )
{
LOG ( WINTUN_LOG_INFO , L " Creating adapter " ) ;
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW ( & GUID_DEVCLASS_NET , NULL , NULL , NULL ) ;
if ( DevInfo = = INVALID_HANDLE_VALUE )
return LOG_LAST_ERROR ( L " Creating empty device information set failed " ) ;
DWORD Result ;
WCHAR ClassName [ MAX_CLASS_NAME_LEN ] ;
if ( ! SetupDiClassNameFromGuidExW ( & GUID_DEVCLASS_NET , ClassName , _countof ( ClassName ) , NULL , NULL , NULL ) )
{
Result = LOG_LAST_ERROR ( L " Retrieving class name associated with class GUID failed " ) ;
goto cleanupDevInfo ;
}
WCHAR PoolDeviceTypeName [ MAX_POOL_DEVICE_TYPE ] ;
Result = GetPoolDeviceTypeName ( Pool , PoolDeviceTypeName ) ;
if ( Result ! = ERROR_SUCCESS )
goto cleanupDevInfo ;
SP_DEVINFO_DATA DevInfoData = { . cbSize = sizeof ( SP_DEVINFO_DATA ) } ;
if ( ! SetupDiCreateDeviceInfoW (
DevInfo , ClassName , & GUID_DEVCLASS_NET , PoolDeviceTypeName , NULL , DICD_GENERATE_ID , & DevInfoData ) )
{
Result = LOG_LAST_ERROR ( L " Creating new device information element failed " ) ;
goto cleanupDevInfo ;
}
SP_DEVINSTALL_PARAMS_W DevInstallParams = { . cbSize = sizeof ( SP_DEVINSTALL_PARAMS_W ) } ;
if ( ! SetupDiGetDeviceInstallParamsW ( DevInfo , & DevInfoData , & DevInstallParams ) )
{
Result = LOG_LAST_ERROR ( L " Retrieving device installation parameters failed " ) ;
goto cleanupDevInfo ;
}
DevInstallParams . Flags | = DI_QUIETINSTALL ;
if ( ! SetupDiSetDeviceInstallParamsW ( DevInfo , & DevInfoData , & DevInstallParams ) )
{
Result = LOG_LAST_ERROR ( L " Setting device installation parameters failed " ) ;
goto cleanupDevInfo ;
}
if ( ! SetupDiSetSelectedDevice ( DevInfo , & DevInfoData ) )
{
Result = LOG_LAST_ERROR ( L " Failed selecting 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 ) ) )
{
Result = LOG_LAST_ERROR ( L " Failed setting hardware ID " ) ;
goto cleanupDevInfo ;
}
Result = SelectDriver ( DevInfo , & DevInfoData , & DevInstallParams , RebootRequired ) ;
if ( Result ! = ERROR_SUCCESS )
{
LOG ( WINTUN_LOG_ERR , L " Failed to select driver " ) ;
goto cleanupDevInfo ;
}
HANDLE Mutex = NamespaceTakePoolMutex ( Pool ) ;
if ( ! Mutex )
{
Result = LOG_LAST_ERROR ( L " Failed to take pool mutex " ) ;
goto cleanupDriverInfoList ;
}
if ( ! SetupDiCallClassInstaller ( DIF_REGISTERDEVICE , DevInfo , & DevInfoData ) )
{
Result = LOG_LAST_ERROR ( L " Registering device failed " ) ;
goto cleanupDevice ;
}
if ( ! SetupDiCallClassInstaller ( DIF_REGISTER_COINSTALLERS , DevInfo , & DevInfoData ) )
LOG_LAST_ERROR ( L " Registering coinstallers failed " ) ;
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 (
DevInfo , & DevInfoData , DICS_FLAG_GLOBAL , 0 , DIREG_DRV , KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY ) ;
2020-07-21 16:38:00 +02:00
}
if ( NetDevRegKey = = INVALID_HANDLE_VALUE )
{
2020-10-14 13:04:29 +02:00
Result = LOG_LAST_ERROR ( L " Failed to open device-specific registry key " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupDevice ;
}
if ( RequestedGUID )
{
WCHAR RequestedGUIDStr [ MAX_GUID_STRING_LEN ] ;
Result = RegSetValueExW (
NetDevRegKey ,
L " NetSetupAnticipatedInstanceId " ,
0 ,
REG_SZ ,
( const BYTE * ) RequestedGUIDStr ,
StringFromGUID2 ( RequestedGUID , RequestedGUIDStr , _countof ( RequestedGUIDStr ) ) * sizeof ( WCHAR ) ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-10-14 13:04:29 +02:00
LOG_LAST_ERROR ( L " Failed to set NetSetupAnticipatedInstanceId " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupNetDevRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
}
2020-10-13 19:40:52 +02:00
if ( ! SetupDiCallClassInstaller ( DIF_INSTALLINTERFACES , DevInfo , & DevInfoData ) )
2020-10-14 13:04:29 +02:00
LOG_LAST_ERROR ( L " Installing interfaces failed " ) ;
2020-07-21 16:38:00 +02:00
if ( ! SetupDiCallClassInstaller ( DIF_INSTALLDEVICE , DevInfo , & DevInfoData ) )
{
2020-10-14 13:04:29 +02:00
Result = LOG_LAST_ERROR ( L " Installing device failed " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupNetDevRegKey ;
}
* RebootRequired = * RebootRequired | | CheckReboot ( DevInfo , & DevInfoData ) ;
if ( ! SetupDiSetDeviceRegistryPropertyW (
DevInfo ,
& DevInfoData ,
SPDRP_DEVICEDESC ,
( const BYTE * ) PoolDeviceTypeName ,
2020-07-22 13:21:51 +02:00
( DWORD ) ( ( wcslen ( PoolDeviceTypeName ) + 1 ) * sizeof ( WCHAR ) ) ) )
2020-07-21 16:38:00 +02:00
{
2020-11-02 11:52:54 +01:00
Result = LOG_LAST_ERROR ( L " Failed to set adapter description " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupNetDevRegKey ;
}
/* 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 . */
2020-07-21 18:19:15 +02:00
WCHAR * DummyStr ;
2020-07-21 16:38:00 +02:00
Result = RegistryQueryStringWait ( NetDevRegKey , L " NetCfgInstanceId " , WAIT_FOR_REGISTRY_TIMEOUT , & DummyStr ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get NetCfgInstanceId " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupNetDevRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , DummyStr ) ;
2020-07-21 16:38:00 +02:00
DWORD DummyDWORD ;
Result = RegistryQueryDWORDWait ( NetDevRegKey , L " NetLuidIndex " , WAIT_FOR_REGISTRY_TIMEOUT , & DummyDWORD ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get NetLuidIndex " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupNetDevRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
Result = RegistryQueryDWORDWait ( NetDevRegKey , L " *IfType " , WAIT_FOR_REGISTRY_TIMEOUT , & DummyDWORD ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get *IfType " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupNetDevRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
2020-10-30 13:08:57 +01:00
WINTUN_ADAPTER * a ;
Result = CreateAdapterData ( Pool , DevInfo , & DevInfoData , & a ) ;
2020-07-21 16:38:00 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-10-15 12:21:55 +02:00
LOG ( WINTUN_LOG_ERR , L " Failed to create adapter data " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupNetDevRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
HKEY TcpipAdapterRegKey ;
2020-07-24 08:10:00 +02:00
WCHAR TcpipAdapterRegPath [ MAX_REG_PATH ] ;
2020-10-30 13:08:57 +01:00
Result = GetTcpipAdapterRegPath ( a , TcpipAdapterRegPath ) ;
2020-10-30 06:51:24 +01:00
if ( Result ! = ERROR_SUCCESS )
goto cleanupAdapter ;
2020-07-21 16:38:00 +02:00
Result = RegistryOpenKeyWait (
HKEY_LOCAL_MACHINE ,
TcpipAdapterRegPath ,
KEY_QUERY_VALUE | KEY_NOTIFY ,
WAIT_FOR_REGISTRY_TIMEOUT ,
& TcpipAdapterRegKey ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to open adapter-specific TCP/IP interface registry key " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupAdapter ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
Result = RegistryQueryStringWait ( TcpipAdapterRegKey , L " IpConfig " , WAIT_FOR_REGISTRY_TIMEOUT , & DummyStr ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get IpConfig " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupTcpipAdapterRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , DummyStr ) ;
2020-07-21 16:38:00 +02:00
HKEY TcpipInterfaceRegKey ;
2020-07-24 08:10:00 +02:00
WCHAR TcpipInterfaceRegPath [ MAX_REG_PATH ] ;
2020-10-30 13:08:57 +01:00
Result = GetTcpipInterfaceRegPath ( a , TcpipInterfaceRegPath ) ;
2020-07-21 16:38:00 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-10-15 12:21:55 +02:00
LOG ( WINTUN_LOG_ERR , L " Failed to determine interface-specific TCP/IP network registry key path " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupTcpipAdapterRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
Result = RegistryOpenKeyWait (
HKEY_LOCAL_MACHINE ,
TcpipInterfaceRegPath ,
KEY_QUERY_VALUE | KEY_SET_VALUE ,
WAIT_FOR_REGISTRY_TIMEOUT ,
& TcpipInterfaceRegKey ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-10-15 12:21:55 +02:00
LOG ( WINTUN_LOG_ERR , L " Failed to open interface-specific TCP/IP network registry key " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupTcpipAdapterRegKey ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
2020-10-15 11:32:06 +02:00
static const DWORD EnableDeadGWDetect = 0 ;
2020-10-13 19:40:52 +02:00
Result = RegSetKeyValueW (
2020-10-13 19:55:41 +02:00
TcpipInterfaceRegKey , NULL , L " EnableDeadGWDetect " , REG_DWORD , & EnableDeadGWDetect , sizeof ( EnableDeadGWDetect ) ) ;
2020-10-13 19:40:52 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-11-01 03:19:21 +01:00
{
2020-10-14 13:04:29 +02:00
LOG_ERROR ( L " Failed to set EnableDeadGWDetect " , Result ) ;
2020-11-01 03:19:21 +01:00
goto cleanupTcpipInterfaceRegKey ;
}
2020-07-21 16:38:00 +02:00
2020-10-30 13:08:57 +01:00
Result = WintunSetAdapterName ( a , Name ) ;
2020-11-01 03:19:21 +01:00
if ( Result ! = ERROR_SUCCESS )
{
2020-10-14 13:04:29 +02:00
LOG_ERROR ( L " Failed to set adapter name " , Result ) ;
2020-11-01 03:19:21 +01:00
goto cleanupTcpipInterfaceRegKey ;
}
2020-11-01 03:47:19 +01:00
DEVPROPTYPE PropertyType ;
for ( int Tries = 0 ; Tries < 1000 ; + + Tries )
{
NTSTATUS ProblemStatus ;
if ( SetupDiGetDevicePropertyW (
DevInfo ,
& DevInfoData ,
& DEVPKEY_Device_ProblemStatus ,
& PropertyType ,
( PBYTE ) & ProblemStatus ,
sizeof ( ProblemStatus ) ,
NULL ,
0 ) & &
PropertyType = = DEVPROP_TYPE_NTSTATUS )
2020-11-01 03:19:21 +01:00
{
2020-11-01 03:47:19 +01:00
Result = RtlNtStatusToDosError ( ProblemStatus ) ;
2020-11-02 17:18:39 +01:00
_Analysis_assume_ ( Result ! = ERROR_SUCCESS ) ;
2020-11-01 03:47:19 +01:00
if ( ProblemStatus ! = STATUS_PNP_DEVICE_CONFIGURATION_PENDING | | Tries = = 999 )
2020-11-01 03:19:21 +01:00
{
2020-11-01 03:47:19 +01:00
LOG_ERROR ( L " Failed to setup adapter " , Result ) ;
goto cleanupTcpipInterfaceRegKey ;
2020-11-01 03:19:21 +01:00
}
2020-11-01 03:47:19 +01:00
Sleep ( 10 ) ;
2020-11-01 03:19:21 +01:00
}
2020-11-01 03:47:19 +01:00
else
break ;
2020-11-01 03:19:21 +01:00
}
2020-11-02 17:18:39 +01:00
Result = ERROR_SUCCESS ;
2020-11-01 03:19:21 +01:00
* Adapter = a ;
cleanupTcpipInterfaceRegKey :
2020-07-21 16:38:00 +02:00
RegCloseKey ( TcpipInterfaceRegKey ) ;
cleanupTcpipAdapterRegKey :
RegCloseKey ( TcpipAdapterRegKey ) ;
cleanupAdapter :
if ( Result ! = ERROR_SUCCESS )
2020-10-30 13:08:57 +01:00
HeapFree ( ModuleHeap , 0 , a ) ;
2020-07-21 16:38:00 +02:00
cleanupNetDevRegKey :
RegCloseKey ( NetDevRegKey ) ;
cleanupDevice :
if ( Result ! = ERROR_SUCCESS )
{
2020-07-21 18:19:15 +02:00
/* The adapter failed to install, or the adapter ID was unobtainable. Clean-up. */
2020-07-21 16:38:00 +02:00
SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { . ClassInstallHeader = { . cbSize = sizeof ( SP_CLASSINSTALL_HEADER ) ,
. InstallFunction = DIF_REMOVE } ,
. Scope = DI_REMOVEDEVICE_GLOBAL } ;
if ( SetupDiSetClassInstallParamsW (
DevInfo , & DevInfoData , & RemoveDeviceParams . ClassInstallHeader , sizeof ( RemoveDeviceParams ) ) & &
SetupDiCallClassInstaller ( DIF_REMOVE , DevInfo , & DevInfoData ) )
* RebootRequired = * RebootRequired | | CheckReboot ( DevInfo , & DevInfoData ) ;
}
2020-11-02 16:28:51 +01:00
NamespaceReleaseMutex ( Mutex ) ;
2020-07-21 16:38:00 +02:00
cleanupDriverInfoList :
SetupDiDestroyDriverInfoList ( DevInfo , & DevInfoData , SPDIT_COMPATDRIVER ) ;
2020-07-07 15:42:39 +02:00
cleanupDevInfo :
SetupDiDestroyDeviceInfoList ( DevInfo ) ;
2020-11-01 01:22:32 +01:00
return Result ;
}
2020-10-19 22:23:09 +02:00
static WINTUN_STATUS
2020-10-31 18:13:36 +01:00
GetAdapter ( _In_z_ const WCHAR * Pool , _In_ const GUID * CfgInstanceID , _Out_ WINTUN_ADAPTER * * Adapter )
2020-10-19 22:23:09 +02:00
{
2020-11-02 12:07:05 +01:00
HANDLE Mutex = NamespaceTakePoolMutex ( Pool ) ;
2020-10-19 22:23:09 +02:00
if ( ! Mutex )
return ERROR_INVALID_HANDLE ;
HDEVINFO DevInfo ;
SP_DEVINFO_DATA DevInfoData ;
DWORD Result = GetDevInfoData ( CfgInstanceID , & DevInfo , & DevInfoData ) ;
if ( Result ! = ERROR_SUCCESS )
{
LOG ( WINTUN_LOG_ERR , L " Failed to locate adapter " ) ;
goto cleanupMutex ;
}
Result = CreateAdapterData ( Pool , DevInfo , & DevInfoData , Adapter ) ;
if ( Result ! = ERROR_SUCCESS )
LOG ( WINTUN_LOG_ERR , L " Failed to create adapter data " ) ;
SetupDiDestroyDeviceInfoList ( DevInfo ) ;
cleanupMutex :
NamespaceReleaseMutex ( Mutex ) ;
return Result ;
}
2020-11-02 23:55:59 +01:00
# include "rundll32.h"
2020-10-16 13:30:51 +02:00
WINTUN_STATUS WINAPI
WintunCreateAdapter (
2020-10-31 18:13:36 +01:00
_In_z_ const WCHAR * Pool ,
_In_z_ const WCHAR * Name ,
2020-10-16 13:30:51 +02:00
_In_opt_ const GUID * RequestedGUID ,
_Out_ WINTUN_ADAPTER * * Adapter ,
2020-10-31 15:40:01 +01:00
_Out_opt_ BOOL * RebootRequired )
2020-10-16 13:30:51 +02:00
{
2020-10-30 12:25:24 +01:00
if ( ! ElevateToSystem ( ) )
2020-11-03 02:24:32 +01:00
return LOG_LAST_ERROR ( L " Failed to impersonate SYSTEM user " ) ;
2020-10-31 15:40:01 +01:00
BOOL DummyRebootRequired ;
if ( ! RebootRequired )
RebootRequired = & DummyRebootRequired ;
2020-10-31 15:33:54 +01:00
* RebootRequired = FALSE ;
2020-11-02 16:28:51 +01:00
DWORD Result ;
2020-11-03 02:09:00 +01:00
if ( MAYBE_WOW64 & & NativeMachine ! = IMAGE_FILE_PROCESS )
2020-11-02 23:55:59 +01:00
Result = CreateAdapterViaRundll32 ( Pool , Name , RequestedGUID , Adapter , RebootRequired ) ;
2020-11-03 02:09:00 +01:00
else
Result = CreateAdapter ( Pool , Name , RequestedGUID , Adapter , RebootRequired ) ;
2020-10-30 12:25:24 +01:00
RevertToSelf ( ) ;
2020-10-15 15:54:37 +02:00
return Result ;
}
2020-07-21 16:43:34 +02:00
WINTUN_STATUS WINAPI
2020-10-31 15:40:01 +01:00
WintunDeleteAdapter ( _In_ const WINTUN_ADAPTER * Adapter , _In_ BOOL ForceCloseSessions , _Out_opt_ BOOL * RebootRequired )
2020-07-21 16:38:00 +02:00
{
2020-10-30 12:25:24 +01:00
if ( ! ElevateToSystem ( ) )
2020-11-03 02:24:32 +01:00
return LOG_LAST_ERROR ( L " Failed to impersonate SYSTEM user " ) ;
2020-10-30 12:25:24 +01:00
2020-10-31 15:40:01 +01:00
BOOL DummyRebootRequired ;
if ( ! RebootRequired )
RebootRequired = & DummyRebootRequired ;
2020-10-31 15:33:54 +01:00
* RebootRequired = FALSE ;
2020-10-30 12:25:24 +01:00
DWORD Result ;
2020-11-03 02:09:00 +01:00
if ( MAYBE_WOW64 & & NativeMachine ! = IMAGE_FILE_PROCESS )
2020-10-30 12:25:24 +01:00
{
2020-11-02 23:55:59 +01:00
Result = DeleteAdapterViaRundll32 ( Adapter , ForceCloseSessions , RebootRequired ) ;
2020-10-30 12:25:24 +01:00
RevertToSelf ( ) ;
return Result ;
}
2020-10-16 13:30:51 +02:00
2020-07-21 16:38:00 +02:00
HDEVINFO DevInfo ;
SP_DEVINFO_DATA DevInfoData ;
2020-10-30 12:25:24 +01:00
Result = GetDevInfoData ( & Adapter - > CfgInstanceID , & DevInfo , & DevInfoData ) ;
2020-07-24 08:26:20 +02:00
if ( Result = = ERROR_FILE_NOT_FOUND )
2020-10-30 12:25:24 +01:00
{
Result = ERROR_SUCCESS ;
goto cleanupToken ;
}
else if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get adapter info data " ) ;
2020-10-30 12:25:24 +01:00
goto cleanupToken ;
2020-10-13 19:40:52 +02:00
}
2020-10-30 14:21:13 +01:00
2020-10-30 14:34:40 +01:00
if ( ForceCloseSessions & & ForceCloseWintunAdapterHandle ( DevInfo , & DevInfoData ) ! = ERROR_SUCCESS )
2020-10-30 14:21:13 +01:00
LOG ( WINTUN_LOG_WARN , L " Failed to force close adapter handles " ) ;
2020-10-13 19:40:52 +02:00
SetQuietInstall ( DevInfo , & DevInfoData ) ;
2020-07-21 16:38:00 +02:00
SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { . ClassInstallHeader = { . cbSize = sizeof ( SP_CLASSINSTALL_HEADER ) ,
. InstallFunction = DIF_REMOVE } ,
. Scope = DI_REMOVEDEVICE_GLOBAL } ;
if ( SetupDiSetClassInstallParamsW (
DevInfo , & DevInfoData , & RemoveDeviceParams . ClassInstallHeader , sizeof ( RemoveDeviceParams ) ) & &
SetupDiCallClassInstaller ( DIF_REMOVE , DevInfo , & DevInfoData ) )
* RebootRequired = * RebootRequired | | CheckReboot ( DevInfo , & DevInfoData ) ;
else
2020-11-02 11:52:54 +01:00
Result = LOG_LAST_ERROR ( L " Failed to remove existing adapter " ) ;
2020-07-21 16:38:00 +02:00
SetupDiDestroyDeviceInfoList ( DevInfo ) ;
2020-10-30 12:25:24 +01:00
cleanupToken :
RevertToSelf ( ) ;
2020-07-21 16:38:00 +02:00
return Result ;
}
2020-11-02 16:28:51 +01:00
static WINTUN_STATUS
2020-11-03 12:45:38 +01:00
DeleteAllOurAdapters ( _In_ const WCHAR Pool [ WINTUN_MAX_POOL ] , _Inout_ BOOL * RebootRequired )
2020-11-02 16:28:51 +01:00
{
2020-11-03 12:27:42 +01:00
HANDLE Mutex = NamespaceTakePoolMutex ( Pool ) ;
if ( ! Mutex )
return ERROR_INVALID_HANDLE ;
2020-11-02 16:28:51 +01:00
DWORD Result = ERROR_SUCCESS ;
HDEVINFO DevInfo = SetupDiGetClassDevsExW ( & GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL ) ;
if ( DevInfo = = INVALID_HANDLE_VALUE )
2020-11-03 12:27:42 +01:00
{
NamespaceReleaseMutex ( Mutex ) ;
2020-11-02 16:28:51 +01:00
return LOG_LAST_ERROR ( L " Failed to get present adapters " ) ;
2020-11-03 12:27:42 +01:00
}
2020-11-02 16:28:51 +01:00
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 IsOurs ;
if ( IsOurAdapter ( DevInfo , & DevInfoData , & IsOurs ) ! = ERROR_SUCCESS | | ! IsOurs )
continue ;
2020-11-03 12:27:42 +01:00
BOOL IsMember ;
Result = IsPoolMember ( Pool , DevInfo , & DevInfoData , & IsMember ) ;
if ( Result ! = ERROR_SUCCESS )
{
LOG ( WINTUN_LOG_ERR , L " Failed to get pool membership " ) ;
break ;
}
if ( ! IsMember )
continue ;
2020-11-02 16:28:51 +01:00
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 " ) ;
LOG ( WINTUN_LOG_INFO , L " Removing existing adapter " ) ;
2020-11-03 12:27:42 +01:00
if ( SetupDiSetClassInstallParamsW ( DevInfo , & DevInfoData , & Params . ClassInstallHeader , sizeof ( Params ) ) & &
SetupDiCallClassInstaller ( DIF_REMOVE , DevInfo , & DevInfoData ) )
* RebootRequired = * RebootRequired | | CheckReboot ( DevInfo , & DevInfoData ) ;
else
2020-11-02 16:28:51 +01:00
{
LOG_LAST_ERROR ( L " Failed to remove existing adapter " ) ;
Result = Result ! = ERROR_SUCCESS ? Result : GetLastError ( ) ;
}
}
SetupDiDestroyDeviceInfoList ( DevInfo ) ;
2020-11-03 12:27:42 +01:00
NamespaceReleaseMutex ( Mutex ) ;
2020-11-02 16:28:51 +01:00
return Result ;
}
WINTUN_STATUS WINAPI
2020-11-03 12:45:38 +01:00
WintunDeletePoolDriver ( _In_z_ const WCHAR Pool [ WINTUN_MAX_POOL ] , _Out_opt_ BOOL * RebootRequired )
2020-11-02 16:28:51 +01:00
{
if ( ! ElevateToSystem ( ) )
2020-11-03 02:24:32 +01:00
return LOG_LAST_ERROR ( L " Failed to impersonate SYSTEM user " ) ;
2020-11-02 16:28:51 +01:00
2020-11-03 12:27:42 +01:00
BOOL DummyRebootRequired ;
if ( ! RebootRequired )
RebootRequired = & DummyRebootRequired ;
* RebootRequired = FALSE ;
2020-11-02 23:55:59 +01:00
2020-11-03 12:27:42 +01:00
DWORD Result ;
2020-11-03 02:09:00 +01:00
if ( MAYBE_WOW64 & & NativeMachine ! = IMAGE_FILE_PROCESS )
2020-11-02 16:28:51 +01:00
{
2020-11-03 12:27:42 +01:00
Result = DeletePoolDriverViaRundll32 ( Pool , RebootRequired ) ;
2020-11-02 16:28:51 +01:00
RevertToSelf ( ) ;
return Result ;
}
2020-11-03 12:27:42 +01:00
Result = DeleteAllOurAdapters ( Pool , RebootRequired ) ;
if ( Result ! = ERROR_SUCCESS )
goto cleanupToken ;
2020-11-02 16:28:51 +01:00
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex ( ) ;
if ( ! DriverInstallationLock )
{
Result = LOG_LAST_ERROR ( L " Failed to take driver installation mutex " ) ;
goto cleanupToken ;
}
HDEVINFO DeviceInfoSet = SetupDiGetClassDevsW ( & GUID_DEVCLASS_NET , NULL , NULL , 0 ) ;
if ( ! DeviceInfoSet )
{
Result = LOG_LAST_ERROR ( L " Failed to get adapter information " ) ;
goto cleanupDriverInstallationLock ;
}
if ( ! SetupDiBuildDriverInfoList ( DeviceInfoSet , NULL , SPDIT_CLASSDRIVER ) )
{
Result = 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 ;
if ( GetAdapterDrvInfoDetail ( DeviceInfoSet , NULL , & DriverInfo , & DriverDetail ) ! = ERROR_SUCCESS )
continue ;
if ( ! _wcsicmp ( DriverDetail - > HardwareID , WINTUN_HWID ) )
{
LOG ( WINTUN_LOG_INFO , TEXT ( " Removing existing driver " ) ) ;
2020-11-03 12:27:42 +01:00
if ( ! SetupUninstallOEMInfW ( PathFindFileNameW ( DriverDetail - > InfFileName ) , 0 , NULL ) )
2020-11-02 16:28:51 +01:00
{
LOG_LAST_ERROR ( TEXT ( " Unable to remove existing driver " ) ) ;
Result = Result ! = ERROR_SUCCESS ? Result : GetLastError ( ) ;
}
}
HeapFree ( ModuleHeap , 0 , DriverDetail ) ;
}
SetupDiDestroyDriverInfoList ( DeviceInfoSet , NULL , SPDIT_CLASSDRIVER ) ;
cleanupDeviceInfoSet :
SetupDiDestroyDeviceInfoList ( DeviceInfoSet ) ;
cleanupDriverInstallationLock :
NamespaceReleaseMutex ( DriverInstallationLock ) ;
cleanupToken :
RevertToSelf ( ) ;
return Result ;
}
2020-07-21 16:43:34 +02:00
WINTUN_STATUS WINAPI
2020-10-31 23:08:00 +01:00
WintunEnumAdapters ( _In_z_ const WCHAR * Pool , _In_ WINTUN_ENUM_CALLBACK_FUNC Func , _In_ LPARAM Param )
2020-07-21 16:38:00 +02:00
{
2020-11-02 12:07:05 +01:00
HANDLE Mutex = NamespaceTakePoolMutex ( Pool ) ;
2020-07-21 16:38:00 +02:00
if ( ! Mutex )
2020-07-24 08:26:20 +02:00
return ERROR_INVALID_HANDLE ;
2020-10-15 11:32:06 +02:00
DWORD Result = ERROR_SUCCESS ;
2020-10-13 19:40:52 +02:00
HDEVINFO DevInfo = SetupDiGetClassDevsExW ( & GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL ) ;
2020-07-21 16:38:00 +02:00
if ( DevInfo = = INVALID_HANDLE_VALUE )
{
2020-11-02 11:52:54 +01:00
Result = LOG_LAST_ERROR ( L " Failed to get present adapters " ) ;
2020-07-21 16:38:00 +02:00
goto cleanupMutex ;
}
2020-10-15 11:32:06 +02:00
BOOL Continue = TRUE ;
for ( DWORD EnumIndex = 0 ; Continue ; + + EnumIndex )
2020-07-21 16:38:00 +02:00
{
SP_DEVINFO_DATA DevInfoData = { . cbSize = sizeof ( SP_DEVINFO_DATA ) } ;
2020-10-13 19:40:52 +02:00
if ( ! SetupDiEnumDeviceInfo ( DevInfo , EnumIndex , & DevInfoData ) )
2020-07-21 16:38:00 +02:00
{
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
break ;
continue ;
}
2020-10-16 15:51:50 +02:00
BOOL IsOurs ;
if ( IsOurAdapter ( DevInfo , & DevInfoData , & IsOurs ) ! = ERROR_SUCCESS | | ! IsOurs )
2020-07-21 16:38:00 +02:00
continue ;
BOOL IsMember ;
Result = IsPoolMember ( Pool , DevInfo , & DevInfoData , & IsMember ) ;
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-11-02 11:52:54 +01:00
LOG ( WINTUN_LOG_ERR , L " Failed to get pool membership " ) ;
2020-07-21 16:38:00 +02:00
break ;
2020-10-13 19:40:52 +02:00
}
2020-07-21 16:38:00 +02:00
if ( ! IsMember )
continue ;
WINTUN_ADAPTER * Adapter ;
2020-07-21 18:19:15 +02:00
Result = CreateAdapterData ( Pool , DevInfo , & DevInfoData , & Adapter ) ;
2020-07-21 16:38:00 +02:00
if ( Result ! = ERROR_SUCCESS )
2020-10-13 19:40:52 +02:00
{
2020-10-15 12:21:55 +02:00
LOG ( WINTUN_LOG_ERR , L " Failed to create adapter data " ) ;
2020-07-21 16:38:00 +02:00
break ;
2020-10-13 19:40:52 +02:00
}
2020-10-15 11:32:06 +02:00
Continue = Func ( Adapter , Param ) ;
2020-10-24 22:12:47 +02:00
HeapFree ( ModuleHeap , 0 , Adapter ) ;
2020-07-21 16:38:00 +02:00
}
SetupDiDestroyDeviceInfoList ( DevInfo ) ;
cleanupMutex :
2020-10-15 11:32:06 +02:00
NamespaceReleaseMutex ( Mutex ) ;
2020-07-21 16:38:00 +02:00
return Result ;
}