api: check buffer overflows in runtime

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-10-31 18:13:36 +01:00
parent 8edd627f4d
commit 60ad907b99
5 changed files with 52 additions and 71 deletions

View File

@ -15,7 +15,7 @@
#include <Windows.h> #include <Windows.h>
#include <winternl.h> #include <winternl.h>
#define _NTDEF_ //TODO: figure out how to include ntsecapi and winternal together without requiring this #define _NTDEF_ /* TODO: figure out how to include ntsecapi and winternal together without requiring this */
#include <cfgmgr32.h> #include <cfgmgr32.h>
#include <devguid.h> #include <devguid.h>
#include <iphlpapi.h> #include <iphlpapi.h>
@ -472,19 +472,15 @@ RemoveNumberedSuffix(_Inout_z_ WCHAR *Name)
} }
static WINTUN_STATUS static WINTUN_STATUS
GetPoolDeviceTypeName(_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _Out_cap_c_(MAX_POOL_DEVICE_TYPE) WCHAR *Name) GetPoolDeviceTypeName(_In_z_ const WCHAR *Pool, _Out_cap_c_(MAX_POOL_DEVICE_TYPE) WCHAR *Name)
{ {
if (_snwprintf_s(Name, MAX_POOL_DEVICE_TYPE, _TRUNCATE, L"%.*s Tunnel", WINTUN_MAX_POOL, Pool) == -1) if (_snwprintf_s(Name, MAX_POOL_DEVICE_TYPE, _TRUNCATE, L"%s Tunnel", Pool) == -1)
return LOG(WINTUN_LOG_ERR, L"Pool name too long"), ERROR_INVALID_PARAMETER; return LOG(WINTUN_LOG_ERR, L"Pool name too long"), ERROR_INVALID_PARAMETER;
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
static WINTUN_STATUS static WINTUN_STATUS
IsPoolMember( IsPoolMember(_In_z_ const WCHAR *Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _Out_ BOOL *IsMember)
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool,
_In_ HDEVINFO DevInfo,
_In_ SP_DEVINFO_DATA *DevInfoData,
_Out_ BOOL *IsMember)
{ {
WCHAR *DeviceDesc, *FriendlyName; WCHAR *DeviceDesc, *FriendlyName;
DWORD Result = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_DEVICEDESC, &DeviceDesc); DWORD Result = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_DEVICEDESC, &DeviceDesc);
@ -525,7 +521,7 @@ cleanupDeviceDesc:
static WINTUN_STATUS static WINTUN_STATUS
CreateAdapterData( CreateAdapterData(
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_z_ const WCHAR *Pool,
_In_ HDEVINFO DevInfo, _In_ HDEVINFO DevInfo,
_In_ SP_DEVINFO_DATA *DevInfoData, _In_ SP_DEVINFO_DATA *DevInfoData,
_Out_ WINTUN_ADAPTER **Adapter) _Out_ WINTUN_ADAPTER **Adapter)
@ -623,10 +619,7 @@ WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter)
} }
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunGetAdapter( WintunGetAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _Out_ WINTUN_ADAPTER **Adapter)
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool,
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name,
_Out_ WINTUN_ADAPTER **Adapter)
{ {
if (!ElevateToSystem()) if (!ElevateToSystem())
return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED; return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
@ -734,13 +727,13 @@ ConvertInterfaceAliasToGuid(_In_z_ const WCHAR *Name, _Out_ GUID *Guid)
} }
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name) WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_ const WCHAR *Name)
{ {
DWORD Result; DWORD Result;
const int MaxSuffix = 1000; const int MaxSuffix = 1000;
WCHAR AvailableName[MAX_ADAPTER_NAME]; WCHAR AvailableName[MAX_ADAPTER_NAME];
if (wcsncpy_s(AvailableName, _countof(AvailableName), Name, _TRUNCATE) == STRUNCATE) if (wcsncpy_s(AvailableName, _countof(AvailableName), Name, _TRUNCATE) == STRUNCATE)
return LOG(WINTUN_LOG_ERR, L"Pool name too long"), ERROR_INVALID_PARAMETER; return LOG(WINTUN_LOG_ERR, L"Adapter name too long"), ERROR_INVALID_PARAMETER;
for (int i = 0;; ++i) for (int i = 0;; ++i)
{ {
Result = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); Result = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName);
@ -753,9 +746,8 @@ WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_count_c_(MAX_ADAP
for (int j = 0; j < MaxSuffix; ++j) for (int j = 0; j < MaxSuffix; ++j)
{ {
WCHAR Proposal[MAX_ADAPTER_NAME]; WCHAR Proposal[MAX_ADAPTER_NAME];
if (_snwprintf_s( if (_snwprintf_s(Proposal, _countof(Proposal), _TRUNCATE, L"%s %d", Name, j + 1) == -1)
Proposal, _countof(Proposal), _TRUNCATE, L"%.*s %d", MAX_ADAPTER_NAME, Name, j + 1) == -1) return LOG(WINTUN_LOG_ERR, L"Adapter name too long"), ERROR_INVALID_PARAMETER;
return LOG(WINTUN_LOG_ERR, L"Pool name too long"), ERROR_INVALID_PARAMETER;
if (_wcsnicmp(Proposal, AvailableName, MAX_ADAPTER_NAME) == 0) if (_wcsnicmp(Proposal, AvailableName, MAX_ADAPTER_NAME) == 0)
continue; continue;
Result2 = NciSetConnectionName(&Guid2, Proposal); Result2 = NciSetConnectionName(&Guid2, Proposal);
@ -775,9 +767,8 @@ WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_count_c_(MAX_ADAP
break; break;
if (i >= MaxSuffix || Result != ERROR_DUP_NAME) if (i >= MaxSuffix || Result != ERROR_DUP_NAME)
return LOG_ERROR(L"Setting adapter name failed", Result); return LOG_ERROR(L"Setting adapter name failed", Result);
if (_snwprintf_s( if (_snwprintf_s(AvailableName, _countof(AvailableName), _TRUNCATE, L"%s %d", Name, i + 1) == -1)
AvailableName, _countof(AvailableName), _TRUNCATE, L"%.*s %d", MAX_ADAPTER_NAME, Name, i + 1) == -1) return LOG(WINTUN_LOG_ERR, L"Adapter name too long"), ERROR_INVALID_PARAMETER;
return LOG(WINTUN_LOG_ERR, L"Pool name too long"), ERROR_INVALID_PARAMETER;
} }
/* TODO: This should use NetSetup2 so that it doesn't get unset. */ /* TODO: This should use NetSetup2 so that it doesn't get unset. */
@ -1055,7 +1046,8 @@ RunningWintunVersion(void)
} }
for (ULONG i = 0; i < Modules->NumberOfModules; ++i) for (ULONG i = 0; i < Modules->NumberOfModules; ++i)
{ {
if (!_stricmp((const char *)&Modules->Modules[i].FullPathName[Modules->Modules[i].OffsetToFileName], "wintun.sys")) if (!_stricmp(
(const char *)&Modules->Modules[i].FullPathName[Modules->Modules[i].OffsetToFileName], "wintun.sys"))
{ {
size_t Size = strlen((const char *)Modules->Modules[i].FullPathName) + 1; size_t Size = strlen((const char *)Modules->Modules[i].FullPathName) + 1;
WCHAR *FilePathName = HeapAlloc(ModuleHeap, 0, Size * 2); WCHAR *FilePathName = HeapAlloc(ModuleHeap, 0, Size * 2);
@ -1085,9 +1077,9 @@ static BOOL EnsureWintunUnloaded(VOID)
static WINTUN_STATUS static WINTUN_STATUS
CreateAdapter( CreateAdapter(
_In_z_count_c_(MAX_PATH) const WCHAR *InfPath, _In_z_ const WCHAR *InfPath,
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_z_ const WCHAR *Pool,
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, _In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID, _In_opt_ const GUID *RequestedGUID,
_Out_ WINTUN_ADAPTER **Adapter, _Out_ WINTUN_ADAPTER **Adapter,
_Inout_ BOOL *RebootRequired) _Inout_ BOOL *RebootRequired)
@ -1129,7 +1121,12 @@ CreateAdapter(
goto cleanupDevInfo; goto cleanupDevInfo;
} }
DevInstallParams.Flags |= DI_QUIETINSTALL | DI_ENUMSINGLEINF; DevInstallParams.Flags |= DI_QUIETINSTALL | DI_ENUMSINGLEINF;
wcscpy_s(DevInstallParams.DriverPath, _countof(DevInstallParams.DriverPath), InfPath); if (wcsncpy_s(DevInstallParams.DriverPath, _countof(DevInstallParams.DriverPath), InfPath, _TRUNCATE) == STRUNCATE)
{
LOG(WINTUN_LOG_ERR, L"Inf path too long");
Result = ERROR_INVALID_PARAMETER;
goto cleanupDevInfo;
}
if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
{ {
Result = LOG_LAST_ERROR(L"Setting device installation parameters failed"); Result = LOG_LAST_ERROR(L"Setting device installation parameters failed");
@ -1604,10 +1601,7 @@ cleanupDirectory:
} }
static WINTUN_STATUS static WINTUN_STATUS
GetAdapter( GetAdapter(_In_z_ const WCHAR *Pool, _In_ const GUID *CfgInstanceID, _Out_ WINTUN_ADAPTER **Adapter)
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool,
_In_ const GUID *CfgInstanceID,
_Out_ WINTUN_ADAPTER **Adapter)
{ {
HANDLE Mutex = NamespaceTakeMutex(Pool); HANDLE Mutex = NamespaceTakeMutex(Pool);
if (!Mutex) if (!Mutex)
@ -1631,8 +1625,8 @@ cleanupMutex:
static WINTUN_STATUS static WINTUN_STATUS
CreateAdapterNatively( CreateAdapterNatively(
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_z_ const WCHAR *Pool,
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, _In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID, _In_opt_ const GUID *RequestedGUID,
_Out_ WINTUN_ADAPTER **Adapter, _Out_ WINTUN_ADAPTER **Adapter,
_Inout_ BOOL *RebootRequired) _Inout_ BOOL *RebootRequired)
@ -1644,10 +1638,8 @@ CreateAdapterNatively(
Arguments, Arguments,
_countof(Arguments), _countof(Arguments),
_TRUNCATE, _TRUNCATE,
RequestedGUID ? L"CreateAdapter \"%.*s\" \"%.*s\" %.*s" : L"CreateAdapter \"%.*s\" \"%.*s\"", RequestedGUID ? L"CreateAdapter \"%s\" \"%s\" %.*s" : L"CreateAdapter \"%s\" \"%s\"",
WINTUN_MAX_POOL,
Pool, Pool,
MAX_ADAPTER_NAME,
Name, Name,
RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0, RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0,
RequestedGUIDStr) == -1) RequestedGUIDStr) == -1)
@ -1685,8 +1677,8 @@ cleanupArgv:
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunCreateAdapter( WintunCreateAdapter(
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_z_ const WCHAR *Pool,
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, _In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID, _In_opt_ const GUID *RequestedGUID,
_Out_ WINTUN_ADAPTER **Adapter, _Out_ WINTUN_ADAPTER **Adapter,
_Out_opt_ BOOL *RebootRequired) _Out_opt_ BOOL *RebootRequired)
@ -1904,7 +1896,7 @@ cleanupToken:
} }
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunEnumAdapters(_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_ WINTUN_ENUM_FUNC Func, _In_ LPARAM Param) WintunEnumAdapters(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_FUNC Func, _In_ LPARAM Param)
{ {
HANDLE Mutex = NamespaceTakeMutex(Pool); HANDLE Mutex = NamespaceTakeMutex(Pool);
if (!Mutex) if (!Mutex)

View File

@ -107,8 +107,8 @@ WintunGetAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *H
*/ */
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunCreateAdapter( WintunCreateAdapter(
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_z_ const WCHAR *Pool,
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, _In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID, _In_opt_ const GUID *RequestedGUID,
_Out_ WINTUN_ADAPTER **Adapter, _Out_ WINTUN_ADAPTER **Adapter,
_Out_opt_ BOOL *RebootRequired); _Out_opt_ BOOL *RebootRequired);

View File

@ -62,15 +62,11 @@ OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGL
} }
WINTUN_STATUS WINTUN_STATUS
RegistryOpenKeyWait( RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut)
_In_ HKEY Key,
_In_z_count_c_(MAX_REG_PATH) const WCHAR *Path,
_In_ DWORD Access,
_In_ DWORD Timeout,
_Out_ HKEY *KeyOut)
{ {
WCHAR Buf[MAX_REG_PATH]; WCHAR Buf[MAX_REG_PATH];
wcscpy_s(Buf, _countof(Buf), Path); if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE)
return LOG(WINTUN_LOG_ERR, L"Registry path too long"), ERROR_INVALID_PARAMETER;
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout, KeyOut); return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout, KeyOut);
} }

