api: upgrade
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
		
							parent
							
								
									d61007297d
								
							
						
					
					
						commit
						d675646ab8
					
				
							
								
								
									
										1129
									
								
								api/adapter.c
									
									
									
									
									
								
							
							
						
						
									
										1129
									
								
								api/adapter.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -13,58 +13,96 @@ | ||||
| #define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ | ||||
| #define WINTUN_HWID L"Wintun" | ||||
| 
 | ||||
| void | ||||
| AdapterInit(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * Wintun adapter descriptor. | ||||
|  */ | ||||
| typedef struct _WINTUN_ADAPTER | ||||
| { | ||||
|     HDEVINFO DevInfo; | ||||
|     SP_DEVINFO_DATA DevInfoData; | ||||
|     GUID CfgInstanceID; | ||||
|     WCHAR DevInstanceID[MAX_INSTANCE_ID]; | ||||
|     DWORD LuidIndex; | ||||
|     DWORD IfType; | ||||
|     DWORD IfIndex; | ||||
|     WCHAR Pool[WINTUN_MAX_POOL]; | ||||
| } WINTUN_ADAPTER; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_FREE_ADAPTER_FUNC | ||||
|  */ | ||||
| void WINAPI | ||||
| WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter); | ||||
| WINTUN_FREE_ADAPTER_FUNC_IMPL WintunFreeAdapter; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_CREATE_ADAPTER_FUNC | ||||
|  */ | ||||
| _Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI WintunCreateAdapter( | ||||
|     _In_z_ const WCHAR *Pool, | ||||
|     _In_z_ const WCHAR *Name, | ||||
|     _In_opt_ const GUID *RequestedGUID, | ||||
|     _Out_opt_ BOOL *RebootRequired); | ||||
| WINTUN_CREATE_ADAPTER_FUNC_IMPL WintunCreateAdapter; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_OPEN_ADAPTER_FUNC | ||||
|  */ | ||||
| WINTUN_OPEN_ADAPTER_FUNC_IMPL WintunOpenAdapter; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_DELETE_ADAPTER_FUNC | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter( | ||||
|     _In_ const WINTUN_ADAPTER *Adapter, | ||||
|     _In_ BOOL ForceCloseSessions, | ||||
|     _Out_opt_ BOOL *RebootRequired); | ||||
| WINTUN_DELETE_ADAPTER_FUNC_IMPL WintunDeleteAdapter; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_ENUM_ADAPTERS_FUNC | ||||
|  */ | ||||
| WINTUN_ENUM_ADAPTERS_FUNC_IMPL WintunEnumAdapters; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL WINAPI | ||||
|     WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired); | ||||
| WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL WintunDeletePoolDriver; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_GET_ADAPTER_LUID_FUNC | ||||
|  */ | ||||
| WINTUN_GET_ADAPTER_LUID_FUNC_IMPL WintunGetAdapterLUID; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_GET_ADAPTER_NAME_FUNC | ||||
|  */ | ||||
| WINTUN_GET_ADAPTER_NAME_FUNC_IMPL WintunGetAdapterName; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_SET_ADAPTER_NAME_FUNC | ||||
|  */ | ||||
| WINTUN_SET_ADAPTER_NAME_FUNC_IMPL WintunSetAdapterName; | ||||
| 
 | ||||
| /**
 | ||||
|  * @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC | ||||
|  */ | ||||
| WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL WintunGetRunningDriverVersion; | ||||
| 
 | ||||
| /**
 | ||||
|  * Returns a handle to the adapter device object. | ||||
|  * | ||||
|  * @param Adapter       Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. | ||||
|  * | ||||
|  * @return If the function succeeds, the return value is adapter device object handle. Must be released with | ||||
|  *         CloseHandle. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error | ||||
|  * @return If the function succeeds, the return value is adapter device object handle. | ||||
|  *         If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error | ||||
|  *         information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI | ||||
|     AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter); | ||||
| _Return_type_success_(return != INVALID_HANDLE_VALUE) | ||||
| HANDLE WINAPI | ||||
| AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter); | ||||
| /**
 | ||||
|  * Returns an adapter object based on a devnode instance ID. | ||||
|  * | ||||
|  * @param Pool          Pool name of adapter object to be opened. | ||||
|  * | ||||
|  * @param DevInstanceID Instance ID of devnode for opening adapter. | ||||
|  * | ||||
|  * @return If the function succeeds, the return value is adapter object.. | ||||
|  *         If the function fails, the return value is NULL. To get extended error | ||||
|  *         information, call GetLastError. | ||||
|  */ | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| WINTUN_ADAPTER * | ||||
| AdapterOpenFromDevInstanceId(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR DevInstanceID); | ||||
|  | ||||
| @ -53,15 +53,13 @@ | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="main.h" /> | ||||
|     <ClInclude Include="adapter.h" /> | ||||
|     <ClInclude Include="rundll32_i.c"> | ||||
|       <ExcludedFromBuild>true</ExcludedFromBuild> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="logger.h" /> | ||||
|     <ClInclude Include="namespace.h" /> | ||||
|     <ClInclude Include="nci.h" /> | ||||
|     <ClInclude Include="ntdll.h" /> | ||||
|     <ClInclude Include="registry.h" /> | ||||
|     <ClInclude Include="resource.h" /> | ||||
|     <ClInclude Include="rundll32.h" /> | ||||
|     <ClInclude Include="wintun.h" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|  | ||||
							
								
								
									
										51
									
								
								api/logger.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								api/logger.c
									
									
									
									
									
								
							| @ -4,6 +4,7 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include "logger.h" | ||||
| #include "adapter.h" | ||||
| #include "ntdll.h" | ||||
| #include <Windows.h> | ||||
| #include <winternl.h> | ||||
| @ -11,17 +12,16 @@ | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| static BOOL CALLBACK | ||||
| NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) | ||||
| NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine) | ||||
| { | ||||
|     UNREFERENCED_PARAMETER(Level); | ||||
|     UNREFERENCED_PARAMETER(LogLine); | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| WINTUN_LOGGER_CALLBACK Logger = NopLogger; | ||||
| 
 | ||||
| void CALLBACK | ||||
| WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger) | ||||
| _Use_decl_annotations_ | ||||
| VOID WINAPI | ||||
| WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger) | ||||
| { | ||||
|     if (!NewLogger) | ||||
|         NewLogger = NopLogger; | ||||
| @ -29,14 +29,15 @@ WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger) | ||||
| } | ||||
| 
 | ||||
| static VOID | ||||
| StrTruncate(_Inout_count_(StrChars) WCHAR *Str, _In_ SIZE_T StrChars) | ||||
| StrTruncate(_Inout_count_(StrChars) LPWSTR Str, _In_ SIZE_T StrChars) | ||||
| { | ||||
|     Str[StrChars - 2] = L'\u2026'; /* Horizontal Ellipsis */ | ||||
|     Str[StrChars - 1] = 0; | ||||
| } | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine) | ||||
| _Use_decl_annotations_ | ||||
| DWORD | ||||
| LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR LogLine) | ||||
| { | ||||
|     DWORD LastError = GetLastError(); | ||||
|     if (Function) | ||||
| @ -52,12 +53,9 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c | ||||
|     return LastError; | ||||
| } | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| LoggerLogV( | ||||
|     _In_ WINTUN_LOGGER_LEVEL Level, | ||||
|     _In_z_ const WCHAR *Function, | ||||
|     _In_z_ _Printf_format_string_ const WCHAR *Format, | ||||
|     _In_ va_list Args) | ||||
| _Use_decl_annotations_ | ||||
| DWORD | ||||
| LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR Format, va_list Args) | ||||
| { | ||||
|     DWORD LastError = GetLastError(); | ||||
|     WCHAR LogLine[0x400]; | ||||
| @ -71,16 +69,17 @@ LoggerLogV( | ||||
|     return LastError; | ||||
| } | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix) | ||||
| _Use_decl_annotations_ | ||||
| DWORD | ||||
| LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix) | ||||
| { | ||||
|     WCHAR *SystemMessage = NULL, *FormattedMessage = NULL; | ||||
|     LPWSTR SystemMessage = NULL, FormattedMessage = NULL; | ||||
|     FormatMessageW( | ||||
|         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK, | ||||
|         NULL, | ||||
|         HRESULT_FROM_SETUPAPI(Error), | ||||
|         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
|         (void *)&SystemMessage, | ||||
|         (VOID *)&SystemMessage, | ||||
|         0, | ||||
|         NULL); | ||||
|     FormatMessageW( | ||||
| @ -89,7 +88,7 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR * | ||||
|         SystemMessage ? L"%4: %1: %3(Code 0x%2!08X!)" : L"%4: %1: Code 0x%2!08X!", | ||||
|         0, | ||||
|         0, | ||||
|         (void *)&FormattedMessage, | ||||
|         (VOID *)&FormattedMessage, | ||||
|         0, | ||||
|         (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function }); | ||||
|     if (FormattedMessage) | ||||
| @ -99,12 +98,9 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR * | ||||
|     return Error; | ||||
| } | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| LoggerErrorV( | ||||
|     _In_ DWORD Error, | ||||
|     _In_z_ const WCHAR *Function, | ||||
|     _In_z_ _Printf_format_string_ const WCHAR *Format, | ||||
|     _In_ va_list Args) | ||||
| _Use_decl_annotations_ | ||||
| DWORD | ||||
| LoggerErrorV(DWORD Error, LPCWSTR Function, LPCWSTR Format, va_list Args) | ||||
| { | ||||
|     WCHAR Prefix[0x400]; | ||||
|     if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1) | ||||
| @ -112,13 +108,14 @@ LoggerErrorV( | ||||
|     return LoggerError(Error, Function, Prefix); | ||||
| } | ||||
| 
 | ||||
| _Use_decl_annotations_ | ||||
| VOID | ||||
| LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path) | ||||
| LoggerGetRegistryKeyPath(HKEY Key, LPWSTR Path) | ||||
| { | ||||
|     DWORD LastError = GetLastError(); | ||||
|     if (Key == NULL) | ||||
|     { | ||||
|         wcscpy_s(Path, MAX_REG_PATH, L"<null>"); | ||||
|         wcsncpy_s(Path, MAX_REG_PATH, L"<null>", _TRUNCATE); | ||||
|         goto out; | ||||
|     } | ||||
|     if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1) | ||||
|  | ||||
							
								
								
									
										123
									
								
								api/logger.h
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								api/logger.h
									
									
									
									
									
								
							| @ -9,6 +9,7 @@ | ||||
| #include "main.h" | ||||
| #include "registry.h" | ||||
| #include <Windows.h> | ||||
| #include <intsafe.h> | ||||
| #include <stdarg.h> | ||||
| #include <wchar.h> | ||||
| 
 | ||||
| @ -17,25 +18,23 @@ extern WINTUN_LOGGER_CALLBACK Logger; | ||||
| /**
 | ||||
|  * @copydoc WINTUN_SET_LOGGER_FUNC | ||||
|  */ | ||||
| void WINAPI | ||||
| WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger); | ||||
| WINTUN_SET_LOGGER_FUNC_IMPL WintunSetLogger; | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine); | ||||
| _Post_equals_last_error_ | ||||
| DWORD | ||||
| LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR LogLine); | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| _Post_equals_last_error_ | ||||
| DWORD | ||||
| LoggerLogV( | ||||
|     _In_ WINTUN_LOGGER_LEVEL Level, | ||||
|     _In_z_ const WCHAR *Function, | ||||
|     _In_z_ _Printf_format_string_ const WCHAR *Format, | ||||
|     _In_z_ LPCWSTR Function, | ||||
|     _In_z_ _Printf_format_string_ LPCWSTR Format, | ||||
|     _In_ va_list Args); | ||||
| 
 | ||||
| static inline _Post_equals_last_error_ DWORD | ||||
| LoggerLogFmt( | ||||
|     _In_ WINTUN_LOGGER_LEVEL Level, | ||||
|     _In_z_ const WCHAR *Function, | ||||
|     _In_z_ _Printf_format_string_ const WCHAR *Format, | ||||
|     ...) | ||||
| _Post_equals_last_error_ | ||||
| static inline DWORD | ||||
| LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) | ||||
| { | ||||
|     va_list Args; | ||||
|     va_start(Args, Format); | ||||
| @ -44,18 +43,21 @@ LoggerLogFmt( | ||||
|     return LastError; | ||||
| } | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix); | ||||
| _Post_equals_last_error_ | ||||
| DWORD | ||||
| LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR Prefix); | ||||
| 
 | ||||
