api: upgrade

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2021-07-28 20:20:09 +02:00
parent d61007297d
commit d675646ab8
20 changed files with 1539 additions and 1383 deletions

File diff suppressed because it is too large Load Diff

View File

@ -13,58 +13,96 @@
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ #define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
#define WINTUN_HWID L"Wintun" #define WINTUN_HWID L"Wintun"
void
AdapterInit(void);
/** /**
* Wintun adapter descriptor. * Wintun adapter descriptor.
*/ */
typedef struct _WINTUN_ADAPTER typedef struct _WINTUN_ADAPTER
{ {
HDEVINFO DevInfo;
SP_DEVINFO_DATA DevInfoData;
GUID CfgInstanceID; GUID CfgInstanceID;
WCHAR DevInstanceID[MAX_INSTANCE_ID]; WCHAR DevInstanceID[MAX_INSTANCE_ID];
DWORD LuidIndex; DWORD LuidIndex;
DWORD IfType; DWORD IfType;
DWORD IfIndex;
WCHAR Pool[WINTUN_MAX_POOL]; WCHAR Pool[WINTUN_MAX_POOL];
} WINTUN_ADAPTER; } WINTUN_ADAPTER;
/** /**
* @copydoc WINTUN_FREE_ADAPTER_FUNC * @copydoc WINTUN_FREE_ADAPTER_FUNC
*/ */
void WINAPI WINTUN_FREE_ADAPTER_FUNC_IMPL WintunFreeAdapter;
WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
/** /**
* @copydoc WINTUN_CREATE_ADAPTER_FUNC * @copydoc WINTUN_CREATE_ADAPTER_FUNC
*/ */
_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI WintunCreateAdapter( WINTUN_CREATE_ADAPTER_FUNC_IMPL WintunCreateAdapter;
_In_z_ const WCHAR *Pool,
_In_z_ const WCHAR *Name, /**
_In_opt_ const GUID *RequestedGUID, * @copydoc WINTUN_OPEN_ADAPTER_FUNC
_Out_opt_ BOOL *RebootRequired); */
WINTUN_OPEN_ADAPTER_FUNC_IMPL WintunOpenAdapter;
/** /**
* @copydoc WINTUN_DELETE_ADAPTER_FUNC * @copydoc WINTUN_DELETE_ADAPTER_FUNC
*/ */
_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter( WINTUN_DELETE_ADAPTER_FUNC_IMPL WintunDeleteAdapter;
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions, /**
_Out_opt_ BOOL *RebootRequired); * @copydoc WINTUN_ENUM_ADAPTERS_FUNC
*/
WINTUN_ENUM_ADAPTERS_FUNC_IMPL WintunEnumAdapters;
/** /**
* @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC * @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
*/ */
_Return_type_success_(return != FALSE) BOOL WINAPI WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL WintunDeletePoolDriver;
WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
/**
* @copydoc WINTUN_GET_ADAPTER_LUID_FUNC
*/
WINTUN_GET_ADAPTER_LUID_FUNC_IMPL WintunGetAdapterLUID;
/**
* @copydoc WINTUN_GET_ADAPTER_NAME_FUNC
*/
WINTUN_GET_ADAPTER_NAME_FUNC_IMPL WintunGetAdapterName;
/**
* @copydoc WINTUN_SET_ADAPTER_NAME_FUNC
*/
WINTUN_SET_ADAPTER_NAME_FUNC_IMPL WintunSetAdapterName;
/**
* @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC
*/
WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL WintunGetRunningDriverVersion;
/** /**
* Returns a handle to the adapter device object. * Returns a handle to the adapter device object.
* *
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
* *
* @return If the function succeeds, the return value is adapter device object handle. Must be released with * @return If the function succeeds, the return value is adapter device object handle.
* CloseHandle. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error * If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error
* information, call GetLastError. * information, call GetLastError.
*/ */
_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI _Return_type_success_(return != INVALID_HANDLE_VALUE)
AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter); HANDLE WINAPI
AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
/**
* Returns an adapter object based on a devnode instance ID.
*
* @param Pool Pool name of adapter object to be opened.
*
* @param DevInstanceID Instance ID of devnode for opening adapter.
*
* @return If the function succeeds, the return value is adapter object..
* If the function fails, the return value is NULL. To get extended error
* information, call GetLastError.
*/
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_ADAPTER *
AdapterOpenFromDevInstanceId(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR DevInstanceID);

View File

@ -53,15 +53,13 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="main.h" /> <ClInclude Include="main.h" />
<ClInclude Include="adapter.h" /> <ClInclude Include="adapter.h" />
<ClInclude Include="rundll32_i.c">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="logger.h" /> <ClInclude Include="logger.h" />
<ClInclude Include="namespace.h" /> <ClInclude Include="namespace.h" />
<ClInclude Include="nci.h" /> <ClInclude Include="nci.h" />
<ClInclude Include="ntdll.h" /> <ClInclude Include="ntdll.h" />
<ClInclude Include="registry.h" /> <ClInclude Include="registry.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="rundll32.h" />
<ClInclude Include="wintun.h" /> <ClInclude Include="wintun.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,6 +4,7 @@
*/ */
#include "logger.h" #include "logger.h"
#include "adapter.h"
#include "ntdll.h" #include "ntdll.h"
#include <Windows.h> #include <Windows.h>
#include <winternl.h> #include <winternl.h>
@ -11,17 +12,16 @@
#include <stdlib.h> #include <stdlib.h>
static BOOL CALLBACK static BOOL CALLBACK
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
{ {
UNREFERENCED_PARAMETER(Level);
UNREFERENCED_PARAMETER(LogLine);
return TRUE; return TRUE;
} }
WINTUN_LOGGER_CALLBACK Logger = NopLogger; WINTUN_LOGGER_CALLBACK Logger = NopLogger;
void CALLBACK _Use_decl_annotations_
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger) VOID WINAPI
WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger)
{ {
if (!NewLogger) if (!NewLogger)
NewLogger = NopLogger; NewLogger = NopLogger;
@ -29,14 +29,15 @@ WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger)
} }
static VOID static VOID
StrTruncate(_Inout_count_(StrChars) WCHAR *Str, _In_ SIZE_T StrChars) StrTruncate(_Inout_count_(StrChars) LPWSTR Str, _In_ SIZE_T StrChars)
{ {
Str[StrChars - 2] = L'\u2026'; /* Horizontal Ellipsis */ Str[StrChars - 2] = L'\u2026'; /* Horizontal Ellipsis */
Str[StrChars - 1] = 0; Str[StrChars - 1] = 0;
} }
_Post_equals_last_error_ DWORD _Use_decl_annotations_
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine) DWORD
LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR LogLine)
{ {
DWORD LastError = GetLastError(); DWORD LastError = GetLastError();
if (Function) if (Function)
@ -52,12 +53,9 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c
return LastError; return LastError;
} }
_Post_equals_last_error_ DWORD _Use_decl_annotations_
LoggerLogV( DWORD
_In_ WINTUN_LOGGER_LEVEL Level, LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR Format, va_list Args)
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args)
{ {
DWORD LastError = GetLastError(); DWORD LastError = GetLastError();
WCHAR LogLine[0x400]; WCHAR LogLine[0x400];
@ -71,16 +69,17 @@ LoggerLogV(
return LastError; return LastError;
} }
_Post_equals_last_error_ DWORD _Use_decl_annotations_
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix) DWORD
LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix)
{ {
WCHAR *SystemMessage = NULL, *FormattedMessage = NULL; LPWSTR SystemMessage = NULL, FormattedMessage = NULL;
FormatMessageW( FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK, FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, NULL,
HRESULT_FROM_SETUPAPI(Error), HRESULT_FROM_SETUPAPI(Error),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(void *)&SystemMessage, (VOID *)&SystemMessage,
0, 0,
NULL); NULL);
FormatMessageW( FormatMessageW(
@ -89,7 +88,7 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *
SystemMessage ? L"%4: %1: %3(Code 0x%2!08X!)" : L"%4: %1: Code 0x%2!08X!", SystemMessage ? L"%4: %1: %3(Code 0x%2!08X!)" : L"%4: %1: Code 0x%2!08X!",
0, 0,
0, 0,
(void *)&FormattedMessage, (VOID *)&FormattedMessage,
0, 0,
(va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function }); (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function });
if (FormattedMessage) if (FormattedMessage)
@ -99,12 +98,9 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *
return Error; return Error;
} }
_Post_equals_last_error_ DWORD _Use_decl_annotations_
LoggerErrorV( DWORD
_In_ DWORD Error, LoggerErrorV(DWORD Error, LPCWSTR Function, LPCWSTR Format, va_list Args)
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args)
{ {
WCHAR Prefix[0x400]; WCHAR Prefix[0x400];
if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1) if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1)
@ -112,13 +108,14 @@ LoggerErrorV(
return LoggerError(Error, Function, Prefix); return LoggerError(Error, Function, Prefix);
} }
_Use_decl_annotations_
VOID VOID
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) LoggerGetRegistryKeyPath(HKEY Key, LPWSTR Path)
{ {
DWORD LastError = GetLastError(); DWORD LastError = GetLastError();
if (Key == NULL) if (Key == NULL)
{ {
wcscpy_s(Path, MAX_REG_PATH, L"<null>"); wcsncpy_s(Path, MAX_REG_PATH, L"<null>", _TRUNCATE);
goto out; goto out;
} }
if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1) if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1)

View File

