From f657e6fd278732d054b064bb4836702d06e176f0 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Tue, 3 Nov 2020 12:29:34 +0100 Subject: api: use GetLastError() to report failures like standard Win32 Signed-off-by: Simon Rozman --- api/adapter.c | 1179 ++++++++++++++++++++++++++++++------------------------- api/adapter.h | 18 +- api/elevate.c | 73 +++- api/elevate.h | 6 +- api/entry.c | 5 +- api/entry.h | 2 + api/logger.h | 19 +- api/namespace.c | 123 +++--- api/namespace.h | 8 +- api/registry.c | 248 +++++++----- api/registry.h | 65 +-- api/resource.c | 60 ++- api/resource.h | 16 +- api/rundll32.c | 38 +- api/rundll32.h | 133 ++++--- api/session.c | 123 +++--- api/wintun.h | 131 +++---- 17 files changed, 1266 insertions(+), 981 deletions(-) (limited to 'api') diff --git a/api/adapter.c b/api/adapter.c index d87ed56..24626e8 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -53,110 +53,110 @@ typedef struct _SP_DEVINFO_DATA_LIST static USHORT NativeMachine = IMAGE_FILE_PROCESS; -static WINTUN_STATUS -GetAdapterDrvInfoDetail( +static _Return_type_success_(return != NULL) SP_DRVINFO_DETAIL_DATA_W *GetAdapterDrvInfoDetail( _In_ HDEVINFO DevInfo, _In_opt_ SP_DEVINFO_DATA *DevInfoData, - _In_ SP_DRVINFO_DATA_W *DrvInfoData, - _Out_ SP_DRVINFO_DETAIL_DATA_W **DrvInfoDetailData) + _In_ SP_DRVINFO_DATA_W *DrvInfoData) { DWORD Size = sizeof(SP_DRVINFO_DETAIL_DATA_W) + 0x100; for (;;) { - SP_DRVINFO_DETAIL_DATA_W *p = HeapAlloc(ModuleHeap, 0, Size); - if (!p) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; - p->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); - if (SetupDiGetDriverInfoDetailW(DevInfo, DevInfoData, DrvInfoData, p, Size, &Size)) + SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = HeapAlloc(ModuleHeap, 0, Size); + if (!DrvInfoDetailData) { - *DrvInfoDetailData = p; - return ERROR_SUCCESS; + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); + if (SetupDiGetDriverInfoDetailW(DevInfo, DevInfoData, DrvInfoData, DrvInfoDetailData, Size, &Size)) + return DrvInfoDetailData; + DWORD LastError = GetLastError(); + HeapFree(ModuleHeap, 0, DrvInfoDetailData); + if (LastError != ERROR_INSUFFICIENT_BUFFER) + { + SetLastError(LOG_ERROR(L"Failed", LastError)); + return NULL; } - DWORD Result = GetLastError(); - HeapFree(ModuleHeap, 0, p); - if (Result != ERROR_INSUFFICIENT_BUFFER) - return LOG_ERROR(L"Failed", Result); } } -static WINTUN_STATUS -GetDeviceRegistryProperty( +static _Return_type_success_(return != NULL) void *GetDeviceRegistryProperty( _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property, _Out_opt_ DWORD *ValueType, - _Out_ void **Buf, _Inout_ DWORD *BufLen) { for (;;) { - BYTE *p = HeapAlloc(ModuleHeap, 0, *BufLen); - if (!p) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; - if (SetupDiGetDeviceRegistryPropertyW(DevInfo, DevInfoData, Property, ValueType, p, *BufLen, BufLen)) + BYTE *Data = HeapAlloc(ModuleHeap, 0, *BufLen); + if (!Data) + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + if (SetupDiGetDeviceRegistryPropertyW(DevInfo, DevInfoData, Property, ValueType, Data, *BufLen, BufLen)) + return Data; + DWORD LastError = GetLastError(); + HeapFree(ModuleHeap, 0, Data); + if (LastError != ERROR_INSUFFICIENT_BUFFER) { - *Buf = p; - return ERROR_SUCCESS; + SetLastError(LOG_ERROR(L"Querying property failed", LastError)); + return NULL; } - DWORD Result = GetLastError(); - HeapFree(ModuleHeap, 0, p); - if (Result != ERROR_INSUFFICIENT_BUFFER) - return LOG_ERROR(L"Querying property failed", Result); } } -static WINTUN_STATUS -GetDeviceRegistryString( - _In_ HDEVINFO DevInfo, - _In_ SP_DEVINFO_DATA *DevInfoData, - _In_ DWORD Property, - _Out_ WCHAR **Buf) +static _Return_type_success_(return != NULL) + WCHAR *GetDeviceRegistryString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) { - DWORD Result, ValueType, Size = 256 * sizeof(WCHAR); - Result = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, Buf, &Size); - if (Result != ERROR_SUCCESS) - return Result; + DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); + WCHAR *Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); + if (!Buf) + return NULL; switch (ValueType) { case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: - Result = RegistryGetString(Buf, Size / sizeof(WCHAR), ValueType); - if (Result != ERROR_SUCCESS) - HeapFree(ModuleHeap, 0, *Buf); - return Result; + if (RegistryGetString(&Buf, Size / sizeof(WCHAR), ValueType)) + return Buf; + LastError = GetLastError(); + break; default: LOG(WINTUN_LOG_ERR, L"Property is not a string"); - HeapFree(ModuleHeap, 0, *Buf); - return ERROR_INVALID_DATATYPE; + LastError = ERROR_INVALID_DATATYPE; } + HeapFree(ModuleHeap, 0, Buf); + SetLastError(LastError); + return NULL; } -static WINTUN_STATUS -GetDeviceRegistryMultiString( - _In_ HDEVINFO DevInfo, - _In_ SP_DEVINFO_DATA *DevInfoData, - _In_ DWORD Property, - _Out_ WCHAR **Buf) +static _Return_type_success_(return != NULL) + WCHAR *GetDeviceRegistryMultiString(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ DWORD Property) { - DWORD Result, ValueType, Size = 256 * sizeof(WCHAR); - Result = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, Buf, &Size); - if (Result != ERROR_SUCCESS) - return Result; + DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); + WCHAR *Buf = GetDeviceRegistryProperty(DevInfo, DevInfoData, Property, &ValueType, &Size); + if (!Buf) + return NULL; switch (ValueType) { case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: - Result = RegistryGetMultiString(Buf, Size / sizeof(WCHAR), ValueType); - if (Result != ERROR_SUCCESS) - HeapFree(ModuleHeap, 0, *Buf); - return Result; + if (RegistryGetMultiString(&Buf, Size / sizeof(WCHAR), ValueType)) + return Buf; + LastError = GetLastError(); + break; default: LOG(WINTUN_LOG_ERR, L"Property is not a string"); - HeapFree(ModuleHeap, 0, *Buf); - return ERROR_INVALID_DATATYPE; + LastError = ERROR_INVALID_DATATYPE; } + HeapFree(ModuleHeap, 0, Buf); + SetLastError(LastError); + return NULL; } static BOOL @@ -168,34 +168,44 @@ IsOurHardwareID(_In_z_ const WCHAR *Hwids) return FALSE; } -static WINTUN_STATUS -IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _Out_ BOOL *IsOurs) +static BOOL +IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - WCHAR *Hwids; - DWORD Result = GetDeviceRegistryMultiString(DevInfo, DevInfoData, SPDRP_HARDWAREID, &Hwids); - if (Result != ERROR_SUCCESS) - return LOG(WINTUN_LOG_ERR, L"Failed to get hardware ID"), Result; - *IsOurs = IsOurHardwareID(Hwids); - return ERROR_SUCCESS; + WCHAR *Hwids = GetDeviceRegistryMultiString(DevInfo, DevInfoData, SPDRP_HARDWAREID); + if (!Hwids) + { + LOG_LAST_ERROR(L"Failed to get hardware ID"); + return FALSE; + } + BOOL IsOurs = IsOurHardwareID(Hwids); + HeapFree(ModuleHeap, 0, Hwids); + return IsOurs; } -static WINTUN_STATUS -GetDeviceObject(_In_opt_z_ const WCHAR *InstanceId, _Out_ HANDLE *Handle) +static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceObject(_In_opt_z_ const WCHAR *InstanceId) { ULONG InterfacesLen; - DWORD Result = CM_MapCrToWin32Err( + DWORD LastError = CM_MapCrToWin32Err( CM_Get_Device_Interface_List_SizeW( &InterfacesLen, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT), ERROR_GEN_FAILURE); - if (Result != ERROR_SUCCESS) - return LOG_ERROR(L"Failed to query associated instances size", Result); + if (LastError != ERROR_SUCCESS) + { + SetLastError(LOG_ERROR(L"Failed to query associated instances size", LastError)); + return INVALID_HANDLE_VALUE; + } WCHAR *Interfaces = HeapAlloc(ModuleHeap, 0, InterfacesLen * sizeof(WCHAR)); if (!Interfaces) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; - Result = CM_MapCrToWin32Err( + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return INVALID_HANDLE_VALUE; + } + HANDLE Handle = INVALID_HANDLE_VALUE; + LastError = CM_MapCrToWin32Err( CM_Get_Device_Interface_ListW( (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)InstanceId, @@ -203,12 +213,12 @@ GetDeviceObject(_In_opt_z_ const WCHAR *InstanceId, _Out_ HANDLE *Handle) InterfacesLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT), ERROR_GEN_FAILURE); - if (Result != ERROR_SUCCESS) + if (LastError != ERROR_SUCCESS) { - LOG_ERROR(L"Failed to get associated instances", Result); + LOG_ERROR(L"Failed to get associated instances", LastError); goto cleanupBuf; } - *Handle = CreateFileW( + Handle = CreateFileW( Interfaces, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -216,65 +226,77 @@ GetDeviceObject(_In_opt_z_ const WCHAR *InstanceId, _Out_ HANDLE *Handle) OPEN_EXISTING, 0, NULL); - Result = *Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR(L"Failed to connect to adapter"); + LastError = Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR(L"Failed to connect to adapter"); cleanupBuf: HeapFree(ModuleHeap, 0, Interfaces); - return Result; + if (LastError != ERROR_SUCCESS) + SetLastError(LastError); + return Handle; } #define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) -static WINTUN_STATUS -ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +static _Return_type_success_(return != FALSE) BOOL + ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - DWORD Result = ERROR_SUCCESS; + DWORD LastError = ERROR_SUCCESS; DWORD RequiredBytes; if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) || - (Result = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) - return LOG_ERROR(L"Failed to query instance ID size", Result); + (LastError = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) + { + LOG_ERROR(L"Failed to query instance ID size", LastError); + return FALSE; + } WCHAR *InstanceId = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(*InstanceId) * RequiredBytes); if (!InstanceId) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes)) { - Result = LOG_LAST_ERROR(L"Failed to get instance ID"); - goto out; + LastError = LOG_LAST_ERROR(L"Failed to get instance ID"); + goto cleanupInstanceId; } - HANDLE NdisHandle; - Result = GetDeviceObject(InstanceId, &NdisHandle); - if (Result != ERROR_SUCCESS) + HANDLE NdisHandle = OpenDeviceObject(InstanceId); + if (NdisHandle == INVALID_HANDLE_VALUE) { - LOG(WINTUN_LOG_ERR, L"Failed to get adapter object"); - goto out; + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get adapter object"); + goto cleanupInstanceId; } if (DeviceIoControl(NdisHandle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL)) { - Result = ERROR_SUCCESS; + LastError = ERROR_SUCCESS; Sleep(200); } else if (GetLastError() == ERROR_NOTHING_TO_TERMINATE) - Result = ERROR_SUCCESS; + LastError = ERROR_SUCCESS; else - Result = LOG_LAST_ERROR(L"Failed to perform ioctl"); + LastError = LOG_LAST_ERROR(L"Failed to perform ioctl"); CloseHandle(NdisHandle); -out: +cleanupInstanceId: HeapFree(ModuleHeap, 0, InstanceId); - return Result; + return RET_ERROR(TRUE, LastError); } -static WINTUN_STATUS -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 }, .StateChange = DICS_DISABLE, .Scope = DICS_FLAG_GLOBAL }; - DWORD Result = ERROR_SUCCESS; + DWORD LastError = ERROR_SUCCESS; for (DWORD EnumIndex = 0;; ++EnumIndex) { SP_DEVINFO_DATA_LIST *DeviceNode = HeapAlloc(ModuleHeap, 0, sizeof(SP_DEVINFO_DATA_LIST)); if (!DeviceNode) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA); if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data)) { @@ -285,8 +307,7 @@ DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **Disa } goto cleanupDeviceNode; } - BOOL IsOurs; - if (IsOurAdapter(DevInfo, &DeviceNode->Data, &IsOurs) != ERROR_SUCCESS || !IsOurs) + if (!IsOurAdapter(DevInfo, &DeviceNode->Data)) goto cleanupDeviceNode; ULONG Status, ProblemCode; @@ -295,7 +316,7 @@ DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **Disa goto cleanupDeviceNode; LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter"); - if (ForceCloseWintunAdapterHandle(DevInfo, &DeviceNode->Data) != ERROR_SUCCESS) + if (!ForceCloseWintunAdapterHandle(DevInfo, &DeviceNode->Data)) LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles"); LOG(WINTUN_LOG_INFO, L"Disabling existing adapter"); @@ -303,7 +324,7 @@ DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **Disa !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data)) { LOG_LAST_ERROR(L"Failed to disable existing adapter"); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); goto cleanupDeviceNode; } @@ -314,17 +335,17 @@ DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **Disa cleanupDeviceNode: HeapFree(ModuleHeap, 0, DeviceNode); } - return Result; + return RET_ERROR(TRUE, LastError); } -static WINTUN_STATUS -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 }, .StateChange = DICS_ENABLE, .Scope = DICS_FLAG_GLOBAL }; - DWORD Result = ERROR_SUCCESS; + DWORD LastError = ERROR_SUCCESS; for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next) { LOG(WINTUN_LOG_INFO, L"Enabling existing adapter"); @@ -332,10 +353,10 @@ EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersT !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data)) { LOG_LAST_ERROR(L"Failed to enable existing adapter"); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); } } - return Result; + return RET_ERROR(TRUE, LastError); } void @@ -367,53 +388,64 @@ CheckReboot(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) LOG_LAST_ERROR(L"Retrieving device installation parameters failed"); return FALSE; } + SetLastError(ERROR_SUCCESS); return (DevInstallParams.Flags & (DI_NEEDREBOOT | DI_NEEDRESTART)) != 0; } -static WINTUN_STATUS -SetQuietInstall(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +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)) - return LOG_LAST_ERROR(L"Retrieving device installation parameters failed"); + { + LOG_LAST_ERROR(L"Retrieving device installation parameters failed"); + return FALSE; + } DevInstallParams.Flags |= DI_QUIETINSTALL; if (!SetupDiSetDeviceInstallParamsW(DevInfo, DevInfoData, &DevInstallParams)) - return LOG_LAST_ERROR(L"Setting device installation parameters failed"); - return ERROR_SUCCESS; + { + LOG_LAST_ERROR(L"Setting device installation parameters failed"); + return FALSE; + } + return TRUE; } -static WINTUN_STATUS -GetNetCfgInstanceId(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _Out_ GUID *CfgInstanceID) +static _Return_type_success_(return != FALSE) BOOL + GetNetCfgInstanceId(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _Out_ GUID *CfgInstanceID) { HKEY Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); if (Key == INVALID_HANDLE_VALUE) - return LOG_LAST_ERROR(L"Opening device registry key failed"); - WCHAR *ValueStr; - DWORD Result = RegistryQueryString(Key, L"NetCfgInstanceId", &ValueStr, TRUE); - if (Result != ERROR_SUCCESS) { - LOG(WINTUN_LOG_ERR, L"Failed to get NetCfgInstanceId"); + LOG_LAST_ERROR(L"Opening device registry key failed"); + return FALSE; + } + DWORD LastError = ERROR_SUCCESS; + WCHAR *ValueStr = RegistryQueryString(Key, L"NetCfgInstanceId", TRUE); + if (!ValueStr) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get NetCfgInstanceId"); goto cleanupKey; } if (FAILED(CLSIDFromString(ValueStr, CfgInstanceID))) { LOG(WINTUN_LOG_ERR, L"NetCfgInstanceId is not a GUID"); - Result = ERROR_INVALID_DATA; + LastError = ERROR_INVALID_DATA; } - else - Result = ERROR_SUCCESS; HeapFree(ModuleHeap, 0, ValueStr); cleanupKey: RegCloseKey(Key); - return Result; + return RET_ERROR(TRUE, LastError); } -static WINTUN_STATUS -GetDevInfoData(_In_ const GUID *CfgInstanceID, _Out_ HDEVINFO *DevInfo, _Out_ SP_DEVINFO_DATA *DevInfoData) +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) - return LOG_LAST_ERROR(L"Failed to get present adapters"); + { + LOG_LAST_ERROR(L"Failed to get present adapters"); + return FALSE; + } for (DWORD EnumIndex = 0;; ++EnumIndex) { DevInfoData->cbSize = sizeof(SP_DEVINFO_DATA); @@ -424,12 +456,13 @@ GetDevInfoData(_In_ const GUID *CfgInstanceID, _Out_ HDEVINFO *DevInfo, _Out_ SP continue; } GUID CfgInstanceID2; - if (GetNetCfgInstanceId(*DevInfo, DevInfoData, &CfgInstanceID2) == ERROR_SUCCESS && + if (GetNetCfgInstanceId(*DevInfo, DevInfoData, &CfgInstanceID2) && !memcmp(CfgInstanceID, &CfgInstanceID2, sizeof(GUID))) - return ERROR_SUCCESS; + return TRUE; } SetupDiDestroyDeviceInfoList(*DevInfo); - return ERROR_FILE_NOT_FOUND; + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; } static void @@ -443,135 +476,135 @@ RemoveNumberedSuffix(_Inout_z_ WCHAR *Name) } } -static WINTUN_STATUS -GetPoolDeviceTypeName(_In_z_ const WCHAR *Pool, _Out_cap_c_(MAX_POOL_DEVICE_TYPE) WCHAR *Name) +static _Return_type_success_(return != FALSE) BOOL + GetPoolDeviceTypeName(_In_z_ const WCHAR *Pool, _Out_cap_c_(MAX_POOL_DEVICE_TYPE) WCHAR *Name) { if (_snwprintf_s(Name, MAX_POOL_DEVICE_TYPE, _TRUNCATE, L"%s Tunnel", Pool) == -1) - return LOG(WINTUN_LOG_ERR, L"Pool name too long"), ERROR_INVALID_PARAMETER; - return ERROR_SUCCESS; + { + LOG(WINTUN_LOG_ERR, L"Pool name too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + return TRUE; } -static WINTUN_STATUS -IsPoolMember(_In_z_ const WCHAR *Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _Out_ BOOL *IsMember) +static BOOL +IsPoolMember(_In_z_ const WCHAR *Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - WCHAR *DeviceDesc, *FriendlyName; - DWORD Result = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_DEVICEDESC, &DeviceDesc); - if (Result != ERROR_SUCCESS) + WCHAR *DeviceDesc = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_DEVICEDESC); + if (!DeviceDesc) { LOG(WINTUN_LOG_ERR, L"Failed to get adapter description"); - return Result; + return FALSE; } - Result = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_FRIENDLYNAME, &FriendlyName); - if (Result != ERROR_SUCCESS) + DWORD LastError = ERROR_SUCCESS; + BOOL Ret = FALSE; + WCHAR *FriendlyName = GetDeviceRegistryString(DevInfo, DevInfoData, SPDRP_FRIENDLYNAME); + if (!FriendlyName) { - LOG(WINTUN_LOG_ERR, L"Failed to get adapter friendly name"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get adapter friendly name"); goto cleanupDeviceDesc; } WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; - Result = GetPoolDeviceTypeName(Pool, PoolDeviceTypeName); - if (Result != ERROR_SUCCESS) + if (!GetPoolDeviceTypeName(Pool, PoolDeviceTypeName)) + { + LastError = GetLastError(); goto cleanupFriendlyName; + } if (!_wcsicmp(FriendlyName, PoolDeviceTypeName) || !_wcsicmp(DeviceDesc, PoolDeviceTypeName)) { - *IsMember = TRUE; + Ret = TRUE; goto cleanupFriendlyName; } RemoveNumberedSuffix(FriendlyName); RemoveNumberedSuffix(DeviceDesc); if (!_wcsicmp(FriendlyName, PoolDeviceTypeName) || !_wcsicmp(DeviceDesc, PoolDeviceTypeName)) { - *IsMember = TRUE; + Ret = TRUE; goto cleanupFriendlyName; } - *IsMember = FALSE; cleanupFriendlyName: HeapFree(ModuleHeap, 0, FriendlyName); cleanupDeviceDesc: HeapFree(ModuleHeap, 0, DeviceDesc); - return Result; + SetLastError(LastError); + return Ret; } -static WINTUN_STATUS -CreateAdapterData( - _In_z_ const WCHAR *Pool, - _In_ HDEVINFO DevInfo, - _In_ SP_DEVINFO_DATA *DevInfoData, - _Out_ WINTUN_ADAPTER **Adapter) +static _Return_type_success_(return != NULL) WINTUN_ADAPTER + *CreateAdapterData(_In_z_ const WCHAR *Pool, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - DWORD Result; - /* Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\\ registry key. */ HKEY Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); if (Key == INVALID_HANDLE_VALUE) - return LOG_LAST_ERROR(L"Opening device registry key failed"); + { + LOG_LAST_ERROR(L"Opening device registry key failed"); + return NULL; + } - WINTUN_ADAPTER *a = HeapAlloc(ModuleHeap, 0, sizeof(WINTUN_ADAPTER)); - if (!a) + DWORD LastError; + WINTUN_ADAPTER *Adapter = HeapAlloc(ModuleHeap, 0, sizeof(WINTUN_ADAPTER)); + if (!Adapter) { LOG(WINTUN_LOG_ERR, L"Out of memory"); - Result = ERROR_OUTOFMEMORY; + LastError = ERROR_OUTOFMEMORY; goto cleanupKey; } - /* Read the NetCfgInstanceId value and convert to GUID. */ - WCHAR *ValueStr; - Result = RegistryQueryString(Key, L"NetCfgInstanceId", &ValueStr, TRUE); - if (Result != ERROR_SUCCESS) + WCHAR *ValueStr = RegistryQueryString(Key, L"NetCfgInstanceId", TRUE); + if (!ValueStr) { - LOG(WINTUN_LOG_ERR, L"Failed to get NetCfgInstanceId"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get NetCfgInstanceId"); goto cleanupAdapter; } - if (FAILED(CLSIDFromString(ValueStr, &a->CfgInstanceID))) + if (FAILED(CLSIDFromString(ValueStr, &Adapter->CfgInstanceID))) { - LOG(WINTUN_LOG_ERR, L"NetCfgInstanceId is not a GUID"); + LOG(WINTUN_LOG_ERR, L"NetCfgInstanceId is not Adapter GUID"); HeapFree(ModuleHeap, 0, ValueStr); - Result = ERROR_INVALID_DATA; + LastError = ERROR_INVALID_DATA; goto cleanupAdapter; } HeapFree(ModuleHeap, 0, ValueStr); - /* Read the NetLuidIndex value. */ - Result = RegistryQueryDWORD(Key, L"NetLuidIndex", &a->LuidIndex, TRUE); - if (Result != ERROR_SUCCESS) + if (!RegistryQueryDWORD(Key, L"NetLuidIndex", &Adapter->LuidIndex, TRUE)) { - LOG(WINTUN_LOG_ERR, L"Failed to get NetLuidIndex"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get NetLuidIndex"); goto cleanupAdapter; } - /* Read the NetLuidIndex value. */ - Result = RegistryQueryDWORD(Key, L"*IfType", &a->IfType, TRUE); - if (Result != ERROR_SUCCESS) + if (!RegistryQueryDWORD(Key, L"*IfType", &Adapter->IfType, TRUE)) { - LOG(WINTUN_LOG_ERR, L"Failed to get *IfType"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get *IfType"); goto cleanupAdapter; } DWORD Size; - if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, a->DevInstanceID, _countof(a->DevInstanceID), &Size)) + if (!SetupDiGetDeviceInstanceIdW( + DevInfo, DevInfoData, Adapter->DevInstanceID, _countof(Adapter->DevInstanceID), &Size)) { - Result = LOG_LAST_ERROR(L"Failed to get instance ID"); + LastError = LOG_LAST_ERROR(L"Failed to get instance ID"); goto cleanupAdapter; } - if (wcsncpy_s(a->Pool, _countof(a->Pool), Pool, _TRUNCATE) == STRUNCATE) + if (wcsncpy_s(Adapter->Pool, _countof(Adapter->Pool), Pool, _TRUNCATE) == STRUNCATE) { LOG(WINTUN_LOG_ERR, L"Pool name too long"); - Result = ERROR_INVALID_PARAMETER; + LastError = ERROR_INVALID_PARAMETER; goto cleanupAdapter; } - *Adapter = a; - Result = ERROR_SUCCESS; + RegCloseKey(Key); + return Adapter; cleanupAdapter: - if (Result != ERROR_SUCCESS) - HeapFree(ModuleHeap, 0, a); + HeapFree(ModuleHeap, 0, Adapter); cleanupKey: RegCloseKey(Key); - return Result; + SetLastError(LastError); + return NULL; } -static WINTUN_STATUS -GetDeviceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) +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, @@ -580,8 +613,12 @@ GetDeviceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) W L"SYSTEM\\CurrentControlSet\\Enum\\%.*s", MAX_INSTANCE_ID, Adapter->DevInstanceID) == -1) - return LOG(WINTUN_LOG_ERR, L"Registry path too long"), ERROR_INVALID_PARAMETER; - return ERROR_SUCCESS; + { + LOG(WINTUN_LOG_ERR, L"Registry path too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + return TRUE; } void WINAPI @@ -590,23 +627,27 @@ WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter) HeapFree(ModuleHeap, 0, Adapter); } -WINTUN_STATUS WINAPI -WintunGetAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _Out_ WINTUN_ADAPTER **Adapter) +_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI + WintunGetAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name) { if (!ElevateToSystem()) - return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user"); - DWORD Result; + { + LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"); + return NULL; + } + DWORD LastError; + WINTUN_ADAPTER *Adapter = NULL; HANDLE Mutex = NamespaceTakePoolMutex(Pool); if (!Mutex) { - Result = ERROR_INVALID_HANDLE; + LastError = LOG(WINTUN_LOG_ERR, L"Failed to take pool mutex"); goto cleanupToken; } HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) { - Result = LOG_LAST_ERROR(L"Failed to get present adapters"); + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); goto cleanupMutex; } @@ -621,7 +662,7 @@ WintunGetAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _Out_ WINTU } GUID CfgInstanceID; - if (GetNetCfgInstanceId(DevInfo, &DevInfoData, &CfgInstanceID) != ERROR_SUCCESS) + if (!GetNetCfgInstanceId(DevInfo, &DevInfoData, &CfgInstanceID)) continue; /* TODO: is there a better way than comparing ifnames? */ @@ -637,134 +678,162 @@ WintunGetAdapter(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _Out_ WINTU } /* Check the Hardware ID to make sure it's a real Wintun device. */ - BOOL IsOurs; - Result = IsOurAdapter(DevInfo, &DevInfoData, &IsOurs); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get hardware ID"); - goto cleanupDevInfo; - } - if (!IsOurs) + if (!IsOurAdapter(DevInfo, &DevInfoData)) { LOG(WINTUN_LOG_ERR, L"Foreign adapter with the same name exists"); - Result = ERROR_ALREADY_EXISTS; + LastError = ERROR_ALREADY_EXISTS; goto cleanupDevInfo; } - BOOL IsMember; - Result = IsPoolMember(Pool, DevInfo, &DevInfoData, &IsMember); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get pool membership"); - goto cleanupDevInfo; - } - if (!IsMember) + if (!IsPoolMember(Pool, DevInfo, &DevInfoData)) { - LOG(WINTUN_LOG_ERR, L"Wintun adapter with the same name exists in another pool"); - Result = ERROR_ALREADY_EXISTS; - goto cleanupDevInfo; + if ((LastError = GetLastError()) == ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Wintun adapter with the same name exists in another pool"); + LastError = ERROR_ALREADY_EXISTS; + goto cleanupDevInfo; + } + else + { + LOG(WINTUN_LOG_ERR, L"Failed to get pool membership"); + goto cleanupDevInfo; + } } - Result = CreateAdapterData(Pool, DevInfo, &DevInfoData, Adapter); - if (Result != ERROR_SUCCESS) - LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); - + Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); + LastError = Adapter ? ERROR_SUCCESS : LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); goto cleanupDevInfo; } - Result = ERROR_FILE_NOT_FOUND; + LastError = ERROR_FILE_NOT_FOUND; cleanupDevInfo: SetupDiDestroyDeviceInfoList(DevInfo); cleanupMutex: NamespaceReleaseMutex(Mutex); cleanupToken: RevertToSelf(); - return Result; + SetLastError(LastError); + return Adapter; } -WINTUN_STATUS WINAPI -WintunGetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name) +_Return_type_success_(return != FALSE) BOOL WINAPI + WintunGetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name) { - return NciGetConnectionName(&Adapter->CfgInstanceID, Name, MAX_ADAPTER_NAME * sizeof(WCHAR), NULL); + DWORD LastError = NciGetConnectionName(&Adapter->CfgInstanceID, Name, MAX_ADAPTER_NAME * sizeof(WCHAR), NULL); + if (LastError != ERROR_SUCCESS) + { + SetLastError(LOG_ERROR(L"Failed to get name", LastError)); + return FALSE; + } + return TRUE; } -static WINTUN_STATUS -ConvertInterfaceAliasToGuid(_In_z_ const WCHAR *Name, _Out_ GUID *Guid) +static _Return_type_success_(return != FALSE) BOOL + ConvertInterfaceAliasToGuid(_In_z_ const WCHAR *Name, _Out_ GUID *Guid) { NET_LUID Luid; - DWORD Result = ConvertInterfaceAliasToLuid(Name, &Luid); - if (Result != NO_ERROR) - return LOG_ERROR(L"Failed convert interface alias name to the locally unique identifier", Result); - return ConvertInterfaceLuidToGuid(&Luid, Guid); + DWORD LastError = ConvertInterfaceAliasToLuid(Name, &Luid); + if (LastError != NO_ERROR) + { + SetLastError(LOG_ERROR(L"Failed convert interface alias name to the locally unique identifier", LastError)); + return FALSE; + } + LastError = ConvertInterfaceLuidToGuid(&Luid, Guid); + if (LastError != NO_ERROR) + { + SetLastError(LOG_ERROR(L"Failed convert interface locally to globally unique identifier", LastError)); + return FALSE; + } + return TRUE; } -WINTUN_STATUS WINAPI -WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_ const WCHAR *Name) +_Return_type_success_(return != FALSE) BOOL WINAPI + WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_ const WCHAR *Name) { - DWORD Result; + DWORD LastError; const int MaxSuffix = 1000; WCHAR AvailableName[MAX_ADAPTER_NAME]; if (wcsncpy_s(AvailableName, _countof(AvailableName), Name, _TRUNCATE) == STRUNCATE) - return LOG(WINTUN_LOG_ERR, L"Adapter name too long"), ERROR_INVALID_PARAMETER; + { + LOG(WINTUN_LOG_ERR, L"Adapter name too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } for (int i = 0;; ++i) { - Result = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); - if (Result == ERROR_DUP_NAME) + LastError = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); + if (LastError == ERROR_DUP_NAME) { GUID Guid2; - DWORD Result2 = ConvertInterfaceAliasToGuid(AvailableName, &Guid2); - if (Result2 == ERROR_SUCCESS) + if (ConvertInterfaceAliasToGuid(AvailableName, &Guid2)) { for (int j = 0; j < MaxSuffix; ++j) { WCHAR Proposal[MAX_ADAPTER_NAME]; if (_snwprintf_s(Proposal, _countof(Proposal), _TRUNCATE, L"%s %d", Name, j + 1) == -1) - return LOG(WINTUN_LOG_ERR, L"Adapter name too long"), ERROR_INVALID_PARAMETER; + { + LOG(WINTUN_LOG_ERR, L"Adapter name too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } if (_wcsnicmp(Proposal, AvailableName, MAX_ADAPTER_NAME) == 0) continue; - Result2 = NciSetConnectionName(&Guid2, Proposal); - if (Result2 == ERROR_DUP_NAME) + DWORD LastError2 = NciSetConnectionName(&Guid2, Proposal); + if (LastError2 == ERROR_DUP_NAME) continue; - if (Result2 == ERROR_SUCCESS) + if (LastError2 == ERROR_SUCCESS) { - Result = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); - if (Result == ERROR_SUCCESS) + LastError = NciSetConnectionName(&Adapter->CfgInstanceID, AvailableName); + if (LastError == ERROR_SUCCESS) break; } break; } } } - if (Result == ERROR_SUCCESS) + if (LastError == ERROR_SUCCESS) break; - if (i >= MaxSuffix || Result != ERROR_DUP_NAME) - return LOG_ERROR(L"Setting adapter name failed", Result); + if (i >= MaxSuffix || LastError != ERROR_DUP_NAME) + { + SetLastError(LOG_ERROR(L"Setting adapter name failed", LastError)); + return FALSE; + } if (_snwprintf_s(AvailableName, _countof(AvailableName), _TRUNCATE, L"%s %d", Name, i + 1) == -1) - return LOG(WINTUN_LOG_ERR, L"Adapter name too long"), ERROR_INVALID_PARAMETER; + { + LOG(WINTUN_LOG_ERR, L"Adapter name too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } } /* TODO: This should use NetSetup2 so that it doesn't get unset. */ HKEY DeviceRegKey; WCHAR DeviceRegPath[MAX_REG_PATH]; - Result = GetDeviceRegPath(Adapter, DeviceRegPath); - if (Result != ERROR_SUCCESS) - return Result; - Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceRegPath, 0, KEY_SET_VALUE, &DeviceRegKey); - if (Result != ERROR_SUCCESS) - return LOG_ERROR(L"Failed to open registry key", Result); + if (!GetDeviceRegPath(Adapter, DeviceRegPath)) + return FALSE; + LastError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceRegPath, 0, KEY_SET_VALUE, &DeviceRegKey); + if (LastError != ERROR_SUCCESS) + { + SetLastError(LOG_ERROR(L"Failed to open registry key", LastError)); + return FALSE; + } WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; - Result = GetPoolDeviceTypeName(Adapter->Pool, PoolDeviceTypeName); - if (Result != ERROR_SUCCESS) + if (!GetPoolDeviceTypeName(Adapter->Pool, PoolDeviceTypeName)) + { + LastError = GetLastError(); goto cleanupDeviceRegKey; - Result = RegSetKeyValueW( + } + LastError = RegSetKeyValueW( DeviceRegKey, NULL, L"FriendlyName", REG_SZ, PoolDeviceTypeName, (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(WCHAR))); + if (LastError != ERROR_SUCCESS) + LOG_ERROR(L"Failed to set FriendlyName", LastError); cleanupDeviceRegKey: RegCloseKey(DeviceRegKey); - return Result; + return RET_ERROR(TRUE, LastError); } void WINAPI @@ -775,10 +844,10 @@ WintunGetAdapterLUID(_In_ const WINTUN_ADAPTER *Adapter, _Out_ NET_LUID *Luid) Luid->Info.IfType = Adapter->IfType; } -WINTUN_STATUS WINAPI -WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle) +_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI + WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter) { - return GetDeviceObject(Adapter->DevInstanceID, Handle); + return OpenDeviceObject(Adapter->DevInstanceID); } static BOOL @@ -793,15 +862,16 @@ HaveWHQL(void) return FALSE; } -static WINTUN_STATUS -InstallCertificate(_In_z_ const WCHAR *SignedResource) +static _Return_type_success_(return != FALSE) BOOL InstallCertificate(_In_z_ const WCHAR *SignedResource) { LOG(WINTUN_LOG_INFO, L"Trusting code signing certificate"); - const void *LockedResource; DWORD SizeResource; - DWORD Result = ResourceGetAddress(SignedResource, &LockedResource, &SizeResource); - if (Result != ERROR_SUCCESS) - return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result; + const void *LockedResource = ResourceGetAddress(SignedResource, &SizeResource); + if (!LockedResource) + { + LOG(WINTUN_LOG_ERR, L"Failed to locate resource"); + return FALSE; + } const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = (BYTE *)LockedResource }; HCERTSTORE QueriedStore; if (!CryptQueryObject( @@ -816,12 +886,16 @@ InstallCertificate(_In_z_ const WCHAR *SignedResource) &QueriedStore, 0, NULL)) - return LOG_LAST_ERROR(L"Failed to find certificate"); + { + LOG_LAST_ERROR(L"Failed to find certificate"); + return FALSE; + } + DWORD LastError = ERROR_SUCCESS; HCERTSTORE TrustedStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"TrustedPublisher"); if (!TrustedStore) { - Result = LOG_LAST_ERROR(L"Failed to open store"); + LastError = LOG_LAST_ERROR(L"Failed to open store"); goto cleanupQueriedStore; } LPSTR CodeSigningOid[] = { szOID_PKIX_KP_CODE_SIGNING }; @@ -852,13 +926,13 @@ InstallCertificate(_In_z_ const WCHAR *SignedResource) if (!CertAddCertificateContextToStore(TrustedStore, CertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL)) { LOG_LAST_ERROR(L"Failed to add certificate to store"); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); } } CertCloseStore(TrustedStore, 0); cleanupQueriedStore: CertCloseStore(QueriedStore, 0); - return Result; + return RET_ERROR(TRUE, LastError); } static BOOL @@ -897,8 +971,8 @@ IsNewer( return FALSE; } -static DWORD -GetTcpipAdapterRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) +static _Return_type_success_(return != FALSE) BOOL + GetTcpipAdapterRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) { WCHAR Guid[MAX_GUID_STRING_LEN]; if (_snwprintf_s( @@ -908,108 +982,134 @@ GetTcpipAdapterRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_P L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%.*s", StringFromGUID2(&Adapter->CfgInstanceID, Guid, _countof(Guid)), Guid) == -1) - return LOG(WINTUN_LOG_ERR, L"Registry path too long"), ERROR_INVALID_PARAMETER; - return ERROR_SUCCESS; + { + LOG(WINTUN_LOG_ERR, L"Registry path too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + return TRUE; } -static WINTUN_STATUS -GetTcpipInterfaceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) +static _Return_type_success_(return != FALSE) BOOL + GetTcpipInterfaceRegPath(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) { - DWORD Result; HKEY TcpipAdapterRegKey; WCHAR TcpipAdapterRegPath[MAX_REG_PATH]; - Result = GetTcpipAdapterRegPath(Adapter, TcpipAdapterRegPath); - if (Result != ERROR_SUCCESS) - return Result; - Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TcpipAdapterRegPath, 0, KEY_QUERY_VALUE, &TcpipAdapterRegKey); - if (Result != ERROR_SUCCESS) - return LOG_ERROR(L"Failed to open registry key", Result); - WCHAR *Paths; - Result = RegistryQueryString(TcpipAdapterRegKey, L"IpConfig", &Paths, TRUE); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get IpConfig"); + if (!GetTcpipAdapterRegPath(Adapter, TcpipAdapterRegPath)) + return FALSE; + DWORD LastError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TcpipAdapterRegPath, 0, KEY_QUERY_VALUE, &TcpipAdapterRegKey); + if (LastError != ERROR_SUCCESS) + { + SetLastError(LOG_ERROR(L"Failed to open registry key", LastError)); + return FALSE; + } + WCHAR *Paths = RegistryQueryString(TcpipAdapterRegKey, L"IpConfig", TRUE); + if (!Paths) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get IpConfig"); goto cleanupTcpipAdapterRegKey; } if (!Paths[0]) { LOG(WINTUN_LOG_ERR, L"IpConfig is empty"); - Result = ERROR_INVALID_DATA; + LastError = ERROR_INVALID_DATA; goto cleanupPaths; } if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"SYSTEM\\CurrentControlSet\\Services\\%s", Paths) == -1) { LOG(WINTUN_LOG_ERR, L"Registry path too long"); - Result = ERROR_INVALID_PARAMETER; + LastError = ERROR_INVALID_PARAMETER; goto cleanupPaths; } - Result = ERROR_SUCCESS; cleanupPaths: HeapFree(ModuleHeap, 0, Paths); cleanupTcpipAdapterRegKey: RegCloseKey(TcpipAdapterRegKey); - return Result; + return RET_ERROR(TRUE, LastError); } -static DWORD -VersionOfFile(_In_z_ const WCHAR *Filename) +static _Return_type_success_(return != 0) DWORD VersionOfFile(_In_z_ const WCHAR *Filename) { - DWORD Version = 0; DWORD Zero; DWORD Len = GetFileVersionInfoSizeW(Filename, &Zero); if (!Len) - return LOG_LAST_ERROR(L"Failed to query version info size"), Version; + { + LOG_LAST_ERROR(L"Failed to query version info size"); + return 0; + } VOID *VersionInfo = HeapAlloc(ModuleHeap, 0, Len); if (!VersionInfo) { LOG(WINTUN_LOG_ERR, L"Out of memory"); - return Version; + SetLastError(ERROR_OUTOFMEMORY); + return 0; } + DWORD LastError = ERROR_SUCCESS, Version = 0; VS_FIXEDFILEINFO *FixedInfo; UINT FixedInfoLen = sizeof(*FixedInfo); if (!GetFileVersionInfoW(Filename, 0, Len, VersionInfo)) { - LOG_LAST_ERROR(L"Failed to get version info"); + LastError = LOG_LAST_ERROR(L"Failed to get version info"); goto out; } if (!VerQueryValueW(VersionInfo, L"\\", &FixedInfo, &FixedInfoLen)) { - LOG_LAST_ERROR(L"Failed to get version info root"); + LastError = LOG_LAST_ERROR(L"Failed to get version info root"); goto out; } Version = FixedInfo->dwFileVersionMS; + if (!Version) + { + LOG(WINTUN_LOG_WARN, L"Determined version of file, but was v0.0, so returning failure"); + LastError = ERROR_VERSION_PARSE_ERROR; + } out: HeapFree(ModuleHeap, 0, VersionInfo); - return Version; + return RET_ERROR(Version, LastError); } -static WINTUN_STATUS -CreateTemporaryDirectory(_Out_cap_c_(MAX_PATH) WCHAR *RandomTempSubDirectory) +static _Return_type_success_(return != FALSE) BOOL + CreateTemporaryDirectory(_Out_cap_c_(MAX_PATH) WCHAR *RandomTempSubDirectory) { WCHAR WindowsDirectory[MAX_PATH]; if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory))) - return LOG_LAST_ERROR(L"Failed to get Windows folder"); + { + LOG_LAST_ERROR(L"Failed to get Windows folder"); + return FALSE; + } WCHAR WindowsTempDirectory[MAX_PATH]; if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp")) - return ERROR_BUFFER_OVERFLOW; + { + SetLastError(ERROR_BUFFER_OVERFLOW); + return FALSE; + } UCHAR RandomBytes[32] = { 0 }; #pragma warning(suppress : 6387) if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes))) - return LOG_LAST_ERROR(L"Failed to generate random"); + { + 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)) - return ERROR_BUFFER_OVERFLOW; + { + SetLastError(ERROR_BUFFER_OVERFLOW); + return FALSE; + } if (!CreateDirectoryW(RandomTempSubDirectory, &SecurityAttributes)) - return LOG_LAST_ERROR(L"Failed to create temporary folder"); - return ERROR_SUCCESS; + { + LOG_LAST_ERROR(L"Failed to create temporary folder"); + return FALSE; + } + return TRUE; } -DWORD +DWORD WINAPI WintunGetVersion(void) { - DWORD Version = 0; PRTL_PROCESS_MODULES Modules; ULONG BufferSize = 128 * 1024; for (;;) @@ -1018,7 +1118,8 @@ WintunGetVersion(void) if (!Modules) { LOG(WINTUN_LOG_ERR, L"Out of memory"); - return Version; + SetLastError(ERROR_OUTOFMEMORY); + return 0; } NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize); if (NT_SUCCESS(Status)) @@ -1027,8 +1128,10 @@ WintunGetVersion(void) if (Status == STATUS_INFO_LENGTH_MISMATCH) continue; LOG(WINTUN_LOG_ERR, L"Failed to enumerate drivers"); - return Version; + SetLastError(ERROR_GEN_FAILURE); + return 0; } + DWORD LastError = ERROR_SUCCESS, Version = 0; for (ULONG i = Modules->NumberOfModules; i-- > 0;) { const char *NtPath = (const char *)Modules->Modules[i].FullPathName; @@ -1038,12 +1141,15 @@ WintunGetVersion(void) if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1) continue; Version = VersionOfFile(FilePath); - goto out; + if (!Version) + LastError = GetLastError(); + goto cleanupModules; } } -out: + LastError = ERROR_FILE_NOT_FOUND; +cleanupModules: HeapFree(ModuleHeap, 0, Modules); - return Version; + return RET_ERROR(Version, LastError); } static BOOL @@ -1055,8 +1161,7 @@ EnsureWintunUnloaded(void) return !Loaded; } -static WINTUN_STATUS -SelectDriver( +static _Return_type_success_(return != FALSE) BOOL SelectDriver( _In_ HDEVINFO DevInfo, _In_opt_ SP_DEVINFO_DATA *DevInfoData, _Inout_ SP_DEVINSTALL_PARAMS_W *DevInstallParams, @@ -1066,11 +1171,14 @@ SelectDriver( static const DWORDLONG OurDriverVersion = WINTUN_INF_VERSION; HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); if (!DriverInstallationLock) - return LOG_LAST_ERROR(L"Failed to take driver installation mutex"); - DWORD Result = ERROR_SUCCESS; + { + LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex"); + return FALSE; + } + DWORD LastError; if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER)) { - Result = LOG_LAST_ERROR(L"Failed building driver info list"); + LastError = LOG_LAST_ERROR(L"Failed building driver info list"); goto cleanupDriverInstallationLock; } BOOL DestroyDriverInfoListOnCleanup = TRUE; @@ -1087,8 +1195,8 @@ SelectDriver( break; continue; } - SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData; - if (GetAdapterDrvInfoDetail(DevInfo, DevInfoData, &DrvInfoData, &DrvInfoDetailData) != ERROR_SUCCESS) + SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = GetAdapterDrvInfoDetail(DevInfo, DevInfoData, &DrvInfoData); + if (!DrvInfoDetailData) { LOG(WINTUN_LOG_WARN, L"Failed getting driver info detail"); continue; @@ -1103,7 +1211,7 @@ SelectDriver( SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE) { - Result = LOG_LAST_ERROR(L"Failed to get present adapters"); + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); HeapFree(ModuleHeap, 0, DrvInfoDetailData); goto cleanupExistingAdapters; } @@ -1114,16 +1222,16 @@ SelectDriver( LOG(WINTUN_LOG_WARN, L"Failed to unload existing driver, which means a reboot will likely be required"); } - LOG(WINTUN_LOG_INFO, TEXT("Removing existing driver")); + LOG(WINTUN_LOG_INFO, L"Removing existing driver"); if (!SetupUninstallOEMInfW(PathFindFileNameW(DrvInfoDetailData->InfFileName), SUOI_FORCEDELETE, NULL)) - LOG_LAST_ERROR(TEXT("Unable to remove existing driver")); + LOG_LAST_ERROR(L"Unable to remove existing driver"); goto next; } if (!IsNewer(&DrvInfoData.DriverDate, DrvInfoData.DriverVersion, &DriverDate, DriverVersion)) goto next; if (!SetupDiSetSelectedDriverW(DevInfo, DevInfoData, &DrvInfoData)) { - LOG_ERROR(L"Failed to select driver", GetLastError()); + LOG_LAST_ERROR(L"Failed to select driver"); goto next; } DriverDate = DrvInfoData.DriverDate; @@ -1134,14 +1242,15 @@ SelectDriver( if (DriverVersion) { + LastError = ERROR_SUCCESS; DestroyDriverInfoListOnCleanup = FALSE; goto cleanupExistingAdapters; } WCHAR RandomTempSubDirectory[MAX_PATH]; - if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) + if (!CreateTemporaryDirectory(RandomTempSubDirectory)) { - LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"); goto cleanupExistingAdapters; } @@ -1152,27 +1261,27 @@ SelectDriver( !PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") || !PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf")) { - Result = ERROR_BUFFER_OVERFLOW; + LastError = ERROR_BUFFER_OVERFLOW; goto cleanupDirectory; } BOOL UseWHQL = HaveWHQL(); - if (!UseWHQL && (Result = InstallCertificate(L"wintun.cat")) != ERROR_SUCCESS) + if (!UseWHQL && !InstallCertificate(L"wintun.cat")) LOG(WINTUN_LOG_WARN, L"Failed to install code signing certificate"); LOG(WINTUN_LOG_INFO, L"Extracting driver"); - if ((Result = ResourceCopyToFile(CatPath, UseWHQL ? L"wintun-whql.cat" : L"wintun.cat")) != ERROR_SUCCESS || - (Result = ResourceCopyToFile(SysPath, UseWHQL ? L"wintun-whql.sys" : L"wintun.sys")) != ERROR_SUCCESS || - (Result = ResourceCopyToFile(InfPath, UseWHQL ? L"wintun-whql.inf" : L"wintun.inf")) != ERROR_SUCCESS) + if (!ResourceCopyToFile(CatPath, UseWHQL ? L"wintun-whql.cat" : L"wintun.cat") || + !ResourceCopyToFile(SysPath, UseWHQL ? L"wintun-whql.sys" : L"wintun.sys") || + !ResourceCopyToFile(InfPath, UseWHQL ? L"wintun-whql.inf" : L"wintun.inf")) { - LOG(WINTUN_LOG_ERR, L"Failed to extract driver"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to extract driver"); goto cleanupDelete; } LOG(WINTUN_LOG_INFO, L"Installing driver"); WCHAR InfStorePath[MAX_PATH]; if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_NONE, 0, InfStorePath, MAX_PATH, NULL, NULL)) { - Result = LOG_LAST_ERROR(L"Could not install driver to store"); + LastError = LOG_LAST_ERROR(L"Could not install driver to store"); goto cleanupDelete; } _Analysis_assume_nullterminated_(InfStorePath); @@ -1190,32 +1299,32 @@ SelectDriver( STRUNCATE) { LOG(WINTUN_LOG_ERR, L"Inf path too long"); - Result = ERROR_INVALID_PARAMETER; + LastError = ERROR_INVALID_PARAMETER; goto cleanupDelete; } if (!SetupDiSetDeviceInstallParamsW(DevInfo, DevInfoData, DevInstallParams)) { - Result = LOG_LAST_ERROR(L"Setting device installation parameters failed"); + LastError = LOG_LAST_ERROR(L"Setting device installation parameters failed"); goto cleanupDelete; } if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER)) { - Result = LOG_LAST_ERROR(L"Failed rebuilding driver info list"); + LastError = LOG_LAST_ERROR(L"Failed rebuilding driver info list"); goto cleanupDelete; } DestroyDriverInfoListOnCleanup = TRUE; SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; if (!SetupDiEnumDriverInfoW(DevInfo, DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData)) { - Result = LOG_LAST_ERROR(L"Failed to get driver"); + LastError = LOG_LAST_ERROR(L"Failed to get driver"); goto cleanupDelete; } if (!SetupDiSetSelectedDriverW(DevInfo, DevInfoData, &DrvInfoData)) { - Result = LOG_LAST_ERROR(L"Failed to set driver"); + LastError = LOG_LAST_ERROR(L"Failed to set driver"); goto cleanupDelete; } - Result = ERROR_SUCCESS; + LastError = ERROR_SUCCESS; DestroyDriverInfoListOnCleanup = FALSE; cleanupDelete: @@ -1241,82 +1350,85 @@ cleanupExistingAdapters: SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER); cleanupDriverInstallationLock: NamespaceReleaseMutex(DriverInstallationLock); - return Result; + return RET_ERROR(TRUE, LastError); } -static WINTUN_STATUS -CreateAdapter( +static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( _In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _In_opt_ const GUID *RequestedGUID, - _Out_ WINTUN_ADAPTER **Adapter, _Inout_ BOOL *RebootRequired) { LOG(WINTUN_LOG_INFO, L"Creating adapter"); HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) - return LOG_LAST_ERROR(L"Creating empty device information set failed"); - DWORD Result; + { + LOG_LAST_ERROR(L"Creating empty device information set failed"); + return NULL; + } + DWORD LastError; + WINTUN_ADAPTER *Adapter = NULL; WCHAR ClassName[MAX_CLASS_NAME_LEN]; if (!SetupDiClassNameFromGuidExW(&GUID_DEVCLASS_NET, ClassName, _countof(ClassName), NULL, NULL, NULL)) { - Result = LOG_LAST_ERROR(L"Retrieving class name associated with class GUID failed"); + LastError = LOG_LAST_ERROR(L"Retrieving class name associated with class GUID failed"); goto cleanupDevInfo; } WCHAR PoolDeviceTypeName[MAX_POOL_DEVICE_TYPE]; - Result = GetPoolDeviceTypeName(Pool, PoolDeviceTypeName); - if (Result != ERROR_SUCCESS) + if (!GetPoolDeviceTypeName(Pool, PoolDeviceTypeName)) + { + LastError = GetLastError(); goto cleanupDevInfo; + } SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; if (!SetupDiCreateDeviceInfoW( DevInfo, ClassName, &GUID_DEVCLASS_NET, PoolDeviceTypeName, NULL, DICD_GENERATE_ID, &DevInfoData)) { - Result = LOG_LAST_ERROR(L"Creating new device information element failed"); + LastError = LOG_LAST_ERROR(L"Creating new device information element failed"); goto cleanupDevInfo; } SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(SP_DEVINSTALL_PARAMS_W) }; if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) { - Result = LOG_LAST_ERROR(L"Retrieving device installation parameters failed"); + LastError = LOG_LAST_ERROR(L"Retrieving device installation parameters failed"); goto cleanupDevInfo; } DevInstallParams.Flags |= DI_QUIETINSTALL; if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) { - Result = LOG_LAST_ERROR(L"Setting device installation parameters failed"); + LastError = LOG_LAST_ERROR(L"Setting device installation parameters failed"); goto cleanupDevInfo; } if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData)) { - Result = LOG_LAST_ERROR(L"Failed selecting device"); + LastError = LOG_LAST_ERROR(L"Failed selecting device"); goto cleanupDevInfo; } static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID; if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids))) { - Result = LOG_LAST_ERROR(L"Failed setting hardware ID"); + LastError = LOG_LAST_ERROR(L"Failed setting hardware ID"); goto cleanupDevInfo; } - Result = SelectDriver(DevInfo, &DevInfoData, &DevInstallParams, RebootRequired); - if (Result != ERROR_SUCCESS) + if (!SelectDriver(DevInfo, &DevInfoData, &DevInstallParams, RebootRequired)) { - LOG(WINTUN_LOG_ERR, L"Failed to select driver"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to select driver"); goto cleanupDevInfo; } HANDLE Mutex = NamespaceTakePoolMutex(Pool); if (!Mutex) { - Result = LOG_LAST_ERROR(L"Failed to take pool mutex"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to take pool mutex"); goto cleanupDriverInfoList; } if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData)) { - Result = LOG_LAST_ERROR(L"Registering device failed"); + LastError = LOG_LAST_ERROR(L"Registering device failed"); goto cleanupDevice; } if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData)) @@ -1333,22 +1445,22 @@ CreateAdapter( } if (NetDevRegKey == INVALID_HANDLE_VALUE) { - Result = LOG_LAST_ERROR(L"Failed to open device-specific registry key"); + LastError = LOG_LAST_ERROR(L"Failed to open device-specific registry key"); goto cleanupDevice; } if (RequestedGUID) { WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; - Result = RegSetValueExW( + LastError = RegSetValueExW( NetDevRegKey, L"NetSetupAnticipatedInstanceId", 0, REG_SZ, (const BYTE *)RequestedGUIDStr, StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) * sizeof(WCHAR)); - if (Result != ERROR_SUCCESS) + if (LastError != ERROR_SUCCESS) { - LOG_LAST_ERROR(L"Failed to set NetSetupAnticipatedInstanceId"); + LOG_ERROR(L"Failed to set NetSetupAnticipatedInstanceId", LastError); goto cleanupNetDevRegKey; } } @@ -1358,7 +1470,7 @@ CreateAdapter( if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData)) { - Result = LOG_LAST_ERROR(L"Installing device failed"); + LastError = LOG_LAST_ERROR(L"Installing device failed"); goto cleanupNetDevRegKey; } *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); @@ -1370,99 +1482,87 @@ CreateAdapter( (const BYTE *)PoolDeviceTypeName, (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(WCHAR)))) { - Result = LOG_LAST_ERROR(L"Failed to set adapter description"); + LastError = LOG_LAST_ERROR(L"Failed to set adapter description"); 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; - Result = RegistryQueryStringWait(NetDevRegKey, L"NetCfgInstanceId", WAIT_FOR_REGISTRY_TIMEOUT, &DummyStr); - if (Result != ERROR_SUCCESS) + WCHAR *DummyStr = RegistryQueryStringWait(NetDevRegKey, L"NetCfgInstanceId", WAIT_FOR_REGISTRY_TIMEOUT); + if (!DummyStr) { - LOG(WINTUN_LOG_ERR, L"Failed to get NetCfgInstanceId"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get NetCfgInstanceId"); goto cleanupNetDevRegKey; } HeapFree(ModuleHeap, 0, DummyStr); DWORD DummyDWORD; - Result = RegistryQueryDWORDWait(NetDevRegKey, L"NetLuidIndex", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD); - if (Result != ERROR_SUCCESS) + if (!RegistryQueryDWORDWait(NetDevRegKey, L"NetLuidIndex", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD)) { - LOG(WINTUN_LOG_ERR, L"Failed to get NetLuidIndex"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get NetLuidIndex"); goto cleanupNetDevRegKey; } - Result = RegistryQueryDWORDWait(NetDevRegKey, L"*IfType", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD); - if (Result != ERROR_SUCCESS) + if (!RegistryQueryDWORDWait(NetDevRegKey, L"*IfType", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD)) { - LOG(WINTUN_LOG_ERR, L"Failed to get *IfType"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get *IfType"); goto cleanupNetDevRegKey; } - WINTUN_ADAPTER *a; - Result = CreateAdapterData(Pool, DevInfo, &DevInfoData, &a); - if (Result != ERROR_SUCCESS) + Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); + if (!Adapter) { - LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); goto cleanupNetDevRegKey; } HKEY TcpipAdapterRegKey; WCHAR TcpipAdapterRegPath[MAX_REG_PATH]; - Result = GetTcpipAdapterRegPath(a, TcpipAdapterRegPath); - if (Result != ERROR_SUCCESS) + if (!GetTcpipAdapterRegPath(Adapter, TcpipAdapterRegPath)) + { + LastError = GetLastError(); goto cleanupAdapter; - Result = RegistryOpenKeyWait( - HKEY_LOCAL_MACHINE, - TcpipAdapterRegPath, - KEY_QUERY_VALUE | KEY_NOTIFY, - WAIT_FOR_REGISTRY_TIMEOUT, - &TcpipAdapterRegKey); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to open adapter-specific TCP/IP interface registry key"); + } + TcpipAdapterRegKey = RegistryOpenKeyWait( + HKEY_LOCAL_MACHINE, TcpipAdapterRegPath, KEY_QUERY_VALUE | KEY_NOTIFY, WAIT_FOR_REGISTRY_TIMEOUT); + if (!TcpipAdapterRegKey) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to open adapter-specific TCP/IP interface registry key"); goto cleanupAdapter; } - Result = RegistryQueryStringWait(TcpipAdapterRegKey, L"IpConfig", WAIT_FOR_REGISTRY_TIMEOUT, &DummyStr); - if (Result != ERROR_SUCCESS) + DummyStr = RegistryQueryStringWait(TcpipAdapterRegKey, L"IpConfig", WAIT_FOR_REGISTRY_TIMEOUT); + if (!DummyStr) { - LOG(WINTUN_LOG_ERR, L"Failed to get IpConfig"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get IpConfig"); goto cleanupTcpipAdapterRegKey; } HeapFree(ModuleHeap, 0, DummyStr); HKEY TcpipInterfaceRegKey; WCHAR TcpipInterfaceRegPath[MAX_REG_PATH]; - Result = GetTcpipInterfaceRegPath(a, TcpipInterfaceRegPath); - if (Result != ERROR_SUCCESS) + if (!GetTcpipInterfaceRegPath(Adapter, TcpipInterfaceRegPath)) { - LOG(WINTUN_LOG_ERR, L"Failed to determine interface-specific TCP/IP network registry key path"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to determine interface-specific TCP/IP network registry key path"); goto cleanupTcpipAdapterRegKey; } - Result = RegistryOpenKeyWait( - HKEY_LOCAL_MACHINE, - TcpipInterfaceRegPath, - KEY_QUERY_VALUE | KEY_SET_VALUE, - WAIT_FOR_REGISTRY_TIMEOUT, - &TcpipInterfaceRegKey); - if (Result != ERROR_SUCCESS) + TcpipInterfaceRegKey = RegistryOpenKeyWait( + HKEY_LOCAL_MACHINE, TcpipInterfaceRegPath, KEY_QUERY_VALUE | KEY_SET_VALUE, WAIT_FOR_REGISTRY_TIMEOUT); + if (!TcpipInterfaceRegKey) { - LOG(WINTUN_LOG_ERR, L"Failed to open interface-specific TCP/IP network registry key"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to open interface-specific TCP/IP network registry key"); goto cleanupTcpipAdapterRegKey; } static const DWORD EnableDeadGWDetect = 0; - Result = RegSetKeyValueW( + LastError = RegSetKeyValueW( TcpipInterfaceRegKey, NULL, L"EnableDeadGWDetect", REG_DWORD, &EnableDeadGWDetect, sizeof(EnableDeadGWDetect)); - if (Result != ERROR_SUCCESS) + if (LastError != ERROR_SUCCESS) { - LOG_ERROR(L"Failed to set EnableDeadGWDetect", Result); + LOG_ERROR(L"Failed to set EnableDeadGWDetect", LastError); goto cleanupTcpipInterfaceRegKey; } - Result = WintunSetAdapterName(a, Name); - if (Result != ERROR_SUCCESS) + if (!WintunSetAdapterName(Adapter, Name)) { - LOG_ERROR(L"Failed to set adapter name", Result); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to set adapter name"); goto cleanupTcpipInterfaceRegKey; } @@ -1481,11 +1581,11 @@ CreateAdapter( 0) && PropertyType == DEVPROP_TYPE_NTSTATUS) { - Result = RtlNtStatusToDosError(ProblemStatus); - _Analysis_assume_(Result != ERROR_SUCCESS); + LastError = RtlNtStatusToDosError(ProblemStatus); + _Analysis_assume_(LastError != ERROR_SUCCESS); if (ProblemStatus != STATUS_PNP_DEVICE_CONFIGURATION_PENDING || Tries == 999) { - LOG_ERROR(L"Failed to setup adapter", Result); + LOG_ERROR(L"Failed to setup adapter", LastError); goto cleanupTcpipInterfaceRegKey; } Sleep(10); @@ -1493,21 +1593,22 @@ CreateAdapter( else break; } - Result = ERROR_SUCCESS; - - *Adapter = a; + LastError = ERROR_SUCCESS; cleanupTcpipInterfaceRegKey: RegCloseKey(TcpipInterfaceRegKey); cleanupTcpipAdapterRegKey: RegCloseKey(TcpipAdapterRegKey); cleanupAdapter: - if (Result != ERROR_SUCCESS) - HeapFree(ModuleHeap, 0, a); + if (LastError != ERROR_SUCCESS) + { + HeapFree(ModuleHeap, 0, Adapter); + Adapter = NULL; + } cleanupNetDevRegKey: RegCloseKey(NetDevRegKey); cleanupDevice: - if (Result != ERROR_SUCCESS) + 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), @@ -1523,120 +1624,137 @@ cleanupDriverInfoList: SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); cleanupDevInfo: SetupDiDestroyDeviceInfoList(DevInfo); - return Result; + return RET_ERROR(Adapter, LastError); } -static WINTUN_STATUS -GetAdapter(_In_z_ const WCHAR *Pool, _In_ const GUID *CfgInstanceID, _Out_ WINTUN_ADAPTER **Adapter) +static _Return_type_success_(return != NULL) + WINTUN_ADAPTER *GetAdapter(_In_z_ const WCHAR *Pool, _In_ const GUID *CfgInstanceID) { HANDLE Mutex = NamespaceTakePoolMutex(Pool); if (!Mutex) - return ERROR_INVALID_HANDLE; + { + LOG(WINTUN_LOG_ERR, L"Failed to take pool mutex"); + return NULL; + } + DWORD LastError; + WINTUN_ADAPTER *Adapter = NULL; HDEVINFO DevInfo; SP_DEVINFO_DATA DevInfoData; - DWORD Result = GetDevInfoData(CfgInstanceID, &DevInfo, &DevInfoData); - if (Result != ERROR_SUCCESS) + if (!GetDevInfoData(CfgInstanceID, &DevInfo, &DevInfoData)) { - LOG(WINTUN_LOG_ERR, L"Failed to locate adapter"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to locate adapter"); goto cleanupMutex; } - Result = CreateAdapterData(Pool, DevInfo, &DevInfoData, Adapter); - if (Result != ERROR_SUCCESS) - LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); + Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); + LastError = Adapter ? ERROR_SUCCESS : LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); SetupDiDestroyDeviceInfoList(DevInfo); cleanupMutex: NamespaceReleaseMutex(Mutex); - return Result; + return RET_ERROR(Adapter, LastError); } #include "rundll32.h" -WINTUN_STATUS WINAPI -WintunCreateAdapter( +_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_ WINTUN_ADAPTER **Adapter, _Out_opt_ BOOL *RebootRequired) { if (!ElevateToSystem()) - return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user"); + { + LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"); + return NULL; + } BOOL DummyRebootRequired; if (!RebootRequired) RebootRequired = &DummyRebootRequired; *RebootRequired = FALSE; - DWORD Result; + DWORD LastError; + WINTUN_ADAPTER *Adapter; if (MAYBE_WOW64 && NativeMachine != IMAGE_FILE_PROCESS) - Result = CreateAdapterViaRundll32(Pool, Name, RequestedGUID, Adapter, RebootRequired); - else - Result = CreateAdapter(Pool, Name, RequestedGUID, Adapter, RebootRequired); + { + Adapter = CreateAdapterViaRundll32(Pool, Name, RequestedGUID, RebootRequired); + LastError = Adapter ? ERROR_SUCCESS : GetLastError(); + goto cleanupToken; + } + Adapter = CreateAdapter(Pool, Name, RequestedGUID, RebootRequired); + LastError = Adapter ? ERROR_SUCCESS : GetLastError(); +cleanupToken: RevertToSelf(); - return Result; + return RET_ERROR(Adapter, LastError); } -WINTUN_STATUS WINAPI -WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired) +_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter( + _In_ const WINTUN_ADAPTER *Adapter, + _In_ BOOL ForceCloseSessions, + _Out_opt_ BOOL *RebootRequired) { if (!ElevateToSystem()) - return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user"); - + { + LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"); + return FALSE; + } BOOL DummyRebootRequired; if (!RebootRequired) RebootRequired = &DummyRebootRequired; *RebootRequired = FALSE; - DWORD Result; + DWORD LastError; if (MAYBE_WOW64 && NativeMachine != IMAGE_FILE_PROCESS) { - Result = DeleteAdapterViaRundll32(Adapter, ForceCloseSessions, RebootRequired); - RevertToSelf(); - return Result; + LastError = + DeleteAdapterViaRundll32(Adapter, ForceCloseSessions, RebootRequired) ? ERROR_SUCCESS : GetLastError(); + goto cleanupToken; } HDEVINFO DevInfo; SP_DEVINFO_DATA DevInfoData; - Result = GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData); - if (Result == ERROR_FILE_NOT_FOUND) + if (!GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData)) { - Result = ERROR_SUCCESS; - goto cleanupToken; - } - else if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get adapter info data"); + if ((LastError = GetLastError()) == ERROR_FILE_NOT_FOUND) + LastError = ERROR_SUCCESS; + else + LOG(WINTUN_LOG_ERR, L"Failed to get adapter info data"); goto cleanupToken; } - if (ForceCloseSessions && ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS) + if (ForceCloseSessions && !ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData)) LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles"); SetQuietInstall(DevInfo, &DevInfoData); - SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_REMOVE }, - .Scope = DI_REMOVEDEVICE_GLOBAL }; - if (SetupDiSetClassInstallParamsW( - DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) && - SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) - *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); - else - Result = LOG_LAST_ERROR(L"Failed to remove existing adapter"); + 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)) + { + LastError = LOG_LAST_ERROR(L"Failed to remove existing adapter"); + goto cleanupDevInfo; + } + LastError = ERROR_SUCCESS; +cleanupDevInfo: + *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); SetupDiDestroyDeviceInfoList(DevInfo); cleanupToken: RevertToSelf(); - return Result; + return RET_ERROR(TRUE, LastError); } -static WINTUN_STATUS -DeleteAllOurAdapters(_In_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired) +static _Return_type_success_(return != FALSE) BOOL + DeleteAllOurAdapters(_In_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired) { HANDLE Mutex = NamespaceTakePoolMutex(Pool); if (!Mutex) - return ERROR_INVALID_HANDLE; - DWORD Result = ERROR_SUCCESS; + { + LOG(WINTUN_LOG_ERR, L"Failed to take pool mutex"); + return FALSE; + } + DWORD LastError = ERROR_SUCCESS; HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) { - NamespaceReleaseMutex(Mutex); - return LOG_LAST_ERROR(L"Failed to get present adapters"); + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); + goto cleanupMutex; } SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), .InstallFunction = DIF_REMOVE }, @@ -1651,76 +1769,70 @@ DeleteAllOurAdapters(_In_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *Reboo continue; } - BOOL IsOurs; - if (IsOurAdapter(DevInfo, &DevInfoData, &IsOurs) != ERROR_SUCCESS || !IsOurs) - continue; - BOOL IsMember; - Result = IsPoolMember(Pool, DevInfo, &DevInfoData, &IsMember); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get pool membership"); - break; - } - if (!IsMember) + if (!IsOurAdapter(DevInfo, &DevInfoData) || !IsPoolMember(Pool, DevInfo, &DevInfoData)) continue; LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter"); - if (ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS) + if (!ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData)) LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles"); LOG(WINTUN_LOG_INFO, L"Removing existing adapter"); - if (SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) && - SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) - *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); - else + if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || + !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) { LOG_LAST_ERROR(L"Failed to remove existing adapter"); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); } + *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); } SetupDiDestroyDeviceInfoList(DevInfo); +cleanupMutex: NamespaceReleaseMutex(Mutex); - return Result; + return RET_ERROR(TRUE, LastError); } -WINTUN_STATUS WINAPI -WintunDeletePoolDriver(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired) +_Return_type_success_(return != FALSE) BOOL WINAPI + WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired) { if (!ElevateToSystem()) - return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user"); + { + LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"); + return FALSE; + } BOOL DummyRebootRequired; if (!RebootRequired) RebootRequired = &DummyRebootRequired; *RebootRequired = FALSE; - DWORD Result; + DWORD LastError = ERROR_SUCCESS; if (MAYBE_WOW64 && NativeMachine != IMAGE_FILE_PROCESS) { - Result = DeletePoolDriverViaRundll32(Pool, RebootRequired); - RevertToSelf(); - return Result; + LastError = DeletePoolDriverViaRundll32(Pool, RebootRequired) ? ERROR_SUCCESS : GetLastError(); + goto cleanupToken; } - Result = DeleteAllOurAdapters(Pool, RebootRequired); - if (Result != ERROR_SUCCESS) + if (!DeleteAllOurAdapters(Pool, RebootRequired)) + { + LastError = GetLastError(); goto cleanupToken; + } HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); if (!DriverInstallationLock) { - Result = LOG_LAST_ERROR(L"Failed to take driver installation mutex"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex"); goto cleanupToken; } HDEVINFO DeviceInfoSet = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, 0); if (!DeviceInfoSet) { - Result = LOG_LAST_ERROR(L"Failed to get adapter information"); + LastError = LOG_LAST_ERROR(L"Failed to get adapter information"); goto cleanupDriverInstallationLock; } if (!SetupDiBuildDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER)) { - Result = LOG_LAST_ERROR(L"Failed building driver info list"); + LastError = LOG_LAST_ERROR(L"Failed building driver info list"); goto cleanupDeviceInfoSet; } for (DWORD EnumIndex = 0;; ++EnumIndex) @@ -1732,16 +1844,16 @@ WintunDeletePoolDriver(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL break; continue; } - SP_DRVINFO_DETAIL_DATA_W *DriverDetail; - if (GetAdapterDrvInfoDetail(DeviceInfoSet, NULL, &DriverInfo, &DriverDetail) != ERROR_SUCCESS) + SP_DRVINFO_DETAIL_DATA_W *DriverDetail = GetAdapterDrvInfoDetail(DeviceInfoSet, NULL, &DriverInfo); + if (!DriverDetail) continue; if (!_wcsicmp(DriverDetail->HardwareID, WINTUN_HWID)) { - LOG(WINTUN_LOG_INFO, TEXT("Removing existing driver")); + LOG(WINTUN_LOG_INFO, L"Removing existing driver"); if (!SetupUninstallOEMInfW(PathFindFileNameW(DriverDetail->InfFileName), 0, NULL)) { - LOG_LAST_ERROR(TEXT("Unable to remove existing driver")); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); + LOG_LAST_ERROR(L"Unable to remove existing driver"); + LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError(); } } HeapFree(ModuleHeap, 0, DriverDetail); @@ -1753,20 +1865,23 @@ cleanupDriverInstallationLock: NamespaceReleaseMutex(DriverInstallationLock); cleanupToken: RevertToSelf(); - return Result; + return RET_ERROR(TRUE, LastError); } -WINTUN_STATUS WINAPI -WintunEnumAdapters(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK_FUNC Func, _In_ LPARAM Param) +_Return_type_success_(return != FALSE) BOOL WINAPI + WintunEnumAdapters(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK_FUNC Func, _In_ LPARAM Param) { HANDLE Mutex = NamespaceTakePoolMutex(Pool); if (!Mutex) - return ERROR_INVALID_HANDLE; - DWORD Result = ERROR_SUCCESS; + { + LOG(WINTUN_LOG_ERR, L"Failed to take pool mutex"); + return FALSE; + } + DWORD LastError = ERROR_SUCCESS; HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) { - Result = LOG_LAST_ERROR(L"Failed to get present adapters"); + LastError = LOG_LAST_ERROR(L"Failed to get present adapters"); goto cleanupMutex; } BOOL Continue = TRUE; @@ -1780,25 +1895,13 @@ WintunEnumAdapters(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK_FUNC Func continue; } - BOOL IsOurs; - if (IsOurAdapter(DevInfo, &DevInfoData, &IsOurs) != ERROR_SUCCESS || !IsOurs) - continue; - - BOOL IsMember; - Result = IsPoolMember(Pool, DevInfo, &DevInfoData, &IsMember); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get pool membership"); - break; - } - if (!IsMember) + if (!IsOurAdapter(DevInfo, &DevInfoData) || !IsPoolMember(Pool, DevInfo, &DevInfoData)) continue; - WINTUN_ADAPTER *Adapter; - Result = CreateAdapterData(Pool, DevInfo, &DevInfoData, &Adapter); - if (Result != ERROR_SUCCESS) + WINTUN_ADAPTER *Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); + if (!Adapter) { - LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); break; } Continue = Func(Adapter, Param); @@ -1807,5 +1910,5 @@ WintunEnumAdapters(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK_FUNC Func SetupDiDestroyDeviceInfoList(DevInfo); cleanupMutex: NamespaceReleaseMutex(Mutex); - return Result; + return RET_ERROR(TRUE, LastError); } diff --git a/api/adapter.h b/api/adapter.h index cd890ab..3f4532a 100644 --- a/api/adapter.h +++ b/api/adapter.h @@ -37,28 +37,28 @@ WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter); /** * @copydoc WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC */ -WINTUN_STATUS WINAPI -WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle); +_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI + WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter); /** * @copydoc WINTUN_CREATE_ADAPTER_FUNC */ -WINTUN_STATUS WINAPI -WintunCreateAdapter( +_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_ WINTUN_ADAPTER **Adapter, _Out_opt_ BOOL *RebootRequired); /** * @copydoc WINTUN_DELETE_ADAPTER_FUNC */ -WINTUN_STATUS WINAPI -WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired); +_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter( + _In_ const WINTUN_ADAPTER *Adapter, + _In_ BOOL ForceCloseSessions, + _Out_opt_ BOOL *RebootRequired); /** * @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC */ -WINTUN_STATUS WINAPI -WintunDeletePoolDriver(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired); +_Return_type_success_(return != FALSE) BOOL WINAPI + WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired); diff --git a/api/elevate.c b/api/elevate.c index e89a54c..57bafbf 100644 --- a/api/elevate.c +++ b/api/elevate.c @@ -4,12 +4,12 @@ */ #include "elevate.h" +#include "logger.h" #include #include -BOOL -ElevateToSystem(void) +_Return_type_success_(return != FALSE) BOOL ElevateToSystem(void) { HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken; PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) }; @@ -25,29 +25,40 @@ ElevateToSystem(void) } TokenUserBuffer; Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes); - LastError = GetLastError(); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to create SID"); goto cleanup; + } Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken); - LastError = GetLastError(); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to open process token"); goto cleanup; + } Ret = GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes); LastError = GetLastError(); CloseHandle(CurrentProcessToken); if (!Ret) + { + LOG_ERROR(L"Failed to get token information", LastError); goto cleanup; + } if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) return TRUE; Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid); - LastError = GetLastError(); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value"); goto cleanup; + } ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - LastError = GetLastError(); if (ProcessSnapshot == INVALID_HANDLE_VALUE) + { + LastError = LOG_LAST_ERROR(L"Failed to create toolhelp snapshot"); goto cleanup; + } for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret; Ret = Process32NextW(ProcessSnapshot, &ProcessEntry)) { @@ -55,13 +66,17 @@ ElevateToSystem(void) continue; RevertToSelf(); Ret = ImpersonateSelf(SecurityImpersonation); - LastError = GetLastError(); if (!Ret) + { + LastError = GetLastError(); continue; + } Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken); - LastError = GetLastError(); if (!Ret) + { + LastError = GetLastError(); continue; + } Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL); LastError = GetLastError(); CloseHandle(ThreadToken); @@ -69,9 +84,11 @@ ElevateToSystem(void) continue; WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID); - LastError = GetLastError(); if (!WinlogonProcess) + { + LastError = GetLastError(); continue; + } Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken); LastError = GetLastError(); CloseHandle(WinlogonProcess); @@ -84,13 +101,15 @@ ElevateToSystem(void) continue; if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes)) goto next; - if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + { + SetLastError(ERROR_ACCESS_DENIED); goto next; + } if (!SetThreadToken(NULL, DuplicatedToken)) goto next; CloseHandle(DuplicatedToken); CloseHandle(ProcessSnapshot); - SetLastError(ERROR_SUCCESS); return TRUE; next: LastError = GetLastError(); @@ -103,8 +122,7 @@ cleanup: return FALSE; } -HANDLE -GetPrimarySystemTokenFromThread(void) +_Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void) { HANDLE CurrentThreadToken, DuplicatedToken; BOOL Ret; @@ -120,26 +138,41 @@ GetPrimarySystemTokenFromThread(void) Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to create SID"); return NULL; + } Ret = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, FALSE, &CurrentThreadToken); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to open thread token"); return NULL; + } Ret = GetTokenInformation(CurrentThreadToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes); - LastError = GetLastError(); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to get token information"); goto cleanup; - LastError = ERROR_ACCESS_DENIED; + } if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + { + LOG(WINTUN_LOG_ERR, L"Not SYSTEM"); + LastError = ERROR_ACCESS_DENIED; goto cleanup; + } Ret = LookupPrivilegeValueW(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &Privileges.Privileges[0].Luid); - LastError = GetLastError(); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value"); goto cleanup; + } Ret = AdjustTokenPrivileges(CurrentThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL); - LastError = GetLastError(); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to adjust token privileges"); goto cleanup; + } Ret = DuplicateTokenEx( CurrentThreadToken, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, @@ -147,14 +180,16 @@ GetPrimarySystemTokenFromThread(void) SecurityImpersonation, TokenPrimary, &DuplicatedToken); - LastError = GetLastError(); if (!Ret) + { + LastError = LOG_LAST_ERROR(L"Failed to duplicate token"); goto cleanup; + } CloseHandle(CurrentThreadToken); return DuplicatedToken; cleanup: CloseHandle(CurrentThreadToken); SetLastError(LastError); - return FALSE; + return NULL; } diff --git a/api/elevate.h b/api/elevate.h index 5f2cbbd..aa0fc60 100644 --- a/api/elevate.h +++ b/api/elevate.h @@ -7,8 +7,6 @@ #include -BOOL -ElevateToSystem(void); +_Return_type_success_(return != FALSE) BOOL ElevateToSystem(void); -HANDLE -GetPrimarySystemTokenFromThread(void); \ No newline at end of file +_Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void); diff --git a/api/entry.c b/api/entry.c index 4b56a12..6afccbc 100644 --- a/api/entry.c +++ b/api/entry.c @@ -22,7 +22,8 @@ HINSTANCE ResourceModule; HANDLE ModuleHeap; SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) }; -static FARPROC WINAPI DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) +static FARPROC WINAPI +DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) { if (dliNotify != dliNotePreLoadLibrary) return NULL; @@ -53,7 +54,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) break; case DLL_PROCESS_DETACH: - NamespaceCleanup(); + NamespaceDone(); LocalFree(SecurityAttributes.lpSecurityDescriptor); HeapDestroy(ModuleHeap); break; diff --git a/api/entry.h b/api/entry.h index ac37680..4f925b1 100644 --- a/api/entry.h +++ b/api/entry.h @@ -26,6 +26,8 @@ #endif #pragma warning(disable : 4127) /* conditional expression is constant */ +#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0)) + extern HINSTANCE ResourceModule; extern HANDLE ModuleHeap; extern SECURITY_ATTRIBUTES SecurityAttributes; diff --git a/api/logger.h b/api/logger.h index 5e26de3..0affdc3 100644 --- a/api/logger.h +++ b/api/logger.h @@ -16,20 +16,29 @@ extern WINTUN_LOGGER_CALLBACK_FUNC Logger; void WINAPI WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK_FUNC NewLogger); +static inline _Post_equals_last_error_ DWORD +LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) +{ + DWORD LastError = GetLastError(); + Logger(Level, LogLine); + SetLastError(LastError); + return LastError; +} + _Post_equals_last_error_ DWORD LoggerError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error); static inline _Post_equals_last_error_ DWORD LoggerLastError(_In_z_ const WCHAR *Prefix) { - DWORD Error = GetLastError(); - LoggerError(Prefix, Error); - SetLastError(Error); - return Error; + DWORD LastError = GetLastError(); + LoggerError(Prefix, LastError); + SetLastError(LastError); + return LastError; } #define __L(x) L##x #define _L(x) __L(x) -#define LOG(lvl, msg) (Logger((lvl), _L(__FUNCTION__) L": " msg)) +#define LOG(lvl, msg) (LoggerLog((lvl), _L(__FUNCTION__) L": " msg)) #define LOG_ERROR(msg, err) (LoggerError(_L(__FUNCTION__) L": " msg, (err))) #define LOG_LAST_ERROR(msg) (LoggerLastError(_L(__FUNCTION__) L": " msg)) diff --git a/api/namespace.c b/api/namespace.c index 7f6959b..883a1a7 100644 --- a/api/namespace.c +++ b/api/namespace.c @@ -15,41 +15,48 @@ static BOOL HasInitialized = FALSE; static CRITICAL_SECTION Initializing; static BCRYPT_ALG_HANDLE AlgProvider; -static WCHAR * -NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source) +static _Return_type_success_( + return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source) { int Len = NormalizeString(NormForm, Source, -1, NULL, 0); for (;;) { WCHAR *Str = HeapAlloc(ModuleHeap, 0, sizeof(WCHAR) * Len); if (!Str) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), NULL; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } Len = NormalizeString(NormForm, Source, -1, Str, Len); if (Len > 0) return Str; - DWORD Result = GetLastError(); + DWORD LastError = GetLastError(); HeapFree(ModuleHeap, 0, Str); - if (Result != ERROR_INSUFFICIENT_BUFFER) - return LOG_ERROR(L"Failed", Result), NULL; + if (LastError != ERROR_INSUFFICIENT_BUFFER) + { + SetLastError(LOG_ERROR(L"Failed", LastError)); + return NULL; + } Len = -Len; } } -static WINTUN_STATUS -NamespaceRuntimeInit(void) +static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void) { - DWORD Result; + DWORD LastError; EnterCriticalSection(&Initializing); if (HasInitialized) { LeaveCriticalSection(&Initializing); - return ERROR_SUCCESS; + return TRUE; } if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0))) { - Result = ERROR_GEN_FAILURE; + LOG(WINTUN_LOG_ERR, L"Failed to open algorithm provider"); + LastError = ERROR_GEN_FAILURE; goto cleanupLeaveCriticalSection; } @@ -57,19 +64,19 @@ NamespaceRuntimeInit(void) DWORD SidSize = MAX_SID_SIZE; if (!CreateWellKnownSid(WinLocalSystemSid, NULL, Sid, &SidSize)) { - Result = GetLastError(); + LastError = LOG_LAST_ERROR(L"Failed to create SID"); goto cleanupBCryptCloseAlgorithmProvider; } HANDLE Boundary = CreateBoundaryDescriptorW(L"Wintun", 0); if (!Boundary) { - Result = GetLastError(); + LastError = LOG_LAST_ERROR(L"Failed to create boundary descriptor"); goto cleanupBCryptCloseAlgorithmProvider; } if (!AddSIDToBoundaryDescriptor(&Boundary, Sid)) { - Result = GetLastError(); + LastError = LOG_LAST_ERROR(L"Failed to add SID to boundary descriptor"); goto cleanupBCryptCloseAlgorithmProvider; } @@ -77,98 +84,124 @@ NamespaceRuntimeInit(void) { if (CreatePrivateNamespaceW(&SecurityAttributes, Boundary, L"Wintun")) break; - Result = GetLastError(); - if (Result == ERROR_ALREADY_EXISTS) + if ((LastError = GetLastError()) == ERROR_ALREADY_EXISTS) { if (OpenPrivateNamespaceW(Boundary, L"Wintun")) break; - Result = GetLastError(); - if (Result == ERROR_PATH_NOT_FOUND) + if ((LastError = GetLastError()) == ERROR_PATH_NOT_FOUND) continue; + LOG_ERROR(L"Failed to open private namespace", LastError); } + else + LOG_ERROR(L"Failed to create private namespace", LastError); goto cleanupBCryptCloseAlgorithmProvider; } HasInitialized = TRUE; - Result = ERROR_SUCCESS; - goto cleanupLeaveCriticalSection; + LeaveCriticalSection(&Initializing); + return TRUE; cleanupBCryptCloseAlgorithmProvider: BCryptCloseAlgorithmProvider(AlgProvider, 0); cleanupLeaveCriticalSection: LeaveCriticalSection(&Initializing); - return Result; + SetLastError(LastError); + return FALSE; } _Check_return_ -HANDLE -NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool) +_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool) { - HANDLE Mutex = NULL; - - if (NamespaceRuntimeInit() != ERROR_SUCCESS) + if (!NamespaceRuntimeInit()) return NULL; BCRYPT_HASH_HANDLE Sha256 = NULL; if (!BCRYPT_SUCCESS(BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0))) + { + LOG(WINTUN_LOG_ERR, L"Failed to create hash"); + SetLastError(ERROR_GEN_FAILURE); return NULL; + } + DWORD LastError; static const WCHAR mutex_label[] = L"Wintun Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com"; - if (!BCRYPT_SUCCESS(BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0))) + if (!BCRYPT_SUCCESS( + BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0))) + { + LOG(WINTUN_LOG_ERR, L"Failed to hash data"); + LastError = ERROR_GEN_FAILURE; goto cleanupSha256; + } WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool); if (!PoolNorm) + { + LastError = GetLastError(); goto cleanupSha256; - if (!BCRYPT_SUCCESS(BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0))) + } + if (!BCRYPT_SUCCESS( + BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0))) + { + LOG(WINTUN_LOG_ERR, L"Failed to hash data"); + LastError = ERROR_GEN_FAILURE; goto cleanupPoolNorm; + } BYTE Hash[32]; if (!BCRYPT_SUCCESS(BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0))) + { + LOG(WINTUN_LOG_ERR, L"Failed to calculate hash"); + LastError = ERROR_GEN_FAILURE; goto cleanupPoolNorm; + } static const WCHAR MutexNamePrefix[] = L"Wintun\\Wintun-Name-Mutex-"; WCHAR MutexName[_countof(MutexNamePrefix) + sizeof(Hash) * 2]; memcpy(MutexName, MutexNamePrefix, sizeof(MutexNamePrefix)); for (size_t i = 0; i < sizeof(Hash); ++i) swprintf_s(&MutexName[_countof(MutexNamePrefix) - 1 + i * 2], 3, L"%02x", Hash[i]); - Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName); + HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName); if (!Mutex) + { + LastError = LOG_LAST_ERROR(L"Failed to create mutex"); goto cleanupPoolNorm; + } switch (WaitForSingleObject(Mutex, INFINITE)) { case WAIT_OBJECT_0: case WAIT_ABANDONED: - goto cleanupPoolNorm; + HeapFree(ModuleHeap, 0, PoolNorm); + BCryptDestroyHash(Sha256); + return Mutex; } - + LOG(WINTUN_LOG_ERR, L"Failed to get mutex"); + LastError = ERROR_GEN_FAILURE; CloseHandle(Mutex); - Mutex = NULL; cleanupPoolNorm: HeapFree(ModuleHeap, 0, PoolNorm); cleanupSha256: BCryptDestroyHash(Sha256); - return Mutex; + SetLastError(LastError); + return NULL; } _Check_return_ -HANDLE -NamespaceTakeDriverInstallationMutex(void) +_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void) { - HANDLE Mutex = NULL; - - if (NamespaceRuntimeInit() != ERROR_SUCCESS) + if (!NamespaceRuntimeInit()) return NULL; - Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex"); + HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex"); if (!Mutex) + { + LOG_LAST_ERROR(L"Failed to create mutex"); return NULL; + } switch (WaitForSingleObject(Mutex, INFINITE)) { case WAIT_OBJECT_0: case WAIT_ABANDONED: - goto out; + return Mutex; } - + LOG(WINTUN_LOG_ERR, L"Failed to get mutex"); CloseHandle(Mutex); - Mutex = NULL; -out: - return Mutex; + SetLastError(ERROR_GEN_FAILURE); + return NULL; } void @@ -185,7 +218,7 @@ NamespaceInit(void) } void -NamespaceCleanup(void) +NamespaceDone(void) { EnterCriticalSection(&Initializing); if (HasInitialized) diff --git a/api/namespace.h b/api/namespace.h index 0f2598a..d0f83a1 100644 --- a/api/namespace.h +++ b/api/namespace.h @@ -8,12 +8,10 @@ #include _Check_return_ -HANDLE -NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool); +_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool); _Check_return_ -HANDLE -NamespaceTakeDriverInstallationMutex(void); +_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void); void NamespaceReleaseMutex(_In_ HANDLE Mutex); @@ -22,4 +20,4 @@ void NamespaceInit(void); void -NamespaceCleanup(void); +NamespaceDone(void); diff --git a/api/registry.c b/api/registry.c index 82e3020..523016e 100644 --- a/api/registry.c +++ b/api/registry.c @@ -9,42 +9,54 @@ #include #include -static WINTUN_STATUS -OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline, _Out_ HKEY *KeyOut) +static _Return_type_success_(return != NULL) HKEY + OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) { - DWORD Result; + DWORD LastError; WCHAR *PathNext = wcschr(Path, L'\\'); if (PathNext) *PathNext = 0; HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); if (!Event) - return LOG_LAST_ERROR(L"Failed to create event"); + { + LOG_LAST_ERROR(L"Failed to create event"); + return NULL; + } for (;;) { - Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE); - if (Result != ERROR_SUCCESS) + LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE); + if (LastError != ERROR_SUCCESS) { - LOG_ERROR(L"Failed to setup notification", Result); + LOG_ERROR(L"Failed to setup notification", LastError); break; } HKEY Subkey; - Result = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey); - if (Result == ERROR_SUCCESS) + LastError = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey); + if (LastError == ERROR_SUCCESS) { if (PathNext) { - Result = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline, KeyOut); - RegCloseKey(Subkey); + HKEY KeyOut = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline); + if (KeyOut) + { + RegCloseKey(Subkey); + CloseHandle(Event); + return KeyOut; + } + LastError = GetLastError(); + break; } else - *KeyOut = Subkey; - break; + { + CloseHandle(Event); + return Subkey; + } } - if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND) + if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) { - LOG_ERROR(L"Failed to open", Result); + LOG_ERROR(L"Failed to open", LastError); break; } @@ -58,27 +70,35 @@ OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGL } } CloseHandle(Event); - return Result; + SetLastError(LastError); + return NULL; } -WINTUN_STATUS -RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut) +_Return_type_success_(return != NULL) HKEY + RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout) { WCHAR Buf[MAX_REG_PATH]; if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE) - return LOG(WINTUN_LOG_ERR, L"Registry path too long"), ERROR_INVALID_PARAMETER; - return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout, KeyOut); + { + LOG(WINTUN_LOG_ERR, L"Registry path too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout); } -WINTUN_STATUS -RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) +_Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) { if (wcsnlen(*Buf, Len) >= Len) { /* String is missing zero-terminator. */ WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR)); if (!BufZ) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } wmemcpy(BufZ, *Buf, Len); BufZ[Len] = 0; HeapFree(ModuleHeap, 0, *Buf); @@ -86,25 +106,30 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) } if (ValueType != REG_EXPAND_SZ) - return ERROR_SUCCESS; + return TRUE; /* ExpandEnvironmentStringsW() returns strlen on success or 0 on error. Bail out on empty input strings to * disambiguate. */ if (!(*Buf)[0]) - return ERROR_SUCCESS; + return TRUE; Len = Len * 2 + 64; for (;;) { WCHAR *Expanded = HeapAlloc(ModuleHeap, 0, Len * sizeof(WCHAR)); if (!Expanded) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len); if (!Result) { - Result = LOG_LAST_ERROR(L"Failed to expand environment variables"); + DWORD LastError = LOG_LAST_ERROR(L"Failed to expand environment variables"); HeapFree(ModuleHeap, 0, Expanded); - return Result; + SetLastError(LastError); + return FALSE; } if (Result > Len) { @@ -114,12 +139,12 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) } HeapFree(ModuleHeap, 0, *Buf); *Buf = Expanded; - return ERROR_SUCCESS; + return TRUE; } } -WINTUN_STATUS -RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) +_Return_type_success_(return != FALSE) BOOL + RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) { if (ValueType == REG_MULTI_SZ) { @@ -130,52 +155,61 @@ RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType /* Missing string and list terminators. */ WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 2) * sizeof(WCHAR)); if (!BufZ) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } wmemcpy(BufZ, *Buf, Len); BufZ[Len] = 0; BufZ[Len + 1] = 0; HeapFree(ModuleHeap, 0, *Buf); *Buf = BufZ; - return ERROR_SUCCESS; + return TRUE; } if (i == Len) { /* Missing list terminator. */ WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR)); if (!BufZ) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } wmemcpy(BufZ, *Buf, Len); BufZ[Len] = 0; HeapFree(ModuleHeap, 0, *Buf); *Buf = BufZ; - return ERROR_SUCCESS; + return TRUE; } if (!(*Buf)[i]) - return ERROR_SUCCESS; + return TRUE; } } /* Sanitize REG_SZ/REG_EXPAND_SZ and append a list terminator to make a multi-string. */ - DWORD Result = RegistryGetString(Buf, Len, ValueType); - if (Result != ERROR_SUCCESS) - return Result; + if (!RegistryGetString(Buf, Len, ValueType)) + return FALSE; Len = (DWORD)wcslen(*Buf) + 1; WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR)); if (!BufZ) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } wmemcpy(BufZ, *Buf, Len); BufZ[Len] = 0; HeapFree(ModuleHeap, 0, *Buf); *Buf = BufZ; - return ERROR_SUCCESS; + return TRUE; } -static WINTUN_STATUS -RegistryQuery( +static _Return_type_success_(return != NULL) void *RegistryQuery( _In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_opt_ DWORD *ValueType, - _Out_ void **Buf, _Inout_ DWORD *BufLen, _In_ BOOL Log) { @@ -183,60 +217,77 @@ RegistryQuery( { BYTE *p = HeapAlloc(ModuleHeap, 0, *BufLen); if (!p) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; - LSTATUS Result = RegQueryValueExW(Key, Name, NULL, ValueType, p, BufLen); - if (Result == ERROR_SUCCESS) { - *Buf = p; - return ERROR_SUCCESS; + LOG(WINTUN_LOG_ERR, L"Out of memory"); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; } + LSTATUS LastError = RegQueryValueExW(Key, Name, NULL, ValueType, p, BufLen); + if (LastError == ERROR_SUCCESS) + return p; HeapFree(ModuleHeap, 0, p); - if (Result != ERROR_MORE_DATA) - return Log ? LOG_ERROR(L"Querying value failed", Result) : Result; + if (LastError != ERROR_MORE_DATA) + { + if (Log) + LOG_ERROR(L"Querying value failed", LastError); + SetLastError(LastError); + return NULL; + } } } -WINTUN_STATUS -RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **Value, _In_ BOOL Log) +_Return_type_success_( + return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log) { - DWORD ValueType, Size = 256 * sizeof(WCHAR); - DWORD Result = RegistryQuery(Key, Name, &ValueType, Value, &Size, Log); - if (Result != ERROR_SUCCESS) - return Result; + DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); + WCHAR *Value = RegistryQuery(Key, Name, &ValueType, &Size, Log); + if (!Value) + return NULL; switch (ValueType) { case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: - Result = RegistryGetString(Value, Size / sizeof(WCHAR), ValueType); - if (Result != ERROR_SUCCESS) - HeapFree(ModuleHeap, 0, *Value); - return Result; + if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType)) + return Value; + LastError = GetLastError(); + break; default: LOG(WINTUN_LOG_ERR, L"Value is not a string"); - HeapFree(ModuleHeap, 0, *Value); - return ERROR_INVALID_DATATYPE; + LastError = ERROR_INVALID_DATATYPE; } + HeapFree(ModuleHeap, 0, Value); + SetLastError(LastError); + return NULL; } -WINTUN_STATUS -RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ WCHAR **Value) +_Return_type_success_( + return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout) { - DWORD Result; + DWORD LastError; ULONGLONG Deadline = GetTickCount64() + Timeout; HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); if (!Event) - return LOG_LAST_ERROR(L"Failed to create event"); + { + LOG_LAST_ERROR(L"Failed to create event"); + return NULL; + } for (;;) { - Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); - if (Result != ERROR_SUCCESS) + LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); + if (LastError != ERROR_SUCCESS) { - LOG_ERROR(L"Failed to setup notification", Result); + LOG_ERROR(L"Failed to setup notification", LastError); break; } - Result = RegistryQueryString(Key, Name, Value, FALSE); - if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND) + WCHAR *Value = RegistryQueryString(Key, Name, FALSE); + if (Value) + { + CloseHandle(Event); + return Value; + } + LastError = GetLastError(); + if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) break; LONGLONG TimeLeft = Deadline - GetTickCount64(); if (TimeLeft < 0) @@ -248,51 +299,63 @@ RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD } } CloseHandle(Event); - return Result; + SetLastError(LastError); + return NULL; } -WINTUN_STATUS -RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log) +_Return_type_success_(return != FALSE) BOOL + RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log) { DWORD ValueType, Size = sizeof(DWORD); - DWORD Result = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size); - if (Result != ERROR_SUCCESS) + DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size); + if (LastError != ERROR_SUCCESS) { if (Log) - LOG_ERROR(L"Querying failed", Result); - return Result; + LOG_ERROR(L"Querying failed", LastError); + SetLastError(LastError); + return FALSE; } if (ValueType != REG_DWORD) { LOG(WINTUN_LOG_ERR, L"Value is not a DWORD"); - return ERROR_INVALID_DATATYPE; + SetLastError(ERROR_INVALID_DATATYPE); + return FALSE; } if (Size != sizeof(DWORD)) { LOG(WINTUN_LOG_ERR, L"Value size is not 4 bytes"); - return ERROR_INVALID_DATA; + SetLastError(ERROR_INVALID_DATA); + return FALSE; } - return ERROR_SUCCESS; + return TRUE; } -WINTUN_STATUS -RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value) +_Return_type_success_(return != FALSE) BOOL + RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value) { - DWORD Result; + DWORD LastError; ULONGLONG Deadline = GetTickCount64() + Timeout; HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); if (!Event) - return LOG_LAST_ERROR(L"Failed to create event"); + { + LOG_LAST_ERROR(L"Failed to create event"); + return FALSE; + } for (;;) { - Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); - if (Result != ERROR_SUCCESS) + LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); + if (LastError != ERROR_SUCCESS) { - LOG_ERROR(L"Failed to setup notification", Result); + LOG_ERROR(L"Failed to setup notification", LastError); break; } - Result = RegistryQueryDWORD(Key, Name, Value, FALSE); - if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND) + if (RegistryQueryDWORD(Key, Name, Value, FALSE)) + { + CloseHandle(Event); + return TRUE; + } + LastError = GetLastError(); + if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) break; LONGLONG TimeLeft = Deadline - GetTickCount64(); if (TimeLeft < 0) @@ -304,5 +367,6 @@ RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD T } } CloseHandle(Event); - return Result; + SetLastError(LastError); + return FALSE; } diff --git a/api/registry.h b/api/registry.h index 0a02d42..a79370d 100644 --- a/api/registry.h +++ b/api/registry.h @@ -23,12 +23,11 @@ * * @param Timeout Timeout to wait for the value in milliseconds. * - * @param KeyOut Pointer to a variable to receive the key handle. - * - * @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; Win32 error code otherwise. + * @return Key handle on success. If the function fails, the return value is zero. To get extended error information, + * call GetLastError. */ -WINTUN_STATUS -RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut); +_Return_type_success_(return != NULL) HKEY + RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout); /** * Validates and/or sanitizes string value read from registry. @@ -42,10 +41,11 @@ RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, * @param ValueType Type of data. Must be either REG_SZ or REG_EXPAND_SZ. REG_MULTI_SZ is treated like REG_SZ; only * the first string of a multi-string is to be used. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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. */ -WINTUN_STATUS -RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); +_Return_type_success_(return != FALSE) BOOL + RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); /** * Validates and/or sanitizes multi-string value read from registry. @@ -58,10 +58,11 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); * * @param ValueType Type of data. Must be one of REG_MULTI_SZ, REG_SZ or REG_EXPAND_SZ. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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. */ -WINTUN_STATUS -RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); +_Return_type_success_(return != FALSE) BOOL + RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); /** * Reads string value from registry key. @@ -79,11 +80,11 @@ RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType * errors reduces log clutter when we are using RegistryQueryString() from * RegistryQueryStringWait() and some errors are expected to occur. * - * @return ERROR_SUCCESS on success; ERROR_INVALID_DATATYPE when the registry value is not a string; Win32 error code - * otherwise. + * @return String with registry value on success; If the function fails, the return value is zero. To get extended error + * information, call GetLastError. */ -WINTUN_STATUS -RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **Value, _In_ BOOL Log); +_Return_type_success_( + return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log); /** * Reads string value from registry key. It waits for the registry value to become available. @@ -94,16 +95,14 @@ RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **V * * @param Timeout Timeout to wait for the value in milliseconds. * - * @param Value Pointer to string to retrieve registry value. If the value type is REG_EXPAND_SZ the value is - * expanded using ExpandEnvironmentStrings(). If the value type is REG_MULTI_SZ, only the first - * string from the multi-string is returned. The string must be released with - * HeapFree(ModuleHeap, 0, Value) after use. - * - * @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; ERROR_INVALID_DATATYPE when the registry value is not a - * string; Win32 error code otherwise. + * @return Registry value. If the value type is REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings(). If + * the value type is REG_MULTI_SZ, only the first string from the multi-string is returned. The string must be + * released with HeapFree(ModuleHeap, 0, Value) after use. If the function fails, the return value is zero. To + * get extended error information, call GetLastError. Possible errors include the following: + * ERROR_INVALID_DATATYPE when the registry value is not a string */ -WINTUN_STATUS -RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ WCHAR **Value); +_Return_type_success_( + return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout); /** * Reads a 32-bit DWORD value from registry key. @@ -118,11 +117,11 @@ RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD * errors reduces log clutter when we are using RegistryQueryDWORD() from * RegistryQueryDWORDWait() and some errors are expected to occur. * - * @return ERROR_SUCCESS on success; ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type; - * ERROR_INVALID_DATA when registry value size is not 4 bytes; Win32 error code otherwise. + * @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. */ -WINTUN_STATUS -RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log); +_Return_type_success_(return != FALSE) BOOL + RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *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. @@ -135,8 +134,10 @@ RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Val * * @param Value Pointer to DWORD to retrieve registry value. * - * @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; ERROR_INVALID_DATATYPE when registry value exist but not - * REG_DWORD type; ERROR_INVALID_DATA when registry value size is not 4 bytes; Win32 error code otherwise. + * @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. Possible errors include the following: + * ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type; + * ERROR_INVALID_DATA when registry value size is not 4 bytes */ -WINTUN_STATUS -RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value); +_Return_type_success_(return != FALSE) BOOL + RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value); diff --git a/api/resource.c b/api/resource.c index ae88353..e4f4aaa 100644 --- a/api/resource.c +++ b/api/resource.c @@ -8,35 +8,47 @@ #include "resource.h" #include -WINTUN_STATUS -ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address, _Out_ DWORD *Size) +_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const + void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size) { HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA); if (!FoundResource) - return LOG_LAST_ERROR(L"Failed to find resource"); + { + LOG_LAST_ERROR(L"Failed to find resource"); + return NULL; + } *Size = SizeofResource(ResourceModule, FoundResource); if (!*Size) - return LOG_LAST_ERROR(L"Failed to query resource size"); + { + LOG_LAST_ERROR(L"Failed to query resource size"); + return NULL; + } HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource); if (!LoadedResource) - return LOG_LAST_ERROR(L"Failed to load resource"); - *Address = LockResource(LoadedResource); - if (!*Address) + { + LOG_LAST_ERROR(L"Failed to load resource"); + return NULL; + } + BYTE *Address = LockResource(LoadedResource); + if (!Address) { LOG(WINTUN_LOG_ERR, L"Failed to lock resource"); - return ERROR_LOCK_FAILED; + SetLastError(ERROR_LOCK_FAILED); + return NULL; } - return ERROR_SUCCESS; + return Address; } -WINTUN_STATUS -ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName) +_Return_type_success_(return != FALSE) BOOL + ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName) { - const void *LockedResource; DWORD SizeResource; - DWORD Result = ResourceGetAddress(ResourceName, &LockedResource, &SizeResource); - if (Result != ERROR_SUCCESS) - return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result; + const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource); + if (!LockedResource) + { + LOG(WINTUN_LOG_ERR, L"Failed to locate resource"); + return FALSE; + } HANDLE DestinationHandle = CreateFileW( DestinationPath, GENERIC_WRITE, @@ -46,15 +58,25 @@ ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *Reso FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY, NULL); if (DestinationHandle == INVALID_HANDLE_VALUE) - return LOG_LAST_ERROR(L"Failed to create file"); + { + LOG_LAST_ERROR(L"Failed to create file"); + return FALSE; + } DWORD BytesWritten; + DWORD LastError; if (!WriteFile(DestinationHandle, LockedResource, SizeResource, &BytesWritten, NULL)) - Result = LOG_LAST_ERROR(L"Failed to write file"); + { + LastError = LOG_LAST_ERROR(L"Failed to write file"); + goto cleanupDestinationHandle; + } if (BytesWritten != SizeResource) { LOG(WINTUN_LOG_ERR, L"Incomplete write"); - Result = Result != ERROR_SUCCESS ? Result : ERROR_WRITE_FAULT; + LastError = ERROR_WRITE_FAULT; + goto cleanupDestinationHandle; } + LastError = ERROR_SUCCESS; +cleanupDestinationHandle: CloseHandle(DestinationHandle); - return Result; + return RET_ERROR(TRUE, LastError); } diff --git a/api/resource.h b/api/resource.h index 3cfc0a3..3572ace 100644 --- a/api/resource.h +++ b/api/resource.h @@ -13,14 +13,13 @@ * * ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. * - * Address Pointer to a pointer variable to receive resource address. - * * Size Pointer to a variable to receive resource size. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @return Resource address on success. If the function fails, the return value is NULL. To get extended error + * information, call GetLastError. */ -WINTUN_STATUS -ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address, _Out_ DWORD *Size); +_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const + void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size); /** * Copies resource to a file. @@ -29,7 +28,8 @@ ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address, * * ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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. */ -WINTUN_STATUS -ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName); +_Return_type_success_(return != FALSE) BOOL + ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName); diff --git a/api/rundll32.c b/api/rundll32.c index bc07597..1d564ae 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -7,16 +7,16 @@ #if ACCEPT_WOW64 == 1 -#include "adapter.h" -#include "logger.h" -#include "wintun.h" +# include "adapter.h" +# include "logger.h" +# include "wintun.h" -#include -#include -#include -#include +# include +# include +# include +# include -#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) +# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) static DWORD WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) @@ -77,7 +77,7 @@ Done(void) LocalFree(Argv); } -#pragma warning(disable: 4100) /* unreferenced formal parameter */ +# pragma warning(disable : 4100) /* unreferenced formal parameter */ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { @@ -94,18 +94,19 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int if (Argc > 4 && FAILED(CLSIDFromString(Argv[4], &RequestedGUID))) goto cleanup; - WINTUN_ADAPTER *Adapter; BOOL RebootRequired; - DWORD Result = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &Adapter, &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!", - Result, - StringFromGUID2(Result == ERROR_SUCCESS ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)), + LastError, + StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)), GuidStr, RebootRequired); - WintunFreeAdapter(Adapter); + if (Adapter) + WintunFreeAdapter(Adapter); cleanup: Done(); @@ -124,8 +125,9 @@ VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID))) goto cleanup; BOOL RebootRequired; - WINTUN_STATUS Ret = WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired); - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired); + DWORD LastError = + WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); cleanup: Done(); @@ -140,8 +142,8 @@ VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, i goto cleanup; BOOL RebootRequired; - WINTUN_STATUS Ret = WintunDeletePoolDriver(Argv[2], &RebootRequired); - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired); + DWORD LastError = WintunDeletePoolDriver(Argv[2], &RebootRequired) ? ERROR_SUCCESS : GetLastError(); + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); cleanup: Done(); diff --git a/api/rundll32.h b/api/rundll32.h index b445cf9..ca4a504 100644 --- a/api/rundll32.h +++ b/api/rundll32.h @@ -72,7 +72,7 @@ ProcessStderr(_In_ HANDLE Stderr) else if (State == OnMsg && c == L'\n') { Msg[Count] = 0; - Logger(Level, Msg); + LoggerLog(Level, Msg); State = OnNone; Count = 0; } @@ -80,27 +80,35 @@ ProcessStderr(_In_ HANDLE Stderr) } } -static WINTUN_STATUS -ExecuteRunDll32( +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))) - return LOG_LAST_ERROR(L"Failed to get Windows folder"); + { + LOG_LAST_ERROR(L"Failed to get Windows folder"); + return FALSE; + } WCHAR RunDll32Path[MAX_PATH]; if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe")) - return ERROR_BUFFER_OVERFLOW; + { + SetLastError(ERROR_BUFFER_OVERFLOW); + return FALSE; + } - DWORD Result; + DWORD LastError; WCHAR RandomTempSubDirectory[MAX_PATH]; - if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) - return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result; + if (!CreateTemporaryDirectory(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")) { - Result = ERROR_BUFFER_OVERFLOW; + LastError = ERROR_BUFFER_OVERFLOW; goto cleanupDirectory; } const WCHAR *WintunDllResourceName; @@ -114,12 +122,12 @@ ExecuteRunDll32( break; default: LOG(WINTUN_LOG_ERR, L"Unsupported platform"); - Result = ERROR_NOT_SUPPORTED; + LastError = ERROR_NOT_SUPPORTED; goto cleanupDirectory; } - if ((Result = ResourceCopyToFile(DllPath, WintunDllResourceName)) != ERROR_SUCCESS) + if (!ResourceCopyToFile(DllPath, WintunDllResourceName)) { - LOG(WINTUN_LOG_ERR, L"Failed to copy resource"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource"); goto cleanupDelete; } size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1; @@ -127,14 +135,14 @@ ExecuteRunDll32( if (!CommandLine) { LOG(WINTUN_LOG_ERR, L"Out of memory"); - Result = ERROR_OUTOFMEMORY; + LastError = ERROR_OUTOFMEMORY; 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"); - Result = ERROR_INVALID_PARAMETER; + LastError = ERROR_INVALID_PARAMETER; goto cleanupDelete; } HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE, @@ -142,13 +150,13 @@ ExecuteRunDll32( if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) || !CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0)) { - Result = LOG_LAST_ERROR(L"Failed to create pipes"); + 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)) { - Result = LOG_LAST_ERROR(L"Failed to set handle info"); + LastError = LOG_LAST_ERROR(L"Failed to set handle info"); goto cleanupPipes; } if (ResponseCapacity) @@ -160,7 +168,7 @@ ExecuteRunDll32( if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL || (ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL) { - Result = LOG_LAST_ERROR(L"Failed to spawn readers"); + LastError = LOG_LAST_ERROR(L"Failed to spawn readers"); goto cleanupThreads; } STARTUPINFOW si = { .cb = sizeof(STARTUPINFO), @@ -172,14 +180,15 @@ ExecuteRunDll32( HANDLE ProcessToken = GetPrimarySystemTokenFromThread(); if (!ProcessToken) { - Result = LOG_LAST_ERROR(L"Failed to get primary system token from thread"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to get primary system token from thread"); goto cleanupThreads; } if (!CreateProcessAsUserW(ProcessToken, RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { - Result = LOG_LAST_ERROR(L"Failed to create process"); + LastError = LOG_LAST_ERROR(L"Failed to create process"); goto cleanupToken; } + LastError = ERROR_SUCCESS; WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); @@ -198,10 +207,10 @@ cleanupThreads: CloseHandle(StreamWStdout); StreamWStdout = INVALID_HANDLE_VALUE; WaitForSingleObject(ThreadStdout, INFINITE); - if (!GetExitCodeThread(ThreadStdout, &Result)) - Result = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); - else if (Result != ERROR_SUCCESS) - LOG_ERROR(L"Failed to read process output", Result); + if (!GetExitCodeThread(ThreadStdout, &LastError)) + LastError = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); + else if (LastError != ERROR_SUCCESS) + LOG_ERROR(L"Failed to read process output", LastError); CloseHandle(ThreadStdout); } cleanupPipes: @@ -214,15 +223,13 @@ cleanupDelete: DeleteFileW(DllPath); cleanupDirectory: RemoveDirectoryW(RandomTempSubDirectory); - return Result; + return RET_ERROR(TRUE, LastError); } -static WINTUN_STATUS -CreateAdapterViaRundll32( +static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapterViaRundll32( _In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name, _In_opt_ const GUID *RequestedGUID, - _Out_ WINTUN_ADAPTER **Adapter, _Inout_ BOOL *RebootRequired) { LOG(WINTUN_LOG_INFO, L"Spawning native process"); @@ -237,38 +244,46 @@ CreateAdapterViaRundll32( Name, RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0, RequestedGUIDStr) == -1) - return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; + { + 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]; - DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); - if (Result != ERROR_SUCCESS) + if (!ExecuteRunDll32(Arguments, Response, _countof(Response))) { LOG(WINTUN_LOG_ERR, L"Error executing worker process"); - return Result; + 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"); - Result = ERROR_INVALID_PARAMETER; + LastError = ERROR_INVALID_PARAMETER; goto cleanupArgv; } - Result = wcstoul(Argv[0], NULL, 16); - if (Result == ERROR_SUCCESS && GetAdapter(Pool, &CfgInstanceID, Adapter) != ERROR_SUCCESS) + LastError = wcstoul(Argv[0], NULL, 16); + if (LastError == ERROR_SUCCESS && (Adapter = GetAdapter(Pool, &CfgInstanceID)) == NULL) { LOG(WINTUN_LOG_ERR, L"Failed to get adapter"); - Result = ERROR_FILE_NOT_FOUND; + LastError = ERROR_FILE_NOT_FOUND; } if (wcstoul(Argv[2], NULL, 16)) *RebootRequired = TRUE; cleanupArgv: LocalFree(Argv); - return Result; + SetLastError(LastError); + return Adapter; } -static WINTUN_STATUS -DeleteAdapterViaRundll32(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Inout_ BOOL *RebootRequired) +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]; @@ -281,57 +296,65 @@ DeleteAdapterViaRundll32(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceClos ForceCloseSessions ? 1 : 0, StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)), GuidStr) == -1) - return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; + { + LOG(WINTUN_LOG_ERR, L"Command line too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } WCHAR Response[8 + 1 + 8 + 1]; - DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); - if (Result != ERROR_SUCCESS) + DWORD LastError; + if (!ExecuteRunDll32(Arguments, Response, _countof(Response))) { LOG(WINTUN_LOG_ERR, L"Error executing worker process"); - return Result; + return FALSE; } int Argc; WCHAR **Argv = CommandLineToArgvW(Response, &Argc); if (Argc < 2) { LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); - Result = ERROR_INVALID_PARAMETER; + LastError = ERROR_INVALID_PARAMETER; goto cleanupArgv; } - Result = wcstoul(Argv[0], NULL, 16); + LastError = wcstoul(Argv[0], NULL, 16); if (wcstoul(Argv[1], NULL, 16)) *RebootRequired = TRUE; cleanupArgv: LocalFree(Argv); - return Result; + return RET_ERROR(TRUE, LastError); } -static WINTUN_STATUS -DeletePoolDriverViaRundll32(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired) +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) - return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; + { + LOG(WINTUN_LOG_ERR, L"Command line too long"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } WCHAR Response[8 + 1 + 8 + 1]; - DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); - if (Result != ERROR_SUCCESS) + DWORD LastError; + if (!ExecuteRunDll32(Arguments, Response, _countof(Response))) { LOG(WINTUN_LOG_ERR, L"Error executing worker process"); - return Result; + return FALSE; } int Argc; WCHAR **Argv = CommandLineToArgvW(Response, &Argc); if (Argc < 2) { LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); - Result = ERROR_INVALID_PARAMETER; + LastError = ERROR_INVALID_PARAMETER; goto cleanupArgv; } - Result = wcstoul(Argv[0], NULL, 16); + LastError = wcstoul(Argv[0], NULL, 16); if (wcstoul(Argv[1], NULL, 16)) *RebootRequired = TRUE; cleanupArgv: LocalFree(Argv); - return Result; -} \ No newline at end of file + return RET_ERROR(TRUE, LastError); +} diff --git a/api/session.c b/api/session.c index ebb8d59..c4e1c04 100644 --- a/api/session.c +++ b/api/session.c @@ -69,86 +69,87 @@ typedef struct _TUN_SESSION HANDLE Handle; } TUN_SESSION; -WINTUN_STATUS WINAPI -WintunStartSession( - _In_ const WINTUN_ADAPTER *Adapter, - _In_ DWORD Capacity, - _Out_ TUN_SESSION **Session) +_Return_type_success_(return != NULL) TUN_SESSION *WINAPI + WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity) { - TUN_SESSION *s = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(TUN_SESSION)); - if (!s) - return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY; + DWORD LastError; + TUN_SESSION *Session = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(TUN_SESSION)); + if (!Session) + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + LastError = ERROR_OUTOFMEMORY; + goto out; + } const ULONG RingSize = TUN_RING_SIZE(Capacity); - DWORD Result; BYTE *AllocatedRegion = VirtualAlloc(0, (size_t)RingSize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!AllocatedRegion) { - Result = LOG_LAST_ERROR(L"Failed to allocate ring memory"); + LastError = LOG_LAST_ERROR(L"Failed to allocate ring memory"); goto cleanupRings; } if (!ElevateToSystem()) { - LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"); - Result = ERROR_ACCESS_DENIED; + LastError = LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"); goto cleanupAllocatedRegion; } - s->Descriptor.Send.RingSize = RingSize; - s->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion; - s->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL); - if (!s->Descriptor.Send.TailMoved) + Session->Descriptor.Send.RingSize = RingSize; + Session->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion; + Session->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL); + if (!Session->Descriptor.Send.TailMoved) { - Result = LOG_LAST_ERROR(L"Failed to create send event"); + LastError = LOG_LAST_ERROR(L"Failed to create send event"); goto cleanupToken; } - s->Descriptor.Receive.RingSize = RingSize; - s->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize); - s->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL); - if (!s->Descriptor.Receive.TailMoved) + Session->Descriptor.Receive.RingSize = RingSize; + Session->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize); + Session->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL); + if (!Session->Descriptor.Receive.TailMoved) { - Result = LOG_LAST_ERROR(L"Failed to create receive event"); + LastError = LOG_LAST_ERROR(L"Failed to create receive event"); goto cleanupSendTailMoved; } - Result = WintunOpenAdapterDeviceObject(Adapter, &s->Handle); - if (Result != ERROR_SUCCESS) + Session->Handle = WintunOpenAdapterDeviceObject(Adapter); + if (Session->Handle == INVALID_HANDLE_VALUE) { - LOG(WINTUN_LOG_ERR, L"Failed to open adapter device object"); + LastError = LOG(WINTUN_LOG_ERR, L"Failed to open adapter device object"); goto cleanupReceiveTailMoved; } DWORD BytesReturned; if (!DeviceIoControl( - s->Handle, + Session->Handle, TUN_IOCTL_REGISTER_RINGS, - &s->Descriptor, + &Session->Descriptor, sizeof(TUN_REGISTER_RINGS), NULL, 0, &BytesReturned, NULL)) { - Result = LOG_LAST_ERROR(L"Failed to register rings"); + LastError = LOG_LAST_ERROR(L"Failed to register rings"); goto cleanupHandle; } RevertToSelf(); - s->Capacity = Capacity; - (void)InitializeCriticalSectionAndSpinCount(&s->Receive.Lock, LOCK_SPIN_COUNT); - (void)InitializeCriticalSectionAndSpinCount(&s->Send.Lock, LOCK_SPIN_COUNT); - *Session = s; - return ERROR_SUCCESS; + Session->Capacity = Capacity; + (void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT); + (void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT); + return Session; cleanupHandle: - CloseHandle(s->Handle); + CloseHandle(Session->Handle); cleanupReceiveTailMoved: - CloseHandle(s->Descriptor.Receive.TailMoved); + CloseHandle(Session->Descriptor.Receive.TailMoved); cleanupSendTailMoved: - CloseHandle(s->Descriptor.Send.TailMoved); + CloseHandle(Session->Descriptor.Send.TailMoved); cleanupToken: RevertToSelf(); cleanupAllocatedRegion: VirtualFree(AllocatedRegion, 0, MEM_RELEASE); cleanupRings: - HeapFree(ModuleHeap, 0, s); - return Result; + HeapFree(ModuleHeap, 0, Session); +out: + SetLastError(LastError); + return NULL; } void WINAPI @@ -170,53 +171,55 @@ WintunGetReadWaitEvent(_In_ TUN_SESSION *Session) return Session->Descriptor.Send.TailMoved; } -WINTUN_STATUS WINAPI -WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_bytecapcount_(*PacketSize) BYTE **Packet, _Out_ DWORD *PacketSize) +_Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI + WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize) { - DWORD Result; + DWORD LastError; EnterCriticalSection(&Session->Send.Lock); if (Session->Send.Head >= Session->Capacity) { - Result = ERROR_HANDLE_EOF; + LastError = ERROR_HANDLE_EOF; goto cleanup; } const ULONG BuffTail = ReadULongAcquire(&Session->Descriptor.Send.Ring->Tail); if (BuffTail >= Session->Capacity) { - Result = ERROR_HANDLE_EOF; + LastError = ERROR_HANDLE_EOF; goto cleanup; } if (Session->Send.Head == BuffTail) { - Result = ERROR_NO_MORE_ITEMS; + LastError = ERROR_NO_MORE_ITEMS; goto cleanup; } const ULONG BuffContent = TUN_RING_WRAP(BuffTail - Session->Send.Head, Session->Capacity); if (BuffContent < sizeof(TUN_PACKET)) { - Result = ERROR_INVALID_DATA; + LastError = ERROR_INVALID_DATA; goto cleanup; } TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.Head]; if (BuffPacket->Size > WINTUN_MAX_IP_PACKET_SIZE) { - Result = ERROR_INVALID_DATA; + LastError = ERROR_INVALID_DATA; goto cleanup; } const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size); if (AlignedPacketSize > BuffContent) { - Result = ERROR_INVALID_DATA; + LastError = ERROR_INVALID_DATA; goto cleanup; } *PacketSize = BuffPacket->Size; - *Packet = BuffPacket->Data; + BYTE *Packet = BuffPacket->Data; Session->Send.Head = TUN_RING_WRAP(Session->Send.Head + AlignedPacketSize, Session->Capacity); Session->Send.PacketsToRelease++; - Result = ERROR_SUCCESS; + LeaveCriticalSection(&Session->Send.Lock); + return Packet; cleanup: LeaveCriticalSection(&Session->Send.Lock); - return Result; + SetLastError(LastError); + return NULL; } void WINAPI @@ -238,38 +241,40 @@ WintunReceiveRelease(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) LeaveCriticalSection(&Session->Send.Lock); } -WINTUN_STATUS WINAPI -WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize, _Out_bytecapcount_(PacketSize) BYTE **Packet) +_Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI + WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize) { - DWORD Result; + DWORD LastError; EnterCriticalSection(&Session->Receive.Lock); if (Session->Receive.Tail >= Session->Capacity) { - Result = ERROR_HANDLE_EOF; + LastError = ERROR_HANDLE_EOF; goto cleanup; } const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize); const ULONG BuffHead = ReadULongAcquire(&Session->Descriptor.Receive.Ring->Head); if (BuffHead >= Session->Capacity) { - Result = ERROR_HANDLE_EOF; + LastError = ERROR_HANDLE_EOF; goto cleanup; } const ULONG BuffSpace = TUN_RING_WRAP(BuffHead - Session->Receive.Tail - TUN_ALIGNMENT, Session->Capacity); if (AlignedPacketSize > BuffSpace) { - Result = ERROR_BUFFER_OVERFLOW; + LastError = ERROR_BUFFER_OVERFLOW; goto cleanup; } TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.Tail]; BuffPacket->Size = PacketSize | TUN_PACKET_RELEASE; - *Packet = BuffPacket->Data; + BYTE *Packet = BuffPacket->Data; Session->Receive.Tail = TUN_RING_WRAP(Session->Receive.Tail + AlignedPacketSize, Session->Capacity); Session->Receive.PacketsToRelease++; - Result = ERROR_SUCCESS; + LeaveCriticalSection(&Session->Receive.Lock); + return Packet; cleanup: LeaveCriticalSection(&Session->Receive.Lock); - return Result; + SetLastError(LastError); + return NULL; } void WINAPI diff --git a/api/wintun.h b/api/wintun.h index bf95492..459a882 100644 --- a/api/wintun.h +++ b/api/wintun.h @@ -13,8 +13,6 @@ extern "C" { #endif -typedef _Return_type_success_(return == ERROR_SUCCESS) DWORD WINTUN_STATUS; - /** * A handle representing Wintun adapter */ @@ -33,24 +31,20 @@ typedef void *WINTUN_ADAPTER_HANDLE; * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1 * characters. * - * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation - * deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence - * a new NLA entry is created for each new adapter. It is called "requested" GUID because the API - * it uses is completely undocumented, and so there could be minor interesting complications with - * its usage. - * - * @param Adapter Pointer to a handle to receive the adapter handle. Must be released with - * WintunFreeAdapter. + * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically. + * If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is + * created for each new adapter. It is called "requested" GUID because the API it uses is + * completely undocumented, and so there could be minor interesting complications with its usage. * * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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. */ -typedef WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)( +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_ WINTUN_ADAPTER_HANDLE *Adapter, _Out_opt_ BOOL *RebootRequired); /** @@ -64,9 +58,10 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)( * * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. * - * @return ERROR_SUCCESS on success or the adapter was not found; Win32 error code otherwise. + * @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 WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)( +typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)( _In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired); @@ -79,11 +74,11 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)( * * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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 WINTUN_STATUS(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)( - _In_z_ const WCHAR Pool[WINTUN_MAX_POOL], - _Out_opt_ BOOL *RebootRequired); +typedef _Return_type_success_(return != FALSE) + BOOL(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired); /** * Called by WintunEnumAdapters for each adapter in the pool. @@ -106,9 +101,10 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ada * * @param Param An application-defined value to be passed to the callback function. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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 WINTUN_STATUS(WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)( +typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)( _In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK_FUNC Callback, _In_ LPARAM Param); @@ -127,27 +123,26 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte * * @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters. * - * @param Adapter Pointer to a handle to receive the adapter handle. Must be released with WintunFreeAdapter. - * - * @return ERROR_SUCCESS on success; 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; Win32 error code otherwise + * @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 */ -typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_FUNC)( - _In_z_ const WCHAR *Pool, - _In_z_ const WCHAR *Name, - _Out_ WINTUN_ADAPTER_HANDLE *Adapter); +typedef _Return_type_success_(return != NULL) + WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_GET_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name); /** * Returns a handle to the adapter device object. * * @param Adapter Adapter handle obtained with WintunGetAdapter or WintunCreateAdapter. * - * @param Handle Pointer to receive the adapter device object handle. Must be released with CloseHandle. - * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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 + * information, call GetLastError. */ -typedef WINTUN_STATUS( - WINAPI *WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ HANDLE *Handle); +typedef _Return_type_success_(return != INVALID_HANDLE_VALUE) + HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter); /** * Returns the LUID of the adapter. @@ -165,9 +160,10 @@ typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ad * * @param Name Pointer to a string to receive adapter name * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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 WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)( +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); @@ -178,15 +174,19 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)( * * @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters. * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @return 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 WINTUN_STATUS( - WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name); +typedef _Return_type_success_(return != FALSE) + BOOL(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name); /** * Determines the version of the Wintun driver currently loaded. * - * @return The version number on success, or 0 if failure or Wintun not loaded. + * @return If the function succeeds, the return value is the version number. If the function fails, the return value is + * zero. To get extended error information, call GetLastError. Possible errors include the following: + * ERROR_FILE_NOT_FOUND Wintun not loaded; + * ERROR_GEN_FAILURE Enumerating drivers failed */ typedef DWORD(WINAPI *WINTUN_GET_VERSION_FUNC)(void); @@ -240,14 +240,11 @@ typedef void *WINTUN_SESSION_HANDLE; * @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.) * Must be a power of two. * - * @param Session Pointer to a variable to receive Wintun session handle - * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. + * @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 WINTUN_STATUS(WINAPI *WINTUN_START_SESSION_FUNC)( - _In_ WINTUN_ADAPTER_HANDLE Adapter, - _In_ DWORD Capacity, - _Out_ WINTUN_SESSION_HANDLE *Session); +typedef _Return_type_success_(return != NULL) + WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); /** * Ends Wintun session. @@ -279,22 +276,17 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND * * @param Session Wintun session handle obtained with WintunStartSession * - * @param Packet Pointer to receive pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at - * will. + * @param PacketSize Pointer to receive packet size. * - * @param PacketSize Pointer to receive Packet size. - * - * @return Returns one of the following values: - * ERROR_HANDLE_EOF Wintun adapter is terminating; - * ERROR_NO_MORE_ITEMS Wintun buffer is exhausted; - * ERROR_INVALID_DATA Wintun buffer is corrupt; - * ERROR_SUCCESS on success. - * Regardless, if the error was returned, some packets might have been read nevertheless. + * @return Pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at will. If the function fails, the + * return value is NULL. To get extended error information, call GetLastError. Possible errors include the + * following: + * ERROR_HANDLE_EOF Wintun adapter is terminating; + * ERROR_NO_MORE_ITEMS Wintun buffer is exhausted; + * ERROR_INVALID_DATA Wintun buffer is corrupt */ -typedef WINTUN_STATUS(WINAPI *WINTUN_RECEIVE_PACKET_FUNC)( - _In_ WINTUN_SESSION_HANDLE *Session, - _Out_bytecapcount_(*PacketSize) BYTE **Packet, - _Out_ DWORD *PacketSize); +typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *( + WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _Out_ DWORD *PacketSize); /** * Releases internal buffer after the received packet has been processed by the client. This function is thread-safe. @@ -314,17 +306,14 @@ typedef void(WINAPI *WINTUN_RECEIVE_RELEASE_FUNC)(_In_ WINTUN_SESSION_HANDLE *Se * * @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE. * - * @param Packet Pointer to receive pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. - * - * @return Returns one of the following values: - * ERROR_HANDLE_EOF Wintun adapter is terminating; - * ERROR_BUFFER_OVERFLOW Wintun buffer is full; - * ERROR_SUCCESS on success. + * @return Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails, + * the return value is NULL. To get extended error information, call GetLastError. Possible errors include the + * following: + * ERROR_HANDLE_EOF Wintun adapter is terminating; + * ERROR_BUFFER_OVERFLOW Wintun buffer is full; */ -typedef WINTUN_STATUS(WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)( - _In_ WINTUN_SESSION_HANDLE *Session, - _In_ DWORD PacketSize, - _Out_bytecapcount_(PacketSize) BYTE **Packet); +typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *( + WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _In_ DWORD PacketSize); /** * Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket -- cgit v1.2.3-59-g8ed1b