| _Post_equals_last_error_ DWORD | ||||
| _Post_equals_last_error_ | ||||
| DWORD | ||||
| LoggerErrorV( | ||||
|     _In_ DWORD Error, | ||||
|     _In_z_ const WCHAR *Function, | ||||
|     _In_z_ _Printf_format_string_ const WCHAR *Format, | ||||
|     _In_z_ LPCWSTR Function, | ||||
|     _In_z_ _Printf_format_string_ LPCWSTR Format, | ||||
|     _In_ va_list Args); | ||||
| 
 | ||||
| static inline _Post_equals_last_error_ DWORD | ||||
| LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...) | ||||
| _Post_equals_last_error_ | ||||
| static inline DWORD | ||||
| LoggerErrorFmt(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) | ||||
| { | ||||
|     va_list Args; | ||||
|     va_start(Args, Format); | ||||
| @ -64,8 +66,9 @@ LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_fo | ||||
|     return LastError; | ||||
| } | ||||
| 
 | ||||
| static inline _Post_equals_last_error_ DWORD | ||||
| LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, _In_ va_list Args) | ||||
| _Post_equals_last_error_ | ||||
| static inline DWORD | ||||
| LoggerLastErrorV(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args) | ||||
| { | ||||
|     DWORD LastError = GetLastError(); | ||||
|     LoggerErrorV(LastError, Function, Format, Args); | ||||
| @ -73,8 +76,9 @@ LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ con | ||||
|     return LastError; | ||||
| } | ||||
| 
 | ||||
| static inline _Post_equals_last_error_ DWORD | ||||
| LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...) | ||||
| _Post_equals_last_error_ | ||||
| static inline DWORD | ||||
| LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...) | ||||
| { | ||||
|     va_list Args; | ||||
|     va_start(Args, Format); | ||||
| @ -84,7 +88,7 @@ LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ c | ||||
| } | ||||
| 
 | ||||
| VOID | ||||
| LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path); | ||||
| LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path); | ||||
| 
 | ||||
| #define __L(x) L##x | ||||
| #define _L(x) __L(x) | ||||
| @ -94,10 +98,31 @@ LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path); | ||||
| 
 | ||||
| #define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0)) | ||||
| 
 | ||||
| static inline _Return_type_success_(return != NULL) _Ret_maybenull_ | ||||
|     _Post_writable_byte_size_(Size) void *LoggerAlloc(_In_z_ const WCHAR *Function, _In_ DWORD Flags, _In_ SIZE_T Size) | ||||
| _Must_inspect_result_ | ||||
| DECLSPEC_ALLOCATOR | ||||
| static inline _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_writable_byte_size_(Size) | ||||
| VOID * | ||||
| LoggerAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T Size) | ||||
| { | ||||
|     void *Data = HeapAlloc(ModuleHeap, Flags, Size); | ||||
|     VOID *Data = HeapAlloc(ModuleHeap, Flags, Size); | ||||
|     if (!Data) | ||||
|     { | ||||
|         LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size); | ||||
|         SetLastError(ERROR_OUTOFMEMORY); | ||||
|     } | ||||
|     return Data; | ||||
| } | ||||
| _Must_inspect_result_ | ||||
| DECLSPEC_ALLOCATOR | ||||
| static inline _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_writable_byte_size_(Size) | ||||
| VOID * | ||||
| LoggerReAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _Frees_ptr_opt_ LPVOID Mem, _In_ SIZE_T Size) | ||||
| { | ||||
|     VOID *Data = Mem ? HeapReAlloc(ModuleHeap, Flags, Mem, Size) : HeapAlloc(ModuleHeap, Flags, Size); | ||||
|     if (!Data) | ||||
|     { | ||||
|         LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size); | ||||
| @ -106,10 +131,48 @@ static inline _Return_type_success_(return != NULL) _Ret_maybenull_ | ||||
|     return Data; | ||||
| } | ||||
| #define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size) | ||||
| #define ReAlloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), 0, Mem, Size) | ||||
| #define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size) | ||||
| #define ReZalloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Size) | ||||
| 
 | ||||
| static inline void | ||||
| Free(void *Ptr) | ||||
| _Must_inspect_result_ | ||||
| DECLSPEC_ALLOCATOR | ||||
| static inline _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement)) | ||||
| VOID * | ||||
| LoggerAllocArray(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T NumberOfElements, _In_ SIZE_T SizeOfOneElement) | ||||
| { | ||||
|     SIZE_T Size; | ||||
|     if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size))) | ||||
|         return NULL; | ||||
|     return LoggerAlloc(Function, Flags, Size); | ||||
| } | ||||
| _Must_inspect_result_ | ||||
| DECLSPEC_ALLOCATOR | ||||
| static inline _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement)) | ||||
| VOID * | ||||
| LoggerReAllocArray( | ||||
|     _In_z_ LPCWSTR Function, | ||||
|     _In_ DWORD Flags, | ||||
|     _Frees_ptr_opt_ LPVOID Mem, | ||||
|     _In_ SIZE_T NumberOfElements, | ||||
|     _In_ SIZE_T SizeOfOneElement) | ||||
| { | ||||
|     SIZE_T Size; | ||||
|     if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size))) | ||||
|         return NULL; | ||||
|     return LoggerReAlloc(Function, Flags, Mem, Size); | ||||
| } | ||||
| #define AllocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), 0, Count, Size) | ||||
| #define ReAllocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), 0, Mem, Count, Size) | ||||
| #define ZallocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Count, Size) | ||||
| #define ReZallocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Count, Size) | ||||
| 
 | ||||
| static inline VOID | ||||
| Free(_Frees_ptr_opt_ VOID *Ptr) | ||||
| { | ||||
|     if (!Ptr) | ||||
|         return; | ||||
|  | ||||
							
								
								
									
										43
									
								
								api/main.c
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								api/main.c
									
									
									
									
									
								
							| @ -3,18 +3,15 @@ | ||||
|  * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. | ||||
|  */ | ||||
| 
 | ||||
| #include "adapter.h" | ||||
| #include "logger.h" | ||||
| #include "registry.h" | ||||
| #include "adapter.h" | ||||
| #include "main.h" | ||||
| #include "namespace.h" | ||||
| #include "wintun.h" | ||||
| #include "registry.h" | ||||
| #include "ntdll.h" | ||||
| 
 | ||||
| #include <Windows.h> | ||||
| #pragma warning(push) | ||||
| #pragma warning(disable : 4201) | ||||
| /* nonstandard extension used: nameless struct/union */ | ||||
| #include <delayimp.h> | ||||
| #pragma warning(pop) | ||||
| #include <sddl.h> | ||||
| #include <winefs.h> | ||||
| #include <stdlib.h> | ||||
| @ -23,6 +20,8 @@ HINSTANCE ResourceModule; | ||||
| HANDLE ModuleHeap; | ||||
| SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) }; | ||||
| BOOL IsLocalSystem; | ||||
| USHORT NativeMachine = IMAGE_FILE_PROCESS; | ||||
| BOOL IsWindows10; | ||||
| 
 | ||||
| static FARPROC WINAPI | ||||
| DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) | ||||
| @ -37,8 +36,7 @@ DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) | ||||
| 
 | ||||
| const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook; | ||||
| 
 | ||||
| static BOOL | ||||
| InitializeSecurityObjects(void) | ||||
| static BOOL InitializeSecurityObjects(VOID) | ||||
| { | ||||
|     BYTE LocalSystemSid[MAX_SID_SIZE]; | ||||
|     DWORD RequiredBytes = sizeof(LocalSystemSid); | ||||
| @ -72,11 +70,32 @@ cleanupProcessToken: | ||||
|     return Ret; | ||||
| } | ||||
| 
 | ||||
| static VOID EnvInit(VOID) | ||||
| { | ||||
|     DWORD MajorVersion; | ||||
|     RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL); | ||||
|     IsWindows10 = MajorVersion >= 10; | ||||
| 
 | ||||
| #ifdef MAYBE_WOW64 | ||||
|     typedef BOOL(WINAPI * IsWow64Process2_t)( | ||||
|         _In_ HANDLE hProcess, _Out_ USHORT * pProcessMachine, _Out_opt_ USHORT * pNativeMachine); | ||||
|     HANDLE Kernel32; | ||||
|     IsWow64Process2_t IsWow64Process2; | ||||
|     USHORT ProcessMachine; | ||||
|     if ((Kernel32 = GetModuleHandleW(L"kernel32.dll")) == NULL || | ||||
|         (IsWow64Process2 = (IsWow64Process2_t)GetProcAddress(Kernel32, "IsWow64Process2")) == NULL || | ||||
|         !IsWow64Process2(GetCurrentProcess(), &ProcessMachine, &NativeMachine)) | ||||
|     { | ||||
|         BOOL IsWoW64; | ||||
|         NativeMachine = | ||||
|             IsWow64Process(GetCurrentProcess(), &IsWoW64) && IsWoW64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_PROCESS; | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| BOOL APIENTRY | ||||
| DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) | ||||
| { | ||||
|     UNREFERENCED_PARAMETER(lpvReserved); | ||||
| 
 | ||||
|     switch (fdwReason) | ||||
|     { | ||||
|     case DLL_PROCESS_ATTACH: | ||||
| @ -89,7 +108,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) | ||||
|             HeapDestroy(ModuleHeap); | ||||
|             return FALSE; | ||||
|         } | ||||
|         AdapterInit(); | ||||
|         EnvInit(); | ||||
|         NamespaceInit(); | ||||
|         break; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										27
									
								
								api/main.h
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								api/main.h
									
									
									
									
									
								
							| @ -7,26 +7,21 @@ | ||||
| 
 | ||||
| #include <Windows.h> | ||||
| 
 | ||||
| /* TODO: Replace with is_defined. MSVC has issues with the linux kernel varadic macro trick for this. */ | ||||
| #if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) | ||||
| #    define MAYBE_WOW64 1 | ||||
| #if defined(_M_IX86) | ||||
| #    define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386 | ||||
| #elif defined(_M_AMD64) | ||||
| #    define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64 | ||||
| #elif defined(_M_ARM) | ||||
| #    define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT | ||||
| #elif defined(_M_ARM64) | ||||
| #    define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64 | ||||
| #else | ||||
| #    define MAYBE_WOW64 0 | ||||
| #    error Unsupported architecture | ||||
| #endif | ||||
| #if defined(_M_AMD64) || defined(_M_ARM64) | ||||
| #    define ACCEPT_WOW64 1 | ||||
| #else | ||||
| #    define ACCEPT_WOW64 0 | ||||
| #endif | ||||
| #ifdef HAVE_WHQL | ||||
| #    undef HAVE_WHQL | ||||
| #    define HAVE_WHQL 1 | ||||
| #else | ||||
| #    define HAVE_WHQL 0 | ||||
| #endif | ||||
| #pragma warning(disable : 4127) /* conditional expression is constant */ | ||||
| 
 | ||||
| extern HINSTANCE ResourceModule; | ||||
| extern HANDLE ModuleHeap; | ||||
| extern SECURITY_ATTRIBUTES SecurityAttributes; | ||||
| extern BOOL IsLocalSystem; | ||||
| extern USHORT NativeMachine; | ||||
| extern BOOL IsWindows10; | ||||
| @ -19,13 +19,16 @@ static HANDLE BoundaryDescriptor = NULL; | ||||
| static CRITICAL_SECTION Initializing; | ||||
| static BCRYPT_ALG_HANDLE AlgProvider; | ||||
| 
 | ||||