@ -9,6 +9,7 @@
#include "main.h" #include "main.h"
#include "registry.h" #include "registry.h"
#include <Windows.h> #include <Windows.h>
#include <intsafe.h>
#include <stdarg.h> #include <stdarg.h>
#include <wchar.h> #include <wchar.h>
@ -17,25 +18,23 @@ extern WINTUN_LOGGER_CALLBACK Logger;
/** /**
* @copydoc WINTUN_SET_LOGGER_FUNC * @copydoc WINTUN_SET_LOGGER_FUNC
*/ */
void WINAPI WINTUN_SET_LOGGER_FUNC_IMPL WintunSetLogger;
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
_Post_equals_last_error_ DWORD _Post_equals_last_error_
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine); DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR LogLine);
_Post_equals_last_error_ DWORD _Post_equals_last_error_
DWORD
LoggerLogV( LoggerLogV(
_In_ WINTUN_LOGGER_LEVEL Level, _In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ const WCHAR *Function, _In_z_ LPCWSTR Function,
_In_z_ _Printf_format_string_ const WCHAR *Format, _In_z_ _Printf_format_string_ LPCWSTR Format,
_In_ va_list Args); _In_ va_list Args);
static inline _Post_equals_last_error_ DWORD _Post_equals_last_error_
LoggerLogFmt( static inline DWORD
_In_ WINTUN_LOGGER_LEVEL Level, LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
...)
{ {
va_list Args; va_list Args;
va_start(Args, Format); va_start(Args, Format);
@ -44,18 +43,21 @@ LoggerLogFmt(
return LastError; return LastError;
} }
_Post_equals_last_error_ DWORD _Post_equals_last_error_
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix); DWORD
LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR Prefix);
_Post_equals_last_error_ DWORD _Post_equals_last_error_
DWORD
LoggerErrorV( LoggerErrorV(
_In_ DWORD Error, _In_ DWORD Error,
_In_z_ const WCHAR *Function, _In_z_ LPCWSTR Function,
_In_z_ _Printf_format_string_ const WCHAR *Format, _In_z_ _Printf_format_string_ LPCWSTR Format,
_In_ va_list Args); _In_ va_list Args);
static inline _Post_equals_last_error_ DWORD _Post_equals_last_error_
LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...) static inline DWORD
LoggerErrorFmt(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{ {
va_list Args; va_list Args;
va_start(Args, Format); va_start(Args, Format);
@ -64,8 +66,9 @@ LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_fo
return LastError; return LastError;
} }
static inline _Post_equals_last_error_ DWORD _Post_equals_last_error_
LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, _In_ va_list Args) static inline DWORD
LoggerLastErrorV(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args)
{ {
DWORD LastError = GetLastError(); DWORD LastError = GetLastError();
LoggerErrorV(LastError, Function, Format, Args); LoggerErrorV(LastError, Function, Format, Args);
@ -73,8 +76,9 @@ LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ con
return LastError; return LastError;
} }
static inline _Post_equals_last_error_ DWORD _Post_equals_last_error_
LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...) static inline DWORD
LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
{ {
va_list Args; va_list Args;
va_start(Args, Format); va_start(Args, Format);
@ -84,7 +88,7 @@ LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ c
} }
VOID VOID
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path); LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path);
#define __L(x) L##x #define __L(x) L##x
#define _L(x) __L(x) #define _L(x) __L(x)
@ -94,10 +98,31 @@ LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path);
#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0)) #define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))
static inline _Return_type_success_(return != NULL) _Ret_maybenull_ _Must_inspect_result_
_Post_writable_byte_size_(Size) void *LoggerAlloc(_In_z_ const WCHAR *Function, _In_ DWORD Flags, _In_ SIZE_T Size) DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(Size)
VOID *
LoggerAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T Size)
{ {
void *Data = HeapAlloc(ModuleHeap, Flags, Size); VOID *Data = HeapAlloc(ModuleHeap, Flags, Size);
if (!Data)
{
LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
SetLastError(ERROR_OUTOFMEMORY);
}
return Data;
}
_Must_inspect_result_
DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(Size)
VOID *
LoggerReAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _Frees_ptr_opt_ LPVOID Mem, _In_ SIZE_T Size)
{
VOID *Data = Mem ? HeapReAlloc(ModuleHeap, Flags, Mem, Size) : HeapAlloc(ModuleHeap, Flags, Size);
if (!Data) if (!Data)
{ {
LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size); LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
@ -106,10 +131,48 @@ static inline _Return_type_success_(return != NULL) _Ret_maybenull_
return Data; return Data;
} }
#define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size) #define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size)
#define ReAlloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), 0, Mem, Size)
#define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size) #define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size)
#define ReZalloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Size)
static inline void _Must_inspect_result_
Free(void *Ptr) DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
VOID *
LoggerAllocArray(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T NumberOfElements, _In_ SIZE_T SizeOfOneElement)
{
SIZE_T Size;
if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
return NULL;
return LoggerAlloc(Function, Flags, Size);
}
_Must_inspect_result_
DECLSPEC_ALLOCATOR
static inline _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
VOID *
LoggerReAllocArray(
_In_z_ LPCWSTR Function,
_In_ DWORD Flags,
_Frees_ptr_opt_ LPVOID Mem,
_In_ SIZE_T NumberOfElements,
_In_ SIZE_T SizeOfOneElement)
{
SIZE_T Size;
if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
return NULL;
return LoggerReAlloc(Function, Flags, Mem, Size);
}
#define AllocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), 0, Count, Size)
#define ReAllocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), 0, Mem, Count, Size)
#define ZallocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Count, Size)
#define ReZallocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Count, Size)
static inline VOID
Free(_Frees_ptr_opt_ VOID *Ptr)
{ {
if (!Ptr) if (!Ptr)
return; return;

View File

@ -3,18 +3,15 @@
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/ */
#include "adapter.h"
#include "logger.h" #include "logger.h"
#include "registry.h" #include "adapter.h"
#include "main.h"
#include "namespace.h" #include "namespace.h"
#include "wintun.h" #include "registry.h"
#include "ntdll.h"
#include <Windows.h> #include <Windows.h>
#pragma warning(push)
#pragma warning(disable : 4201)
/* nonstandard extension used: nameless struct/union */
#include <delayimp.h> #include <delayimp.h>
#pragma warning(pop)
#include <sddl.h> #include <sddl.h>
#include <winefs.h> #include <winefs.h>
#include <stdlib.h> #include <stdlib.h>
@ -23,6 +20,8 @@ HINSTANCE ResourceModule;
HANDLE ModuleHeap; HANDLE ModuleHeap;
SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) }; SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
BOOL IsLocalSystem; BOOL IsLocalSystem;
USHORT NativeMachine = IMAGE_FILE_PROCESS;
BOOL IsWindows10;
static FARPROC WINAPI static FARPROC WINAPI
DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
@ -37,8 +36,7 @@ DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook; const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook;
static BOOL static BOOL InitializeSecurityObjects(VOID)
InitializeSecurityObjects(void)
{ {
BYTE LocalSystemSid[MAX_SID_SIZE]; BYTE LocalSystemSid[MAX_SID_SIZE];
DWORD RequiredBytes = sizeof(LocalSystemSid); DWORD RequiredBytes = sizeof(LocalSystemSid);
@ -72,11 +70,32 @@ cleanupProcessToken:
return Ret; return Ret;
} }
static VOID EnvInit(VOID)
{
DWORD MajorVersion;
RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
IsWindows10 = MajorVersion >= 10;
#ifdef MAYBE_WOW64
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;
}
#endif
}
BOOL APIENTRY BOOL APIENTRY
DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
{ {
UNREFERENCED_PARAMETER(lpvReserved);
switch (fdwReason) switch (fdwReason)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
@ -89,7 +108,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
HeapDestroy(ModuleHeap); HeapDestroy(ModuleHeap);
return FALSE; return FALSE;
} }
AdapterInit(); EnvInit();
NamespaceInit(); NamespaceInit();
break; break;

View File

@ -7,26 +7,21 @@
#include <Windows.h> #include <Windows.h>
/* TODO: Replace with is_defined. MSVC has issues with the linux kernel varadic macro trick for this. */ #if defined(_M_IX86)
#if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) # define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386
# define MAYBE_WOW64 1 #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 #else
# define MAYBE_WOW64 0 # error Unsupported architecture
#endif #endif
#if defined(_M_AMD64) || defined(_M_ARM64)
# define ACCEPT_WOW64 1
#else
# define ACCEPT_WOW64 0
#endif
#ifdef HAVE_WHQL
# undef HAVE_WHQL
# define HAVE_WHQL 1
#else
# define HAVE_WHQL 0
#endif
#pragma warning(disable : 4127) /* conditional expression is constant */
extern HINSTANCE ResourceModule; extern HINSTANCE ResourceModule;
extern HANDLE ModuleHeap; extern HANDLE ModuleHeap;
extern SECURITY_ATTRIBUTES SecurityAttributes; extern SECURITY_ATTRIBUTES SecurityAttributes;
extern BOOL IsLocalSystem; extern BOOL IsLocalSystem;
extern USHORT NativeMachine;
extern BOOL IsWindows10;

View File