View File

@ -17,7 +17,7 @@
* *
* @param Key Handle of the parent registry key. Must be opened with notify access. * @param Key Handle of the parent registry key. Must be opened with notify access.
* *
* @param Path Subpath of the registry key to open. * @param Path Subpath of the registry key to open. Zero-terminated string of up to MAX_REG_PATH-1 characters.
* *
* @param Access A mask that specifies the desired access rights to the key to be opened. * @param Access A mask that specifies the desired access rights to the key to be opened.
* *
@ -28,12 +28,7 @@
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; Win32 error code otherwise. * @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; Win32 error code otherwise.
*/ */
WINTUN_STATUS WINTUN_STATUS
RegistryOpenKeyWait( RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut);
_In_ HKEY Key,
_In_z_count_c_(MAX_REG_PATH) const WCHAR *Path,
_In_ DWORD Access,
_In_ DWORD Timeout,
_Out_ HKEY *KeyOut);
/** /**
* Validates and/or sanitizes string value read from registry. * Validates and/or sanitizes string value read from registry.

View File

@ -27,9 +27,10 @@ typedef void *WINTUN_ADAPTER_HANDLE;
/** /**
* Creates a Wintun adapter. * Creates a Wintun adapter.
* *
* @param Pool Name of the adapter pool. * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
* *
* @param Name The requested name of the adapter. * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
* *
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation
* deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence * deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence
@ -45,8 +46,8 @@ typedef void *WINTUN_ADAPTER_HANDLE;
* @return ERROR_SUCCESS on success; Win32 error code otherwise. * @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/ */
typedef WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)( typedef WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_z_ const WCHAR *Pool,
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, _In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID, _In_opt_ const GUID *RequestedGUID,
_Out_ WINTUN_ADAPTER_HANDLE *Adapter, _Out_ WINTUN_ADAPTER_HANDLE *Adapter,
_Out_opt_ BOOL *RebootRequired); _Out_opt_ BOOL *RebootRequired);
@ -83,7 +84,7 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In
/** /**
* Enumerates all Wintun adapters. * Enumerates all Wintun adapters.
* *
* @param Pool Name of the adapter pool. * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
* *
* @param Func Callback function. To continue enumeration, the callback function must return TRUE; to stop * @param Func Callback function. To continue enumeration, the callback function must return TRUE; to stop
* enumeration, it must return FALSE. * enumeration, it must return FALSE.
@ -92,10 +93,8 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In
* *
* @return ERROR_SUCCESS on success; Win32 error code otherwise. * @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/ */
typedef WINTUN_STATUS(WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)( typedef WINTUN_STATUS(
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_FUNC Func, _In_ LPARAM Param);
_In_ WINTUN_ENUM_FUNC Func,
_In_ LPARAM Param);
/** /**
* Releases Wintun adapter resources. * Releases Wintun adapter resources.
@ -107,9 +106,9 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte
/** /**
* Finds a Wintun adapter by its name. * Finds a Wintun adapter by its name.
* *
* @param Pool Name of the adapter pool. * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
* *
* @param Name Adapter name. * @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
* *
* @param Adapter Pointer to a handle to receive the adapter handle. Must be released with WintunFreeAdapter. * @param Adapter Pointer to a handle to receive the adapter handle. Must be released with WintunFreeAdapter.
* *
@ -117,8 +116,8 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte
* if adapter is found but not a Wintun-class or not a member of the pool; Win32 error code otherwise * if adapter is found but not a Wintun-class or not a member of the pool; Win32 error code otherwise
*/ */
typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_FUNC)( typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_FUNC)(
_In_z_count_c_(WINTUN_MAX_POOL) const WCHAR *Pool, _In_z_ const WCHAR *Pool,
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, _In_z_ const WCHAR *Name,
_Out_ WINTUN_ADAPTER_HANDLE *Adapter); _Out_ WINTUN_ADAPTER_HANDLE *Adapter);
/** /**
@ -188,13 +187,12 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_GET_VERSION_FUNC)(
* *
* @param Adapter Adapter handle obtained with WintunGetAdapter or WintunCreateAdapter * @param Adapter Adapter handle obtained with WintunGetAdapter or WintunCreateAdapter
* *
* @param Name Adapter name * @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
* *
* @return ERROR_SUCCESS on success; Win32 error code otherwise. * @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/ */
typedef WINTUN_STATUS(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)( typedef WINTUN_STATUS(
_In_ WINTUN_ADAPTER_HANDLE Adapter, WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name);
_In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name);
typedef enum _WINTUN_LOGGER_LEVEL typedef enum _WINTUN_LOGGER_LEVEL
{ {