| static _Return_type_success_( | ||||
|     return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source) | ||||
| _Must_inspect_result_ | ||||
| static _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| LPWSTR | ||||
| NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ LPCWSTR Source) | ||||
| { | ||||
|     int Len = NormalizeString(NormForm, Source, -1, NULL, 0); | ||||
|     for (;;) | ||||
|     { | ||||
|         WCHAR *Str = Alloc(sizeof(WCHAR) * Len); | ||||
|         LPWSTR Str = AllocArray(Len, sizeof(*Str)); | ||||
|         if (!Str) | ||||
|             return NULL; | ||||
|         Len = NormalizeString(NormForm, Source, -1, Str, Len); | ||||
| @ -41,7 +44,8 @@ static _Return_type_success_( | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void) | ||||
| static _Return_type_success_(return != FALSE) | ||||
| BOOL NamespaceRuntimeInit(VOID) | ||||
| { | ||||
|     DWORD LastError; | ||||
| 
 | ||||
| @ -110,8 +114,9 @@ cleanupLeaveCriticalSection: | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| _Check_return_ | ||||
| _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool) | ||||
| _Use_decl_annotations_ | ||||
| HANDLE | ||||
| NamespaceTakePoolMutex(LPCWSTR Pool) | ||||
| { | ||||
|     if (!NamespaceRuntimeInit()) | ||||
|         return NULL; | ||||
| @ -133,7 +138,7 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const | ||||
|         LastError = RtlNtStatusToDosError(Status); | ||||
|         goto cleanupSha256; | ||||
|     } | ||||
|     WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool); | ||||
|     LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool); | ||||
|     if (!PoolNorm) | ||||
|     { | ||||
|         LastError = GetLastError(); | ||||
| @ -184,8 +189,9 @@ cleanupSha256: | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| _Check_return_ | ||||
| _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void) | ||||
| _Use_decl_annotations_ | ||||
| HANDLE | ||||
| NamespaceTakeDriverInstallationMutex(VOID) | ||||
| { | ||||
|     if (!NamespaceRuntimeInit()) | ||||
|         return NULL; | ||||
| @ -208,21 +214,20 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMute | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| NamespaceReleaseMutex(_In_ HANDLE Mutex) | ||||
| _Use_decl_annotations_ | ||||
| VOID | ||||
| NamespaceReleaseMutex(HANDLE Mutex) | ||||
| { | ||||
|     ReleaseMutex(Mutex); | ||||
|     CloseHandle(Mutex); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| NamespaceInit(void) | ||||
| VOID NamespaceInit(VOID) | ||||
| { | ||||
|     InitializeCriticalSection(&Initializing); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| NamespaceDone(void) | ||||
| VOID NamespaceDone(VOID) | ||||
| { | ||||
|     EnterCriticalSection(&Initializing); | ||||
|     if (PrivateNamespace) | ||||
|  | ||||
| @ -7,17 +7,24 @@ | ||||
| 
 | ||||
| #include <Windows.h> | ||||
| 
 | ||||
| _Check_return_ | ||||
| _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Acquires_lock_(_Curr_) | ||||
| HANDLE | ||||
| NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool); | ||||
| 
 | ||||
| _Check_return_ | ||||
| _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Acquires_lock_(_Curr_) | ||||
| HANDLE | ||||
| NamespaceTakeDriverInstallationMutex(VOID); | ||||
| 
 | ||||
| void | ||||
| _Releases_lock_(Mutex) | ||||
| VOID | ||||
| NamespaceReleaseMutex(_In_ HANDLE Mutex); | ||||
| 
 | ||||
| void | ||||
| NamespaceInit(void); | ||||
| VOID NamespaceInit(VOID); | ||||
| 
 | ||||
| void | ||||
| NamespaceDone(void); | ||||
| VOID NamespaceDone(VOID); | ||||
|  | ||||
							
								
								
									
										16
									
								
								api/nci.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								api/nci.h
									
									
									
									
									
								
							| @ -9,19 +9,23 @@ | ||||
| 
 | ||||
| #ifdef GENERATE_LIB | ||||
| #    define DECLSPEC __declspec(dllexport) | ||||
| #    define STUB { return 0; } | ||||
| #    define STUB \ | ||||
|         { \ | ||||
|             return 0; \ | ||||
|         } | ||||
| #else | ||||
| #    define DECLSPEC __declspec(dllimport) | ||||
| #    define STUB ; | ||||
| #endif | ||||
| 
 | ||||
| EXTERN_C | ||||
| DECLSPEC DWORD WINAPI | ||||
| NciSetConnectionName(_In_ const GUID *Guid, _In_z_ LPCWSTR NewName) STUB | ||||
| 
 | ||||
| EXTERN_C DECLSPEC DWORD WINAPI | ||||
| NciSetConnectionName(_In_ const GUID *Guid, _In_z_ const WCHAR *NewName) STUB | ||||
| 
 | ||||
| EXTERN_C DECLSPEC DWORD WINAPI | ||||
|     EXTERN_C | ||||
| DECLSPEC DWORD WINAPI | ||||
| NciGetConnectionName( | ||||
|     _In_ const GUID *Guid, | ||||
|     _Out_z_bytecap_(InDestNameBytes) WCHAR *Name, | ||||
|     _Out_z_bytecap_(InDestNameBytes) LPWSTR Name, | ||||
|     _In_ DWORD InDestNameBytes, | ||||
|     _Out_opt_ DWORD *OutDestNameBytes) STUB | ||||
| @ -45,7 +45,7 @@ typedef struct _KEY_NAME_INFORMATION | ||||
|  * when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers. | ||||
|  * | ||||
|  * Another way would be reading from the PEB directly: | ||||
|  *   ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41] | ||||
|  *   ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(VOID *) == 8 ? 70 : 41] | ||||
|  * Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit: | ||||
|  *    *(DWORD *)0x7FFE026C | ||||
|  */ | ||||
| @ -61,9 +61,3 @@ NtQueryKey( | ||||
|     _Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation, | ||||
|     _In_ ULONG Length, | ||||
|     _Out_ PULONG ResultLength); | ||||
| 
 | ||||
| /* This is documented in NTSecAPI.h, which we can't include, due to header conflicts. It actually lives in advapi32.dll. */ | ||||
| #define RtlGenRandom SystemFunction036 | ||||
| BOOLEAN | ||||
| NTAPI | ||||
| RtlGenRandom(_Out_writes_bytes_all_(RandomBufferLength) PVOID RandomBuffer, _In_ ULONG RandomBufferLength); | ||||
							
								
								
									
										160
									
								
								api/registry.c
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								api/registry.c
									
									
									
									
									
								
							| @ -10,11 +10,14 @@ | ||||
| #include <stdlib.h> | ||||
| #include <strsafe.h> | ||||
| 
 | ||||
| static _Return_type_success_(return != NULL) HKEY | ||||
|     OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) | ||||
| _Must_inspect_result_ | ||||
| static _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| HKEY | ||||
| OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) | ||||
| { | ||||
|     DWORD LastError; | ||||
|     WCHAR *PathNext = wcschr(Path, L'\\'); | ||||
|     LPWSTR PathNext = wcschr(Path, L'\\'); | ||||
|     if (PathNext) | ||||
|         *PathNext = 0; | ||||
| 
 | ||||
| @ -87,8 +90,9 @@ static _Return_type_success_(return != NULL) HKEY | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != NULL) HKEY | ||||
|     RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout) | ||||
| _Use_decl_annotations_ | ||||
| HKEY | ||||
| RegistryOpenKeyWait(HKEY Key, LPCWSTR Path, DWORD Access, DWORD Timeout) | ||||
| { | ||||
|     WCHAR Buf[MAX_REG_PATH]; | ||||
|     if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE) | ||||
| @ -100,17 +104,17 @@ _Return_type_success_(return != NULL) HKEY | ||||
|     return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout); | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) | ||||
| _Use_decl_annotations_ | ||||
| BOOL | ||||
| RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType) | ||||
| { | ||||
|     if (wcsnlen(*Buf, Len) >= Len) | ||||
|     { | ||||
|         /* String is missing zero-terminator. */ | ||||
|         WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR)); | ||||
|         LPWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ)); | ||||
|         if (!BufZ) | ||||
|             return FALSE; | ||||
|         wmemcpy(BufZ, *Buf, Len); | ||||
|         BufZ[Len] = 0; | ||||
|         Free(*Buf); | ||||
|         _Analysis_assume_((wmemset(BufZ, L'A', (SIZE_T)Len + 1), TRUE)); | ||||
|         *Buf = BufZ; | ||||
|     } | ||||
| 
 | ||||
| @ -122,10 +126,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu | ||||
|     if (!(*Buf)[0]) | ||||
|         return TRUE; | ||||
| 
 | ||||
|     Len = Len * 2 + 64; | ||||
|     for (;;) | ||||
|     { | ||||
|         WCHAR *Expanded = Alloc(Len * sizeof(WCHAR)); | ||||
|         LPWSTR Expanded = AllocArray(Len, sizeof(*Expanded)); | ||||
|         if (!Expanded) | ||||
|             return FALSE; | ||||
|         DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len); | ||||
| @ -147,8 +150,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType) | ||||
| _Use_decl_annotations_ | ||||
| BOOL | ||||
| RegistryGetMultiString(PZZWSTR *Buf, DWORD Len, DWORD ValueType) | ||||
| { | ||||
|     if (ValueType == REG_MULTI_SZ) | ||||
|     { | ||||
| @ -157,25 +161,18 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|             if (i > Len) | ||||
|             { | ||||
|                 /* Missing string and list terminators. */ | ||||
|                 WCHAR *BufZ = Alloc(((size_t)Len + 2) * sizeof(WCHAR)); | ||||
|                 PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 2, sizeof(*BufZ)); | ||||
|                 if (!BufZ) | ||||
|                     return FALSE; | ||||
|                 wmemcpy(BufZ, *Buf, Len); | ||||
|                 BufZ[Len] = 0; | ||||
|                 BufZ[Len + 1] = 0; | ||||
|                 Free(*Buf); | ||||
|                 *Buf = BufZ; | ||||
|                 return TRUE; | ||||
|             } | ||||
|             if (i == Len) | ||||
|             { | ||||
|                 /* Missing list terminator. */ | ||||
|                 WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR)); | ||||
|                 PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ)); | ||||
|                 if (!BufZ) | ||||
|                     return FALSE; | ||||
|                 wmemcpy(BufZ, *Buf, Len); | ||||
|                 BufZ[Len] = 0; | ||||
|                 Free(*Buf); | ||||
|                 *Buf = BufZ; | ||||
|                 return TRUE; | ||||
|             } | ||||
| @ -188,22 +185,19 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|     if (!RegistryGetString(Buf, Len, ValueType)) | ||||
|         return FALSE; | ||||
|     Len = (DWORD)wcslen(*Buf) + 1; | ||||
|     WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR)); | ||||
|     PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(WCHAR)); | ||||
|     if (!BufZ) | ||||
|         return FALSE; | ||||
|     wmemcpy(BufZ, *Buf, Len); | ||||
|     BufZ[Len] = 0; | ||||
|     Free(*Buf); | ||||
|     *Buf = BufZ; | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| static _Return_type_success_(return != NULL) void *RegistryQuery( | ||||
|     _In_ HKEY Key, | ||||
|     _In_opt_z_ const WCHAR *Name, | ||||
|     _Out_opt_ DWORD *ValueType, | ||||
|     _Inout_ DWORD *BufLen, | ||||
|     _In_ BOOL Log) | ||||
| _Must_inspect_result_ | ||||
| static _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_writable_byte_size_(*BufLen) | ||||
| VOID * | ||||
| RegistryQuery(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_opt_ DWORD *ValueType, _Inout_ DWORD *BufLen, _In_ BOOL Log) | ||||
| { | ||||
|     for (;;) | ||||
|     { | ||||
| @ -220,7 +214,7 @@ static _Return_type_success_(return != NULL) void *RegistryQuery( | ||||
|             { | ||||
|                 WCHAR RegPath[MAX_REG_PATH]; | ||||
|                 LoggerGetRegistryKeyPath(Key, RegPath); | ||||
|                 LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name); | ||||
|                 LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name); | ||||
|             } | ||||
|             SetLastError(LastError); | ||||
|             return NULL; | ||||
| @ -228,11 +222,12 @@ static _Return_type_success_(return != NULL) void *RegistryQuery( | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_( | ||||
|     return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log) | ||||
| _Use_decl_annotations_ | ||||
| LPWSTR | ||||
| RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log) | ||||
| { | ||||
|     DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR); | ||||
|     WCHAR *Value = RegistryQuery(Key, Name, &ValueType, &Size, Log); | ||||
|     LPWSTR Value = RegistryQuery(Key, Name, &ValueType, &Size, Log); | ||||
|     if (!Value) | ||||
|         return NULL; | ||||
|     switch (ValueType) | ||||
| @ -240,7 +235,7 @@ _Return_type_success_( | ||||
|     case REG_SZ: | ||||
|     case REG_EXPAND_SZ: | ||||
|     case REG_MULTI_SZ: | ||||
|         if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType)) | ||||
|         if (RegistryGetString(&Value, Size / sizeof(*Value), ValueType)) | ||||
|             return Value; | ||||
|         LastError = GetLastError(); | ||||
|         break; | ||||
| @ -261,8 +256,9 @@ _Return_type_success_( | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_( | ||||
|     return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout) | ||||
| _Use_decl_annotations_ | ||||
| LPWSTR | ||||
| RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout) | ||||
| { | ||||
|     DWORD LastError; | ||||
|     ULONGLONG Deadline = GetTickCount64() + Timeout; | ||||
| @ -282,7 +278,7 @@ _Return_type_success_( | ||||
|             LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); | ||||
|             break; | ||||
|         } | ||||
|         WCHAR *Value = RegistryQueryString(Key, Name, FALSE); | ||||
|         LPWSTR Value = RegistryQueryString(Key, Name, FALSE); | ||||
|         if (Value) | ||||
|         { | ||||
|             CloseHandle(Event); | ||||
| @ -313,8 +309,9 @@ _Return_type_success_( | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log) | ||||
| _Use_decl_annotations_ | ||||
| BOOL | ||||
| RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log) | ||||
| { | ||||
|     DWORD ValueType, Size = sizeof(DWORD); | ||||
|     DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size); | ||||
| @ -324,7 +321,7 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|         { | ||||
|             WCHAR RegPath[MAX_REG_PATH]; | ||||
|             LoggerGetRegistryKeyPath(Key, RegPath); | ||||
|             LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name); | ||||
|             LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name); | ||||
|         } | ||||
|         SetLastError(LastError); | ||||
|         return FALSE; | ||||
| @ -348,8 +345,9 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value) | ||||
| _Use_decl_annotations_ | ||||
| BOOL | ||||
| RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value) | ||||
| { | ||||
|     DWORD LastError; | ||||
|     ULONGLONG Deadline = GetTickCount64() + Timeout; | ||||
| @ -398,73 +396,3 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|     SetLastError(LastError); | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) static BOOL | ||||
|     DeleteNodeRecurse(_In_ HKEY Key, _In_z_ WCHAR *Name) | ||||
| { | ||||
|     LSTATUS Ret; | ||||
|     DWORD Size; | ||||
|     SIZE_T Len; | ||||
|     WCHAR SubName[MAX_REG_PATH], *End; | ||||
|     HKEY SubKey; | ||||
| 
 | ||||
|     Len = wcslen(Name); | ||||
|     if (Len >= MAX_REG_PATH || !Len) | ||||
|         return TRUE; | ||||
| 
 | ||||
|     if (RegDeleteKeyW(Key, Name) == ERROR_SUCCESS) | ||||
|         return TRUE; | ||||
| 
 | ||||
|     Ret = RegOpenKeyEx(Key, Name, 0, KEY_READ, &SubKey); | ||||
|     if (Ret != ERROR_SUCCESS) | ||||
|     { | ||||
|         if (Ret == ERROR_FILE_NOT_FOUND) | ||||
|             return TRUE; | ||||
|         SetLastError(Ret); | ||||
|         return FALSE; | ||||
|     } | ||||
| 
 | ||||
|     End = Name + Len; | ||||
|     if (End[-1] != L'\\') | ||||
|     { | ||||
|         *(End++) = L'\\'; | ||||
|         *End = L'\0'; | ||||
|     } | ||||
|     Size = MAX_REG_PATH; | ||||
|     Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL); | ||||
|     if (Ret == ERROR_SUCCESS) | ||||
|     { | ||||
|         do | ||||
|         { | ||||
|             End[0] = L'\0'; | ||||
|             StringCchCatW(Name, MAX_REG_PATH * 2, SubName); | ||||
|             if (!DeleteNodeRecurse(Key, Name)) | ||||
|                 break; | ||||
|             Size = MAX_REG_PATH; | ||||
|             Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL); | ||||
|         } while (Ret == ERROR_SUCCESS); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         SetLastError(Ret); | ||||
|         *(--End) = L'\0'; | ||||
|         RegCloseKey(SubKey); | ||||
|         return FALSE; | ||||
|     } | ||||
|     *(--End) = L'\0'; | ||||
|     RegCloseKey(SubKey); | ||||
| 
 | ||||