@ -19,13 +19,16 @@ static HANDLE BoundaryDescriptor = NULL;
static CRITICAL_SECTION Initializing; static CRITICAL_SECTION Initializing;
static BCRYPT_ALG_HANDLE AlgProvider; static BCRYPT_ALG_HANDLE AlgProvider;
static _Return_type_success_( _Must_inspect_result_
return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source) static _Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ LPCWSTR Source)
{ {
int Len = NormalizeString(NormForm, Source, -1, NULL, 0); int Len = NormalizeString(NormForm, Source, -1, NULL, 0);
for (;;) for (;;)
{ {
WCHAR *Str = Alloc(sizeof(WCHAR) * Len); LPWSTR Str = AllocArray(Len, sizeof(*Str));
if (!Str) if (!Str)
return NULL; return NULL;
Len = NormalizeString(NormForm, Source, -1, Str, Len); Len = NormalizeString(NormForm, Source, -1, Str, Len);
@ -41,7 +44,8 @@ static _Return_type_success_(
} }
} }
static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void) static _Return_type_success_(return != FALSE)
BOOL NamespaceRuntimeInit(VOID)
{ {
DWORD LastError; DWORD LastError;
@ -110,8 +114,9 @@ cleanupLeaveCriticalSection:
return FALSE; return FALSE;
} }
_Check_return_ _Use_decl_annotations_
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool) HANDLE
NamespaceTakePoolMutex(LPCWSTR Pool)
{ {
if (!NamespaceRuntimeInit()) if (!NamespaceRuntimeInit())
return NULL; return NULL;
@ -133,7 +138,7 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const
LastError = RtlNtStatusToDosError(Status); LastError = RtlNtStatusToDosError(Status);
goto cleanupSha256; goto cleanupSha256;
} }
WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool); LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
if (!PoolNorm) if (!PoolNorm)
{ {
LastError = GetLastError(); LastError = GetLastError();
@ -184,8 +189,9 @@ cleanupSha256:
return NULL; return NULL;
} }
_Check_return_ _Use_decl_annotations_
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void) HANDLE
NamespaceTakeDriverInstallationMutex(VOID)
{ {
if (!NamespaceRuntimeInit()) if (!NamespaceRuntimeInit())
return NULL; return NULL;
@ -208,21 +214,20 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMute
return NULL; return NULL;
} }
void _Use_decl_annotations_
NamespaceReleaseMutex(_In_ HANDLE Mutex) VOID
NamespaceReleaseMutex(HANDLE Mutex)
{ {
ReleaseMutex(Mutex); ReleaseMutex(Mutex);
CloseHandle(Mutex); CloseHandle(Mutex);
} }
void VOID NamespaceInit(VOID)
NamespaceInit(void)
{ {
InitializeCriticalSection(&Initializing); InitializeCriticalSection(&Initializing);
} }
void VOID NamespaceDone(VOID)
NamespaceDone(void)
{ {
EnterCriticalSection(&Initializing); EnterCriticalSection(&Initializing);
if (PrivateNamespace) if (PrivateNamespace)

View File

@ -7,17 +7,24 @@
#include <Windows.h> #include <Windows.h>
_Check_return_ _Must_inspect_result_
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool); _Return_type_success_(return != NULL)
_Post_maybenull_
_Acquires_lock_(_Curr_)
HANDLE
NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool);
_Check_return_ _Must_inspect_result_
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void); _Return_type_success_(return != NULL)
_Post_maybenull_
_Acquires_lock_(_Curr_)
HANDLE
NamespaceTakeDriverInstallationMutex(VOID);
void _Releases_lock_(Mutex)
VOID
NamespaceReleaseMutex(_In_ HANDLE Mutex); NamespaceReleaseMutex(_In_ HANDLE Mutex);
void VOID NamespaceInit(VOID);
NamespaceInit(void);
void VOID NamespaceDone(VOID);
NamespaceDone(void);

View File

@ -9,19 +9,23 @@
#ifdef GENERATE_LIB #ifdef GENERATE_LIB
# define DECLSPEC __declspec(dllexport) # define DECLSPEC __declspec(dllexport)
# define STUB { return 0; } # define STUB \
{ \
return 0; \
}
#else #else
# define DECLSPEC __declspec(dllimport) # define DECLSPEC __declspec(dllimport)
# define STUB ; # define STUB ;
#endif #endif
EXTERN_C
DECLSPEC DWORD WINAPI
NciSetConnectionName(_In_ const GUID *Guid, _In_z_ LPCWSTR NewName) STUB
EXTERN_C DECLSPEC DWORD WINAPI EXTERN_C
NciSetConnectionName(_In_ const GUID *Guid, _In_z_ const WCHAR *NewName) STUB DECLSPEC DWORD WINAPI
EXTERN_C DECLSPEC DWORD WINAPI
NciGetConnectionName( NciGetConnectionName(
_In_ const GUID *Guid, _In_ const GUID *Guid,
_Out_z_bytecap_(InDestNameBytes) WCHAR *Name, _Out_z_bytecap_(InDestNameBytes) LPWSTR Name,
_In_ DWORD InDestNameBytes, _In_ DWORD InDestNameBytes,
_Out_opt_ DWORD *OutDestNameBytes) STUB _Out_opt_ DWORD *OutDestNameBytes) STUB

View File

@ -45,7 +45,7 @@ typedef struct _KEY_NAME_INFORMATION
* when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers. * when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.
* *
* Another way would be reading from the PEB directly: * Another way would be reading from the PEB directly:
* ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41] * ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(VOID *) == 8 ? 70 : 41]
* Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit: * Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
* *(DWORD *)0x7FFE026C * *(DWORD *)0x7FFE026C
*/ */
@ -61,9 +61,3 @@ NtQueryKey(
_Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation, _Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation,
_In_ ULONG Length, _In_ ULONG Length,
_Out_ PULONG ResultLength); _Out_ PULONG ResultLength);
/* This is documented in NTSecAPI.h, which we can't include, due to header conflicts. It actually lives in advapi32.dll. */
#define RtlGenRandom SystemFunction036
BOOLEAN
NTAPI
RtlGenRandom(_Out_writes_bytes_all_(RandomBufferLength) PVOID RandomBuffer, _In_ ULONG RandomBufferLength);

View File

