From d675646ab8df227ba39c9d0160d0ba77e8f85479 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Wed, 28 Jul 2021 20:20:09 +0200 Subject: [PATCH] api: upgrade Signed-off-by: Simon Rozman --- api/adapter.c | 1129 +++++++++++++++++++++------------------------- api/adapter.h | 78 +++- api/api.vcxproj | 4 +- api/logger.c | 51 +-- api/logger.h | 123 +++-- api/main.c | 43 +- api/main.h | 27 +- api/namespace.c | 35 +- api/namespace.h | 25 +- api/nci.h | 16 +- api/ntdll.h | 8 +- api/registry.c | 160 ++----- api/registry.h | 57 +-- api/resource.c | 53 ++- api/resource.h | 31 +- api/rundll32.c | 544 ++++++++++++++++++++-- api/rundll32.h | 29 ++ api/rundll32_i.c | 352 --------------- api/session.c | 47 +- api/wintun.h | 110 +++-- 20 files changed, 1539 insertions(+), 1383 deletions(-) create mode 100644 api/rundll32.h delete mode 100644 api/rundll32_i.c diff --git a/api/adapter.c b/api/adapter.c index 4d75351..2635a5c 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -28,38 +28,35 @@ #include "ntdll.h" #include "registry.h" #include "resource.h" +#include "rundll32.h" #include "wintun-inf.h" #pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ #define WAIT_FOR_REGISTRY_TIMEOUT 10000 /* ms */ #define MAX_POOL_DEVICE_TYPE (WINTUN_MAX_POOL + 8) /* Should accommodate a pool name with " Tunnel" appended */ -#if defined(_M_IX86) -# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386 -#elif defined(_M_AMD64) -# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64 -#elif defined(_M_ARM) -# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT -#elif defined(_M_ARM64) -# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64 -#else -# error Unsupported architecture -#endif static const DEVPROPKEY DEVPKEY_Wintun_Pool = { { 0xaba51201, 0xdf7a, 0x3a38, { 0x0a, 0xd9, 0x90, 0x64, 0x42, 0xd2, 0x71, 0xae } }, DEVPROPID_FIRST_USABLE + 0 }; +static const DEVPROPKEY DEVPKEY_Wintun_Name = { + { 0x3361c968, 0x2f2e, 0x4660, { 0xb4, 0x7e, 0x69, 0x9c, 0xdc, 0x4c, 0x32, 0xb9 } }, + DEVPROPID_FIRST_USABLE + 1 +}; + typedef struct _SP_DEVINFO_DATA_LIST { SP_DEVINFO_DATA Data; struct _SP_DEVINFO_DATA_LIST *Next; } SP_DEVINFO_DATA_LIST; -static USHORT NativeMachine = IMAGE_FILE_PROCESS; - -static _Return_type_success_(return != NULL) SP_DRVINFO_DETAIL_DATA_W *GetAdapterDrvInfoDetail( +_Must_inspect_result_ +static _Return_type_success_(return != NULL) +_Post_maybenull_ +SP_DRVINFO_DETAIL_DATA_W * +GetAdapterDrvInfoDetail( _In_ HDEVINFO DevInfo, _In_opt_ SP_DEVINFO_DATA *DevInfoData, _In_ SP_DRVINFO_DATA_W *DrvInfoData) @@ -87,7 +84,12 @@ static _Return_type_success_(return != NULL) SP_DRVINFO_DETAIL_DATA_W *GetAdapte } } -static _Return_type_success_(return != NULL) void *GetDeviceRegistryProperty( +_Must_inspect_result_ +static _Return_type_success_(return != NULL) +_Post_maybenull_ +_Post_writable_byte_size_(*BufLen) +VOID * +GetDeviceRegistryProperty( _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property, @@ -106,17 +108,20 @@ static _Return_type_success_(return != NULL) void *GetDeviceRegistryProperty( if (LastError != ERROR_INSUFFICIENT_BUFFER) { SetLastError( - LOG_ERROR(LastError, L"Querying adapter %u property 0x%x failed", DevInfoData->DevInst, Property)); + LOG_ERROR(LastError, L"Failed to query adapter %u property 0x%x", DevInfoData->DevInst, Property)); return NULL; } } } +_Must_inspect_result_ static _Return_type_success_(return != NULL) - WCHAR *GetDeviceRegistryString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) +_Post_maybenull_ +LPWSTR +GetDeviceRegistryString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) { DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); - WCHAR *Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); + LPWSTR Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); if (!Buf) return NULL; switch (ValueType) @@ -124,7 +129,7 @@ static _Return_type_success_(return != NULL) case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: - if (RegistryGetString(&Buf, Size / sizeof(WCHAR), ValueType)) + if (RegistryGetString(&Buf, Size / sizeof(*Buf), ValueType)) return Buf; LastError = GetLastError(); break; @@ -141,11 +146,14 @@ static _Return_type_success_(return != NULL) return NULL; } +_Must_inspect_result_ static _Return_type_success_(return != NULL) - WCHAR *GetDeviceRegistryMultiString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) +_Post_maybenull_ +PZZWSTR +GetDeviceRegistryMultiString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) { DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); - WCHAR *Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); + PZZWSTR Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); if (!Buf) return NULL; switch (ValueType) @@ -153,7 +161,7 @@ static _Return_type_success_(return != NULL) case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: - if (RegistryGetMultiString(&Buf, Size / sizeof(WCHAR), ValueType)) + if (RegistryGetMultiString(&Buf, Size / sizeof(*Buf), ValueType)) return Buf; LastError = GetLastError(); break; @@ -171,7 +179,7 @@ static _Return_type_success_(return != NULL) } static BOOL -IsOurHardwareID(_In_z_ const WCHAR *Hwids) +IsOurHardwareID(_In_z_ PCZZWSTR Hwids) { for (; Hwids[0]; Hwids += wcslen(Hwids) + 1) if (!_wcsicmp(Hwids, WINTUN_HWID)) @@ -182,7 +190,7 @@ IsOurHardwareID(_In_z_ const WCHAR *Hwids) static BOOL IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - WCHAR *Hwids = GetDeviceRegistryMultiString(DevInfo, DevInfoData, SPDRP_HARDWAREID); + PZZWSTR Hwids = GetDeviceRegistryMultiString(DevInfo, DevInfoData, SPDRP_HARDWAREID); if (!Hwids) { LOG_LAST_ERROR(L"Failed to get adapter %u hardware ID", DevInfoData->DevInst); @@ -193,7 +201,11 @@ IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) return IsOurs; } -static _Return_type_success_(return != NULL) WCHAR *GetDeviceObjectFileName(_In_z_ const WCHAR *InstanceId) +_Must_inspect_result_ +static _Return_type_success_(return != NULL) +_Post_maybenull_ +LPWSTR +GetDeviceObjectFileName(_In_z_ LPCWSTR InstanceId) { ULONG InterfacesLen; DWORD LastError = CM_MapCrToWin32Err( @@ -208,7 +220,7 @@ static _Return_type_success_(return != NULL) WCHAR *GetDeviceObjectFileName(_In_ SetLastError(LOG_ERROR(LastError, L"Failed to query adapter %s associated instances size", InstanceId)); return NULL; } - WCHAR *Interfaces = Alloc(InterfacesLen * sizeof(WCHAR)); + LPWSTR Interfaces = AllocArray(InterfacesLen, sizeof(*Interfaces)); if (!Interfaces) return NULL; LastError = CM_MapCrToWin32Err( @@ -228,7 +240,6 @@ static _Return_type_success_(return != NULL) WCHAR *GetDeviceObjectFileName(_In_ } if (!Interfaces[0]) { - LOG(WINTUN_LOG_ERR, L"Received empty adapter %s object file name", InstanceId); Free(Interfaces); SetLastError(ERROR_DEVICE_NOT_AVAILABLE); return NULL; @@ -236,9 +247,12 @@ static _Return_type_success_(return != NULL) WCHAR *GetDeviceObjectFileName(_In_ return Interfaces; } -static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceObject(_In_z_ const WCHAR *InstanceId) +_Must_inspect_result_ +static _Return_type_success_(return != INVALID_HANDLE_VALUE) +HANDLE +OpenDeviceObject(_In_z_ LPCWSTR InstanceId) { - WCHAR *Filename = GetDeviceObjectFileName(InstanceId); + LPWSTR Filename = GetDeviceObjectFileName(InstanceId); if (!Filename) return INVALID_HANDLE_VALUE; HANDLE Handle = CreateFileW( @@ -256,11 +270,14 @@ static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceOb } static BOOL -EnsureDeviceObject(_In_z_ const WCHAR *InstanceId) +EnsureDeviceObject(_In_z_ LPCWSTR InstanceId) { - WCHAR *Filename = GetDeviceObjectFileName(InstanceId); + LPWSTR Filename = GetDeviceObjectFileName(InstanceId); if (!Filename) + { + LOG_LAST_ERROR(L"Failed to determine adapter %s device object", InstanceId); return FALSE; + } BOOL Exists = TRUE; const int Attempts = 100; for (int i = 0; i < Attempts; ++i) @@ -283,8 +300,9 @@ out: #define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) -static _Return_type_success_(return != FALSE) BOOL - ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +static _Return_type_success_(return != FALSE) +BOOL +ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { DWORD LastError = ERROR_SUCCESS; DWORD RequiredBytes; @@ -294,7 +312,8 @@ static _Return_type_success_(return != FALSE) BOOL LOG_ERROR(LastError, L"Failed to query adapter %u instance ID size", DevInfoData->DevInst); return FALSE; } - WCHAR *InstanceId = Zalloc(sizeof(*InstanceId) * RequiredBytes); + LastError = ERROR_SUCCESS; + LPWSTR InstanceId = ZallocArray(RequiredBytes, sizeof(*InstanceId)); if (!InstanceId) return FALSE; if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes)) @@ -323,8 +342,9 @@ cleanupInstanceId: return RET_ERROR(TRUE, LastError); } -static _Return_type_success_(return != FALSE) BOOL - DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters) +static _Return_type_success_(return != FALSE) +BOOL +DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters) { SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), .InstallFunction = DIF_PROPERTYCHANGE }, @@ -333,7 +353,7 @@ static _Return_type_success_(return != FALSE) BOOL DWORD LastError = ERROR_SUCCESS; for (DWORD EnumIndex = 0;; ++EnumIndex) { - SP_DEVINFO_DATA_LIST *DeviceNode = Alloc(sizeof(SP_DEVINFO_DATA_LIST)); + SP_DEVINFO_DATA_LIST *DeviceNode = Zalloc(sizeof(*DeviceNode)); if (!DeviceNode) return FALSE; DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA); @@ -377,8 +397,9 @@ static _Return_type_success_(return != FALSE) BOOL return RET_ERROR(TRUE, LastError); } -static _Return_type_success_(return != FALSE) BOOL - EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable) +static _Return_type_success_(return != FALSE) +BOOL +EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable) { SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), .InstallFunction = DIF_PROPERTYCHANGE }, @@ -398,135 +419,23 @@ static _Return_type_success_(return != FALSE) BOOL return RET_ERROR(TRUE, LastError); } -void -AdapterInit(void) -{ -#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 -} - static BOOL CheckReboot(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(SP_DEVINSTALL_PARAMS_W) }; if (!SetupDiGetDeviceInstallParamsW(DevInfo, DevInfoData, &DevInstallParams)) { - LOG_LAST_ERROR(L"Retrieving adapter %u device installation parameters failed", DevInfoData->DevInst); + LOG_LAST_ERROR(L"Failed to retrieve adapter %u device installation parameters", DevInfoData->DevInst); return FALSE; } SetLastError(ERROR_SUCCESS); return (DevInstallParams.Flags & (DI_NEEDREBOOT | DI_NEEDRESTART)) != 0; } -static _Return_type_success_(return != FALSE) BOOL - SetQuietInstall(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) -{ - SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(SP_DEVINSTALL_PARAMS_W) }; - if (!SetupDiGetDeviceInstallParamsW(DevInfo, DevInfoData, &DevInstallParams)) - { - LOG_LAST_ERROR(L"Retrieving adapter %u device installation parameters failed", DevInfoData->DevInst); - return FALSE; - } - DevInstallParams.Flags |= DI_QUIETINSTALL; - if (!SetupDiSetDeviceInstallParamsW(DevInfo, DevInfoData, &DevInstallParams)) - { - LOG_LAST_ERROR(L"Setting adapter %u device installation parameters failed", DevInfoData->DevInst); - return FALSE; - } - return TRUE; -} - -static _Return_type_success_(return != FALSE) BOOL GetNetCfgInstanceIdFromHKEY(_In_ HKEY Key, _Out_ GUID *CfgInstanceID) -{ - WCHAR *ValueStr = RegistryQueryString(Key, L"NetCfgInstanceId", TRUE); - if (!ValueStr) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - return RET_ERROR(TRUE, LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\NetCfgInstanceId", MAX_REG_PATH, RegPath)); - } - DWORD LastError = ERROR_SUCCESS; - if (FAILED(CLSIDFromString(ValueStr, CfgInstanceID))) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG(WINTUN_LOG_ERR, L"%.*s\\NetCfgInstanceId is not a GUID: %s", MAX_REG_PATH, RegPath, ValueStr); - LastError = ERROR_INVALID_DATA; - } - Free(ValueStr); - return RET_ERROR(TRUE, LastError); -} - -static _Return_type_success_(return != FALSE) BOOL - GetNetCfgInstanceIdFromDevInfo(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _Out_ GUID *CfgInstanceID) -{ - HKEY Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); - if (Key == INVALID_HANDLE_VALUE) - { - LOG_LAST_ERROR(L"Opening adapter %u device registry key failed", DevInfoData->DevInst); - return FALSE; - } - DWORD LastError = ERROR_SUCCESS; - if (!GetNetCfgInstanceIdFromHKEY(Key, CfgInstanceID)) - LastError = GetLastError(); - RegCloseKey(Key); - return RET_ERROR(TRUE, LastError); -} - -static _Return_type_success_(return != FALSE) BOOL - GetDevInfoData(_In_ const GUID *CfgInstanceID, _Out_ HDEVINFO *DevInfo, _Out_ SP_DEVINFO_DATA *DevInfoData) -{ - *DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (!*DevInfo) - { - LOG_LAST_ERROR(L"Failed to get present adapters"); - return FALSE; - } - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - DevInfoData->cbSize = sizeof(SP_DEVINFO_DATA); - if (!SetupDiEnumDeviceInfo(*DevInfo, EnumIndex, DevInfoData)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } - GUID CfgInstanceID2; - if (GetNetCfgInstanceIdFromDevInfo(*DevInfo, DevInfoData, &CfgInstanceID2) && - !memcmp(CfgInstanceID, &CfgInstanceID2, sizeof(GUID))) - return TRUE; - } - SetupDiDestroyDeviceInfoList(*DevInfo); - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; -} - -static void -RemoveNumberedSuffix(_Inout_z_ WCHAR *Name) -{ - for (size_t i = wcslen(Name); i--;) - { - if ((Name[i] < L'0' || Name[i] > L'9') && !iswspace(Name[i])) - return; - Name[i] = 0; - } -} - -static _Return_type_success_(return != FALSE) BOOL - GetPoolDeviceTypeName(_In_z_ const WCHAR *Pool, _Out_cap_c_(MAX_POOL_DEVICE_TYPE) WCHAR *Name) +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +GetPoolDeviceTypeName(_In_z_ LPCWSTR Pool, _Out_writes_z_(MAX_POOL_DEVICE_TYPE) LPWSTR Name) { if (_snwprintf_s(Name, MAX_POOL_DEVICE_TYPE, _TRUNCATE, L"%s Tunnel", Pool) == -1) { @@ -538,74 +447,62 @@ static _Return_type_success_(return != FALSE) BOOL } static BOOL -IsPoolMember(_In_z_ const WCHAR *Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +IsPoolMember(_In_z_ LPCWSTR Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { WCHAR PoolProp[MAX_POOL_DEVICE_TYPE]; DEVPROPTYPE PropType; - if (SetupDiGetDevicePropertyW( - DevInfo, DevInfoData, &DEVPKEY_Wintun_Pool, &PropType, (PBYTE)PoolProp, sizeof(PoolProp), NULL, 0) && - PropType == DEVPROP_TYPE_STRING) - return !_wcsicmp(PoolProp, Pool); - - LOG_LAST_ERROR(L"Reading pool devpkey failed, falling back"); - DWORD LastError = ERROR_SUCCESS; - BOOL Ret = FALSE; - WCHAR *DeviceDesc = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_DEVICEDESC); - WCHAR *FriendlyName = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_FRIENDLYNAME); - WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; - if (!GetPoolDeviceTypeName(Pool, PoolDeviceTypeName)) + if (!SetupDiGetDevicePropertyW( + DevInfo, DevInfoData, &DEVPKEY_Wintun_Pool, &PropType, (PBYTE)PoolProp, sizeof(PoolProp), NULL, 0)) + return FALSE; + if (PropType != DEVPROP_TYPE_STRING) { - LastError = GetLastError(); - goto cleanupNames; + SetLastError(ERROR_BAD_DEVICE); + return FALSE; } - Ret = (FriendlyName && !_wcsicmp(FriendlyName, PoolDeviceTypeName)) || - (DeviceDesc && !_wcsicmp(DeviceDesc, PoolDeviceTypeName)); - if (Ret) - goto cleanupNames; - if (FriendlyName) - RemoveNumberedSuffix(FriendlyName); - if (DeviceDesc) - RemoveNumberedSuffix(DeviceDesc); - Ret = (FriendlyName && !_wcsicmp(FriendlyName, PoolDeviceTypeName)) || - (DeviceDesc && !_wcsicmp(DeviceDesc, PoolDeviceTypeName)); -cleanupNames: - Free(FriendlyName); - Free(DeviceDesc); - SetLastError(LastError); - return Ret; + SetLastError(ERROR_SUCCESS); + return !_wcsicmp(PoolProp, Pool); } -static _Return_type_success_(return != NULL) WINTUN_ADAPTER - *CreateAdapterData(_In_z_ const WCHAR *Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +PopulateAdapterData(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR Pool) { + DWORD LastError = ERROR_SUCCESS; + /* Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\\ registry key. */ - HKEY Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + HKEY Key = + SetupDiOpenDevRegKey(Adapter->DevInfo, &Adapter->DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); if (Key == INVALID_HANDLE_VALUE) { - LOG_LAST_ERROR(L"Opening adapter %u device registry key failed", DevInfoData->DevInst); - return NULL; + LOG_LAST_ERROR(L"Failed to open adapter %u device registry key", Adapter->DevInfoData.DevInst); + return FALSE; } - DWORD LastError; - WINTUN_ADAPTER *Adapter = Alloc(sizeof(WINTUN_ADAPTER)); - if (!Adapter) + LPWSTR ValueStr = RegistryQueryString(Key, L"NetCfgInstanceId", TRUE); + if (!ValueStr) { - LastError = GetLastError(); + WCHAR RegPath[MAX_REG_PATH]; + LoggerGetRegistryKeyPath(Key, RegPath); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\NetCfgInstanceId", MAX_REG_PATH, RegPath); goto cleanupKey; } - - if (!GetNetCfgInstanceIdFromHKEY(Key, &Adapter->CfgInstanceID)) + if (FAILED(CLSIDFromString(ValueStr, &Adapter->CfgInstanceID))) { - LastError = GetLastError(); - goto cleanupAdapter; + WCHAR RegPath[MAX_REG_PATH]; + LoggerGetRegistryKeyPath(Key, RegPath); + LastError = LOG(WINTUN_LOG_ERR, L"%.*s\\NetCfgInstanceId is not a GUID: %s", MAX_REG_PATH, RegPath, ValueStr); + Free(ValueStr); + goto cleanupKey; } + Free(ValueStr); if (!RegistryQueryDWORD(Key, L"NetLuidIndex", &Adapter->LuidIndex, TRUE)) { WCHAR RegPath[MAX_REG_PATH]; LoggerGetRegistryKeyPath(Key, RegPath); LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\NetLuidIndex", MAX_REG_PATH, RegPath); - goto cleanupAdapter; + goto cleanupKey; } if (!RegistryQueryDWORD(Key, L"*IfType", &Adapter->IfType, TRUE)) @@ -613,166 +510,67 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER WCHAR RegPath[MAX_REG_PATH]; LoggerGetRegistryKeyPath(Key, RegPath); LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\*IfType", MAX_REG_PATH, RegPath); - goto cleanupAdapter; + goto cleanupKey; } DWORD Size; if (!SetupDiGetDeviceInstanceIdW( - DevInfo, DevInfoData, Adapter->DevInstanceID, _countof(Adapter->DevInstanceID), &Size)) + Adapter->DevInfo, &Adapter->DevInfoData, Adapter->DevInstanceID, _countof(Adapter->DevInstanceID), &Size)) { - LastError = LOG_LAST_ERROR(L"Failed to get adapter %u instance ID", DevInfoData->DevInst); - goto cleanupAdapter; + LastError = LOG_LAST_ERROR(L"Failed to get adapter %u instance ID", Adapter->DevInfoData.DevInst); + goto cleanupKey; } if (wcsncpy_s(Adapter->Pool, _countof(Adapter->Pool), Pool, _TRUNCATE) == STRUNCATE) { LOG(WINTUN_LOG_ERR, L"Pool name too long: %s", Pool); LastError = ERROR_INVALID_PARAMETER; - goto cleanupAdapter; + goto cleanupKey; } - RegCloseKey(Key); - return Adapter; -cleanupAdapter: - Free(Adapter); cleanupKey: RegCloseKey(Key); - SetLastError(LastError); - return NULL; + return RET_ERROR(TRUE, LastError); } -static _Return_type_success_(return != FALSE) BOOL - GetDeviceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) -{ - if (_snwprintf_s( - Path, - MAX_REG_PATH, - _TRUNCATE, - L"SYSTEM\\CurrentControlSet\\Enum\\%.*s", - MAX_INSTANCE_ID, - Adapter->DevInstanceID) == -1) - { - LOG(WINTUN_LOG_ERR, L"Registry path too long: %.*s", MAX_INSTANCE_ID, Adapter->DevInstanceID); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - return TRUE; -} - -void WINAPI -WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter) +_Use_decl_annotations_ +VOID WINAPI +WintunFreeAdapter(WINTUN_ADAPTER *Adapter) { + if (!Adapter) + return; + if (Adapter->DevInfo) + SetupDiDestroyDeviceInfoList(Adapter->DevInfo); Free(Adapter); } -_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI - WintunOpenAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name) +_Use_decl_annotations_ +BOOL WINAPI +WintunGetAdapterName(WINTUN_ADAPTER *Adapter, LPWSTR Name) { - DWORD LastError; - WINTUN_ADAPTER *Adapter = NULL; - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) + DEVPROPTYPE PropType; + if (!SetupDiGetDevicePropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + &DEVPKEY_Wintun_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(*Name), + NULL, + 0)) + return FALSE; + if (PropType != DEVPROP_TYPE_STRING || !*Name) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Pool); - goto cleanup; - } - - HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (DevInfo == INVALID_HANDLE_VALUE) - { - LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); - goto cleanupMutex; - } - - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; - if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } - - GUID CfgInstanceID; - if (!GetNetCfgInstanceIdFromDevInfo(DevInfo, &DevInfoData, &CfgInstanceID)) - continue; - - /* TODO: is there a better way than comparing ifnames? */ - WCHAR Name2[MAX_ADAPTER_NAME]; - if (NciGetConnectionName(&CfgInstanceID, Name2, sizeof(Name2), NULL) != ERROR_SUCCESS) - continue; - Name2[_countof(Name2) - 1] = 0; - if (_wcsicmp(Name, Name2)) - { - RemoveNumberedSuffix(Name2); - if (_wcsicmp(Name, Name2)) - continue; - } - - /* Check the Hardware ID to make sure it's a real Wintun device. */ - if (!IsOurAdapter(DevInfo, &DevInfoData)) - { - LOG(WINTUN_LOG_ERR, L"Foreign adapter %u named %s exists", DevInfoData.DevInst, Name); - LastError = ERROR_ALREADY_EXISTS; - goto cleanupDevInfo; - } - - if (!IsPoolMember(Pool, DevInfo, &DevInfoData)) - { - if ((LastError = GetLastError()) == ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Adapter %u named %s is not a member of %s pool", DevInfoData.DevInst, Name, Pool); - LastError = ERROR_ALREADY_EXISTS; - goto cleanupDevInfo; - } - else - { - LOG(WINTUN_LOG_ERR, L"Failed to get adapter %u pool membership", DevInfoData.DevInst); - goto cleanupDevInfo; - } - } - - Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); - if (!Adapter) - { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to create adapter %u data", DevInfoData.DevInst); - goto cleanupDevInfo; - } - - if (!EnsureDeviceObject(Adapter->DevInstanceID)) - { - LastError = GetLastError(); - goto cleanupDevInfo; - } - - LastError = ERROR_SUCCESS; - goto cleanupDevInfo; - } - LastError = ERROR_FILE_NOT_FOUND; -cleanupDevInfo: - SetupDiDestroyDeviceInfoList(DevInfo); -cleanupMutex: - NamespaceReleaseMutex(Mutex); -cleanup: - SetLastError(LastError); - return Adapter; -} - -_Return_type_success_(return != FALSE) BOOL WINAPI - WintunGetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name) -{ - DWORD LastError = NciGetConnectionName(&Adapter->CfgInstanceID, Name, MAX_ADAPTER_NAME * sizeof(WCHAR), NULL); - if (LastError != ERROR_SUCCESS) - { - SetLastError(LOG_ERROR(LastError, L"Failed to get name")); + SetLastError(ERROR_BAD_DEVICE); return FALSE; } return TRUE; } -static _Return_type_success_(return != FALSE) BOOL - ConvertInterfaceAliasToGuid(_In_z_ const WCHAR *Name, _Out_ GUID *Guid) +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +ConvertInterfaceAliasToGuid(_In_z_ LPCWSTR Name, _Out_ GUID *Guid) { NET_LUID Luid; DWORD LastError = ConvertInterfaceAliasToLuid(Name, &Luid); @@ -790,10 +588,10 @@ static _Return_type_success_(return != FALSE) BOOL return TRUE; } -_Return_type_success_(return != FALSE) BOOL WINAPI - WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_ const WCHAR *Name) +_Use_decl_annotations_ +BOOL WINAPI +WintunSetAdapterName(WINTUN_ADAPTER *Adapter, LPCWSTR Name) { - DWORD LastError; const int MaxSuffix = 1000; WCHAR AvailableName[MAX_ADAPTER_NAME]; if (wcsncpy_s(AvailableName, _countof(AvailableName), Name, _TRUNCATE) == STRUNCATE) @@ -802,9 +600,24 @@ _Return_type_success_(return != FALSE) BOOL WINAPI SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } + + if (!SetupDiSetDevicePropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + &DEVPKEY_Wintun_Name, + DEVPROP_TYPE_STRING, +#pragma warning(suppress : 4090) + (const BYTE *)Name, + (DWORD)((wcslen(Name) + 1) * sizeof(*Name)), + 0)) + { + LOG_LAST_ERROR(L"Failed to set adapter %u name", Adapter->DevInfoData.DevInst); + return FALSE; + } + for (int i = 0;; ++i) { - LastError = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); + DWORD LastError = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); if (LastError == ERROR_DUP_NAME) { GUID Guid2; @@ -838,7 +651,7 @@ _Return_type_success_(return != FALSE) BOOL WINAPI break; if (i >= MaxSuffix || LastError != ERROR_DUP_NAME) { - SetLastError(LOG_ERROR(LastError, L"Setting adapter name failed")); + SetLastError(LOG_ERROR(LastError, L"Failed to set adapter name")); return FALSE; } if (_snwprintf_s(AvailableName, _countof(AvailableName), _TRUNCATE, L"%s %d", Name, i + 1) == -1) @@ -849,74 +662,162 @@ _Return_type_success_(return != FALSE) BOOL WINAPI } } - /* TODO: This should use NetSetup2 so that it doesn't get unset. */ - HKEY DeviceRegKey; - WCHAR DeviceRegPath[MAX_REG_PATH]; - if (!GetDeviceRegPath(Adapter, DeviceRegPath)) - return FALSE; - LastError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceRegPath, 0, KEY_SET_VALUE, &DeviceRegKey); - if (LastError != ERROR_SUCCESS) + if (!SetupDiSetDevicePropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + &DEVPKEY_Wintun_Pool, + DEVPROP_TYPE_STRING, +#pragma warning(suppress : 4090) + (const BYTE *)Adapter->Pool, + (DWORD)((wcslen(Adapter->Pool) + 1) * sizeof(*Adapter->Pool)), + 0)) { - SetLastError(LOG_ERROR(LastError, L"Failed to open registry key %s", DeviceRegPath)); + LOG_LAST_ERROR(L"Failed to set adapter %u pool", Adapter->DevInfoData.DevInst); return FALSE; } + WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; if (!GetPoolDeviceTypeName(Adapter->Pool, PoolDeviceTypeName)) + return FALSE; + if (!SetupDiSetDeviceRegistryPropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + SPDRP_FRIENDLYNAME, + (const BYTE *)PoolDeviceTypeName, + (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(*PoolDeviceTypeName)))) { - LastError = GetLastError(); - goto cleanupDeviceRegKey; + LOG_LAST_ERROR(L"Failed to set adapter %u friendly name", Adapter->DevInfoData.DevInst); + return FALSE; } - LastError = RegSetKeyValueW( - DeviceRegKey, - NULL, - L"FriendlyName", - REG_SZ, - PoolDeviceTypeName, - (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(WCHAR))); - if (LastError != ERROR_SUCCESS) - LOG_ERROR(LastError, L"Failed to set %s\\FriendlyName", DeviceRegPath); -cleanupDeviceRegKey: - RegCloseKey(DeviceRegKey); - return RET_ERROR(TRUE, LastError); + + return TRUE; } -void WINAPI -WintunGetAdapterLUID(_In_ const WINTUN_ADAPTER *Adapter, _Out_ NET_LUID *Luid) +_Use_decl_annotations_ +WINTUN_ADAPTER_HANDLE WINAPI +WintunOpenAdapter(LPCWSTR Pool, LPCWSTR Name) +{ + WINTUN_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); + if (!Adapter) + return FALSE; + + DWORD LastError = ERROR_SUCCESS; + HANDLE Mutex = NamespaceTakePoolMutex(Pool); + if (!Mutex) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Pool); + goto cleanup; + } + + Adapter->DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); + if (Adapter->DevInfo == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); + goto cleanupMutex; + } + + Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + if (!SetupDiEnumDeviceInfo(Adapter->DevInfo, EnumIndex, &Adapter->DevInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + + WCHAR Name2[MAX_ADAPTER_NAME]; + if (!WintunGetAdapterName(Adapter, Name2)) + continue; + if (_wcsicmp(Name, Name2)) + continue; + + /* Check the Hardware ID to make sure it's a real Wintun device. */ + if (!IsOurAdapter(Adapter->DevInfo, &Adapter->DevInfoData)) + { + LOG(WINTUN_LOG_ERR, L"Foreign adapter %u named %s exists", Adapter->DevInfoData.DevInst, Name); + LastError = ERROR_ALREADY_EXISTS; + goto cleanupMutex; + } + + if (!IsPoolMember(Pool, Adapter->DevInfo, &Adapter->DevInfoData)) + { + if ((LastError = GetLastError()) == ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, + L"Adapter %u named %s is not a member of %s pool", + Adapter->DevInfoData.DevInst, + Name, + Pool); + LastError = ERROR_ALREADY_EXISTS; + goto cleanupMutex; + } + else + { + LOG(WINTUN_LOG_ERR, L"Failed to get adapter %u pool membership", Adapter->DevInfoData.DevInst); + goto cleanupMutex; + } + } + + if (!PopulateAdapterData(Adapter, Pool)) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); + goto cleanupMutex; + } + + if (!EnsureDeviceObject(Adapter->DevInstanceID)) + { + LastError = GetLastError(); + goto cleanupMutex; + } + + /* Our comparison was case-insensitive, and we also might want to reenforce the NCI connection. */ + WintunSetAdapterName(Adapter, Name); + + LastError = ERROR_SUCCESS; + goto cleanupMutex; + } + LastError = ERROR_FILE_NOT_FOUND; +cleanupMutex: + NamespaceReleaseMutex(Mutex); +cleanup: + if (LastError != ERROR_SUCCESS) + WintunFreeAdapter(Adapter); + return RET_ERROR(Adapter, LastError); +} + +_Use_decl_annotations_ +VOID WINAPI +WintunGetAdapterLUID(WINTUN_ADAPTER *Adapter, NET_LUID *Luid) { Luid->Info.Reserved = 0; Luid->Info.NetLuidIndex = Adapter->LuidIndex; Luid->Info.IfType = Adapter->IfType; } -_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI - AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter) +_Use_decl_annotations_ +HANDLE WINAPI +AdapterOpenDeviceObject(const WINTUN_ADAPTER *Adapter) { return OpenDeviceObject(Adapter->DevInstanceID); } -static BOOL -IsWindows10(void) -{ - DWORD MajorVersion; - RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL); - return MajorVersion >= 10; -} - -static BOOL -HaveWHQL(void) +static BOOL HaveWHQL(VOID) { #if defined(HAVE_WHQL) - return IsWindows10(); + return IsWindows10; #else return FALSE; #endif } -static _Return_type_success_(return != FALSE) BOOL InstallCertificate(_In_z_ const WCHAR *SignedResource) +static _Return_type_success_(return != FALSE) +BOOL +InstallCertificate(_In_z_ LPCWSTR SignedResource) { LOG(WINTUN_LOG_INFO, L"Trusting code signing certificate"); DWORD SizeResource; - const void *LockedResource = ResourceGetAddress(SignedResource, &SizeResource); + const VOID *LockedResource = ResourceGetAddress(SignedResource, &SizeResource); if (!LockedResource) { LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", SignedResource); @@ -1021,8 +922,10 @@ IsNewer( return FALSE; } -static _Return_type_success_(return != FALSE) BOOL - GetTcpipAdapterRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +GetTcpipAdapterRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path) { WCHAR Guid[MAX_GUID_STRING_LEN]; if (_snwprintf_s( @@ -1040,8 +943,10 @@ static _Return_type_success_(return != FALSE) BOOL return TRUE; } -static _Return_type_success_(return != FALSE) BOOL - GetTcpipInterfaceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +GetTcpipInterfaceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path) { HKEY TcpipAdapterRegKey; WCHAR TcpipAdapterRegPath[MAX_REG_PATH]; @@ -1053,7 +958,7 @@ static _Return_type_success_(return != FALSE) BOOL SetLastError(LOG_ERROR(LastError, L"Failed to open registry key %s", TcpipAdapterRegPath)); return FALSE; } - WCHAR *Paths = RegistryQueryString(TcpipAdapterRegKey, L"IpConfig", TRUE); + LPWSTR Paths = RegistryQueryString(TcpipAdapterRegKey, L"IpConfig", TRUE); if (!Paths) { LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %s\\IpConfig", TcpipAdapterRegPath); @@ -1078,7 +983,9 @@ cleanupTcpipAdapterRegKey: return RET_ERROR(TRUE, LastError); } -static _Return_type_success_(return != 0) DWORD VersionOfFile(_In_z_ const WCHAR *Filename) +static _Return_type_success_(return != 0) +DWORD +VersionOfFile(_In_z_ LPCWSTR Filename) { DWORD Zero; DWORD Len = GetFileVersionInfoSizeW(Filename, &Zero); @@ -1114,45 +1021,6 @@ out: return RET_ERROR(Version, LastError); } -static _Return_type_success_(return != FALSE) BOOL - CreateTemporaryDirectory(_Out_cap_c_(MAX_PATH) WCHAR *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 }; -#pragma warning(suppress : 6387) - 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; -} - static DWORD WINAPI MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion) { @@ -1176,7 +1044,7 @@ MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion) DWORD LastError = ERROR_SUCCESS, Version = 0; for (ULONG i = Modules->NumberOfModules; i-- > 0;) { - const char *NtPath = (const char *)Modules->Modules[i].FullPathName; + LPCSTR NtPath = (LPCSTR)Modules->Modules[i].FullPathName; if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wintun.sys")) { if (ReturnOneIfRunningInsteadOfVersion) @@ -1199,14 +1067,13 @@ cleanupModules: return RET_ERROR(Version, LastError); } -DWORD WINAPI -WintunGetRunningDriverVersion(void) +_Use_decl_annotations_ +DWORD WINAPI WintunGetRunningDriverVersion(VOID) { return MaybeGetRunningDriverVersion(FALSE); } -static BOOL -EnsureWintunUnloaded(void) +static BOOL EnsureWintunUnloaded(VOID) { BOOL Loaded; for (int i = 0; (Loaded = MaybeGetRunningDriverVersion(TRUE) != 0) != FALSE && i < 300; ++i) @@ -1214,10 +1081,32 @@ EnsureWintunUnloaded(void) return !Loaded; } -static _Return_type_success_(return != FALSE) BOOL SelectDriver( +static VOID +SelectDriverDeferredCleanup(_In_ HDEVINFO DevInfoExistingAdapters, _In_opt_ SP_DEVINFO_DATA_LIST *ExistingAdapters) +{ + if (ExistingAdapters) + { + EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters); + while (ExistingAdapters) + { + SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; + Free(ExistingAdapters); + ExistingAdapters = Next; + } + } + if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE) + SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters); +} + +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +SelectDriver( _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, - _Inout_ SP_DEVINSTALL_PARAMS_W *DevInstallParams) + _Inout_ SP_DEVINSTALL_PARAMS_W *DevInstallParams, + _Out_ HDEVINFO *DevInfoExistingAdaptersForCleanup, + _Out_ SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup) { static const FILETIME OurDriverDate = WINTUN_INF_FILETIME; static const DWORDLONG OurDriverVersion = WINTUN_INF_VERSION; @@ -1313,7 +1202,7 @@ static _Return_type_success_(return != FALSE) BOOL SelectDriver( (DWORD)((OurDriverVersion & 0xffff000000000000) >> 48), (DWORD)((OurDriverVersion & 0x0000ffff00000000) >> 32)); WCHAR RandomTempSubDirectory[MAX_PATH]; - if (!CreateTemporaryDirectory(RandomTempSubDirectory)) + if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory)) { LastError = LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory); goto cleanupExistingAdapters; @@ -1363,7 +1252,7 @@ static _Return_type_success_(return != FALSE) BOOL SelectDriver( } if (!SetupDiSetDeviceInstallParamsW(DevInfo, DevInfoData, DevInstallParams)) { - LastError = LOG_LAST_ERROR(L"Setting adapter %u device installation parameters failed", DevInfoData->DevInst); + LastError = LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", DevInfoData->DevInst); goto cleanupDelete; } if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER)) @@ -1393,18 +1282,13 @@ cleanupDelete: cleanupDirectory: RemoveDirectoryW(RandomTempSubDirectory); cleanupExistingAdapters: - if (ExistingAdapters) + if (LastError == ERROR_SUCCESS) { - EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters); - while (ExistingAdapters) - { - SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; - Free(ExistingAdapters); - ExistingAdapters = Next; - } + *DevInfoExistingAdaptersForCleanup = DevInfoExistingAdapters; + *ExistingAdaptersForCleanup = ExistingAdapters; } - if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE) - SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters); + else + SelectDriverDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); if (DestroyDriverInfoListOnCleanup) SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER); cleanupDriverInstallationLock: @@ -1412,73 +1296,136 @@ cleanupDriverInstallationLock: return RET_ERROR(TRUE, LastError); } -static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( - _In_z_ const WCHAR *Pool, - _In_z_ const WCHAR *Name, - _In_opt_ const GUID *RequestedGUID, - _Inout_ BOOL *RebootRequired) +_Use_decl_annotations_ +WINTUN_ADAPTER * +AdapterOpenFromDevInstanceId(LPCWSTR Pool, LPCWSTR DevInstanceID) { + WINTUN_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); + if (!Adapter) + return FALSE; + + DWORD LastError = ERROR_SUCCESS; + HANDLE Mutex = NamespaceTakePoolMutex(Pool); + if (!Mutex) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Pool); + goto cleanup; + } + Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (Adapter->DevInfo == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); + goto cleanupMutex; + } + Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); + if (!SetupDiOpenDeviceInfoW(Adapter->DevInfo, DevInstanceID, NULL, 0, &Adapter->DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to open device instance ID %s", DevInstanceID); + goto cleanupMutex; + } + if (!PopulateAdapterData(Adapter, Pool)) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); + goto cleanupMutex; + } +cleanupMutex: + NamespaceReleaseMutex(Mutex); +cleanup: + if (LastError != ERROR_SUCCESS) + WintunFreeAdapter(Adapter); + return RET_ERROR(Adapter, LastError); +} + +_Use_decl_annotations_ +WINTUN_ADAPTER_HANDLE WINAPI +WintunCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired) +{ + BOOL DummyRebootRequired; + if (!RebootRequired) + RebootRequired = &DummyRebootRequired; + *RebootRequired = FALSE; + +#ifdef MAYBE_WOW64 + if (NativeMachine != IMAGE_FILE_PROCESS) + return CreateAdapterViaRundll32(Pool, Name, RequestedGUID, RebootRequired); +#endif + + DWORD LastError = ERROR_SUCCESS; LOG(WINTUN_LOG_INFO, L"Creating adapter"); - if (!IsWindows10()) + if (!IsWindows10) RequestedGUID = NULL; - HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); - if (DevInfo == INVALID_HANDLE_VALUE) - { - LOG_LAST_ERROR(L"Creating empty device information set failed"); + WINTUN_ADAPTER *Adapter = Zalloc(sizeof(*Adapter)); + if (!Adapter) return NULL; + + Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (Adapter->DevInfo == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to create empty device information set"); + goto cleanupAdapter; } - DWORD LastError; - WINTUN_ADAPTER *Adapter = NULL; WCHAR ClassName[MAX_CLASS_NAME_LEN]; if (!SetupDiClassNameFromGuidExW(&GUID_DEVCLASS_NET, ClassName, _countof(ClassName), NULL, NULL, NULL)) { - LastError = LOG_LAST_ERROR(L"Retrieving class name associated with class GUID failed"); - goto cleanupDevInfo; + LastError = LOG_LAST_ERROR(L"Failed to retrieve class name associated with class GUID"); + goto cleanupAdapter; } WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; if (!GetPoolDeviceTypeName(Pool, PoolDeviceTypeName)) { LastError = GetLastError(); - goto cleanupDevInfo; + goto cleanupAdapter; } - SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; + Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData); if (!SetupDiCreateDeviceInfoW( - DevInfo, ClassName, &GUID_DEVCLASS_NET, PoolDeviceTypeName, NULL, DICD_GENERATE_ID, &DevInfoData)) + Adapter->DevInfo, + ClassName, + &GUID_DEVCLASS_NET, + PoolDeviceTypeName, + NULL, + DICD_GENERATE_ID, + &Adapter->DevInfoData)) { - LastError = LOG_LAST_ERROR(L"Creating new device information element failed"); - goto cleanupDevInfo; + LastError = LOG_LAST_ERROR(L"Failed to create new device information element"); + goto cleanupAdapter; } - SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(SP_DEVINSTALL_PARAMS_W) }; - if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; + if (!SetupDiGetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) { - LastError = LOG_LAST_ERROR(L"Retrieving adapter %u device installation parameters failed", DevInfoData.DevInst); - goto cleanupDevInfo; + LastError = LOG_LAST_ERROR( + L"Failed to retrieve adapter %u device installation parameters", Adapter->DevInfoData.DevInst); + goto cleanupAdapter; } DevInstallParams.Flags |= DI_QUIETINSTALL; - if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + if (!SetupDiSetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) { - LastError = LOG_LAST_ERROR(L"Setting adapter %u device installation parameters failed", DevInfoData.DevInst); - goto cleanupDevInfo; + LastError = + LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", Adapter->DevInfoData.DevInst); + goto cleanupAdapter; } - if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData)) + if (!SetupDiSetSelectedDevice(Adapter->DevInfo, &Adapter->DevInfoData)) { - LastError = LOG_LAST_ERROR(L"Failed selecting adapter %u device", DevInfoData.DevInst); - goto cleanupDevInfo; + LastError = LOG_LAST_ERROR(L"Failed to select adapter %u device", Adapter->DevInfoData.DevInst); + goto cleanupAdapter; } static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID; - if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) + if (!SetupDiSetDeviceRegistryPropertyW( + Adapter->DevInfo, &Adapter->DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) { - LastError = LOG_LAST_ERROR(L"Failed setting adapter %u hardware ID", DevInfoData.DevInst); - goto cleanupDevInfo; + LastError = LOG_LAST_ERROR(L"Failed to set adapter %u hardware ID", Adapter->DevInfoData.DevInst); + goto cleanupAdapter; } - if (!SelectDriver(DevInfo, &DevInfoData, &DevInstallParams)) + HDEVINFO DevInfoExistingAdapters; + SP_DEVINFO_DATA_LIST *ExistingAdapters; + if (!SelectDriver( + Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams, &DevInfoExistingAdapters, &ExistingAdapters)) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to select adapter %u driver", DevInfoData.DevInst); - goto cleanupDevInfo; + LastError = LOG(WINTUN_LOG_ERR, L"Failed to select adapter %u driver", Adapter->DevInfoData.DevInst); + goto cleanupAdapter; } HANDLE Mutex = NamespaceTakePoolMutex(Pool); @@ -1488,13 +1435,13 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( goto cleanupDriverInfoList; } - if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData)) + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, Adapter->DevInfo, &Adapter->DevInfoData)) { - LastError = LOG_LAST_ERROR(L"Registering adapter %u device failed", DevInfoData.DevInst); + LastError = LOG_LAST_ERROR(L"Failed to register adapter %u device", Adapter->DevInfoData.DevInst); goto cleanupDevice; } - if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData)) - LOG_LAST_ERROR(L"Registering adapter %u coinstallers failed", DevInfoData.DevInst); + if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, Adapter->DevInfo, &Adapter->DevInfoData)) + LOG_LAST_ERROR(L"Failed to register adapter %u coinstallers", Adapter->DevInfoData.DevInst); HKEY NetDevRegKey = INVALID_HANDLE_VALUE; const int PollTimeout = 50 /* ms */; @@ -1503,11 +1450,17 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( if (i) Sleep(PollTimeout); NetDevRegKey = SetupDiOpenDevRegKey( - DevInfo, &DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY); + Adapter->DevInfo, + &Adapter->DevInfoData, + DICS_FLAG_GLOBAL, + 0, + DIREG_DRV, + KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY); } if (NetDevRegKey == INVALID_HANDLE_VALUE) { - LastError = LOG_LAST_ERROR(L"Failed to open adapter %u device-specific registry key", DevInfoData.DevInst); + LastError = + LOG_LAST_ERROR(L"Failed to open adapter %u device-specific registry key", Adapter->DevInfoData.DevInst); goto cleanupDevice; } if (RequestedGUID) @@ -1523,43 +1476,43 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( } } - if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData)) - LOG_LAST_ERROR(L"Installing adapter %u interfaces failed", DevInfoData.DevInst); + if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, Adapter->DevInfo, &Adapter->DevInfoData)) + LOG_LAST_ERROR(L"Failed to install adapter %u interfaces", Adapter->DevInfoData.DevInst); - if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData)) + if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, Adapter->DevInfo, &Adapter->DevInfoData)) { - LastError = LOG_LAST_ERROR(L"Installing adapter %u device failed", DevInfoData.DevInst); + LastError = LOG_LAST_ERROR(L"Failed to install adapter %u device", Adapter->DevInfoData.DevInst); goto cleanupNetDevRegKey; } - *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); + *RebootRequired = *RebootRequired || CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData); if (!SetupDiSetDevicePropertyW( - DevInfo, - &DevInfoData, + Adapter->DevInfo, + &Adapter->DevInfoData, &DEVPKEY_Wintun_Pool, DEVPROP_TYPE_STRING, #pragma warning(suppress : 4090) (const BYTE *)Pool, - (DWORD)((wcslen(Pool) + 1) * sizeof(WCHAR)), + (DWORD)((wcslen(Pool) + 1) * sizeof(*Pool)), 0)) { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u pool", DevInfoData.DevInst); + LastError = LOG_LAST_ERROR(L"Failed to set adapter %u pool", Adapter->DevInfoData.DevInst); goto cleanupNetDevRegKey; } if (!SetupDiSetDeviceRegistryPropertyW( - DevInfo, - &DevInfoData, + Adapter->DevInfo, + &Adapter->DevInfoData, SPDRP_DEVICEDESC, (const BYTE *)PoolDeviceTypeName, - (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(WCHAR)))) + (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(*PoolDeviceTypeName)))) { - LastError = LOG_LAST_ERROR(L"Failed to set adapter %u description", DevInfoData.DevInst); + LastError = LOG_LAST_ERROR(L"Failed to set adapter %u description", Adapter->DevInfoData.DevInst); goto cleanupNetDevRegKey; } /* DIF_INSTALLDEVICE returns almost immediately, while the device installation continues in the background. It might * take a while, before all registry keys and values are populated. */ - WCHAR *DummyStr = RegistryQueryStringWait(NetDevRegKey, L"NetCfgInstanceId", WAIT_FOR_REGISTRY_TIMEOUT); + LPWSTR DummyStr = RegistryQueryStringWait(NetDevRegKey, L"NetCfgInstanceId", WAIT_FOR_REGISTRY_TIMEOUT); if (!DummyStr) { WCHAR RegPath[MAX_REG_PATH]; @@ -1584,10 +1537,9 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( goto cleanupNetDevRegKey; } - Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); - if (!Adapter) + if (!PopulateAdapterData(Adapter, Pool)) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to create adapter %u data", DevInfoData.DevInst); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); goto cleanupNetDevRegKey; } @@ -1663,8 +1615,8 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( DEVPROPTYPE PropertyType; NTSTATUS ProblemStatus; if (SetupDiGetDevicePropertyW( - DevInfo, - &DevInfoData, + Adapter->DevInfo, + &Adapter->DevInfoData, &DEVPKEY_Device_ProblemStatus, &PropertyType, (PBYTE)&ProblemStatus, @@ -1677,8 +1629,8 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( { INT32 ProblemCode; if (!SetupDiGetDevicePropertyW( - DevInfo, - &DevInfoData, + Adapter->DevInfo, + &Adapter->DevInfoData, &DEVPKEY_Device_ProblemCode, &PropertyType, (PBYTE)&ProblemCode, @@ -1707,112 +1659,46 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( cleanupTcpipAdapterRegKey: RegCloseKey(TcpipAdapterRegKey); -cleanupAdapter: - if (LastError != ERROR_SUCCESS) - { - Free(Adapter); - Adapter = NULL; - } cleanupNetDevRegKey: RegCloseKey(NetDevRegKey); cleanupDevice: if (LastError != ERROR_SUCCESS) { - /* The adapter failed to install, or the adapter ID was unobtainable. Clean-up. */ SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), .InstallFunction = DIF_REMOVE }, .Scope = DI_REMOVEDEVICE_GLOBAL }; if (SetupDiSetClassInstallParamsW( - DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) && - SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) - *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); + Adapter->DevInfo, + &Adapter->DevInfoData, + &RemoveDeviceParams.ClassInstallHeader, + sizeof(RemoveDeviceParams)) && + SetupDiCallClassInstaller(DIF_REMOVE, Adapter->DevInfo, &Adapter->DevInfoData)) + *RebootRequired = *RebootRequired || CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData); } NamespaceReleaseMutex(Mutex); cleanupDriverInfoList: - SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); -cleanupDevInfo: - SetupDiDestroyDeviceInfoList(DevInfo); + SelectDriverDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters); + SetupDiDestroyDriverInfoList(Adapter->DevInfo, &Adapter->DevInfoData, SPDIT_COMPATDRIVER); +cleanupAdapter: + if (LastError != ERROR_SUCCESS) + WintunFreeAdapter(Adapter); return RET_ERROR(Adapter, LastError); } -static _Return_type_success_(return != NULL) - WINTUN_ADAPTER *GetAdapter(_In_z_ const WCHAR *Pool, _In_ const GUID *CfgInstanceID) -{ - HANDLE Mutex = NamespaceTakePoolMutex(Pool); - if (!Mutex) - { - LOG(WINTUN_LOG_ERR, L"Failed to take %s pool mutex", Pool); - return NULL; - } - DWORD LastError; - WINTUN_ADAPTER *Adapter = NULL; - HDEVINFO DevInfo; - SP_DEVINFO_DATA DevInfoData; - if (!GetDevInfoData(CfgInstanceID, &DevInfo, &DevInfoData)) - { - WCHAR Guid[MAX_GUID_STRING_LEN]; - LastError = - LOG(WINTUN_LOG_ERR, - L"Failed to locate adapter %.*s", - StringFromGUID2(CfgInstanceID, Guid, _countof(Guid)), - Guid); - goto cleanupMutex; - } - Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); - LastError = Adapter ? ERROR_SUCCESS : LOG(WINTUN_LOG_ERR, L"Failed to create adapter %u data", DevInfoData.DevInst); - SetupDiDestroyDeviceInfoList(DevInfo); -cleanupMutex: - NamespaceReleaseMutex(Mutex); - return RET_ERROR(Adapter, LastError); -} - -#include "rundll32_i.c" - -_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI WintunCreateAdapter( - _In_z_ const WCHAR *Pool, - _In_z_ const WCHAR *Name, - _In_opt_ const GUID *RequestedGUID, - _Out_opt_ BOOL *RebootRequired) +_Use_decl_annotations_ +BOOL WINAPI +WintunDeleteAdapter(WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired) { BOOL DummyRebootRequired; if (!RebootRequired) RebootRequired = &DummyRebootRequired; *RebootRequired = FALSE; - DWORD LastError; - WINTUN_ADAPTER *Adapter; #ifdef MAYBE_WOW64 if (NativeMachine != IMAGE_FILE_PROCESS) - { - Adapter = CreateAdapterViaRundll32(Pool, Name, RequestedGUID, RebootRequired); - LastError = Adapter ? ERROR_SUCCESS : GetLastError(); - goto cleanup; - } -#endif - Adapter = CreateAdapter(Pool, Name, RequestedGUID, RebootRequired); - LastError = Adapter ? ERROR_SUCCESS : GetLastError(); -cleanup: - return RET_ERROR(Adapter, LastError); -} - -_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter( - _In_ const WINTUN_ADAPTER *Adapter, - _In_ BOOL ForceCloseSessions, - _Out_opt_ BOOL *RebootRequired) -{ - BOOL DummyRebootRequired; - if (!RebootRequired) - RebootRequired = &DummyRebootRequired; - *RebootRequired = FALSE; - DWORD LastError; -#ifdef MAYBE_WOW64 - if (NativeMachine != IMAGE_FILE_PROCESS) - { - LastError = - DeleteAdapterViaRundll32(Adapter, ForceCloseSessions, RebootRequired) ? ERROR_SUCCESS : GetLastError(); - goto cleanup; - } + return DeleteAdapterViaRundll32(Adapter, ForceCloseSessions, RebootRequired); #endif + DWORD LastError = ERROR_SUCCESS; HANDLE Mutex = NamespaceTakePoolMutex(Adapter->Pool); if (!Mutex) { @@ -1820,49 +1706,44 @@ _Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter( goto cleanup; } - HDEVINFO DevInfo; - SP_DEVINFO_DATA DevInfoData; - if (!GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData)) + SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; + if (!SetupDiGetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) { - if ((LastError = GetLastError()) == ERROR_FILE_NOT_FOUND) - LastError = ERROR_SUCCESS; - else - { - WCHAR Guid[MAX_GUID_STRING_LEN]; - LOG(WINTUN_LOG_ERR, - L"Failed to get adapter %.*s info data", - StringFromGUID2(&Adapter->CfgInstanceID, Guid, _countof(Guid)), - Guid); - } + LastError = LOG_LAST_ERROR( + L"Failed to retrieve adapter %u device installation parameters", Adapter->DevInfoData.DevInst); + goto cleanupMutex; + } + DevInstallParams.Flags |= DI_QUIETINSTALL; + if (!SetupDiSetDeviceInstallParamsW(Adapter->DevInfo, &Adapter->DevInfoData, &DevInstallParams)) + { + LastError = + LOG_LAST_ERROR(L"Failed to set adapter %u device installation parameters", Adapter->DevInfoData.DevInst); goto cleanupMutex; } - if (ForceCloseSessions && !ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData)) - LOG(WINTUN_LOG_WARN, L"Failed to force close adapter %u handles", DevInfoData.DevInst); + if (ForceCloseSessions && !ForceCloseWintunAdapterHandle(Adapter->DevInfo, &Adapter->DevInfoData)) + LOG(WINTUN_LOG_WARN, L"Failed to force close adapter %u handles", Adapter->DevInfoData.DevInst); - SetQuietInstall(DevInfo, &DevInfoData); SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), .InstallFunction = DIF_REMOVE }, .Scope = DI_REMOVEDEVICE_GLOBAL }; - if ((!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) && + if ((!SetupDiSetClassInstallParamsW( + Adapter->DevInfo, &Adapter->DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || + !SetupDiCallClassInstaller(DIF_REMOVE, Adapter->DevInfo, &Adapter->DevInfoData)) && GetLastError() != ERROR_NO_SUCH_DEVINST) - { - LastError = LOG_LAST_ERROR(L"Failed to remove adapter %u", DevInfoData.DevInst); - goto cleanupDevInfo; - } - LastError = ERROR_SUCCESS; -cleanupDevInfo: - *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); - SetupDiDestroyDeviceInfoList(DevInfo); + LastError = LOG_LAST_ERROR(L"Failed to remove adapter %u", Adapter->DevInfoData.DevInst); + + *RebootRequired = *RebootRequired || CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData); + cleanupMutex: NamespaceReleaseMutex(Mutex); cleanup: return RET_ERROR(TRUE, LastError); } -static _Return_type_success_(return != FALSE) BOOL - DeleteAllOurAdapters(_In_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired) +static _Return_type_success_(return != FALSE) +BOOL +DeleteAllOurAdapters(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired) { HANDLE Mutex = NamespaceTakePoolMutex(Pool); if (!Mutex) @@ -1913,8 +1794,9 @@ cleanupMutex: return RET_ERROR(TRUE, LastError); } -_Return_type_success_(return != FALSE) BOOL WINAPI - WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired) +_Use_decl_annotations_ +BOOL WINAPI +WintunDeletePoolDriver(LPCWSTR Pool, BOOL *RebootRequired) { BOOL DummyRebootRequired; if (!RebootRequired) @@ -1986,8 +1868,9 @@ cleanup: return RET_ERROR(TRUE, LastError); } -_Return_type_success_(return != FALSE) BOOL WINAPI - WintunEnumAdapters(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK Func, _In_ LPARAM Param) +_Use_decl_annotations_ +BOOL WINAPI +WintunEnumAdapters(LPCWSTR Pool, WINTUN_ENUM_CALLBACK Func, LPARAM Param) { DWORD LastError = ERROR_SUCCESS; HANDLE Mutex = NamespaceTakePoolMutex(Pool); @@ -2005,25 +1888,23 @@ _Return_type_success_(return != FALSE) BOOL WINAPI BOOL Continue = TRUE; for (DWORD EnumIndex = 0; Continue; ++EnumIndex) { - SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; - if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + WINTUN_ADAPTER Adapter = { .DevInfo = DevInfo, .DevInfoData.cbSize = sizeof(Adapter.DevInfoData) }; + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &Adapter.DevInfoData)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) break; continue; } - if (!IsOurAdapter(DevInfo, &DevInfoData) || !IsPoolMember(Pool, DevInfo, &DevInfoData)) + if (!IsOurAdapter(DevInfo, &Adapter.DevInfoData) || !IsPoolMember(Pool, DevInfo, &Adapter.DevInfoData)) continue; - WINTUN_ADAPTER *Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); - if (!Adapter) + if (!PopulateAdapterData(&Adapter, Pool)) { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to create adapter %u data", DevInfoData.DevInst); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter %u data", Adapter.DevInfoData.DevInst); break; } - Continue = Func(Adapter, Param); - Free(Adapter); + Continue = Func(&Adapter, Param); } SetupDiDestroyDeviceInfoList(DevInfo); cleanupMutex: diff --git a/api/adapter.h b/api/adapter.h index 940330b..5f468b0 100644 --- a/api/adapter.h +++ b/api/adapter.h @@ -13,58 +13,96 @@ #define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ #define WINTUN_HWID L"Wintun" -void -AdapterInit(void); - /** * Wintun adapter descriptor. */ typedef struct _WINTUN_ADAPTER { + HDEVINFO DevInfo; + SP_DEVINFO_DATA DevInfoData; GUID CfgInstanceID; WCHAR DevInstanceID[MAX_INSTANCE_ID]; DWORD LuidIndex; DWORD IfType; + DWORD IfIndex; WCHAR Pool[WINTUN_MAX_POOL]; } WINTUN_ADAPTER; /** * @copydoc WINTUN_FREE_ADAPTER_FUNC */ -void WINAPI -WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter); +WINTUN_FREE_ADAPTER_FUNC_IMPL WintunFreeAdapter; /** * @copydoc WINTUN_CREATE_ADAPTER_FUNC */ -_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI WintunCreateAdapter( - _In_z_ const WCHAR *Pool, - _In_z_ const WCHAR *Name, - _In_opt_ const GUID *RequestedGUID, - _Out_opt_ BOOL *RebootRequired); +WINTUN_CREATE_ADAPTER_FUNC_IMPL WintunCreateAdapter; + +/** + * @copydoc WINTUN_OPEN_ADAPTER_FUNC + */ +WINTUN_OPEN_ADAPTER_FUNC_IMPL WintunOpenAdapter; /** * @copydoc WINTUN_DELETE_ADAPTER_FUNC */ -_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter( - _In_ const WINTUN_ADAPTER *Adapter, - _In_ BOOL ForceCloseSessions, - _Out_opt_ BOOL *RebootRequired); +WINTUN_DELETE_ADAPTER_FUNC_IMPL WintunDeleteAdapter; + +/** + * @copydoc WINTUN_ENUM_ADAPTERS_FUNC + */ +WINTUN_ENUM_ADAPTERS_FUNC_IMPL WintunEnumAdapters; /** * @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC */ -_Return_type_success_(return != FALSE) BOOL WINAPI - WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired); +WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL WintunDeletePoolDriver; + +/** + * @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. * * @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 - * CloseHandle. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error + * @return If the function succeeds, the return value is adapter device object handle. + * If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error * information, call GetLastError. */ -_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI - AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter); \ No newline at end of file +_Return_type_success_(return != INVALID_HANDLE_VALUE) +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); diff --git a/api/api.vcxproj b/api/api.vcxproj index 00a6266..9c477cd 100644 --- a/api/api.vcxproj +++ b/api/api.vcxproj @@ -53,15 +53,13 @@ - - true - + diff --git a/api/logger.c b/api/logger.c index 253d525..71dff5b 100644 --- a/api/logger.c +++ b/api/logger.c @@ -4,6 +4,7 @@ */ #include "logger.h" +#include "adapter.h" #include "ntdll.h" #include #include @@ -11,17 +12,16 @@ #include 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; } WINTUN_LOGGER_CALLBACK Logger = NopLogger; -void CALLBACK -WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger) +_Use_decl_annotations_ +VOID WINAPI +WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger) { if (!NewLogger) NewLogger = NopLogger; @@ -29,14 +29,15 @@ WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger) } 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 - 1] = 0; } -_Post_equals_last_error_ DWORD -LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine) +_Use_decl_annotations_ +DWORD +LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR LogLine) { DWORD LastError = GetLastError(); if (Function) @@ -52,12 +53,9 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c return LastError; } -_Post_equals_last_error_ DWORD -LoggerLogV( - _In_ WINTUN_LOGGER_LEVEL Level, - _In_z_ const WCHAR *Function, - _In_z_ _Printf_format_string_ const WCHAR *Format, - _In_ va_list Args) +_Use_decl_annotations_ +DWORD +LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR Format, va_list Args) { DWORD LastError = GetLastError(); WCHAR LogLine[0x400]; @@ -71,16 +69,17 @@ LoggerLogV( return LastError; } -_Post_equals_last_error_ DWORD -LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix) +_Use_decl_annotations_ +DWORD +LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix) { - WCHAR *SystemMessage = NULL, *FormattedMessage = NULL; + LPWSTR SystemMessage = NULL, FormattedMessage = NULL; FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, HRESULT_FROM_SETUPAPI(Error), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (void *)&SystemMessage, + (VOID *)&SystemMessage, 0, NULL); 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!", 0, 0, - (void *)&FormattedMessage, + (VOID *)&FormattedMessage, 0, (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function }); if (FormattedMessage) @@ -99,12 +98,9 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR * return Error; } -_Post_equals_last_error_ DWORD -LoggerErrorV( - _In_ DWORD Error, - _In_z_ const WCHAR *Function, - _In_z_ _Printf_format_string_ const WCHAR *Format, - _In_ va_list Args) +_Use_decl_annotations_ +DWORD +LoggerErrorV(DWORD Error, LPCWSTR Function, LPCWSTR Format, va_list Args) { WCHAR Prefix[0x400]; if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1) @@ -112,13 +108,14 @@ LoggerErrorV( return LoggerError(Error, Function, Prefix); } +_Use_decl_annotations_ VOID -LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) +LoggerGetRegistryKeyPath(HKEY Key, LPWSTR Path) { DWORD LastError = GetLastError(); if (Key == NULL) { - wcscpy_s(Path, MAX_REG_PATH, L""); + wcsncpy_s(Path, MAX_REG_PATH, L"", _TRUNCATE); goto out; } if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1) diff --git a/api/logger.h b/api/logger.h index 0ba4d55..72853cc 100644 --- a/api/logger.h +++ b/api/logger.h @@ -9,6 +9,7 @@ #include "main.h" #include "registry.h" #include +#include #include #include @@ -17,25 +18,23 @@ extern WINTUN_LOGGER_CALLBACK Logger; /** * @copydoc WINTUN_SET_LOGGER_FUNC */ -void WINAPI -WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger); +WINTUN_SET_LOGGER_FUNC_IMPL WintunSetLogger; -_Post_equals_last_error_ DWORD -LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine); +_Post_equals_last_error_ +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( _In_ WINTUN_LOGGER_LEVEL Level, - _In_z_ const WCHAR *Function, - _In_z_ _Printf_format_string_ const WCHAR *Format, + _In_z_ LPCWSTR Function, + _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args); -static inline _Post_equals_last_error_ DWORD -LoggerLogFmt( - _In_ WINTUN_LOGGER_LEVEL Level, - _In_z_ const WCHAR *Function, - _In_z_ _Printf_format_string_ const WCHAR *Format, - ...) +_Post_equals_last_error_ +static inline DWORD +LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) { va_list Args; va_start(Args, Format); @@ -44,18 +43,21 @@ LoggerLogFmt( return LastError; } -_Post_equals_last_error_ DWORD -LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix); +_Post_equals_last_error_ +DWORD +LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR Prefix); -_Post_equals_last_error_ DWORD +_Post_equals_last_error_ +DWORD LoggerErrorV( _In_ DWORD Error, - _In_z_ const WCHAR *Function, - _In_z_ _Printf_format_string_ const WCHAR *Format, + _In_z_ LPCWSTR Function, + _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args); -static inline _Post_equals_last_error_ DWORD -LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...) +_Post_equals_last_error_ +static inline DWORD +LoggerErrorFmt(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) { va_list Args; va_start(Args, Format); @@ -64,8 +66,9 @@ LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_fo return LastError; } -static inline _Post_equals_last_error_ DWORD -LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, _In_ va_list Args) +_Post_equals_last_error_ +static inline DWORD +LoggerLastErrorV(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args) { DWORD LastError = GetLastError(); LoggerErrorV(LastError, Function, Format, Args); @@ -73,8 +76,9 @@ LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ con return LastError; } -static inline _Post_equals_last_error_ DWORD -LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...) +_Post_equals_last_error_ +static inline DWORD +LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) { va_list Args; va_start(Args, Format); @@ -84,7 +88,7 @@ LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ c } 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) @@ -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)) -static inline _Return_type_success_(return != NULL) _Ret_maybenull_ - _Post_writable_byte_size_(Size) void *LoggerAlloc(_In_z_ const WCHAR *Function, _In_ DWORD Flags, _In_ SIZE_T Size) +_Must_inspect_result_ +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) { 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; } #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 ReZalloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Size) -static inline void -Free(void *Ptr) +_Must_inspect_result_ +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) return; diff --git a/api/main.c b/api/main.c index 16d3b7c..294f35d 100644 --- a/api/main.c +++ b/api/main.c @@ -3,18 +3,15 @@ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. */ -#include "adapter.h" #include "logger.h" -#include "registry.h" +#include "adapter.h" +#include "main.h" #include "namespace.h" -#include "wintun.h" +#include "registry.h" +#include "ntdll.h" #include -#pragma warning(push) -#pragma warning(disable : 4201) -/* nonstandard extension used: nameless struct/union */ #include -#pragma warning(pop) #include #include #include @@ -23,6 +20,8 @@ HINSTANCE ResourceModule; HANDLE ModuleHeap; SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) }; BOOL IsLocalSystem; +USHORT NativeMachine = IMAGE_FILE_PROCESS; +BOOL IsWindows10; static FARPROC WINAPI DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) @@ -37,8 +36,7 @@ DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook; -static BOOL -InitializeSecurityObjects(void) +static BOOL InitializeSecurityObjects(VOID) { BYTE LocalSystemSid[MAX_SID_SIZE]; DWORD RequiredBytes = sizeof(LocalSystemSid); @@ -72,11 +70,32 @@ cleanupProcessToken: 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 DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) { - UNREFERENCED_PARAMETER(lpvReserved); - switch (fdwReason) { case DLL_PROCESS_ATTACH: @@ -89,7 +108,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) HeapDestroy(ModuleHeap); return FALSE; } - AdapterInit(); + EnvInit(); NamespaceInit(); break; diff --git a/api/main.h b/api/main.h index 9f6b0de..5d3ebb1 100644 --- a/api/main.h +++ b/api/main.h @@ -7,26 +7,21 @@ #include -/* TODO: Replace with is_defined. MSVC has issues with the linux kernel varadic macro trick for this. */ -#if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) -# define MAYBE_WOW64 1 +#if defined(_M_IX86) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386 +#elif defined(_M_AMD64) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64 +#elif defined(_M_ARM) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT +#elif defined(_M_ARM64) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64 #else -# define MAYBE_WOW64 0 +# error Unsupported architecture #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 HANDLE ModuleHeap; extern SECURITY_ATTRIBUTES SecurityAttributes; extern BOOL IsLocalSystem; +extern USHORT NativeMachine; +extern BOOL IsWindows10; \ No newline at end of file diff --git a/api/namespace.c b/api/namespace.c index 8f1449a..760dc6f 100644 --- a/api/namespace.c +++ b/api/namespace.c @@ -19,13 +19,16 @@ static HANDLE BoundaryDescriptor = NULL; static CRITICAL_SECTION Initializing; static BCRYPT_ALG_HANDLE AlgProvider; -static _Return_type_success_( - return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source) +_Must_inspect_result_ +static _Return_type_success_(return != NULL) +_Post_maybenull_ +LPWSTR +NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ LPCWSTR Source) { int Len = NormalizeString(NormForm, Source, -1, NULL, 0); for (;;) { - WCHAR *Str = Alloc(sizeof(WCHAR) * Len); + LPWSTR Str = AllocArray(Len, sizeof(*Str)); if (!Str) return NULL; 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; @@ -110,8 +114,9 @@ cleanupLeaveCriticalSection: return FALSE; } -_Check_return_ -_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool) +_Use_decl_annotations_ +HANDLE +NamespaceTakePoolMutex(LPCWSTR Pool) { if (!NamespaceRuntimeInit()) return NULL; @@ -133,7 +138,7 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const LastError = RtlNtStatusToDosError(Status); goto cleanupSha256; } - WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool); + LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool); if (!PoolNorm) { LastError = GetLastError(); @@ -184,8 +189,9 @@ cleanupSha256: return NULL; } -_Check_return_ -_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void) +_Use_decl_annotations_ +HANDLE +NamespaceTakeDriverInstallationMutex(VOID) { if (!NamespaceRuntimeInit()) return NULL; @@ -208,21 +214,20 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMute return NULL; } -void -NamespaceReleaseMutex(_In_ HANDLE Mutex) +_Use_decl_annotations_ +VOID +NamespaceReleaseMutex(HANDLE Mutex) { ReleaseMutex(Mutex); CloseHandle(Mutex); } -void -NamespaceInit(void) +VOID NamespaceInit(VOID) { InitializeCriticalSection(&Initializing); } -void -NamespaceDone(void) +VOID NamespaceDone(VOID) { EnterCriticalSection(&Initializing); if (PrivateNamespace) diff --git a/api/namespace.h b/api/namespace.h index 35d9930..cbd9100 100644 --- a/api/namespace.h +++ b/api/namespace.h @@ -7,17 +7,24 @@ #include -_Check_return_ -_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool); +_Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +_Acquires_lock_(_Curr_) +HANDLE +NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool); -_Check_return_ -_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void); +_Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +_Acquires_lock_(_Curr_) +HANDLE +NamespaceTakeDriverInstallationMutex(VOID); -void +_Releases_lock_(Mutex) +VOID NamespaceReleaseMutex(_In_ HANDLE Mutex); -void -NamespaceInit(void); +VOID NamespaceInit(VOID); -void -NamespaceDone(void); +VOID NamespaceDone(VOID); diff --git a/api/nci.h b/api/nci.h index 40e964e..ba99fa6 100644 --- a/api/nci.h +++ b/api/nci.h @@ -9,19 +9,23 @@ #ifdef GENERATE_LIB # define DECLSPEC __declspec(dllexport) -# define STUB { return 0; } +# define STUB \ + { \ + return 0; \ + } #else # define DECLSPEC __declspec(dllimport) # define STUB ; #endif +EXTERN_C +DECLSPEC DWORD WINAPI +NciSetConnectionName(_In_ const GUID *Guid, _In_z_ LPCWSTR NewName) STUB -EXTERN_C DECLSPEC DWORD WINAPI -NciSetConnectionName(_In_ const GUID *Guid, _In_z_ const WCHAR *NewName) STUB - -EXTERN_C DECLSPEC DWORD WINAPI + EXTERN_C +DECLSPEC DWORD WINAPI NciGetConnectionName( _In_ const GUID *Guid, - _Out_z_bytecap_(InDestNameBytes) WCHAR *Name, + _Out_z_bytecap_(InDestNameBytes) LPWSTR Name, _In_ DWORD InDestNameBytes, _Out_opt_ DWORD *OutDestNameBytes) STUB \ No newline at end of file diff --git a/api/ntdll.h b/api/ntdll.h index 825119b..3782a30 100644 --- a/api/ntdll.h +++ b/api/ntdll.h @@ -45,7 +45,7 @@ typedef struct _KEY_NAME_INFORMATION * when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers. * * 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: * *(DWORD *)0x7FFE026C */ @@ -61,9 +61,3 @@ NtQueryKey( _Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation, _In_ ULONG Length, _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); \ No newline at end of file diff --git a/api/registry.c b/api/registry.c index 5da05e7..d385d86 100644 --- a/api/registry.c +++ b/api/registry.c @@ -10,11 +10,14 @@ #include #include -static _Return_type_success_(return != NULL) HKEY - OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) +_Must_inspect_result_ +static _Return_type_success_(return != NULL) +_Post_maybenull_ +HKEY +OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) { DWORD LastError; - WCHAR *PathNext = wcschr(Path, L'\\'); + LPWSTR PathNext = wcschr(Path, L'\\'); if (PathNext) *PathNext = 0; @@ -87,8 +90,9 @@ static _Return_type_success_(return != NULL) HKEY return NULL; } -_Return_type_success_(return != NULL) HKEY - RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout) +_Use_decl_annotations_ +HKEY +RegistryOpenKeyWait(HKEY Key, LPCWSTR Path, DWORD Access, DWORD Timeout) { WCHAR Buf[MAX_REG_PATH]; if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE) @@ -100,17 +104,17 @@ _Return_type_success_(return != NULL) HKEY 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) { /* 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) return FALSE; - wmemcpy(BufZ, *Buf, Len); - BufZ[Len] = 0; - Free(*Buf); + _Analysis_assume_((wmemset(BufZ, L'A', (SIZE_T)Len + 1), TRUE)); *Buf = BufZ; } @@ -122,10 +126,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu if (!(*Buf)[0]) return TRUE; - Len = Len * 2 + 64; for (;;) { - WCHAR *Expanded = Alloc(Len * sizeof(WCHAR)); + LPWSTR Expanded = AllocArray(Len, sizeof(*Expanded)); if (!Expanded) return FALSE; 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 - RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) +_Use_decl_annotations_ +BOOL +RegistryGetMultiString(PZZWSTR *Buf, DWORD Len, DWORD ValueType) { if (ValueType == REG_MULTI_SZ) { @@ -157,25 +161,18 @@ _Return_type_success_(return != FALSE) BOOL if (i > Len) { /* 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) return FALSE; - wmemcpy(BufZ, *Buf, Len); - BufZ[Len] = 0; - BufZ[Len + 1] = 0; - Free(*Buf); *Buf = BufZ; return TRUE; } if (i == Len) { /* Missing list terminator. */ - WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR)); + PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ)); if (!BufZ) return FALSE; - wmemcpy(BufZ, *Buf, Len); - BufZ[Len] = 0; - Free(*Buf); *Buf = BufZ; return TRUE; } @@ -188,22 +185,19 @@ _Return_type_success_(return != FALSE) BOOL if (!RegistryGetString(Buf, Len, ValueType)) return FALSE; 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) return FALSE; - wmemcpy(BufZ, *Buf, Len); - BufZ[Len] = 0; - Free(*Buf); *Buf = BufZ; return TRUE; } -static _Return_type_success_(return != NULL) void *RegistryQuery( - _In_ HKEY Key, - _In_opt_z_ const WCHAR *Name, - _Out_opt_ DWORD *ValueType, - _Inout_ DWORD *BufLen, - _In_ BOOL Log) +_Must_inspect_result_ +static _Return_type_success_(return != NULL) +_Post_maybenull_ +_Post_writable_byte_size_(*BufLen) +VOID * +RegistryQuery(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_opt_ DWORD *ValueType, _Inout_ DWORD *BufLen, _In_ BOOL Log) { for (;;) { @@ -220,7 +214,7 @@ static _Return_type_success_(return != NULL) void *RegistryQuery( { WCHAR RegPath[MAX_REG_PATH]; 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); return NULL; @@ -228,11 +222,12 @@ static _Return_type_success_(return != NULL) void *RegistryQuery( } } -_Return_type_success_( - return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log) +_Use_decl_annotations_ +LPWSTR +RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log) { 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) return NULL; switch (ValueType) @@ -240,7 +235,7 @@ _Return_type_success_( case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: - if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType)) + if (RegistryGetString(&Value, Size / sizeof(*Value), ValueType)) return Value; LastError = GetLastError(); break; @@ -261,8 +256,9 @@ _Return_type_success_( return NULL; } -_Return_type_success_( - return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout) +_Use_decl_annotations_ +LPWSTR +RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout) { DWORD LastError; 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); break; } - WCHAR *Value = RegistryQueryString(Key, Name, FALSE); + LPWSTR Value = RegistryQueryString(Key, Name, FALSE); if (Value) { CloseHandle(Event); @@ -313,8 +309,9 @@ _Return_type_success_( return NULL; } -_Return_type_success_(return != FALSE) BOOL - RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log) +_Use_decl_annotations_ +BOOL +RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log) { DWORD ValueType, Size = sizeof(DWORD); 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]; 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); return FALSE; @@ -348,8 +345,9 @@ _Return_type_success_(return != FALSE) BOOL return TRUE; } -_Return_type_success_(return != FALSE) BOOL - RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value) +_Use_decl_annotations_ +BOOL +RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value) { DWORD LastError; ULONGLONG Deadline = GetTickCount64() + Timeout; @@ -398,73 +396,3 @@ _Return_type_success_(return != FALSE) BOOL SetLastError(LastError); 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); -} \ No newline at end of file diff --git a/api/registry.h b/api/registry.h index 106a79d..7a366b0 100644 --- a/api/registry.h +++ b/api/registry.h @@ -26,8 +26,11 @@ * @return Key handle on success. If the function fails, the return value is zero. To get extended error information, * call GetLastError. */ -_Return_type_success_(return != NULL) HKEY - RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout); +_Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +HKEY +RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ LPCWSTR Path, _In_ DWORD Access, _In_ DWORD Timeout); /** * Validates and/or sanitizes string value read from registry. @@ -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 * get extended error information, call GetLastError. */ -_Return_type_success_(return != FALSE) BOOL - RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); +_Must_inspect_result_ +_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. @@ -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 * get extended error information, call GetLastError. */ -_Return_type_success_(return != FALSE) BOOL - RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); +_Must_inspect_result_ +_Return_type_success_(return != FALSE) +BOOL +RegistryGetMultiString(_Inout_ PZZWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType); /** * Reads string value from registry key. @@ -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 * information, call GetLastError. */ -_Return_type_success_( - return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log); +_Must_inspect_result_ +_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. @@ -101,8 +111,11 @@ _Return_type_success_( * get extended error information, call GetLastError. Possible errors include the following: * ERROR_INVALID_DATATYPE when the registry value is not a string */ -_Return_type_success_( - return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout); +_Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +LPWSTR +RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout); /** * Reads a 32-bit DWORD value from registry key. @@ -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 * get extended error information, call GetLastError. */ -_Return_type_success_(return != FALSE) BOOL - RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log); +_Must_inspect_result_ +_Return_type_success_(return != FALSE) +BOOL +RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log); /** * Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available. @@ -139,17 +154,7 @@ _Return_type_success_(return != FALSE) BOOL * ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type; * ERROR_INVALID_DATA when registry value size is not 4 bytes */ -_Return_type_success_(return != FALSE) BOOL - RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *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); +_Must_inspect_result_ +_Return_type_success_(return != FALSE) +BOOL +RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value); diff --git a/api/resource.c b/api/resource.c index ce590e1..648f568 100644 --- a/api/resource.c +++ b/api/resource.c @@ -7,9 +7,12 @@ #include "main.h" #include "resource.h" #include +#include +#include -_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const - void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size) +_Use_decl_annotations_ +const VOID * +ResourceGetAddress(LPCWSTR ResourceName, DWORD *Size) { HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA); if (!FoundResource) @@ -39,11 +42,12 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const return Address; } -_Return_type_success_(return != FALSE) BOOL - ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName) +_Use_decl_annotations_ +BOOL +ResourceCopyToFile(LPCWSTR DestinationPath, LPCWSTR ResourceName) { DWORD SizeResource; - const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource); + const VOID *LockedResource = ResourceGetAddress(ResourceName, &SizeResource); if (!LockedResource) { LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", ResourceName); @@ -84,3 +88,42 @@ cleanupDestinationHandle: CloseHandle(DestinationHandle); 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; +} diff --git a/api/resource.h b/api/resource.h index 8938241..ae1210b 100644 --- a/api/resource.h +++ b/api/resource.h @@ -11,25 +11,40 @@ /** * 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 * information, call GetLastError. */ -_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const - void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size); +_Must_inspect_result_ +_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. * - * 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 * get extended error information, call GetLastError. */ -_Return_type_success_(return != FALSE) BOOL - ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName); +_Return_type_success_(return != FALSE) +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); diff --git a/api/rundll32.c b/api/rundll32.c index 99b1b26..77d7651 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -3,12 +3,14 @@ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. */ +#include "rundll32.h" #include "adapter.h" +#include "main.h" #include "logger.h" -#include "wintun.h" - +#include "resource.h" #include #include +#include #include #include #include @@ -18,10 +20,10 @@ # define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) static DWORD -WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) +WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...) { - WCHAR *FormattedMessage = NULL; - DWORD SizeWritten; + LPWSTR FormattedMessage = NULL; + DWORD Size; va_list Arguments; va_start(Arguments, Template); DWORD Len = FormatMessageW( @@ -29,19 +31,22 @@ WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) Template, 0, 0, - (void *)&FormattedMessage, + (VOID *)&FormattedMessage, 0, &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); va_end(Arguments); - return SizeWritten / sizeof(WCHAR); + return Size / sizeof(*FormattedMessage); } -static void CALLBACK -ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) +static VOID CALLBACK +ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine) { - const WCHAR *Template; + LPCWSTR Template; switch (Level) { 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); } -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) { # pragma EXPORT - Init(); + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + WintunSetLogger(ConsoleLogger); + if (Argc < 4) goto cleanup; if (wcslen(Argv[2]) >= WINTUN_MAX_POOL) @@ -95,47 +85,52 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int BOOL RebootRequired; WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired); DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError(); - WCHAR GuidStr[MAX_GUID_STRING_LEN]; WriteFormatted( - STD_OUTPUT_HANDLE, - L"%1!X! %2!.*s! %3!X!", - LastError, - StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)), - GuidStr, - RebootRequired); + STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"", RebootRequired); if (Adapter) WintunFreeAdapter(Adapter); cleanup: - Done(); + LocalFree(Argv); } VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { # pragma EXPORT - Init(); - if (Argc < 3) + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + WintunSetLogger(ConsoleLogger); + + if (Argc < 4) goto cleanup; - WINTUN_ADAPTER Adapter = { 0 }; - BOOL ForceCloseSessions = wcstoul(Argv[2], NULL, 10); - if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID))) - goto cleanup; - BOOL RebootRequired; - DWORD LastError = - WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); + DWORD LastError; + BOOL RebootRequired = FALSE; + WINTUN_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]); + if (!Adapter) + { + LastError = GetLastError(); + goto write; + } + BOOL ForceCloseSessions = wcstoul(Argv[4], NULL, 10); + LastError = WintunDeleteAdapter(Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); + WintunFreeAdapter(Adapter); +write: WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); cleanup: - Done(); + LocalFree(Argv); } VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { # pragma EXPORT - Init(); + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + WintunSetLogger(ConsoleLogger); + if (Argc < 2) 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); 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 diff --git a/api/rundll32.h b/api/rundll32.h new file mode 100644 index 0000000..1cd3cae --- /dev/null +++ b/api/rundll32.h @@ -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); diff --git a/api/rundll32_i.c b/api/rundll32_i.c deleted file mode 100644 index 17598da..0000000 --- a/api/rundll32_i.c +++ /dev/null @@ -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); -} diff --git a/api/session.c b/api/session.c index ff158a8..d620411 100644 --- a/api/session.c +++ b/api/session.c @@ -70,8 +70,10 @@ typedef struct _TUN_SESSION HANDLE Handle; } TUN_SESSION; -_Return_type_success_(return != NULL) TUN_SESSION *WINAPI - WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity) +WINTUN_START_SESSION_FUNC_IMPL WintunStartSession; +_Use_decl_annotations_ +TUN_SESSION *WINAPI +WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity) { DWORD LastError; TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION)); @@ -126,8 +128,8 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI goto cleanupHandle; } Session->Capacity = Capacity; - (void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT); - (void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT); + (VOID) InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT); + (VOID) InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT); return Session; cleanupHandle: CloseHandle(Session->Handle); @@ -144,8 +146,10 @@ cleanup: return NULL; } -void WINAPI -WintunEndSession(_In_ TUN_SESSION *Session) +WINTUN_END_SESSION_FUNC_IMPL WintunEndSession; +_Use_decl_annotations_ +VOID WINAPI +WintunEndSession(TUN_SESSION *Session) { DeleteCriticalSection(&Session->Send.Lock); DeleteCriticalSection(&Session->Receive.Lock); @@ -156,14 +160,18 @@ WintunEndSession(_In_ TUN_SESSION *Session) Free(Session); } +WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL WintunGetReadWaitEvent; +_Use_decl_annotations_ HANDLE WINAPI -WintunGetReadWaitEvent(_In_ TUN_SESSION *Session) +WintunGetReadWaitEvent(TUN_SESSION *Session) { return Session->Descriptor.Send.TailMoved; } -_Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI - WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize) +WINTUN_RECEIVE_PACKET_FUNC_IMPL WintunReceivePacket; +_Use_decl_annotations_ +BYTE *WINAPI +WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize) { DWORD LastError; EnterCriticalSection(&Session->Send.Lock); @@ -213,8 +221,10 @@ cleanup: return NULL; } -void WINAPI -WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) +WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL WintunReleaseReceivePacket; +_Use_decl_annotations_ +VOID WINAPI +WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet) { EnterCriticalSection(&Session->Send.Lock); 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); } -_Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI - WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize) +WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL WintunAllocateSendPacket; +_Use_decl_annotations_ +BYTE *WINAPI +WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize) { DWORD LastError; EnterCriticalSection(&Session->Receive.Lock); @@ -268,8 +280,10 @@ cleanup: return NULL; } -void WINAPI -WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) +WINTUN_SEND_PACKET_FUNC_IMPL WintunSendPacket; +_Use_decl_annotations_ +VOID WINAPI +WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet) { EnterCriticalSection(&Session->Receive.Lock); 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); 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); if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable)) SetEvent(Session->Descriptor.Receive.TailMoved); diff --git a/api/wintun.h b/api/wintun.h index 2b03d33..9464a96 100644 --- a/api/wintun.h +++ b/api/wintun.h @@ -16,7 +16,7 @@ extern "C" { /** * A handle representing Wintun adapter */ -typedef void *WINTUN_ADAPTER_HANDLE; +typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE; /** * Maximum pool name length including zero terminator @@ -39,13 +39,14 @@ typedef void *WINTUN_ADAPTER_HANDLE; * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. * * @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. If - * the function fails, the return value is NULL. To get extended error information, call GetLastError. + * 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)( - _In_z_ const WCHAR *Pool, - _In_z_ const WCHAR *Name, - _In_opt_ const GUID *RequestedGUID, - _Out_opt_ BOOL *RebootRequired); +typedef _Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC_IMPL) +(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name, _In_opt_ const GUID *RequestedGUID, _Out_opt_ BOOL *RebootRequired); +typedef WINTUN_CREATE_ADAPTER_FUNC_IMPL *WINTUN_CREATE_ADAPTER_FUNC; /** * 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. * * @return If the function succeeds, the return value is adapter handle. Must be released with WintunFreeAdapter. If the - * function fails, the return value is NULL. To get extended error information, call GetLastError. Possible - * errors include the following: - * ERROR_FILE_NOT_FOUND if adapter with given name is not found; - * ERROR_ALREADY_EXISTS if adapter is found but not a Wintun-class or not a member of the pool + * function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors + * include the following: ERROR_FILE_NOT_FOUND if adapter with given name is not found; ERROR_ALREADY_EXISTS if adapter + * is found but not a Wintun-class or not a member of the pool */ -typedef _Return_type_success_(return != NULL) - WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name); - +typedef _Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name); +typedef WINTUN_OPEN_ADAPTER_FUNC_IMPL *WINTUN_OPEN_ADAPTER_FUNC; /** * Deletes a Wintun adapter. @@ -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 * get extended error information, call GetLastError. */ -typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)( - _In_ WINTUN_ADAPTER_HANDLE Adapter, - _In_ BOOL ForceCloseSessions, - _Out_opt_ BOOL *RebootRequired); +typedef _Return_type_success_(return != FALSE) +BOOL(WINAPI WINTUN_DELETE_ADAPTER_FUNC_IMPL) +(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired); +typedef WINTUN_DELETE_ADAPTER_FUNC_IMPL *WINTUN_DELETE_ADAPTER_FUNC; /** * Called by WintunEnumAdapters for each adapter in the pool. @@ -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 * get extended error information, call GetLastError. */ -typedef _Return_type_success_(return != FALSE) BOOL( - WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param); +typedef _Return_type_success_(return != FALSE) +BOOL(WINAPI WINTUN_ENUM_ADAPTERS_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param); +typedef WINTUN_ENUM_ADAPTERS_FUNC_IMPL *WINTUN_ENUM_ADAPTERS_FUNC; /** * Releases Wintun adapter resources. * * @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 @@ -129,7 +133,8 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte * get extended error information, call GetLastError. */ 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. @@ -138,7 +143,8 @@ typedef _Return_type_success_(return != FALSE) * * @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. @@ -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 * get extended error information, call GetLastError. */ -typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)( - _In_ WINTUN_ADAPTER_HANDLE Adapter, - _Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name); +typedef _Must_inspect_result_ +_Return_type_success_(return != FALSE) +BOOL(WINAPI WINTUN_GET_ADAPTER_NAME_FUNC_IMPL) +(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_writes_z_(MAX_ADAPTER_NAME) LPWSTR Name); +typedef WINTUN_GET_ADAPTER_NAME_FUNC_IMPL *WINTUN_GET_ADAPTER_NAME_FUNC; /** * Sets name of the Wintun adapter. @@ -165,7 +173,8 @@ typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_N * get extended error information, call GetLastError. */ 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. @@ -174,7 +183,9 @@ typedef _Return_type_success_(return != FALSE) * zero. To get extended error information, call GetLastError. Possible errors include the following: * 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. @@ -193,7 +204,7 @@ typedef enum * * @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. @@ -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 * 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. @@ -217,7 +229,7 @@ typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogg /** * A handle representing Wintun session */ -typedef void *WINTUN_SESSION_HANDLE; +typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE; /** * 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 * NULL. To get extended error information, call GetLastError. */ -typedef _Return_type_success_(return != NULL) - WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); +typedef _Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); +typedef WINTUN_START_SESSION_FUNC_IMPL *WINTUN_START_SESSION_FUNC; /** * Ends Wintun session. * * @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. @@ -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 * 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 @@ -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_INVALID_DATA Wintun buffer is corrupt */ -typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *( - WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize); +typedef _Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +_Post_writable_byte_size_(*PacketSize) +BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize); +typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC; /** * 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 */ -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 @@ -299,8 +322,12 @@ typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HAN * ERROR_HANDLE_EOF Wintun adapter is terminating; * ERROR_BUFFER_OVERFLOW Wintun buffer is full; */ -typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *( - WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize); +typedef _Must_inspect_result_ +_Return_type_success_(return != NULL) +_Post_maybenull_ +_Post_writable_byte_size_(PacketSize) +BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize); +typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC; /** * 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 */ -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 }