|     Ret = RegDeleteKey(Key, Name); | ||||
|     if (Ret == ERROR_SUCCESS) | ||||
|         return TRUE; | ||||
|     SetLastError(Ret); | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
| RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name) | ||||
| { | ||||
|     WCHAR NameBuf[(MAX_REG_PATH + 2) * 2] = { 0 }; | ||||
|     StringCchCopyW(NameBuf, MAX_REG_PATH * 2, Name); | ||||
|     return DeleteNodeRecurse(Key, NameBuf); | ||||
| } | ||||
| @ -26,8 +26,11 @@ | ||||
|  * @return Key handle on success. If the function fails, the return value is zero. To get extended error information, | ||||
|  *         call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != NULL) HKEY | ||||
|     RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| HKEY | ||||
| RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ LPCWSTR Path, _In_ DWORD Access, _In_ DWORD Timeout); | ||||
| 
 | ||||
| /**
 | ||||
|  * Validates and/or sanitizes string value read from registry. | ||||
| @ -44,8 +47,10 @@ _Return_type_success_(return != NULL) HKEY | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType); | ||||
| 
 | ||||
| /**
 | ||||
|  * Validates and/or sanitizes multi-string value read from registry. | ||||
| @ -61,8 +66,10 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| RegistryGetMultiString(_Inout_ PZZWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reads string value from registry key. | ||||
| @ -83,8 +90,11 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|  * @return String with registry value on success; If the function fails, the return value is zero. To get extended error | ||||
|  *         information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_( | ||||
|     return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| LPWSTR | ||||
| RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ BOOL Log); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reads string value from registry key. It waits for the registry value to become available. | ||||
| @ -101,8 +111,11 @@ _Return_type_success_( | ||||
|  *         get extended error information, call GetLastError. Possible errors include the following: | ||||
|  *         ERROR_INVALID_DATATYPE when the registry value is not a string | ||||
|  */ | ||||
| _Return_type_success_( | ||||
|     return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| LPWSTR | ||||
| RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reads a 32-bit DWORD value from registry key. | ||||
| @ -120,8 +133,10 @@ _Return_type_success_( | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available. | ||||
| @ -139,17 +154,7 @@ _Return_type_success_(return != FALSE) BOOL | ||||
|  *         ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type; | ||||
|  *         ERROR_INVALID_DATA when registry value size is not 4 bytes | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deletes the entire registry key subtree recursively. | ||||
|  * | ||||
|  * @param Key           Handle of the registry key to at which the subtree is rooted. | ||||
|  * | ||||
|  * @param Name          Name of the subtree to delete. | ||||
|  * | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value); | ||||
|  | ||||
| @ -7,9 +7,12 @@ | ||||
| #include "main.h" | ||||
| #include "resource.h" | ||||
| #include <Windows.h> | ||||
| #include <Shlwapi.h> | ||||
| #include <NTSecAPI.h> | ||||
| 
 | ||||
| _Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const | ||||
|     void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size) | ||||
| _Use_decl_annotations_ | ||||
| const VOID * | ||||
| ResourceGetAddress(LPCWSTR ResourceName, DWORD *Size) | ||||
| { | ||||
|     HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA); | ||||
|     if (!FoundResource) | ||||
| @ -39,11 +42,12 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const | ||||
|     return Address; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName) | ||||
| _Use_decl_annotations_ | ||||
| BOOL | ||||
| ResourceCopyToFile(LPCWSTR DestinationPath, LPCWSTR ResourceName) | ||||
| { | ||||
|     DWORD SizeResource; | ||||
|     const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource); | ||||
|     const VOID *LockedResource = ResourceGetAddress(ResourceName, &SizeResource); | ||||
|     if (!LockedResource) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", ResourceName); | ||||
| @ -84,3 +88,42 @@ cleanupDestinationHandle: | ||||
|     CloseHandle(DestinationHandle); | ||||
|     return RET_ERROR(TRUE, LastError); | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory) | ||||
| { | ||||
|     WCHAR WindowsDirectory[MAX_PATH]; | ||||
|     if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory))) | ||||
|     { | ||||
|         LOG_LAST_ERROR(L"Failed to get Windows folder"); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR WindowsTempDirectory[MAX_PATH]; | ||||
|     if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp")) | ||||
|     { | ||||
|         SetLastError(ERROR_BUFFER_OVERFLOW); | ||||
|         return FALSE; | ||||
|     } | ||||
|     UCHAR RandomBytes[32] = { 0 }; | ||||
|     if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes))) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Failed to generate random"); | ||||
|         SetLastError(ERROR_GEN_FAILURE); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1]; | ||||
|     for (int i = 0; i < sizeof(RandomBytes); ++i) | ||||
|         swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]); | ||||
|     if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory)) | ||||
|     { | ||||
|         SetLastError(ERROR_BUFFER_OVERFLOW); | ||||
|         return FALSE; | ||||
|     } | ||||
|     if (!CreateDirectoryW(RandomTempSubDirectory, &SecurityAttributes)) | ||||
|     { | ||||
|         LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory); | ||||
|         return FALSE; | ||||
|     } | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| @ -11,25 +11,40 @@ | ||||
| /**
 | ||||
|  * Locates RT_RCDATA resource memory address and size. | ||||
|  * | ||||
|  * ResourceName         Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. | ||||
|  * @param ResourceName         Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. | ||||
|  * | ||||
|  * Size                 Pointer to a variable to receive resource size. | ||||
|  * @param Size                 Pointer to a variable to receive resource size. | ||||
|  * | ||||
|  * @return Resource address on success. If the function fails, the return value is NULL. To get extended error | ||||
|  *         information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const | ||||
|     void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size); | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_readable_byte_size_(*Size) const VOID *ResourceGetAddress(_In_z_ LPCWSTR ResourceName, _Out_ DWORD *Size); | ||||
| 
 | ||||
| /**
 | ||||
|  * Copies resource to a file. | ||||
|  * | ||||
|  * DestinationPath      File path | ||||
|  * @param DestinationPath   File path | ||||
|  * | ||||
|  * ResourceName         Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. | ||||
|  * @param ResourceName      Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID. | ||||
|  * | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) BOOL | ||||
|     ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName); | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| ResourceCopyToFile(_In_z_ LPCWSTR DestinationPath, _In_z_ LPCWSTR ResourceName); | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates a temporary directory. | ||||
|  * | ||||
|  * @param RandomTempSubDirectory    Name of random temporary directory. | ||||
|  * | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory); | ||||
|  | ||||
							
								
								
									
										544
									
								
								api/rundll32.c
									
									
									
									
									
								
							
							
						
						
									
										544
									
								
								api/rundll32.c
									
									
									
									
									
								
							| @ -3,12 +3,14 @@ | ||||
|  * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. | ||||
|  */ | ||||
| 
 | ||||
| #include "rundll32.h" | ||||
| #include "adapter.h" | ||||
| #include "main.h" | ||||
| #include "logger.h" | ||||
| #include "wintun.h" | ||||
| 
 | ||||
| #include "resource.h" | ||||
| #include <Windows.h> | ||||
| #include <shellapi.h> | ||||
| #include <Shlwapi.h> | ||||
| #include <cfgmgr32.h> | ||||
| #include <objbase.h> | ||||
| #include <assert.h> | ||||
| @ -18,10 +20,10 @@ | ||||
| #    define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) | ||||
| 
 | ||||
| static DWORD | ||||
| WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) | ||||
| WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...) | ||||
| { | ||||
|     WCHAR *FormattedMessage = NULL; | ||||
|     DWORD SizeWritten; | ||||
|     LPWSTR FormattedMessage = NULL; | ||||
|     DWORD Size; | ||||
|     va_list Arguments; | ||||
|     va_start(Arguments, Template); | ||||
|     DWORD Len = FormatMessageW( | ||||
| @ -29,19 +31,22 @@ WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...) | ||||
|         Template, | ||||
|         0, | ||||
|         0, | ||||
|         (void *)&FormattedMessage, | ||||
|         (VOID *)&FormattedMessage, | ||||
|         0, | ||||
|         &Arguments); | ||||
|     WriteFile(GetStdHandle(StdHandle), FormattedMessage, Len * sizeof(WCHAR), &SizeWritten, NULL); | ||||
|     if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size))) | ||||
|         WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL); | ||||
|     else | ||||
|         Size = 0; | ||||
|     LocalFree(FormattedMessage); | ||||
|     va_end(Arguments); | ||||
|     return SizeWritten / sizeof(WCHAR); | ||||
|     return Size / sizeof(*FormattedMessage); | ||||
| } | ||||
| 
 | ||||
| static void CALLBACK | ||||
| ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) | ||||
| static VOID CALLBACK | ||||
| ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine) | ||||
| { | ||||
|     const WCHAR *Template; | ||||
|     LPCWSTR Template; | ||||
|     switch (Level) | ||||
|     { | ||||
|     case WINTUN_LOG_INFO: | ||||
| @ -59,29 +64,14 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine) | ||||
|     WriteFormatted(STD_ERROR_HANDLE, Template, LogLine); | ||||
| } | ||||
| 
 | ||||
| static int Argc; | ||||
| static WCHAR **Argv; | ||||
| 
 | ||||
| static void | ||||
| Init(void) | ||||
| { | ||||
|     WintunSetLogger(ConsoleLogger); | ||||
|     Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| Done(void) | ||||
| { | ||||
|     LocalFree(Argv); | ||||
| } | ||||
| 
 | ||||
| #    pragma warning(disable : 4100) /* unreferenced formal parameter */ | ||||
| 
 | ||||
| VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) | ||||
| { | ||||
| #    pragma EXPORT | ||||
| 
 | ||||
|     Init(); | ||||
|     int Argc; | ||||
|     LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); | ||||
|     WintunSetLogger(ConsoleLogger); | ||||
| 
 | ||||