@ -10,11 +10,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <strsafe.h> #include <strsafe.h>
static _Return_type_success_(return != NULL) HKEY _Must_inspect_result_
OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) static _Return_type_success_(return != NULL)
_Post_maybenull_
HKEY
OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline)
{ {
DWORD LastError; DWORD LastError;
WCHAR *PathNext = wcschr(Path, L'\\'); LPWSTR PathNext = wcschr(Path, L'\\');
if (PathNext) if (PathNext)
*PathNext = 0; *PathNext = 0;
@ -87,8 +90,9 @@ static _Return_type_success_(return != NULL) HKEY
return NULL; return NULL;
} }
_Return_type_success_(return != NULL) HKEY _Use_decl_annotations_
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout) HKEY
RegistryOpenKeyWait(HKEY Key, LPCWSTR Path, DWORD Access, DWORD Timeout)
{ {
WCHAR Buf[MAX_REG_PATH]; WCHAR Buf[MAX_REG_PATH];
if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE) if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE)
@ -100,17 +104,17 @@ _Return_type_success_(return != NULL) HKEY
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout); return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout);
} }
_Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) _Use_decl_annotations_
BOOL
RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType)
{ {
if (wcsnlen(*Buf, Len) >= Len) if (wcsnlen(*Buf, Len) >= Len)
{ {
/* String is missing zero-terminator. */ /* String is missing zero-terminator. */
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR)); LPWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
if (!BufZ) if (!BufZ)
return FALSE; return FALSE;
wmemcpy(BufZ, *Buf, Len); _Analysis_assume_((wmemset(BufZ, L'A', (SIZE_T)Len + 1), TRUE));
BufZ[Len] = 0;
Free(*Buf);
*Buf = BufZ; *Buf = BufZ;
} }
@ -122,10 +126,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu
if (!(*Buf)[0]) if (!(*Buf)[0])
return TRUE; return TRUE;
Len = Len * 2 + 64;
for (;;) for (;;)
{ {
WCHAR *Expanded = Alloc(Len * sizeof(WCHAR)); LPWSTR Expanded = AllocArray(Len, sizeof(*Expanded));
if (!Expanded) if (!Expanded)
return FALSE; return FALSE;
DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len); DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
@ -147,8 +150,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu
} }
} }
_Return_type_success_(return != FALSE) BOOL _Use_decl_annotations_
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) BOOL
RegistryGetMultiString(PZZWSTR *Buf, DWORD Len, DWORD ValueType)
{ {
if (ValueType == REG_MULTI_SZ) if (ValueType == REG_MULTI_SZ)
{ {
@ -157,25 +161,18 @@ _Return_type_success_(return != FALSE) BOOL
if (i > Len) if (i > Len)
{ {
/* Missing string and list terminators. */ /* Missing string and list terminators. */
WCHAR *BufZ = Alloc(((size_t)Len + 2) * sizeof(WCHAR)); PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 2, sizeof(*BufZ));
if (!BufZ) if (!BufZ)
return FALSE; return FALSE;
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
BufZ[Len + 1] = 0;
Free(*Buf);
*Buf = BufZ; *Buf = BufZ;
return TRUE; return TRUE;
} }
if (i == Len) if (i == Len)
{ {
/* Missing list terminator. */ /* Missing list terminator. */
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR)); PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
if (!BufZ) if (!BufZ)
return FALSE; return FALSE;
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
Free(*Buf);
*Buf = BufZ; *Buf = BufZ;
return TRUE; return TRUE;
} }
@ -188,22 +185,19 @@ _Return_type_success_(return != FALSE) BOOL
if (!RegistryGetString(Buf, Len, ValueType)) if (!RegistryGetString(Buf, Len, ValueType))
return FALSE; return FALSE;
Len = (DWORD)wcslen(*Buf) + 1; Len = (DWORD)wcslen(*Buf) + 1;
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR)); PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(WCHAR));
if (!BufZ) if (!BufZ)
return FALSE; return FALSE;
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
Free(*Buf);
*Buf = BufZ; *Buf = BufZ;
return TRUE; return TRUE;
} }
static _Return_type_success_(return != NULL) void *RegistryQuery( _Must_inspect_result_
_In_ HKEY Key, static _Return_type_success_(return != NULL)
_In_opt_z_ const WCHAR *Name, _Post_maybenull_
_Out_opt_ DWORD *ValueType, _Post_writable_byte_size_(*BufLen)
_Inout_ DWORD *BufLen, VOID *
_In_ BOOL Log) RegistryQuery(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_opt_ DWORD *ValueType, _Inout_ DWORD *BufLen, _In_ BOOL Log)
{ {
for (;;) for (;;)
{ {
@ -220,7 +214,7 @@ static _Return_type_success_(return != NULL) void *RegistryQuery(
{ {
WCHAR RegPath[MAX_REG_PATH]; WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath); LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name); LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
} }
SetLastError(LastError); SetLastError(LastError);
return NULL; return NULL;
@ -228,11 +222,12 @@ static _Return_type_success_(return != NULL) void *RegistryQuery(
} }
} }
_Return_type_success_( _Use_decl_annotations_
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log) LPWSTR
RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log)
{ {
DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR);
WCHAR *Value = RegistryQuery(Key, Name, &ValueType, &Size, Log); LPWSTR Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
if (!Value) if (!Value)
return NULL; return NULL;
switch (ValueType) switch (ValueType)
@ -240,7 +235,7 @@ _Return_type_success_(
case REG_SZ: case REG_SZ:
case REG_EXPAND_SZ: case REG_EXPAND_SZ:
case REG_MULTI_SZ: case REG_MULTI_SZ:
if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType)) if (RegistryGetString(&Value, Size / sizeof(*Value), ValueType))
return Value; return Value;
LastError = GetLastError(); LastError = GetLastError();
break; break;
@ -261,8 +256,9 @@ _Return_type_success_(
return NULL; return NULL;
} }
_Return_type_success_( _Use_decl_annotations_
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout) LPWSTR
RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout)
{ {
DWORD LastError; DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout; ULONGLONG Deadline = GetTickCount64() + Timeout;
@ -282,7 +278,7 @@ _Return_type_success_(
LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath);
break; break;
} }
WCHAR *Value = RegistryQueryString(Key, Name, FALSE); LPWSTR Value = RegistryQueryString(Key, Name, FALSE);
if (Value) if (Value)
{ {
CloseHandle(Event); CloseHandle(Event);
@ -313,8 +309,9 @@ _Return_type_success_(
return NULL; return NULL;
} }
_Return_type_success_(return != FALSE) BOOL _Use_decl_annotations_
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log) BOOL
RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log)
{ {
DWORD ValueType, Size = sizeof(DWORD); DWORD ValueType, Size = sizeof(DWORD);
DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size); DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
@ -324,7 +321,7 @@ _Return_type_success_(return != FALSE) BOOL
{ {
WCHAR RegPath[MAX_REG_PATH]; WCHAR RegPath[MAX_REG_PATH];
LoggerGetRegistryKeyPath(Key, RegPath); LoggerGetRegistryKeyPath(Key, RegPath);
LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name); LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
} }
SetLastError(LastError); SetLastError(LastError);
return FALSE; return FALSE;
@ -348,8 +345,9 @@ _Return_type_success_(return != FALSE) BOOL
return TRUE; return TRUE;
} }
_Return_type_success_(return != FALSE) BOOL _Use_decl_annotations_
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value) BOOL
RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value)
{ {
DWORD LastError; DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout; ULONGLONG Deadline = GetTickCount64() + Timeout;
@ -398,73 +396,3 @@ _Return_type_success_(return != FALSE) BOOL
SetLastError(LastError); SetLastError(LastError);
return FALSE; return FALSE;
} }
_Return_type_success_(return != FALSE) static BOOL
DeleteNodeRecurse(_In_ HKEY Key, _In_z_ WCHAR *Name)
{
LSTATUS Ret;
DWORD Size;
SIZE_T Len;
WCHAR SubName[MAX_REG_PATH], *End;
HKEY SubKey;
Len = wcslen(Name);
if (Len >= MAX_REG_PATH || !Len)
return TRUE;
if (RegDeleteKeyW(Key, Name) == ERROR_SUCCESS)
return TRUE;
Ret = RegOpenKeyEx(Key, Name, 0, KEY_READ, &SubKey);
if (Ret != ERROR_SUCCESS)
{
if (Ret == ERROR_FILE_NOT_FOUND)
return TRUE;
SetLastError(Ret);
return FALSE;
}
End = Name + Len;
if (End[-1] != L'\\')
{
*(End++) = L'\\';
*End = L'\0';
}
Size = MAX_REG_PATH;
Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL);
if (Ret == ERROR_SUCCESS)
{
do
{
End[0] = L'\0';
StringCchCatW(Name, MAX_REG_PATH * 2, SubName);
if (!DeleteNodeRecurse(Key, Name))
break;
Size = MAX_REG_PATH;
Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL);
} while (Ret == ERROR_SUCCESS);
}
else
{
SetLastError(Ret);
*(--End) = L'\0';
RegCloseKey(SubKey);
return FALSE;
}
*(--End) = L'\0';
RegCloseKey(SubKey);
Ret = RegDeleteKey(Key, Name);
if (Ret == ERROR_SUCCESS)
return TRUE;
SetLastError(Ret);
return FALSE;
}
_Return_type_success_(return != FALSE) BOOL
RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name)
{
WCHAR NameBuf[(MAX_REG_PATH + 2) * 2] = { 0 };
StringCchCopyW(NameBuf, MAX_REG_PATH * 2, Name);
return DeleteNodeRecurse(Key, NameBuf);
}

View File

@ -26,8 +26,11 @@
* @return Key handle on success. If the function fails, the return value is zero. To get extended error information, * @return Key handle on success. If the function fails, the return value is zero. To get extended error information,
* call GetLastError. * call GetLastError.
*/ */
_Return_type_success_(return != NULL) HKEY _Must_inspect_result_
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout); _Return_type_success_(return != NULL)
_Post_maybenull_
HKEY
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ LPCWSTR Path, _In_ DWORD Access, _In_ DWORD Timeout);
/** /**
* Validates and/or sanitizes string value read from registry. * Validates and/or sanitizes string value read from registry.
@ -44,8 +47,10 @@ _Return_type_success_(return != NULL) HKEY
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
_Return_type_success_(return != FALSE) BOOL _Must_inspect_result_
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); _Return_type_success_(return != FALSE)
BOOL
RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
/** /**
* Validates and/or sanitizes multi-string value read from registry. * Validates and/or sanitizes multi-string value read from registry.
@ -61,8 +66,10 @@ _Return_type_success_(return != FALSE) BOOL
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
_Return_type_success_(return != FALSE) BOOL _Must_inspect_result_
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); _Return_type_success_(return != FALSE)
BOOL
RegistryGetMultiString(_Inout_ PZZWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
/** /**
* Reads string value from registry key. * Reads string value from registry key.
@ -83,8 +90,11 @@ _Return_type_success_(return != FALSE) BOOL
* @return String with registry value on success; If the function fails, the return value is zero. To get extended error * @return String with registry value on success; If the function fails, the return value is zero. To get extended error
* information, call GetLastError. * information, call GetLastError.
*/ */
_Return_type_success_( _Must_inspect_result_
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log); _Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ BOOL Log);
/** /**
* Reads string value from registry key. It waits for the registry value to become available. * Reads string value from registry key. It waits for the registry value to become available.
@ -101,8 +111,11 @@ _Return_type_success_(
* get extended error information, call GetLastError. Possible errors include the following: * get extended error information, call GetLastError. Possible errors include the following:
* ERROR_INVALID_DATATYPE when the registry value is not a string * ERROR_INVALID_DATATYPE when the registry value is not a string
*/ */
_Return_type_success_( _Must_inspect_result_
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout); _Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout);
/** /**
* Reads a 32-bit DWORD value from registry key. * Reads a 32-bit DWORD value from registry key.
@ -120,8 +133,10 @@ _Return_type_success_(
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
_Return_type_success_(return != FALSE) BOOL _Must_inspect_result_
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log); _Return_type_success_(return != FALSE)
BOOL
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log);
/** /**
* Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available. * Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available.
@ -139,17 +154,7 @@ _Return_type_success_(return != FALSE) BOOL
* ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type; * ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
* ERROR_INVALID_DATA when registry value size is not 4 bytes * ERROR_INVALID_DATA when registry value size is not 4 bytes
*/ */
_Return_type_success_(return != FALSE) BOOL _Must_inspect_result_
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value); _Return_type_success_(return != FALSE)
BOOL
/** RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
* Deletes the entire registry key subtree recursively.
*
* @param Key Handle of the registry key to at which the subtree is rooted.
*
* @param Name Name of the subtree to delete.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE) BOOL RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name);

View File

@ -7,9 +7,12 @@
#include "main.h" #include "main.h"
#include "resource.h" #include "resource.h"
#include <Windows.h> #include <Windows.h>
#include <Shlwapi.h>
#include <NTSecAPI.h>
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const _Use_decl_annotations_
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size) const VOID *
ResourceGetAddress(LPCWSTR ResourceName, DWORD *Size)
{ {
HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA); HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA);
if (!FoundResource) if (!FoundResource)
@ -39,11 +42,12 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
return Address; return Address;
} }
_Return_type_success_(return != FALSE) BOOL _Use_decl_annotations_
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName) BOOL
ResourceCopyToFile(LPCWSTR DestinationPath, LPCWSTR ResourceName)
{ {
DWORD SizeResource; DWORD SizeResource;
const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource); const VOID *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
if (!LockedResource) if (!LockedResource)
{ {
LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", ResourceName); LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", ResourceName);
@ -84,3 +88,42 @@ cleanupDestinationHandle:
CloseHandle(DestinationHandle); CloseHandle(DestinationHandle);
return RET_ERROR(TRUE, LastError); return RET_ERROR(TRUE, LastError);
} }
_Return_type_success_(return != FALSE)
BOOL
ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory)
{
WCHAR WindowsDirectory[MAX_PATH];
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
{
LOG_LAST_ERROR(L"Failed to get Windows folder");
return FALSE;
}
WCHAR WindowsTempDirectory[MAX_PATH];
if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp"))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
UCHAR RandomBytes[32] = { 0 };
if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
{
LOG(WINTUN_LOG_ERR, L"Failed to generate random");
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
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))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
if (!CreateDirectoryW(RandomTempSubDirectory, &SecurityAttributes))
{
LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory);
return FALSE;
}
return TRUE;
}

View File

@ -11,25 +11,40 @@
/** /**
* Locates RT_RCDATA resource memory address and size. * Locates RT_RCDATA resource memory address and size.
* *
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. * @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
* *
* Size Pointer to a variable to receive resource size. * @param Size Pointer to a variable to receive resource size.
* *
* @return Resource address on success. If the function fails, the return value is NULL. To get extended error * @return Resource address on success. If the function fails, the return value is NULL. To get extended error
* information, call GetLastError. * information, call GetLastError.
*/ */
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const _Must_inspect_result_
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size); _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_readable_byte_size_(*Size) const VOID *ResourceGetAddress(_In_z_ LPCWSTR ResourceName, _Out_ DWORD *Size);
/** /**
* Copies resource to a file. * Copies resource to a file.
* *
* DestinationPath File path * @param DestinationPath File path
* *
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. * @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
* *
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
_Return_type_success_(return != FALSE) BOOL _Return_type_success_(return != FALSE)
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName); BOOL
ResourceCopyToFile(_In_z_ LPCWSTR DestinationPath, _In_z_ LPCWSTR ResourceName);
/**
* Creates a temporary directory.
*
* @param RandomTempSubDirectory Name of random temporary directory.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
_Return_type_success_(return != FALSE)
BOOL
ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory);

View File

@ -3,12 +3,14 @@
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/ */
#include "rundll32.h"
#include "adapter.h" #include "adapter.h"
#include "main.h"
#include "logger.h" #include "logger.h"
#include "wintun.h" #include "resource.h"
#include <Windows.h> #include <Windows.h>
#include <shellapi.h> #include <shellapi.h>
#include <Shlwapi.h>
#include <cfgmgr32.h> #include <cfgmgr32.h>
#include <objbase.h> #include <objbase.h>
#include <assert.h> #include <assert.h>
@ -18,10 +20,10 @@
# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) # define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
static DWORD static DWORD
WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...)
{ {
WCHAR *FormattedMessage = NULL; LPWSTR FormattedMessage = NULL;
DWORD SizeWritten; DWORD Size;
va_list Arguments; va_list Arguments;
va_start(Arguments, Template); va_start(Arguments, Template);
DWORD Len = FormatMessageW( DWORD Len = FormatMessageW(
@ -29,19 +31,22 @@ WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...)
Template, Template,
0, 0,
0, 0,
(void *)&FormattedMessage, (VOID *)&FormattedMessage,
0, 0,
&Arguments); &Arguments);
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Len * sizeof(WCHAR), &SizeWritten, NULL); if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size)))
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL);
else
Size = 0;
LocalFree(FormattedMessage); LocalFree(FormattedMessage);
va_end(Arguments); va_end(Arguments);
return SizeWritten / sizeof(WCHAR); return Size / sizeof(*FormattedMessage);
} }
static void CALLBACK static VOID CALLBACK
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
{ {
const WCHAR *Template; LPCWSTR Template;
switch (Level) switch (Level)
{ {
case WINTUN_LOG_INFO: case WINTUN_LOG_INFO:
@ -59,29 +64,14 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
WriteFormatted(STD_ERROR_HANDLE, Template, LogLine); WriteFormatted(STD_ERROR_HANDLE, Template, LogLine);
} }
static int Argc;
static WCHAR **Argv;
static void
Init(void)
{
WintunSetLogger(ConsoleLogger);
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
}
static void
Done(void)
{
LocalFree(Argv);
}
# pragma warning(disable : 4100) /* unreferenced formal parameter */
VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{ {
# pragma EXPORT # pragma EXPORT
Init(); int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 4) if (Argc < 4)
goto cleanup; goto cleanup;
if (wcslen(Argv[2]) >= WINTUN_MAX_POOL) if (wcslen(Argv[2]) >= WINTUN_MAX_POOL)
@ -95,47 +85,52 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int
BOOL RebootRequired; BOOL RebootRequired;
WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired); WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired);
DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError(); DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError();
WCHAR GuidStr[MAX_GUID_STRING_LEN];
WriteFormatted( WriteFormatted(
STD_OUTPUT_HANDLE, STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"", RebootRequired);
L"%1!X! %2!.*s! %3!X!",
LastError,
StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)),
GuidStr,
RebootRequired);
if (Adapter) if (Adapter)
WintunFreeAdapter(Adapter); WintunFreeAdapter(Adapter);
cleanup: cleanup:
Done(); LocalFree(Argv);
} }
VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{ {
# pragma EXPORT # pragma EXPORT
Init(); int Argc;
if (Argc < 3) LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 4)
goto cleanup; goto cleanup;
WINTUN_ADAPTER Adapter = { 0 }; DWORD LastError;
BOOL ForceCloseSessions = wcstoul(Argv[2], NULL, 10); BOOL RebootRequired = FALSE;
if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID))) WINTUN_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]);
goto cleanup; if (!Adapter)
BOOL RebootRequired; {
DWORD LastError = LastError = GetLastError();
WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); goto write;
}
BOOL ForceCloseSessions = wcstoul(Argv[4], NULL, 10);
LastError = WintunDeleteAdapter(Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError();
WintunFreeAdapter(Adapter);
write:
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
cleanup: cleanup:
Done(); LocalFree(Argv);
} }
VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{ {
# pragma EXPORT # pragma EXPORT
Init(); int Argc;
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
WintunSetLogger(ConsoleLogger);
if (Argc < 2) if (Argc < 2)
goto cleanup; goto cleanup;
@ -144,6 +139,455 @@ VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, i
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
cleanup: cleanup:
Done(); LocalFree(Argv);
}
#endif
#ifdef MAYBE_WOW64
_Return_type_success_(return != FALSE)
static BOOL
AppendToBuffer(_Inout_ LPWSTR *Buffer, _In_ CONST WCHAR Addition, _Inout_ SIZE_T *BufferPos, _Inout_ SIZE_T *BufferLen)
{
SIZE_T NewPos;
if (FAILED(SIZETAdd(*BufferPos, sizeof(Addition), &NewPos)))
return FALSE;
if (NewPos >= *BufferLen)
{
SIZE_T NewLen;
if (FAILED(SIZETMult(NewPos, 3, &NewLen)))
return FALSE;
LPWSTR NewBuffer = ReZalloc(*Buffer, NewLen);
if (!NewBuffer)
return FALSE;
*Buffer = NewBuffer;
*BufferLen = NewLen;
}
SIZE_T NewIndex = *BufferPos / sizeof(**Buffer);
if (*Buffer + NewIndex < *Buffer)
return FALSE;
(*Buffer)[NewIndex] = Addition;
*BufferPos = NewPos;
return TRUE;
}
_Must_inspect_result_
static _Return_type_success_(return != NULL)
_Post_maybenull_
LPWSTR
ArgvToCommandLineW(_In_ SIZE_T ArgCount, ...)
{
LPWSTR Output = NULL;
SIZE_T BufferPos = 0, BufferLen = 0;
# define Append(Char) \
do \
{ \
if (!AppendToBuffer(&Output, Char, &BufferPos, &BufferLen)) \
goto cleanupBuffer; \
} while (0)
va_list Args;
va_start(Args, ArgCount);
for (SIZE_T i = 0; i < ArgCount; ++i)
{
LPCWSTR Arg = va_arg(Args, LPCWSTR);
SIZE_T ArgLen = wcslen(Arg);
if (ArgLen >= DWORD_MAX >> 3)
goto cleanupBuffer;
if (i)
Append(L' ');
Append(L'"');
for (SIZE_T j = 0;; ++j)
{
SIZE_T NumberBackslashes = 0;
while (j < ArgLen && Arg[j] == L'\\')
{
++j;
++NumberBackslashes;
}
if (j >= ArgLen)
{
for (SIZE_T k = 0; k < NumberBackslashes * 2; ++k)
Append(L'\\');
break;
}
else if (Arg[j] == L'"')
{
for (SIZE_T k = 0; k < NumberBackslashes * 2 + 1; ++k)
Append(L'\\');
Append(Arg[j]);
}
else
{
for (SIZE_T k = 0; k < NumberBackslashes; ++k)
Append(L'\\');
Append(Arg[j]);
}
}
Append(L'"');
}
va_end(Args);
return Output;
cleanupBuffer:
Free(Output);
return NULL;
# undef Append
}
typedef struct _PROCESS_STDOUT_STATE
{
HANDLE Stdout;
LPWSTR Response;
DWORD ResponseCapacity;
} PROCESS_STDOUT_STATE;
_Return_type_success_(return != ERROR_SUCCESS)
static DWORD WINAPI
ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
{
for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;)
{
DWORD Size;
if (FAILED(DWordMult(MaxLen - Offset, sizeof(WCHAR), &Size)))
return ERROR_BUFFER_OVERFLOW;
if (!ReadFile(State->Stdout, State->Response + Offset, Size, &Size, NULL))
return ERROR_SUCCESS;
if (Size % sizeof(WCHAR))
return ERROR_INVALID_DATA;
Offset += Size / sizeof(WCHAR);
State->Response[Offset] = 0;
}
return ERROR_BUFFER_OVERFLOW;
}
static DWORD WINAPI
ProcessStderr(_In_ HANDLE Stderr)
{
enum
{
OnNone,
OnLevelStart,
OnLevel,
OnLevelEnd,
OnSpace,
OnMsg
} State = OnNone;
WCHAR Msg[0x200];
DWORD Count = 0;
WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO;
for (;;)
{
WCHAR Buf[0x200];
DWORD SizeRead;
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL))
return ERROR_SUCCESS;
if (SizeRead % sizeof(*Buf))
return ERROR_INVALID_DATA;
SizeRead /= sizeof(*Buf);
for (DWORD i = 0; i < SizeRead; ++i)
{
WCHAR c = Buf[i];
if (State == OnNone && c == L'[')
State = OnLevelStart;
else if (
State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') ||
(Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!')))
State = OnLevelEnd;
else if (State == OnLevelEnd && c == L']')
State = OnSpace;
else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n')
{
if (Count < _countof(Msg) - 1)
Msg[Count++] = c;
State = OnMsg;
}
else if (State == OnMsg && c == L'\n')
{
Msg[Count] = 0;
LoggerLog(Level, NULL, Msg);
State = OnNone;
Count = 0;
}
}
}
}
static _Return_type_success_(return != FALSE)
BOOL
ExecuteRunDll32(
_In_z_ LPCWSTR Function,
_In_z_ LPCWSTR Arguments,
_Out_z_cap_c_(ResponseCapacity) LPWSTR Response,
_In_ DWORD ResponseCapacity)
{
WCHAR WindowsDirectory[MAX_PATH];
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
{
LOG_LAST_ERROR(L"Failed to get Windows folder");
return FALSE;
}
WCHAR RunDll32Path[MAX_PATH];
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
DWORD LastError;
WCHAR RandomTempSubDirectory[MAX_PATH];
if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory))
{
LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder");
return FALSE;
}
WCHAR DllPath[MAX_PATH] = { 0 };
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
{
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDirectory;
}
LPCWSTR WintunDllResourceName;
switch (NativeMachine)
{
case IMAGE_FILE_MACHINE_AMD64:
WintunDllResourceName = L"wintun-amd64.dll";
break;
case IMAGE_FILE_MACHINE_ARM64:
WintunDllResourceName = L"wintun-arm64.dll";
break;
default:
LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
LastError = ERROR_NOT_SUPPORTED;
goto cleanupDirectory;
}
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
{
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath);
goto cleanupDelete;
}
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1 + wcslen(Function) + 1;
LPWSTR CommandLine = AllocArray(CommandLineLen, sizeof(*CommandLine));
if (!CommandLine)
{
LastError = GetLastError();
goto cleanupDelete;
}
if (_snwprintf_s(
CommandLine,
CommandLineLen,
_TRUNCATE,
L"rundll32 \"%.*s\",%s %s",
MAX_PATH,
DllPath,
Function,
Arguments) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
LastError = ERROR_INVALID_PARAMETER;
goto cleanupDelete;
}
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE;
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
{
LastError = LOG_LAST_ERROR(L"Failed to create pipes");
goto cleanupPipes;
}
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
goto cleanupPipes;
}
if (ResponseCapacity)
Response[0] = 0;
PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout,
.Response = Response,
.ResponseCapacity = ResponseCapacity };
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
{
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
goto cleanupThreads;
}
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
.wShowWindow = SW_HIDE,
.hStdOutput = StreamWStdout,
.hStdError = StreamWStderr };
PROCESS_INFORMATION pi;
if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine);
goto cleanupThreads;
}
LastError = ERROR_SUCCESS;
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
cleanupThreads:
if (ThreadStderr)
{
CloseHandle(StreamWStderr);
StreamWStderr = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStderr, INFINITE);
CloseHandle(ThreadStderr);
}
if (ThreadStdout)
{
CloseHandle(StreamWStdout);
StreamWStdout = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStdout, INFINITE);
DWORD ThreadResult;
if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
else if (ThreadResult != ERROR_SUCCESS)
LOG_ERROR(LastError, L"Failed to read process output");
CloseHandle(ThreadStdout);
}
cleanupPipes:
CloseHandle(StreamRStderr);
CloseHandle(StreamWStderr);
CloseHandle(StreamRStdout);
CloseHandle(StreamWStdout);
Free(CommandLine);
cleanupDelete:
DeleteFileW(DllPath);
cleanupDirectory:
RemoveDirectoryW(RandomTempSubDirectory);
return RET_ERROR(TRUE, LastError);
}
_Use_decl_annotations_
WINTUN_ADAPTER *
CreateAdapterViaRundll32(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
LPWSTR Arguments = NULL;
if (RequestedGUID)
{
WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN];
if (StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)))
Arguments = ArgvToCommandLineW(3, Pool, Name, RequestedGUIDStr);
}
else
Arguments = ArgvToCommandLineW(2, Pool, Name);
if (!Arguments)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
WINTUN_ADAPTER *Adapter = NULL;
DWORD LastError;
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
if (!ExecuteRunDll32(L"CreateAdapter", Arguments, Response, _countof(Response)))
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 3)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (LastError == ERROR_SUCCESS && (Adapter = AdapterOpenFromDevInstanceId(Pool, Argv[1])) == NULL)
{
LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]);
LastError = ERROR_FILE_NOT_FOUND;
}
if (wcstoul(Argv[2], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
Free(Arguments);
SetLastError(LastError);
return Adapter;
}
_Use_decl_annotations_
BOOL
DeleteAdapterViaRundll32(const WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
LPWSTR Arguments = ArgvToCommandLineW(3, Adapter->Pool, Adapter->DevInstanceID, ForceCloseSessions ? L"1" : L"0");
if (!Arguments)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(L"DeleteAdapter", Arguments, Response, _countof(Response)))
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
Free(Arguments);
return RET_ERROR(TRUE, LastError);
}
_Use_decl_annotations_
BOOL
DeletePoolDriverViaRundll32(LPCWSTR Pool, BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
LPWSTR Arguments = ArgvToCommandLineW(1, Pool);
if (!Arguments)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response)))
{
LastError = GetLastError();
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
goto cleanupArguments;
}
int Argc;
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
cleanupArguments:
Free(Arguments);
return RET_ERROR(TRUE, LastError);
} }
#endif #endif