|     if (Argc < 4) | ||||
|         goto cleanup; | ||||
|     if (wcslen(Argv[2]) >= WINTUN_MAX_POOL) | ||||
| @ -95,47 +85,52 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int | ||||
|     BOOL RebootRequired; | ||||
|     WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired); | ||||
|     DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError(); | ||||
|     WCHAR GuidStr[MAX_GUID_STRING_LEN]; | ||||
|     WriteFormatted( | ||||
|         STD_OUTPUT_HANDLE, | ||||
|         L"%1!X! %2!.*s! %3!X!", | ||||
|         LastError, | ||||
|         StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)), | ||||
|         GuidStr, | ||||
|         RebootRequired); | ||||
|         STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"", RebootRequired); | ||||
|     if (Adapter) | ||||
|         WintunFreeAdapter(Adapter); | ||||
| 
 | ||||
| cleanup: | ||||
|     Done(); | ||||
|     LocalFree(Argv); | ||||
| } | ||||
| 
 | ||||
| VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) | ||||
| { | ||||
| #    pragma EXPORT | ||||
| 
 | ||||
|     Init(); | ||||
|     if (Argc < 3) | ||||
|     int Argc; | ||||
|     LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); | ||||
|     WintunSetLogger(ConsoleLogger); | ||||
| 
 | ||||
|     if (Argc < 4) | ||||
|         goto cleanup; | ||||
| 
 | ||||
|     WINTUN_ADAPTER Adapter = { 0 }; | ||||
|     BOOL ForceCloseSessions = wcstoul(Argv[2], NULL, 10); | ||||
|     if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID))) | ||||
|         goto cleanup; | ||||
|     BOOL RebootRequired; | ||||
|     DWORD LastError = | ||||
|         WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); | ||||
|     DWORD LastError; | ||||
|     BOOL RebootRequired = FALSE; | ||||
|     WINTUN_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]); | ||||
|     if (!Adapter) | ||||
|     { | ||||
|         LastError = GetLastError(); | ||||
|         goto write; | ||||
|     } | ||||
|     BOOL ForceCloseSessions = wcstoul(Argv[4], NULL, 10); | ||||
|     LastError = WintunDeleteAdapter(Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); | ||||
|     WintunFreeAdapter(Adapter); | ||||
| write: | ||||
|     WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); | ||||
| 
 | ||||
| cleanup: | ||||
|     Done(); | ||||
|     LocalFree(Argv); | ||||
| } | ||||
| 
 | ||||
| VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) | ||||
| { | ||||
| #    pragma EXPORT | ||||
| 
 | ||||
|     Init(); | ||||
|     int Argc; | ||||
|     LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); | ||||
|     WintunSetLogger(ConsoleLogger); | ||||
| 
 | ||||
|     if (Argc < 2) | ||||
|         goto cleanup; | ||||
| 
 | ||||
| @ -144,6 +139,455 @@ VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, i | ||||
|     WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); | ||||
| 
 | ||||
| cleanup: | ||||
|     Done(); | ||||
|     LocalFree(Argv); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef MAYBE_WOW64 | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) | ||||
| static BOOL | ||||
| AppendToBuffer(_Inout_ LPWSTR *Buffer, _In_ CONST WCHAR Addition, _Inout_ SIZE_T *BufferPos, _Inout_ SIZE_T *BufferLen) | ||||
| { | ||||
|     SIZE_T NewPos; | ||||
|     if (FAILED(SIZETAdd(*BufferPos, sizeof(Addition), &NewPos))) | ||||
|         return FALSE; | ||||
|     if (NewPos >= *BufferLen) | ||||
|     { | ||||
|         SIZE_T NewLen; | ||||
|         if (FAILED(SIZETMult(NewPos, 3, &NewLen))) | ||||
|             return FALSE; | ||||
|         LPWSTR NewBuffer = ReZalloc(*Buffer, NewLen); | ||||
|         if (!NewBuffer) | ||||
|             return FALSE; | ||||
|         *Buffer = NewBuffer; | ||||
|         *BufferLen = NewLen; | ||||
|     } | ||||
|     SIZE_T NewIndex = *BufferPos / sizeof(**Buffer); | ||||
|     if (*Buffer + NewIndex < *Buffer) | ||||
|         return FALSE; | ||||
|     (*Buffer)[NewIndex] = Addition; | ||||
|     *BufferPos = NewPos; | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| _Must_inspect_result_ | ||||
| static _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| LPWSTR | ||||
| ArgvToCommandLineW(_In_ SIZE_T ArgCount, ...) | ||||
| { | ||||
|     LPWSTR Output = NULL; | ||||
|     SIZE_T BufferPos = 0, BufferLen = 0; | ||||
| #    define Append(Char) \ | ||||
|         do \ | ||||
|         { \ | ||||
|             if (!AppendToBuffer(&Output, Char, &BufferPos, &BufferLen)) \ | ||||
|                 goto cleanupBuffer; \ | ||||
|         } while (0) | ||||
| 
 | ||||
|     va_list Args; | ||||
|     va_start(Args, ArgCount); | ||||
|     for (SIZE_T i = 0; i < ArgCount; ++i) | ||||
|     { | ||||
|         LPCWSTR Arg = va_arg(Args, LPCWSTR); | ||||
|         SIZE_T ArgLen = wcslen(Arg); | ||||
|         if (ArgLen >= DWORD_MAX >> 3) | ||||
|             goto cleanupBuffer; | ||||
|         if (i) | ||||
|             Append(L' '); | ||||
|         Append(L'"'); | ||||
|         for (SIZE_T j = 0;; ++j) | ||||
|         { | ||||
|             SIZE_T NumberBackslashes = 0; | ||||
| 
 | ||||
|             while (j < ArgLen && Arg[j] == L'\\') | ||||
|             { | ||||
|                 ++j; | ||||
|                 ++NumberBackslashes; | ||||
|             } | ||||
|             if (j >= ArgLen) | ||||
|             { | ||||
|                 for (SIZE_T k = 0; k < NumberBackslashes * 2; ++k) | ||||
|                     Append(L'\\'); | ||||
|                 break; | ||||
|             } | ||||
|             else if (Arg[j] == L'"') | ||||
|             { | ||||
|                 for (SIZE_T k = 0; k < NumberBackslashes * 2 + 1; ++k) | ||||
|                     Append(L'\\'); | ||||
|                 Append(Arg[j]); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 for (SIZE_T k = 0; k < NumberBackslashes; ++k) | ||||
|                     Append(L'\\'); | ||||
|                 Append(Arg[j]); | ||||
|             } | ||||
|         } | ||||
|         Append(L'"'); | ||||
|     } | ||||
|     va_end(Args); | ||||
|     return Output; | ||||
| 
 | ||||
| cleanupBuffer: | ||||
|     Free(Output); | ||||
|     return NULL; | ||||
| #    undef Append | ||||
| } | ||||
| 
 | ||||
| typedef struct _PROCESS_STDOUT_STATE | ||||
| { | ||||
|     HANDLE Stdout; | ||||
|     LPWSTR Response; | ||||
|     DWORD ResponseCapacity; | ||||
| } PROCESS_STDOUT_STATE; | ||||
| 
 | ||||
| _Return_type_success_(return != ERROR_SUCCESS) | ||||
| static DWORD WINAPI | ||||
| ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State) | ||||
| { | ||||
|     for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;) | ||||
|     { | ||||
|         DWORD Size; | ||||
|         if (FAILED(DWordMult(MaxLen - Offset, sizeof(WCHAR), &Size))) | ||||
|             return ERROR_BUFFER_OVERFLOW; | ||||
|         if (!ReadFile(State->Stdout, State->Response + Offset, Size, &Size, NULL)) | ||||
|             return ERROR_SUCCESS; | ||||
|         if (Size % sizeof(WCHAR)) | ||||
|             return ERROR_INVALID_DATA; | ||||
|         Offset += Size / sizeof(WCHAR); | ||||
|         State->Response[Offset] = 0; | ||||
|     } | ||||
|     return ERROR_BUFFER_OVERFLOW; | ||||
| } | ||||
| 
 | ||||
| static DWORD WINAPI | ||||
| ProcessStderr(_In_ HANDLE Stderr) | ||||
| { | ||||
|     enum | ||||
|     { | ||||
|         OnNone, | ||||
|         OnLevelStart, | ||||
|         OnLevel, | ||||
|         OnLevelEnd, | ||||
|         OnSpace, | ||||
|         OnMsg | ||||
|     } State = OnNone; | ||||
|     WCHAR Msg[0x200]; | ||||
|     DWORD Count = 0; | ||||
|     WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO; | ||||
|     for (;;) | ||||
|     { | ||||
|         WCHAR Buf[0x200]; | ||||
|         DWORD SizeRead; | ||||
|         if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL)) | ||||
|             return ERROR_SUCCESS; | ||||
|         if (SizeRead % sizeof(*Buf)) | ||||
|             return ERROR_INVALID_DATA; | ||||
|         SizeRead /= sizeof(*Buf); | ||||
|         for (DWORD i = 0; i < SizeRead; ++i) | ||||
|         { | ||||
|             WCHAR c = Buf[i]; | ||||
|             if (State == OnNone && c == L'[') | ||||
|                 State = OnLevelStart; | ||||
|             else if ( | ||||
|                 State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') || | ||||
|                                           (Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!'))) | ||||
|                 State = OnLevelEnd; | ||||
|             else if (State == OnLevelEnd && c == L']') | ||||
|                 State = OnSpace; | ||||
|             else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n') | ||||
|             { | ||||
|                 if (Count < _countof(Msg) - 1) | ||||
|                     Msg[Count++] = c; | ||||
|                 State = OnMsg; | ||||
|             } | ||||
|             else if (State == OnMsg && c == L'\n') | ||||
|             { | ||||
|                 Msg[Count] = 0; | ||||
|                 LoggerLog(Level, NULL, Msg); | ||||
|                 State = OnNone; | ||||
|                 Count = 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| ExecuteRunDll32( | ||||
|     _In_z_ LPCWSTR Function, | ||||
|     _In_z_ LPCWSTR Arguments, | ||||
|     _Out_z_cap_c_(ResponseCapacity) LPWSTR Response, | ||||
|     _In_ DWORD ResponseCapacity) | ||||
| { | ||||
|     WCHAR WindowsDirectory[MAX_PATH]; | ||||
|     if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory))) | ||||
|     { | ||||
|         LOG_LAST_ERROR(L"Failed to get Windows folder"); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR RunDll32Path[MAX_PATH]; | ||||
|     if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe")) | ||||
|     { | ||||
|         SetLastError(ERROR_BUFFER_OVERFLOW); | ||||
|         return FALSE; | ||||
|     } | ||||
| 
 | ||||
|     DWORD LastError; | ||||
|     WCHAR RandomTempSubDirectory[MAX_PATH]; | ||||
|     if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory)) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR DllPath[MAX_PATH] = { 0 }; | ||||
|     if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll")) | ||||
|     { | ||||
|         LastError = ERROR_BUFFER_OVERFLOW; | ||||
|         goto cleanupDirectory; | ||||
|     } | ||||
|     LPCWSTR WintunDllResourceName; | ||||
|     switch (NativeMachine) | ||||
|     { | ||||
|     case IMAGE_FILE_MACHINE_AMD64: | ||||
|         WintunDllResourceName = L"wintun-amd64.dll"; | ||||
|         break; | ||||
|     case IMAGE_FILE_MACHINE_ARM64: | ||||
|         WintunDllResourceName = L"wintun-arm64.dll"; | ||||
|         break; | ||||
|     default: | ||||
|         LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine); | ||||
|         LastError = ERROR_NOT_SUPPORTED; | ||||
|         goto cleanupDirectory; | ||||
|     } | ||||
|     if (!ResourceCopyToFile(DllPath, WintunDllResourceName)) | ||||
|     { | ||||
|         LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath); | ||||
|         goto cleanupDelete; | ||||
|     } | ||||
|     size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1 + wcslen(Function) + 1; | ||||
|     LPWSTR CommandLine = AllocArray(CommandLineLen, sizeof(*CommandLine)); | ||||
|     if (!CommandLine) | ||||
|     { | ||||
|         LastError = GetLastError(); | ||||
|         goto cleanupDelete; | ||||
|     } | ||||
|     if (_snwprintf_s( | ||||
|             CommandLine, | ||||
|             CommandLineLen, | ||||
|             _TRUNCATE, | ||||
|             L"rundll32 \"%.*s\",%s %s", | ||||
|             MAX_PATH, | ||||
|             DllPath, | ||||
|             Function, | ||||
|             Arguments) == -1) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupDelete; | ||||
|     } | ||||
|     HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE, | ||||
|            StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE; | ||||
|     if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) || | ||||
|         !CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0)) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to create pipes"); | ||||
|         goto cleanupPipes; | ||||
|     } | ||||
|     if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) || | ||||
|         !SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to set handle info"); | ||||
|         goto cleanupPipes; | ||||
|     } | ||||
|     if (ResponseCapacity) | ||||
|         Response[0] = 0; | ||||
|     PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout, | ||||
|                                                 .Response = Response, | ||||
|                                                 .ResponseCapacity = ResponseCapacity }; | ||||
|     HANDLE ThreadStdout = NULL, ThreadStderr = NULL; | ||||
|     if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL || | ||||
|         (ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to spawn readers"); | ||||
|         goto cleanupThreads; | ||||
|     } | ||||
|     STARTUPINFOW si = { .cb = sizeof(STARTUPINFO), | ||||
|                         .dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES, | ||||
|                         .wShowWindow = SW_HIDE, | ||||
|                         .hStdOutput = StreamWStdout, | ||||
|                         .hStdError = StreamWStderr }; | ||||
|     PROCESS_INFORMATION pi; | ||||
|     if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine); | ||||
|         goto cleanupThreads; | ||||
|     } | ||||
|     LastError = ERROR_SUCCESS; | ||||
|     WaitForSingleObject(pi.hProcess, INFINITE); | ||||
|     CloseHandle(pi.hProcess); | ||||
|     CloseHandle(pi.hThread); | ||||
| cleanupThreads: | ||||
|     if (ThreadStderr) | ||||
|     { | ||||
|         CloseHandle(StreamWStderr); | ||||
|         StreamWStderr = INVALID_HANDLE_VALUE; | ||||
|         WaitForSingleObject(ThreadStderr, INFINITE); | ||||
|         CloseHandle(ThreadStderr); | ||||
|     } | ||||
|     if (ThreadStdout) | ||||
|     { | ||||
|         CloseHandle(StreamWStdout); | ||||
|         StreamWStdout = INVALID_HANDLE_VALUE; | ||||
|         WaitForSingleObject(ThreadStdout, INFINITE); | ||||
|         DWORD ThreadResult; | ||||
|         if (!GetExitCodeThread(ThreadStdout, &ThreadResult)) | ||||
|             LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); | ||||
|         else if (ThreadResult != ERROR_SUCCESS) | ||||
|             LOG_ERROR(LastError, L"Failed to read process output"); | ||||
|         CloseHandle(ThreadStdout); | ||||
|     } | ||||
| cleanupPipes: | ||||
|     CloseHandle(StreamRStderr); | ||||
|     CloseHandle(StreamWStderr); | ||||
|     CloseHandle(StreamRStdout); | ||||
|     CloseHandle(StreamWStdout); | ||||
|     Free(CommandLine); | ||||
| cleanupDelete: | ||||
|     DeleteFileW(DllPath); | ||||
| cleanupDirectory: | ||||
|     RemoveDirectoryW(RandomTempSubDirectory); | ||||
|     return RET_ERROR(TRUE, LastError); | ||||
| } | ||||
| 
 | ||||