29
api/rundll32.h Normal file
View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#pragma once
#include "adapter.h"
_Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_ADAPTER *
CreateAdapterViaRundll32(
_In_z_ LPCWSTR Pool,
_In_z_ LPCWSTR Name,
_In_opt_ const GUID *RequestedGUID,
_Inout_ BOOL *RebootRequired);
_Return_type_success_(return != FALSE)
BOOL
DeleteAdapterViaRundll32(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions,
_Inout_ BOOL *RebootRequired);
_Return_type_success_(return != FALSE)
BOOL
DeletePoolDriverViaRundll32(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired);

View File

@ -1,352 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
/* TODO: This is currently #include'd in adapter.c. Move into rundll32.c properly. */
typedef struct _PROCESS_STDOUT_STATE
{
HANDLE Stdout;
WCHAR *Response;
DWORD ResponseCapacity;
} PROCESS_STDOUT_STATE;
static DWORD WINAPI
ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
{
for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;)
{
DWORD SizeRead;
if (!ReadFile(State->Stdout, State->Response + Offset, sizeof(WCHAR) * (MaxLen - Offset), &SizeRead, NULL))
return ERROR_SUCCESS;
if (SizeRead % sizeof(WCHAR))
return ERROR_INVALID_DATA;
Offset += SizeRead / sizeof(WCHAR);
State->Response[Offset] = 0;
}
return ERROR_BUFFER_OVERFLOW;
}
static DWORD WINAPI
ProcessStderr(_In_ HANDLE Stderr)
{
enum
{
OnNone,
OnLevelStart,
OnLevel,
OnLevelEnd,
OnSpace,
OnMsg
} State = OnNone;
WCHAR Msg[0x200];
DWORD Count = 0;
WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO;
for (;;)
{
WCHAR Buf[0x200];
DWORD SizeRead;
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL))
return ERROR_SUCCESS;
if (SizeRead % sizeof(WCHAR))
return ERROR_INVALID_DATA;
SizeRead /= sizeof(WCHAR);
for (DWORD i = 0; i < SizeRead; ++i)
{
WCHAR c = Buf[i];
if (State == OnNone && c == L'[')
State = OnLevelStart;
else if (
State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') ||
(Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!')))
State = OnLevelEnd;
else if (State == OnLevelEnd && c == L']')
State = OnSpace;
else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n')
{
if (Count < _countof(Msg) - 1)
Msg[Count++] = c;
State = OnMsg;
}
else if (State == OnMsg && c == L'\n')
{
Msg[Count] = 0;
LoggerLog(Level, NULL, Msg);
State = OnNone;
Count = 0;
}
}
}
}
static _Return_type_success_(return != FALSE) BOOL ExecuteRunDll32(
_In_z_ const WCHAR *Arguments,
_Out_z_cap_c_(ResponseCapacity) WCHAR *Response,
_In_ DWORD ResponseCapacity)
{
WCHAR WindowsDirectory[MAX_PATH];
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
{
LOG_LAST_ERROR(L"Failed to get Windows folder");
return FALSE;
}
WCHAR RunDll32Path[MAX_PATH];
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
DWORD LastError;
WCHAR RandomTempSubDirectory[MAX_PATH];
if (!CreateTemporaryDirectory(RandomTempSubDirectory))
{
LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder %s", RandomTempSubDirectory);
return FALSE;
}
WCHAR DllPath[MAX_PATH] = { 0 };
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
{
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDirectory;
}
const WCHAR *WintunDllResourceName;
switch (NativeMachine)
{
case IMAGE_FILE_MACHINE_AMD64:
WintunDllResourceName = L"wintun-amd64.dll";
break;
case IMAGE_FILE_MACHINE_ARM64:
WintunDllResourceName = L"wintun-arm64.dll";
break;
default:
LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
LastError = ERROR_NOT_SUPPORTED;
goto cleanupDirectory;
}
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
{
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath);
goto cleanupDelete;
}
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1;
WCHAR *CommandLine = Alloc(CommandLineLen * sizeof(WCHAR));
if (!CommandLine)
{
LastError = GetLastError();
goto cleanupDelete;
}
if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) ==
-1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
LastError = ERROR_INVALID_PARAMETER;
goto cleanupDelete;
}
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE;
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
{
LastError = LOG_LAST_ERROR(L"Failed to create pipes");
goto cleanupPipes;
}
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
goto cleanupPipes;
}
if (ResponseCapacity)
Response[0] = 0;
PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout,
.Response = Response,
.ResponseCapacity = ResponseCapacity };
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
{
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
goto cleanupThreads;
}
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
.wShowWindow = SW_HIDE,
.hStdOutput = StreamWStdout,
.hStdError = StreamWStderr };
PROCESS_INFORMATION pi;
if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine);
goto cleanupThreads;
}
LastError = ERROR_SUCCESS;
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
cleanupThreads:
if (ThreadStderr)
{
CloseHandle(StreamWStderr);
StreamWStderr = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStderr, INFINITE);
CloseHandle(ThreadStderr);
}
if (ThreadStdout)
{
CloseHandle(StreamWStdout);
StreamWStdout = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStdout, INFINITE);
DWORD ThreadResult;
if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
else if (ThreadResult != ERROR_SUCCESS)
LOG_ERROR(LastError, L"Failed to read process output");
CloseHandle(ThreadStdout);
}
cleanupPipes:
CloseHandle(StreamRStderr);
CloseHandle(StreamWStderr);
CloseHandle(StreamRStdout);
CloseHandle(StreamWStdout);
Free(CommandLine);
cleanupDelete:
DeleteFileW(DllPath);
cleanupDirectory:
RemoveDirectoryW(RandomTempSubDirectory);
return RET_ERROR(TRUE, LastError);
}
static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapterViaRundll32(
_In_z_ const WCHAR *Pool,
_In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID,
_Inout_ BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN];
WCHAR Arguments[15 + WINTUN_MAX_POOL + 3 + MAX_ADAPTER_NAME + 2 + MAX_GUID_STRING_LEN + 1];
if (_snwprintf_s(
Arguments,
_countof(Arguments),
_TRUNCATE,
RequestedGUID ? L"CreateAdapter \"%s\" \"%s\" %.*s" : L"CreateAdapter \"%s\" \"%s\"",
Pool,
Name,
RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0,
RequestedGUIDStr) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
return NULL;
}
DWORD LastError;
WINTUN_ADAPTER *Adapter = NULL;
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
GUID CfgInstanceID;
if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID)))
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (LastError == ERROR_SUCCESS && (Adapter = GetAdapter(Pool, &CfgInstanceID)) == NULL)
{
LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]);
LastError = ERROR_FILE_NOT_FOUND;
}
if (wcstoul(Argv[2], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
SetLastError(LastError);
return Adapter;
}
static _Return_type_success_(return != FALSE) BOOL DeleteAdapterViaRundll32(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions,
_Inout_ BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
WCHAR GuidStr[MAX_GUID_STRING_LEN];
WCHAR Arguments[16 + MAX_GUID_STRING_LEN + 1];
if (_snwprintf_s(
Arguments,
_countof(Arguments),
_TRUNCATE,
L"DeleteAdapter %d %.*s",
ForceCloseSessions ? 1 : 0,
StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)),
GuidStr) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
return FALSE;
}
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
return RET_ERROR(TRUE, LastError);
}
static _Return_type_success_(return != FALSE) BOOL
DeletePoolDriverViaRundll32(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
WCHAR Arguments[17 + WINTUN_MAX_POOL + 1];
if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1)
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD LastError;
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
return FALSE;
}
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
return RET_ERROR(TRUE, LastError);
}

View File

@ -70,8 +70,10 @@ typedef struct _TUN_SESSION
HANDLE Handle; HANDLE Handle;
} TUN_SESSION; } TUN_SESSION;
_Return_type_success_(return != NULL) TUN_SESSION *WINAPI WINTUN_START_SESSION_FUNC_IMPL WintunStartSession;
WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity) _Use_decl_annotations_
TUN_SESSION *WINAPI
WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity)
{ {
DWORD LastError; DWORD LastError;
TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION)); TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION));
@ -126,8 +128,8 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI
goto cleanupHandle; goto cleanupHandle;
} }
Session->Capacity = Capacity; Session->Capacity = Capacity;
(void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT); (VOID) InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
(void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT); (VOID) InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
return Session; return Session;
cleanupHandle: cleanupHandle:
CloseHandle(Session->Handle); CloseHandle(Session->Handle);
@ -144,8 +146,10 @@ cleanup:
return NULL; return NULL;
} }
void WINAPI WINTUN_END_SESSION_FUNC_IMPL WintunEndSession;
WintunEndSession(_In_ TUN_SESSION *Session) _Use_decl_annotations_
VOID WINAPI
WintunEndSession(TUN_SESSION *Session)
{ {
DeleteCriticalSection(&Session->Send.Lock); DeleteCriticalSection(&Session->Send.Lock);
DeleteCriticalSection(&Session->Receive.Lock); DeleteCriticalSection(&Session->Receive.Lock);
@ -156,14 +160,18 @@ WintunEndSession(_In_ TUN_SESSION *Session)
Free(Session); Free(Session);
} }
WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL WintunGetReadWaitEvent;
_Use_decl_annotations_
HANDLE WINAPI HANDLE WINAPI
WintunGetReadWaitEvent(_In_ TUN_SESSION *Session) WintunGetReadWaitEvent(TUN_SESSION *Session)
{ {
return Session->Descriptor.Send.TailMoved; return Session->Descriptor.Send.TailMoved;
} }
_Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI WINTUN_RECEIVE_PACKET_FUNC_IMPL WintunReceivePacket;
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize) _Use_decl_annotations_
BYTE *WINAPI
WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize)
{ {
DWORD LastError; DWORD LastError;
EnterCriticalSection(&Session->Send.Lock); EnterCriticalSection(&Session->Send.Lock);
@ -213,8 +221,10 @@ cleanup:
return NULL; return NULL;
} }
void WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL WintunReleaseReceivePacket;
WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) _Use_decl_annotations_
VOID WINAPI
WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet)
{ {
EnterCriticalSection(&Session->Send.Lock); EnterCriticalSection(&Session->Send.Lock);
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data)); TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
@ -232,8 +242,10 @@ WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
LeaveCriticalSection(&Session->Send.Lock); LeaveCriticalSection(&Session->Send.Lock);
} }
_Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL WintunAllocateSendPacket;
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize) _Use_decl_annotations_
BYTE *WINAPI
WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize)
{ {
DWORD LastError; DWORD LastError;
EnterCriticalSection(&Session->Receive.Lock); EnterCriticalSection(&Session->Receive.Lock);
@ -268,8 +280,10 @@ cleanup:
return NULL; return NULL;
} }
void WINAPI WINTUN_SEND_PACKET_FUNC_IMPL WintunSendPacket;
WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) _Use_decl_annotations_
VOID WINAPI
WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet)
{ {
EnterCriticalSection(&Session->Receive.Lock); EnterCriticalSection(&Session->Receive.Lock);
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data)); TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
@ -285,7 +299,8 @@ WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity); TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity);
Session->Receive.PacketsToRelease--; Session->Receive.PacketsToRelease--;
} }
if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease) { if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease)
{
WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease); WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease);
if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable)) if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable))
SetEvent(Session->Descriptor.Receive.TailMoved); SetEvent(Session->Descriptor.Receive.TailMoved);

View File