| _Use_decl_annotations_ | ||||
| WINTUN_ADAPTER * | ||||
| CreateAdapterViaRundll32(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired) | ||||
| { | ||||
|     LOG(WINTUN_LOG_INFO, L"Spawning native process"); | ||||
|     LPWSTR Arguments = NULL; | ||||
|     if (RequestedGUID) | ||||
|     { | ||||
|         WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; | ||||
|         if (StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr))) | ||||
|             Arguments = ArgvToCommandLineW(3, Pool, Name, RequestedGUIDStr); | ||||
|     } | ||||
|     else | ||||
|         Arguments = ArgvToCommandLineW(2, Pool, Name); | ||||
|     if (!Arguments) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         SetLastError(ERROR_INVALID_PARAMETER); | ||||
|         return NULL; | ||||
|     } | ||||
|     WINTUN_ADAPTER *Adapter = NULL; | ||||
|     DWORD LastError; | ||||
|     WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1]; | ||||
|     if (!ExecuteRunDll32(L"CreateAdapter", Arguments, Response, _countof(Response))) | ||||
|     { | ||||
|         LastError = GetLastError(); | ||||
|         LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); | ||||
|         goto cleanupArguments; | ||||
|     } | ||||
|     int Argc; | ||||
|     LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); | ||||
|     if (Argc < 3) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupArgv; | ||||
|     } | ||||
|     LastError = wcstoul(Argv[0], NULL, 16); | ||||
|     if (LastError == ERROR_SUCCESS && (Adapter = AdapterOpenFromDevInstanceId(Pool, Argv[1])) == NULL) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]); | ||||
|         LastError = ERROR_FILE_NOT_FOUND; | ||||
|     } | ||||
|     if (wcstoul(Argv[2], NULL, 16)) | ||||
|         *RebootRequired = TRUE; | ||||
| cleanupArgv: | ||||
|     LocalFree(Argv); | ||||
| cleanupArguments: | ||||
|     Free(Arguments); | ||||
|     SetLastError(LastError); | ||||
|     return Adapter; | ||||
| } | ||||
| 
 | ||||
| _Use_decl_annotations_ | ||||
| BOOL | ||||
| DeleteAdapterViaRundll32(const WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired) | ||||
| { | ||||
|     LOG(WINTUN_LOG_INFO, L"Spawning native process"); | ||||
|     LPWSTR Arguments = ArgvToCommandLineW(3, Adapter->Pool, Adapter->DevInstanceID, ForceCloseSessions ? L"1" : L"0"); | ||||
|     if (!Arguments) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         SetLastError(ERROR_INVALID_PARAMETER); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR Response[8 + 1 + 8 + 1]; | ||||
|     DWORD LastError; | ||||
|     if (!ExecuteRunDll32(L"DeleteAdapter", Arguments, Response, _countof(Response))) | ||||
|     { | ||||
|         LastError = GetLastError(); | ||||
|         LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); | ||||
|         goto cleanupArguments; | ||||
|     } | ||||
|     int Argc; | ||||
|     LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); | ||||
|     if (Argc < 2) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupArgv; | ||||
|     } | ||||
|     LastError = wcstoul(Argv[0], NULL, 16); | ||||
|     if (wcstoul(Argv[1], NULL, 16)) | ||||
|         *RebootRequired = TRUE; | ||||
| cleanupArgv: | ||||
|     LocalFree(Argv); | ||||
| cleanupArguments: | ||||
|     Free(Arguments); | ||||
|     return RET_ERROR(TRUE, LastError); | ||||
| } | ||||
| 
 | ||||
| _Use_decl_annotations_ | ||||
| BOOL | ||||
| DeletePoolDriverViaRundll32(LPCWSTR Pool, BOOL *RebootRequired) | ||||
| { | ||||
|     LOG(WINTUN_LOG_INFO, L"Spawning native process"); | ||||
|     LPWSTR Arguments = ArgvToCommandLineW(1, Pool); | ||||
|     if (!Arguments) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         SetLastError(ERROR_INVALID_PARAMETER); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR Response[8 + 1 + 8 + 1]; | ||||
|     DWORD LastError; | ||||
|     if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response))) | ||||
|     { | ||||
|         LastError = GetLastError(); | ||||
|         LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); | ||||
|         goto cleanupArguments; | ||||
|     } | ||||
|     int Argc; | ||||
|     LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); | ||||
|     if (Argc < 2) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupArgv; | ||||
|     } | ||||
|     LastError = wcstoul(Argv[0], NULL, 16); | ||||
|     if (wcstoul(Argv[1], NULL, 16)) | ||||
|         *RebootRequired = TRUE; | ||||
| cleanupArgv: | ||||
|     LocalFree(Argv); | ||||
| cleanupArguments: | ||||
|     Free(Arguments); | ||||
|     return RET_ERROR(TRUE, LastError); | ||||
| } | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										29
									
								
								api/rundll32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								api/rundll32.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0
 | ||||
|  * | ||||
|  * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "adapter.h" | ||||
| 
 | ||||
| _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| WINTUN_ADAPTER * | ||||
| CreateAdapterViaRundll32( | ||||
|     _In_z_ LPCWSTR Pool, | ||||
|     _In_z_ LPCWSTR Name, | ||||
|     _In_opt_ const GUID *RequestedGUID, | ||||
|     _Inout_ BOOL *RebootRequired); | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| DeleteAdapterViaRundll32( | ||||
|     _In_ const WINTUN_ADAPTER *Adapter, | ||||
|     _In_ BOOL ForceCloseSessions, | ||||
|     _Inout_ BOOL *RebootRequired); | ||||
| 
 | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL | ||||
| DeletePoolDriverViaRundll32(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired); | ||||
							
								
								
									
										352
									
								
								api/rundll32_i.c
									
									
									
									
									
								
							
							
						
						
									
										352
									
								
								api/rundll32_i.c
									
									
									
									
									
								
							| @ -1,352 +0,0 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0
 | ||||
|  * | ||||
|  * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. | ||||
|  */ | ||||
| 
 | ||||
| /* TODO: This is currently #include'd in adapter.c. Move into rundll32.c properly. */ | ||||
| 
 | ||||
| typedef struct _PROCESS_STDOUT_STATE | ||||
| { | ||||
|     HANDLE Stdout; | ||||
|     WCHAR *Response; | ||||
|     DWORD ResponseCapacity; | ||||
| } PROCESS_STDOUT_STATE; | ||||
| 
 | ||||
| static DWORD WINAPI | ||||
| ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State) | ||||
| { | ||||
|     for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;) | ||||
|     { | ||||
|         DWORD SizeRead; | ||||
|         if (!ReadFile(State->Stdout, State->Response + Offset, sizeof(WCHAR) * (MaxLen - Offset), &SizeRead, NULL)) | ||||
|             return ERROR_SUCCESS; | ||||
|         if (SizeRead % sizeof(WCHAR)) | ||||
|             return ERROR_INVALID_DATA; | ||||
|         Offset += SizeRead / sizeof(WCHAR); | ||||
|         State->Response[Offset] = 0; | ||||
|     } | ||||
|     return ERROR_BUFFER_OVERFLOW; | ||||
| } | ||||
| 
 | ||||