@ -16,7 +16,7 @@ extern "C" {
/** /**
* A handle representing Wintun adapter * A handle representing Wintun adapter
*/ */
typedef void *WINTUN_ADAPTER_HANDLE; typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE;
/** /**
* Maximum pool name length including zero terminator * Maximum pool name length including zero terminator
@ -41,11 +41,12 @@ typedef void *WINTUN_ADAPTER_HANDLE;
* @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. If * @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. If
* the function fails, the return value is NULL. To get extended error information, call GetLastError. * the function fails, the return value is NULL. To get extended error information, call GetLastError.
*/ */
typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)( typedef _Must_inspect_result_
_In_z_ const WCHAR *Pool, _Return_type_success_(return != NULL)
_In_z_ const WCHAR *Name, _Post_maybenull_
_In_opt_ const GUID *RequestedGUID, WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC_IMPL)
_Out_opt_ BOOL *RebootRequired); (_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name, _In_opt_ const GUID *RequestedGUID, _Out_opt_ BOOL *RebootRequired);
typedef WINTUN_CREATE_ADAPTER_FUNC_IMPL *WINTUN_CREATE_ADAPTER_FUNC;
/** /**
* Opens an existing Wintun adapter. * Opens an existing Wintun adapter.
@ -55,14 +56,15 @@ typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINT
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters. * @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
* *
* @return If the function succeeds, the return value is adapter handle. Must be released with WintunFreeAdapter. If the * @return If the function succeeds, the return value is adapter handle. Must be released with WintunFreeAdapter. If the
* function fails, the return value is NULL. To get extended error information, call GetLastError. Possible * function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors
* errors include the following: * include the following: ERROR_FILE_NOT_FOUND if adapter with given name is not found; ERROR_ALREADY_EXISTS if adapter
* ERROR_FILE_NOT_FOUND if adapter with given name is not found; * is found but not a Wintun-class or not a member of the pool
* ERROR_ALREADY_EXISTS if adapter is found but not a Wintun-class or not a member of the pool
*/ */
typedef _Return_type_success_(return != NULL) typedef _Must_inspect_result_
WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name); _Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name);
typedef WINTUN_OPEN_ADAPTER_FUNC_IMPL *WINTUN_OPEN_ADAPTER_FUNC;
/** /**
* Deletes a Wintun adapter. * Deletes a Wintun adapter.
@ -78,10 +80,10 @@ typedef _Return_type_success_(return != NULL)
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)( typedef _Return_type_success_(return != FALSE)
_In_ WINTUN_ADAPTER_HANDLE Adapter, BOOL(WINAPI WINTUN_DELETE_ADAPTER_FUNC_IMPL)
_In_ BOOL ForceCloseSessions, (_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired);
_Out_opt_ BOOL *RebootRequired); typedef WINTUN_DELETE_ADAPTER_FUNC_IMPL *WINTUN_DELETE_ADAPTER_FUNC;
/** /**
* Called by WintunEnumAdapters for each adapter in the pool. * Called by WintunEnumAdapters for each adapter in the pool.
@ -107,15 +109,17 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK)(_In_ WINTUN_ADAPTER_HANDLE Adapter,
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
typedef _Return_type_success_(return != FALSE) BOOL( typedef _Return_type_success_(return != FALSE)
WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param); BOOL(WINAPI WINTUN_ENUM_ADAPTERS_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param);
typedef WINTUN_ENUM_ADAPTERS_FUNC_IMPL *WINTUN_ENUM_ADAPTERS_FUNC;
/** /**
* Releases Wintun adapter resources. * Releases Wintun adapter resources.
* *
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
*/ */
typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter); typedef VOID(WINAPI WINTUN_FREE_ADAPTER_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter);
typedef WINTUN_FREE_ADAPTER_FUNC_IMPL *WINTUN_FREE_ADAPTER_FUNC;
/** /**
* Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun * Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun
@ -129,7 +133,8 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
typedef _Return_type_success_(return != FALSE) typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired); BOOL(WINAPI WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _Out_opt_ BOOL *RebootRequired);
typedef WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL *WINTUN_DELETE_POOL_DRIVER_FUNC;
/** /**
* Returns the LUID of the adapter. * Returns the LUID of the adapter.
@ -138,7 +143,8 @@ typedef _Return_type_success_(return != FALSE)
* *
* @param Luid Pointer to LUID to receive adapter LUID. * @param Luid Pointer to LUID to receive adapter LUID.
*/ */
typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid); typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
typedef WINTUN_GET_ADAPTER_LUID_FUNC_IMPL *WINTUN_GET_ADAPTER_LUID_FUNC;
/** /**
* Returns the name of the Wintun adapter. * Returns the name of the Wintun adapter.
@ -150,9 +156,11 @@ typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ad
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)( typedef _Must_inspect_result_
_In_ WINTUN_ADAPTER_HANDLE Adapter, _Return_type_success_(return != FALSE)
_Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name); BOOL(WINAPI WINTUN_GET_ADAPTER_NAME_FUNC_IMPL)
(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_writes_z_(MAX_ADAPTER_NAME) LPWSTR Name);
typedef WINTUN_GET_ADAPTER_NAME_FUNC_IMPL *WINTUN_GET_ADAPTER_NAME_FUNC;
/** /**
* Sets name of the Wintun adapter. * Sets name of the Wintun adapter.
@ -165,7 +173,8 @@ typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_N
* get extended error information, call GetLastError. * get extended error information, call GetLastError.
*/ */
typedef _Return_type_success_(return != FALSE) typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name); BOOL(WINAPI WINTUN_SET_ADAPTER_NAME_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ LPCWSTR Name);
typedef WINTUN_SET_ADAPTER_NAME_FUNC_IMPL *WINTUN_SET_ADAPTER_NAME_FUNC;
/** /**
* Determines the version of the Wintun driver currently loaded. * Determines the version of the Wintun driver currently loaded.
@ -174,7 +183,9 @@ typedef _Return_type_success_(return != FALSE)
* zero. To get extended error information, call GetLastError. Possible errors include the following: * zero. To get extended error information, call GetLastError. Possible errors include the following:
* ERROR_FILE_NOT_FOUND Wintun not loaded * ERROR_FILE_NOT_FOUND Wintun not loaded
*/ */
typedef DWORD(WINAPI *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(void); typedef _Return_type_success_(return != 0)
DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL)(VOID);
typedef WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC;
/** /**
* Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK. * Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK.
@ -193,7 +204,7 @@ typedef enum
* *
* @param Message Message text. * @param Message Message text.
*/ */
typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Message); typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Message);
/** /**
* Sets logger callback function. * Sets logger callback function.
@ -202,7 +213,8 @@ typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _
* threads concurrently. Should the logging require serialization, you must handle serialization in * threads concurrently. Should the logging require serialization, you must handle serialization in
* NewLogger. Set to NULL to disable. * NewLogger. Set to NULL to disable.
*/ */
typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger); typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC_IMPL)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
typedef WINTUN_SET_LOGGER_FUNC_IMPL *WINTUN_SET_LOGGER_FUNC;
/** /**
* Minimum ring capacity. * Minimum ring capacity.
@ -217,7 +229,7 @@ typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogg
/** /**
* A handle representing Wintun session * A handle representing Wintun session
*/ */
typedef void *WINTUN_SESSION_HANDLE; typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE;
/** /**
* Starts Wintun session. * Starts Wintun session.
@ -230,15 +242,19 @@ typedef void *WINTUN_SESSION_HANDLE;
* @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is * @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is
* NULL. To get extended error information, call GetLastError. * NULL. To get extended error information, call GetLastError.
*/ */
typedef _Return_type_success_(return != NULL) typedef _Must_inspect_result_
WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); _Return_type_success_(return != NULL)
_Post_maybenull_
WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
typedef WINTUN_START_SESSION_FUNC_IMPL *WINTUN_START_SESSION_FUNC;
/** /**
* Ends Wintun session. * Ends Wintun session.
* *
* @param Session Wintun session handle obtained with WintunStartSession * @param Session Wintun session handle obtained with WintunStartSession
*/ */
typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session); typedef VOID(WINAPI WINTUN_END_SESSION_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC;
/** /**
* Gets Wintun session's read-wait event handle. * Gets Wintun session's read-wait event handle.
@ -250,7 +266,8 @@ typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session
* load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call * load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call
* CloseHandle on this event - it is managed by the session. * CloseHandle on this event - it is managed by the session.
*/ */
typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session); typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
typedef WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL *WINTUN_GET_READ_WAIT_EVENT_FUNC;
/** /**
* Maximum IP packet size * Maximum IP packet size
@ -272,8 +289,12 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted; * ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
* ERROR_INVALID_DATA Wintun buffer is corrupt * ERROR_INVALID_DATA Wintun buffer is corrupt
*/ */
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *( typedef _Must_inspect_result_
WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize); _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(*PacketSize)
BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC;
/** /**
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe. * Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
@ -282,7 +303,9 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE
* *
* @param Packet Packet obtained with WintunReceivePacket * @param Packet Packet obtained with WintunReceivePacket
*/ */
typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); typedef VOID(
WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
typedef WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RELEASE_RECEIVE_PACKET_FUNC;
/** /**
* Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send * Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
@ -299,8 +322,12 @@ typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HAN
* ERROR_HANDLE_EOF Wintun adapter is terminating; * ERROR_HANDLE_EOF Wintun adapter is terminating;
* ERROR_BUFFER_OVERFLOW Wintun buffer is full; * ERROR_BUFFER_OVERFLOW Wintun buffer is full;
*/ */
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *( typedef _Must_inspect_result_
WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize); _Return_type_success_(return != NULL)
_Post_maybenull_
_Post_writable_byte_size_(PacketSize)
BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC;
/** /**
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket * Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
@ -311,7 +338,8 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *
* *
* @param Packet Packet obtained with WintunAllocateSendPacket * @param Packet Packet obtained with WintunAllocateSendPacket
*/ */
typedef void(WINAPI *WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
typedef WINTUN_SEND_PACKET_FUNC_IMPL *WINTUN_SEND_PACKET_FUNC;
#ifdef __cplusplus #ifdef __cplusplus
} }