| static DWORD WINAPI | ||||
| ProcessStderr(_In_ HANDLE Stderr) | ||||
| { | ||||
|     enum | ||||
|     { | ||||
|         OnNone, | ||||
|         OnLevelStart, | ||||
|         OnLevel, | ||||
|         OnLevelEnd, | ||||
|         OnSpace, | ||||
|         OnMsg | ||||
|     } State = OnNone; | ||||
|     WCHAR Msg[0x200]; | ||||
|     DWORD Count = 0; | ||||
|     WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO; | ||||
|     for (;;) | ||||
|     { | ||||
|         WCHAR Buf[0x200]; | ||||
|         DWORD SizeRead; | ||||
|         if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL)) | ||||
|             return ERROR_SUCCESS; | ||||
|         if (SizeRead % sizeof(WCHAR)) | ||||
|             return ERROR_INVALID_DATA; | ||||
|         SizeRead /= sizeof(WCHAR); | ||||
|         for (DWORD i = 0; i < SizeRead; ++i) | ||||
|         { | ||||
|             WCHAR c = Buf[i]; | ||||
|             if (State == OnNone && c == L'[') | ||||
|                 State = OnLevelStart; | ||||
|             else if ( | ||||
|                 State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') || | ||||
|                                           (Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!'))) | ||||
|                 State = OnLevelEnd; | ||||
|             else if (State == OnLevelEnd && c == L']') | ||||
|                 State = OnSpace; | ||||
|             else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n') | ||||
|             { | ||||
|                 if (Count < _countof(Msg) - 1) | ||||
|                     Msg[Count++] = c; | ||||
|                 State = OnMsg; | ||||
|             } | ||||
|             else if (State == OnMsg && c == L'\n') | ||||
|             { | ||||
|                 Msg[Count] = 0; | ||||
|                 LoggerLog(Level, NULL, Msg); | ||||
|                 State = OnNone; | ||||
|                 Count = 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static _Return_type_success_(return != FALSE) BOOL ExecuteRunDll32( | ||||
|     _In_z_ const WCHAR *Arguments, | ||||
|     _Out_z_cap_c_(ResponseCapacity) WCHAR *Response, | ||||
|     _In_ DWORD ResponseCapacity) | ||||
| { | ||||
|     WCHAR WindowsDirectory[MAX_PATH]; | ||||
|     if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory))) | ||||
|     { | ||||
|         LOG_LAST_ERROR(L"Failed to get Windows folder"); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR RunDll32Path[MAX_PATH]; | ||||
|     if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe")) | ||||
|     { | ||||
|         SetLastError(ERROR_BUFFER_OVERFLOW); | ||||
|         return FALSE; | ||||
|     } | ||||
| 
 | ||||
|     DWORD LastError; | ||||
|     WCHAR RandomTempSubDirectory[MAX_PATH]; | ||||
|     if (!CreateTemporaryDirectory(RandomTempSubDirectory)) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder %s", RandomTempSubDirectory); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR DllPath[MAX_PATH] = { 0 }; | ||||
|     if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll")) | ||||
|     { | ||||
|         LastError = ERROR_BUFFER_OVERFLOW; | ||||
|         goto cleanupDirectory; | ||||
|     } | ||||
|     const WCHAR *WintunDllResourceName; | ||||
|     switch (NativeMachine) | ||||
|     { | ||||
|     case IMAGE_FILE_MACHINE_AMD64: | ||||
|         WintunDllResourceName = L"wintun-amd64.dll"; | ||||
|         break; | ||||
|     case IMAGE_FILE_MACHINE_ARM64: | ||||
|         WintunDllResourceName = L"wintun-arm64.dll"; | ||||
|         break; | ||||
|     default: | ||||
|         LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine); | ||||
|         LastError = ERROR_NOT_SUPPORTED; | ||||
|         goto cleanupDirectory; | ||||
|     } | ||||
|     if (!ResourceCopyToFile(DllPath, WintunDllResourceName)) | ||||
|     { | ||||
|         LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath); | ||||
|         goto cleanupDelete; | ||||
|     } | ||||
|     size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1; | ||||
|     WCHAR *CommandLine = Alloc(CommandLineLen * sizeof(WCHAR)); | ||||
|     if (!CommandLine) | ||||
|     { | ||||
|         LastError = GetLastError(); | ||||
|         goto cleanupDelete; | ||||
|     } | ||||
|     if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) == | ||||
|         -1) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupDelete; | ||||
|     } | ||||
|     HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE, | ||||
|            StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE; | ||||
|     if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) || | ||||
|         !CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0)) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to create pipes"); | ||||
|         goto cleanupPipes; | ||||
|     } | ||||
|     if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) || | ||||
|         !SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to set handle info"); | ||||
|         goto cleanupPipes; | ||||
|     } | ||||
|     if (ResponseCapacity) | ||||
|         Response[0] = 0; | ||||
|     PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout, | ||||
|                                                 .Response = Response, | ||||
|                                                 .ResponseCapacity = ResponseCapacity }; | ||||
|     HANDLE ThreadStdout = NULL, ThreadStderr = NULL; | ||||
|     if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL || | ||||
|         (ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to spawn readers"); | ||||
|         goto cleanupThreads; | ||||
|     } | ||||
|     STARTUPINFOW si = { .cb = sizeof(STARTUPINFO), | ||||
|                         .dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES, | ||||
|                         .wShowWindow = SW_HIDE, | ||||
|                         .hStdOutput = StreamWStdout, | ||||
|                         .hStdError = StreamWStderr }; | ||||
|     PROCESS_INFORMATION pi; | ||||
|     if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) | ||||
|     { | ||||
|         LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine); | ||||
|         goto cleanupThreads; | ||||
|     } | ||||
|     LastError = ERROR_SUCCESS; | ||||
|     WaitForSingleObject(pi.hProcess, INFINITE); | ||||
|     CloseHandle(pi.hProcess); | ||||
|     CloseHandle(pi.hThread); | ||||
| cleanupThreads: | ||||
|     if (ThreadStderr) | ||||
|     { | ||||
|         CloseHandle(StreamWStderr); | ||||
|         StreamWStderr = INVALID_HANDLE_VALUE; | ||||
|         WaitForSingleObject(ThreadStderr, INFINITE); | ||||
|         CloseHandle(ThreadStderr); | ||||
|     } | ||||
|     if (ThreadStdout) | ||||
|     { | ||||
|         CloseHandle(StreamWStdout); | ||||
|         StreamWStdout = INVALID_HANDLE_VALUE; | ||||
|         WaitForSingleObject(ThreadStdout, INFINITE); | ||||
|         DWORD ThreadResult; | ||||
|         if (!GetExitCodeThread(ThreadStdout, &ThreadResult)) | ||||
|             LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); | ||||
|         else if (ThreadResult != ERROR_SUCCESS) | ||||
|             LOG_ERROR(LastError, L"Failed to read process output"); | ||||
|         CloseHandle(ThreadStdout); | ||||
|     } | ||||
| cleanupPipes: | ||||
|     CloseHandle(StreamRStderr); | ||||
|     CloseHandle(StreamWStderr); | ||||
|     CloseHandle(StreamRStdout); | ||||
|     CloseHandle(StreamWStdout); | ||||
|     Free(CommandLine); | ||||
| cleanupDelete: | ||||
|     DeleteFileW(DllPath); | ||||
| cleanupDirectory: | ||||
|     RemoveDirectoryW(RandomTempSubDirectory); | ||||
|     return RET_ERROR(TRUE, LastError); | ||||
| } | ||||
| 
 | ||||
| static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapterViaRundll32( | ||||
|     _In_z_ const WCHAR *Pool, | ||||
|     _In_z_ const WCHAR *Name, | ||||
|     _In_opt_ const GUID *RequestedGUID, | ||||
|     _Inout_ BOOL *RebootRequired) | ||||
| { | ||||
|     LOG(WINTUN_LOG_INFO, L"Spawning native process"); | ||||
|     WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; | ||||
|     WCHAR Arguments[15 + WINTUN_MAX_POOL + 3 + MAX_ADAPTER_NAME + 2 + MAX_GUID_STRING_LEN + 1]; | ||||
|     if (_snwprintf_s( | ||||
|             Arguments, | ||||
|             _countof(Arguments), | ||||
|             _TRUNCATE, | ||||
|             RequestedGUID ? L"CreateAdapter \"%s\" \"%s\" %.*s" : L"CreateAdapter \"%s\" \"%s\"", | ||||
|             Pool, | ||||
|             Name, | ||||
|             RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0, | ||||
|             RequestedGUIDStr) == -1) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         SetLastError(ERROR_INVALID_PARAMETER); | ||||
|         return NULL; | ||||
|     } | ||||
|     WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1]; | ||||
|     if (!ExecuteRunDll32(Arguments, Response, _countof(Response))) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); | ||||
|         return NULL; | ||||
|     } | ||||
|     DWORD LastError; | ||||
|     WINTUN_ADAPTER *Adapter = NULL; | ||||
|     int Argc; | ||||
|     WCHAR **Argv = CommandLineToArgvW(Response, &Argc); | ||||
|     GUID CfgInstanceID; | ||||
|     if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID))) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupArgv; | ||||
|     } | ||||
|     LastError = wcstoul(Argv[0], NULL, 16); | ||||
|     if (LastError == ERROR_SUCCESS && (Adapter = GetAdapter(Pool, &CfgInstanceID)) == NULL) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]); | ||||
|         LastError = ERROR_FILE_NOT_FOUND; | ||||
|     } | ||||
|     if (wcstoul(Argv[2], NULL, 16)) | ||||
|         *RebootRequired = TRUE; | ||||
| cleanupArgv: | ||||
|     LocalFree(Argv); | ||||
|     SetLastError(LastError); | ||||
|     return Adapter; | ||||
| } | ||||
| 
 | ||||
| static _Return_type_success_(return != FALSE) BOOL DeleteAdapterViaRundll32( | ||||
|     _In_ const WINTUN_ADAPTER *Adapter, | ||||
|     _In_ BOOL ForceCloseSessions, | ||||
|     _Inout_ BOOL *RebootRequired) | ||||
| { | ||||
|     LOG(WINTUN_LOG_INFO, L"Spawning native process"); | ||||
|     WCHAR GuidStr[MAX_GUID_STRING_LEN]; | ||||
|     WCHAR Arguments[16 + MAX_GUID_STRING_LEN + 1]; | ||||
|     if (_snwprintf_s( | ||||
|             Arguments, | ||||
|             _countof(Arguments), | ||||
|             _TRUNCATE, | ||||
|             L"DeleteAdapter %d %.*s", | ||||
|             ForceCloseSessions ? 1 : 0, | ||||
|             StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)), | ||||
|             GuidStr) == -1) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         SetLastError(ERROR_INVALID_PARAMETER); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR Response[8 + 1 + 8 + 1]; | ||||
|     DWORD LastError; | ||||
|     if (!ExecuteRunDll32(Arguments, Response, _countof(Response))) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); | ||||
|         return FALSE; | ||||
|     } | ||||
|     int Argc; | ||||
|     WCHAR **Argv = CommandLineToArgvW(Response, &Argc); | ||||
|     if (Argc < 2) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupArgv; | ||||
|     } | ||||
|     LastError = wcstoul(Argv[0], NULL, 16); | ||||
|     if (wcstoul(Argv[1], NULL, 16)) | ||||
|         *RebootRequired = TRUE; | ||||
| cleanupArgv: | ||||
|     LocalFree(Argv); | ||||
|     return RET_ERROR(TRUE, LastError); | ||||
| } | ||||
| 
 | ||||
| static _Return_type_success_(return != FALSE) BOOL | ||||
|     DeletePoolDriverViaRundll32(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired) | ||||
| { | ||||
|     LOG(WINTUN_LOG_INFO, L"Spawning native process"); | ||||
| 
 | ||||
|     WCHAR Arguments[17 + WINTUN_MAX_POOL + 1]; | ||||
|     if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Command line too long"); | ||||
|         SetLastError(ERROR_INVALID_PARAMETER); | ||||
|         return FALSE; | ||||
|     } | ||||
|     WCHAR Response[8 + 1 + 8 + 1]; | ||||
|     DWORD LastError; | ||||
|     if (!ExecuteRunDll32(Arguments, Response, _countof(Response))) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); | ||||
|         return FALSE; | ||||
|     } | ||||
|     int Argc; | ||||
|     WCHAR **Argv = CommandLineToArgvW(Response, &Argc); | ||||
|     if (Argc < 2) | ||||
|     { | ||||
|         LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response); | ||||
|         LastError = ERROR_INVALID_PARAMETER; | ||||
|         goto cleanupArgv; | ||||
|     } | ||||
|     LastError = wcstoul(Argv[0], NULL, 16); | ||||
|     if (wcstoul(Argv[1], NULL, 16)) | ||||
|         *RebootRequired = TRUE; | ||||
| cleanupArgv: | ||||
|     LocalFree(Argv); | ||||
|     return RET_ERROR(TRUE, LastError); | ||||
| } | ||||
| @ -70,8 +70,10 @@ typedef struct _TUN_SESSION | ||||
|     HANDLE Handle; | ||||
| } TUN_SESSION; | ||||
| 
 | ||||
| _Return_type_success_(return != NULL) TUN_SESSION *WINAPI | ||||
|     WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity) | ||||
| WINTUN_START_SESSION_FUNC_IMPL WintunStartSession; | ||||
| _Use_decl_annotations_ | ||||
| TUN_SESSION *WINAPI | ||||
| WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity) | ||||
| { | ||||
|     DWORD LastError; | ||||
|     TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION)); | ||||
| @ -126,8 +128,8 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI | ||||
|         goto cleanupHandle; | ||||
|     } | ||||
|     Session->Capacity = Capacity; | ||||
|     (void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT); | ||||
|     (void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT); | ||||
|     (VOID) InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT); | ||||
|     (VOID) InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT); | ||||
|     return Session; | ||||
| cleanupHandle: | ||||
|     CloseHandle(Session->Handle); | ||||
| @ -144,8 +146,10 @@ cleanup: | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| void WINAPI | ||||
| WintunEndSession(_In_ TUN_SESSION *Session) | ||||
| WINTUN_END_SESSION_FUNC_IMPL WintunEndSession; | ||||
| _Use_decl_annotations_ | ||||
| VOID WINAPI | ||||
| WintunEndSession(TUN_SESSION *Session) | ||||
| { | ||||
|     DeleteCriticalSection(&Session->Send.Lock); | ||||
|     DeleteCriticalSection(&Session->Receive.Lock); | ||||
| @ -156,14 +160,18 @@ WintunEndSession(_In_ TUN_SESSION *Session) | ||||
|     Free(Session); | ||||
| } | ||||
| 
 | ||||
| WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL WintunGetReadWaitEvent; | ||||
| _Use_decl_annotations_ | ||||
| HANDLE WINAPI | ||||
| WintunGetReadWaitEvent(_In_ TUN_SESSION *Session) | ||||
| WintunGetReadWaitEvent(TUN_SESSION *Session) | ||||
| { | ||||
|     return Session->Descriptor.Send.TailMoved; | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI | ||||
|     WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize) | ||||
| WINTUN_RECEIVE_PACKET_FUNC_IMPL WintunReceivePacket; | ||||
| _Use_decl_annotations_ | ||||
| BYTE *WINAPI | ||||
| WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize) | ||||
| { | ||||
|     DWORD LastError; | ||||
|     EnterCriticalSection(&Session->Send.Lock); | ||||
| @ -213,8 +221,10 @@ cleanup: | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| void WINAPI | ||||
| WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) | ||||
| WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL WintunReleaseReceivePacket; | ||||
| _Use_decl_annotations_ | ||||
| VOID WINAPI | ||||
| WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet) | ||||
| { | ||||
|     EnterCriticalSection(&Session->Send.Lock); | ||||
|     TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data)); | ||||
| @ -232,8 +242,10 @@ WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) | ||||
|     LeaveCriticalSection(&Session->Send.Lock); | ||||
| } | ||||
| 
 | ||||
| _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI | ||||
|     WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize) | ||||
| WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL WintunAllocateSendPacket; | ||||
| _Use_decl_annotations_ | ||||
| BYTE *WINAPI | ||||
| WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize) | ||||
| { | ||||
|     DWORD LastError; | ||||
|     EnterCriticalSection(&Session->Receive.Lock); | ||||
| @ -268,8 +280,10 @@ cleanup: | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| void WINAPI | ||||
| WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) | ||||
| WINTUN_SEND_PACKET_FUNC_IMPL WintunSendPacket; | ||||
| _Use_decl_annotations_ | ||||
| VOID WINAPI | ||||
| WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet) | ||||
| { | ||||
|     EnterCriticalSection(&Session->Receive.Lock); | ||||
|     TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data)); | ||||
| @ -285,7 +299,8 @@ WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet) | ||||
|             TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity); | ||||
|         Session->Receive.PacketsToRelease--; | ||||
|     } | ||||
|     if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease) { | ||||
|     if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease) | ||||
|     { | ||||
|         WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease); | ||||
|         if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable)) | ||||
|             SetEvent(Session->Descriptor.Receive.TailMoved); | ||||
|  | ||||
							
								
								
									
										110
									
								
								api/wintun.h
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								api/wintun.h
									
									
									
									
									
								
							| @ -16,7 +16,7 @@ extern "C" { | ||||
| /**
 | ||||
|  * A handle representing Wintun adapter | ||||
|  */ | ||||
| typedef void *WINTUN_ADAPTER_HANDLE; | ||||
| typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE; | ||||
| 
 | ||||
| /**
 | ||||
|  * Maximum pool name length including zero terminator | ||||
| @ -39,13 +39,14 @@ typedef void *WINTUN_ADAPTER_HANDLE; | ||||
|  * @param RebootRequired  Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. | ||||
|  * | ||||
|  * @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. If | ||||
|  *         the function fails, the return value is NULL. To get extended error information, call GetLastError. | ||||
|  * the function fails, the return value is NULL. To get extended error information, call GetLastError. | ||||
|  */ | ||||
| typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)( | ||||
|     _In_z_ const WCHAR *Pool, | ||||
|     _In_z_ const WCHAR *Name, | ||||
|     _In_opt_ const GUID *RequestedGUID, | ||||
|     _Out_opt_ BOOL *RebootRequired); | ||||
| typedef _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC_IMPL) | ||||
| (_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name, _In_opt_ const GUID *RequestedGUID, _Out_opt_ BOOL *RebootRequired); | ||||
| typedef WINTUN_CREATE_ADAPTER_FUNC_IMPL *WINTUN_CREATE_ADAPTER_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Opens an existing Wintun adapter. | ||||
| @ -55,14 +56,15 @@ typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINT | ||||
|  * @param Name          Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters. | ||||
|  * | ||||
|  * @return If the function succeeds, the return value is adapter handle. Must be released with WintunFreeAdapter. If the | ||||
|  *         function fails, the return value is NULL. To get extended error information, call GetLastError. Possible | ||||
|  *         errors include the following: | ||||
|  *         ERROR_FILE_NOT_FOUND if adapter with given name is not found; | ||||
|  *         ERROR_ALREADY_EXISTS if adapter is found but not a Wintun-class or not a member of the pool | ||||
|  * function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors | ||||
|  * include the following: ERROR_FILE_NOT_FOUND if adapter with given name is not found; ERROR_ALREADY_EXISTS if adapter | ||||
|  * is found but not a Wintun-class or not a member of the pool | ||||
|  */ | ||||
| typedef _Return_type_success_(return != NULL) | ||||
|     WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name); | ||||
| 
 | ||||
| typedef _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name); | ||||
| typedef WINTUN_OPEN_ADAPTER_FUNC_IMPL *WINTUN_OPEN_ADAPTER_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Deletes a Wintun adapter. | ||||
| @ -78,10 +80,10 @@ typedef _Return_type_success_(return != NULL) | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)( | ||||
|     _In_ WINTUN_ADAPTER_HANDLE Adapter, | ||||
|     _In_ BOOL ForceCloseSessions, | ||||
|     _Out_opt_ BOOL *RebootRequired); | ||||
| typedef _Return_type_success_(return != FALSE) | ||||
| BOOL(WINAPI WINTUN_DELETE_ADAPTER_FUNC_IMPL) | ||||
| (_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired); | ||||
| typedef WINTUN_DELETE_ADAPTER_FUNC_IMPL *WINTUN_DELETE_ADAPTER_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Called by WintunEnumAdapters for each adapter in the pool. | ||||
| @ -107,15 +109,17 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK)(_In_ WINTUN_ADAPTER_HANDLE Adapter, | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| typedef _Return_type_success_(return != FALSE) BOOL( | ||||
|     WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param); | ||||
| typedef _Return_type_success_(return != FALSE) | ||||
| BOOL(WINAPI WINTUN_ENUM_ADAPTERS_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param); | ||||
| typedef WINTUN_ENUM_ADAPTERS_FUNC_IMPL *WINTUN_ENUM_ADAPTERS_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Releases Wintun adapter resources. | ||||
|  * | ||||
|  * @param Adapter       Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter. | ||||
|  */ | ||||
| typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter); | ||||
| typedef VOID(WINAPI WINTUN_FREE_ADAPTER_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter); | ||||
| typedef WINTUN_FREE_ADAPTER_FUNC_IMPL *WINTUN_FREE_ADAPTER_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun | ||||
| @ -129,7 +133,8 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| typedef _Return_type_success_(return != FALSE) | ||||
|     BOOL(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired); | ||||
| BOOL(WINAPI WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _Out_opt_ BOOL *RebootRequired); | ||||
| typedef WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL *WINTUN_DELETE_POOL_DRIVER_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Returns the LUID of the adapter. | ||||
| @ -138,7 +143,8 @@ typedef _Return_type_success_(return != FALSE) | ||||
|  * | ||||
|  * @param Luid          Pointer to LUID to receive adapter LUID. | ||||
|  */ | ||||
| typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid); | ||||
| typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid); | ||||
| typedef WINTUN_GET_ADAPTER_LUID_FUNC_IMPL *WINTUN_GET_ADAPTER_LUID_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Returns the name of the Wintun adapter. | ||||
| @ -150,9 +156,11 @@ typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ad | ||||
|  * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)( | ||||
|     _In_ WINTUN_ADAPTER_HANDLE Adapter, | ||||
|     _Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name); | ||||
| typedef _Must_inspect_result_ | ||||
| _Return_type_success_(return != FALSE) | ||||
| BOOL(WINAPI WINTUN_GET_ADAPTER_NAME_FUNC_IMPL) | ||||
| (_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_writes_z_(MAX_ADAPTER_NAME) LPWSTR Name); | ||||
| typedef WINTUN_GET_ADAPTER_NAME_FUNC_IMPL *WINTUN_GET_ADAPTER_NAME_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Sets name of the Wintun adapter. | ||||
| @ -165,7 +173,8 @@ typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_N | ||||
|  *         get extended error information, call GetLastError. | ||||
|  */ | ||||
| typedef _Return_type_success_(return != FALSE) | ||||
|     BOOL(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name); | ||||
| BOOL(WINAPI WINTUN_SET_ADAPTER_NAME_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ LPCWSTR Name); | ||||
| typedef WINTUN_SET_ADAPTER_NAME_FUNC_IMPL *WINTUN_SET_ADAPTER_NAME_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Determines the version of the Wintun driver currently loaded. | ||||
| @ -174,7 +183,9 @@ typedef _Return_type_success_(return != FALSE) | ||||
|  *         zero. To get extended error information, call GetLastError. Possible errors include the following: | ||||
|  *         ERROR_FILE_NOT_FOUND  Wintun not loaded | ||||
|  */ | ||||
| typedef DWORD(WINAPI *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(void); | ||||
| typedef _Return_type_success_(return != 0) | ||||
| DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL)(VOID); | ||||
| typedef WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK. | ||||
| @ -193,7 +204,7 @@ typedef enum | ||||
|  * | ||||
|  * @param Message       Message text. | ||||
|  */ | ||||
| typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Message); | ||||
| typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Message); | ||||
| 
 | ||||
| /**
 | ||||
|  * Sets logger callback function. | ||||
| @ -202,7 +213,8 @@ typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _ | ||||
|  *                      threads concurrently. Should the logging require serialization, you must handle serialization in | ||||
|  *                      NewLogger. Set to NULL to disable. | ||||
|  */ | ||||
| typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger); | ||||
| typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC_IMPL)(_In_ WINTUN_LOGGER_CALLBACK NewLogger); | ||||
| typedef WINTUN_SET_LOGGER_FUNC_IMPL *WINTUN_SET_LOGGER_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Minimum ring capacity. | ||||
| @ -217,7 +229,7 @@ typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogg | ||||
| /**
 | ||||
|  * A handle representing Wintun session | ||||
|  */ | ||||
| typedef void *WINTUN_SESSION_HANDLE; | ||||
| typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE; | ||||
| 
 | ||||
| /**
 | ||||
|  * Starts Wintun session. | ||||
| @ -230,15 +242,19 @@ typedef void *WINTUN_SESSION_HANDLE; | ||||
|  * @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is | ||||
|  *         NULL. To get extended error information, call GetLastError. | ||||
|  */ | ||||
| typedef _Return_type_success_(return != NULL) | ||||
|     WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); | ||||
| typedef _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity); | ||||
| typedef WINTUN_START_SESSION_FUNC_IMPL *WINTUN_START_SESSION_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Ends Wintun session. | ||||
|  * | ||||
|  * @param Session       Wintun session handle obtained with WintunStartSession | ||||
|  */ | ||||
| typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session); | ||||
| typedef VOID(WINAPI WINTUN_END_SESSION_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session); | ||||
| typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets Wintun session's read-wait event handle. | ||||
| @ -250,7 +266,8 @@ typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session | ||||
|  *         load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call | ||||
|  *         CloseHandle on this event - it is managed by the session. | ||||
|  */ | ||||
| typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session); | ||||
| typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session); | ||||
| typedef WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL *WINTUN_GET_READ_WAIT_EVENT_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Maximum IP packet size | ||||
| @ -272,8 +289,12 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND | ||||
|  *         ERROR_NO_MORE_ITEMS  Wintun buffer is exhausted; | ||||
|  *         ERROR_INVALID_DATA   Wintun buffer is corrupt | ||||
|  */ | ||||
| typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *( | ||||
|     WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize); | ||||
| typedef _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_writable_byte_size_(*PacketSize) | ||||
| BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize); | ||||
| typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Releases internal buffer after the received packet has been processed by the client. This function is thread-safe. | ||||
| @ -282,7 +303,9 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE | ||||
|  * | ||||
|  * @param Packet        Packet obtained with WintunReceivePacket | ||||
|  */ | ||||
| typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); | ||||
| typedef VOID( | ||||
|     WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); | ||||
| typedef WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RELEASE_RECEIVE_PACKET_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send | ||||
| @ -299,8 +322,12 @@ typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HAN | ||||
|  *         ERROR_HANDLE_EOF       Wintun adapter is terminating; | ||||
|  *         ERROR_BUFFER_OVERFLOW  Wintun buffer is full; | ||||
|  */ | ||||
| typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *( | ||||
|     WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize); | ||||
| typedef _Must_inspect_result_ | ||||
| _Return_type_success_(return != NULL) | ||||
| _Post_maybenull_ | ||||
| _Post_writable_byte_size_(PacketSize) | ||||
| BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize); | ||||
| typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC; | ||||
| 
 | ||||
| /**
 | ||||
|  * Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket | ||||
| @ -311,7 +338,8 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE * | ||||
|  * | ||||
|  * @param Packet        Packet obtained with WintunAllocateSendPacket | ||||
|  */ | ||||
| typedef void(WINAPI *WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); | ||||
| typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet); | ||||
| typedef WINTUN_SEND_PACKET_FUNC_IMPL *WINTUN_SEND_PACKET_FUNC; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user