api: use GetLastError() to report failures like standard Win32
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
5ad7d10589
commit
f657e6fd27
1197
api/adapter.c
1197
api/adapter.c
File diff suppressed because it is too large
Load Diff
@ -37,28 +37,28 @@ WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
|
|||||||
/**
|
/**
|
||||||
* @copydoc WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC
|
* @copydoc WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS WINAPI
|
_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI
|
||||||
WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle);
|
WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @copydoc WINTUN_CREATE_ADAPTER_FUNC
|
* @copydoc WINTUN_CREATE_ADAPTER_FUNC
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS WINAPI
|
_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI WintunCreateAdapter(
|
||||||
WintunCreateAdapter(
|
|
||||||
_In_z_ const WCHAR *Pool,
|
_In_z_ const WCHAR *Pool,
|
||||||
_In_z_ const WCHAR *Name,
|
_In_z_ const WCHAR *Name,
|
||||||
_In_opt_ const GUID *RequestedGUID,
|
_In_opt_ const GUID *RequestedGUID,
|
||||||
_Out_ WINTUN_ADAPTER **Adapter,
|
|
||||||
_Out_opt_ BOOL *RebootRequired);
|
_Out_opt_ BOOL *RebootRequired);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @copydoc WINTUN_DELETE_ADAPTER_FUNC
|
* @copydoc WINTUN_DELETE_ADAPTER_FUNC
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS WINAPI
|
_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter(
|
||||||
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired);
|
_In_ const WINTUN_ADAPTER *Adapter,
|
||||||
|
_In_ BOOL ForceCloseSessions,
|
||||||
|
_Out_opt_ BOOL *RebootRequired);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
|
* @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS WINAPI
|
_Return_type_success_(return != FALSE) BOOL WINAPI
|
||||||
WintunDeletePoolDriver(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired);
|
WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "elevate.h"
|
#include "elevate.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
|
|
||||||
BOOL
|
_Return_type_success_(return != FALSE) BOOL ElevateToSystem(void)
|
||||||
ElevateToSystem(void)
|
|
||||||
{
|
{
|
||||||
HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken;
|
HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken;
|
||||||
PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) };
|
PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) };
|
||||||
@ -25,29 +25,40 @@ ElevateToSystem(void)
|
|||||||
} TokenUserBuffer;
|
} TokenUserBuffer;
|
||||||
|
|
||||||
Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
|
Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to create SID");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken);
|
Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to open process token");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
Ret =
|
Ret =
|
||||||
GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
|
GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
|
||||||
LastError = GetLastError();
|
LastError = GetLastError();
|
||||||
CloseHandle(CurrentProcessToken);
|
CloseHandle(CurrentProcessToken);
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LOG_ERROR(L"Failed to get token information", LastError);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
|
if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid);
|
Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
LastError = GetLastError();
|
|
||||||
if (ProcessSnapshot == INVALID_HANDLE_VALUE)
|
if (ProcessSnapshot == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to create toolhelp snapshot");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret;
|
for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret;
|
||||||
Ret = Process32NextW(ProcessSnapshot, &ProcessEntry))
|
Ret = Process32NextW(ProcessSnapshot, &ProcessEntry))
|
||||||
{
|
{
|
||||||
@ -55,13 +66,17 @@ ElevateToSystem(void)
|
|||||||
continue;
|
continue;
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
Ret = ImpersonateSelf(SecurityImpersonation);
|
Ret = ImpersonateSelf(SecurityImpersonation);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = GetLastError();
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken);
|
Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = GetLastError();
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
|
Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
|
||||||
LastError = GetLastError();
|
LastError = GetLastError();
|
||||||
CloseHandle(ThreadToken);
|
CloseHandle(ThreadToken);
|
||||||
@ -69,9 +84,11 @@ ElevateToSystem(void)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID);
|
WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!WinlogonProcess)
|
if (!WinlogonProcess)
|
||||||
|
{
|
||||||
|
LastError = GetLastError();
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken);
|
Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken);
|
||||||
LastError = GetLastError();
|
LastError = GetLastError();
|
||||||
CloseHandle(WinlogonProcess);
|
CloseHandle(WinlogonProcess);
|
||||||
@ -84,13 +101,15 @@ ElevateToSystem(void)
|
|||||||
continue;
|
continue;
|
||||||
if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes))
|
if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes))
|
||||||
goto next;
|
goto next;
|
||||||
if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
|
if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_ACCESS_DENIED);
|
||||||
goto next;
|
goto next;
|
||||||
|
}
|
||||||
if (!SetThreadToken(NULL, DuplicatedToken))
|
if (!SetThreadToken(NULL, DuplicatedToken))
|
||||||
goto next;
|
goto next;
|
||||||
CloseHandle(DuplicatedToken);
|
CloseHandle(DuplicatedToken);
|
||||||
CloseHandle(ProcessSnapshot);
|
CloseHandle(ProcessSnapshot);
|
||||||
SetLastError(ERROR_SUCCESS);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
next:
|
next:
|
||||||
LastError = GetLastError();
|
LastError = GetLastError();
|
||||||
@ -103,8 +122,7 @@ cleanup:
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE
|
_Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void)
|
||||||
GetPrimarySystemTokenFromThread(void)
|
|
||||||
{
|
{
|
||||||
HANDLE CurrentThreadToken, DuplicatedToken;
|
HANDLE CurrentThreadToken, DuplicatedToken;
|
||||||
BOOL Ret;
|
BOOL Ret;
|
||||||
@ -120,26 +138,41 @@ GetPrimarySystemTokenFromThread(void)
|
|||||||
|
|
||||||
Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
|
Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to create SID");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
Ret = OpenThreadToken(
|
Ret = OpenThreadToken(
|
||||||
GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, FALSE, &CurrentThreadToken);
|
GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, FALSE, &CurrentThreadToken);
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to open thread token");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
Ret = GetTokenInformation(CurrentThreadToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
|
Ret = GetTokenInformation(CurrentThreadToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to get token information");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
LastError = ERROR_ACCESS_DENIED;
|
}
|
||||||
if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
|
if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
|
||||||
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Not SYSTEM");
|
||||||
|
LastError = ERROR_ACCESS_DENIED;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
Ret = LookupPrivilegeValueW(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &Privileges.Privileges[0].Luid);
|
Ret = LookupPrivilegeValueW(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &Privileges.Privileges[0].Luid);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
Ret = AdjustTokenPrivileges(CurrentThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
|
Ret = AdjustTokenPrivileges(CurrentThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to adjust token privileges");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
Ret = DuplicateTokenEx(
|
Ret = DuplicateTokenEx(
|
||||||
CurrentThreadToken,
|
CurrentThreadToken,
|
||||||
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
|
||||||
@ -147,14 +180,16 @@ GetPrimarySystemTokenFromThread(void)
|
|||||||
SecurityImpersonation,
|
SecurityImpersonation,
|
||||||
TokenPrimary,
|
TokenPrimary,
|
||||||
&DuplicatedToken);
|
&DuplicatedToken);
|
||||||
LastError = GetLastError();
|
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to duplicate token");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
CloseHandle(CurrentThreadToken);
|
CloseHandle(CurrentThreadToken);
|
||||||
return DuplicatedToken;
|
return DuplicatedToken;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
CloseHandle(CurrentThreadToken);
|
CloseHandle(CurrentThreadToken);
|
||||||
SetLastError(LastError);
|
SetLastError(LastError);
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
BOOL
|
_Return_type_success_(return != FALSE) BOOL ElevateToSystem(void);
|
||||||
ElevateToSystem(void);
|
|
||||||
|
|
||||||
HANDLE
|
_Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void);
|
||||||
GetPrimarySystemTokenFromThread(void);
|
|
||||||
|
@ -22,7 +22,8 @@ HINSTANCE ResourceModule;
|
|||||||
HANDLE ModuleHeap;
|
HANDLE ModuleHeap;
|
||||||
SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
|
SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
|
||||||
|
|
||||||
static FARPROC WINAPI DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
static FARPROC WINAPI
|
||||||
|
DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
||||||
{
|
{
|
||||||
if (dliNotify != dliNotePreLoadLibrary)
|
if (dliNotify != dliNotePreLoadLibrary)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -53,7 +54,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
NamespaceCleanup();
|
NamespaceDone();
|
||||||
LocalFree(SecurityAttributes.lpSecurityDescriptor);
|
LocalFree(SecurityAttributes.lpSecurityDescriptor);
|
||||||
HeapDestroy(ModuleHeap);
|
HeapDestroy(ModuleHeap);
|
||||||
break;
|
break;
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#pragma warning(disable : 4127) /* conditional expression is constant */
|
#pragma warning(disable : 4127) /* conditional expression is constant */
|
||||||
|
|
||||||
|
#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))
|
||||||
|
|
||||||
extern HINSTANCE ResourceModule;
|
extern HINSTANCE ResourceModule;
|
||||||
extern HANDLE ModuleHeap;
|
extern HANDLE ModuleHeap;
|
||||||
extern SECURITY_ATTRIBUTES SecurityAttributes;
|
extern SECURITY_ATTRIBUTES SecurityAttributes;
|
||||||
|
19
api/logger.h
19
api/logger.h
@ -16,20 +16,29 @@ extern WINTUN_LOGGER_CALLBACK_FUNC Logger;
|
|||||||
void WINAPI
|
void WINAPI
|
||||||
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK_FUNC NewLogger);
|
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK_FUNC NewLogger);
|
||||||
|
|
||||||
|
static inline _Post_equals_last_error_ DWORD
|
||||||
|
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
|
||||||
|
{
|
||||||
|
DWORD LastError = GetLastError();
|
||||||
|
Logger(Level, LogLine);
|
||||||
|
SetLastError(LastError);
|
||||||
|
return LastError;
|
||||||
|
}
|
||||||
|
|
||||||
_Post_equals_last_error_ DWORD
|
_Post_equals_last_error_ DWORD
|
||||||
LoggerError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error);
|
LoggerError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error);
|
||||||
|
|
||||||
static inline _Post_equals_last_error_ DWORD
|
static inline _Post_equals_last_error_ DWORD
|
||||||
LoggerLastError(_In_z_ const WCHAR *Prefix)
|
LoggerLastError(_In_z_ const WCHAR *Prefix)
|
||||||
{
|
{
|
||||||
DWORD Error = GetLastError();
|
DWORD LastError = GetLastError();
|
||||||
LoggerError(Prefix, Error);
|
LoggerError(Prefix, LastError);
|
||||||
SetLastError(Error);
|
SetLastError(LastError);
|
||||||
return Error;
|
return LastError;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __L(x) L##x
|
#define __L(x) L##x
|
||||||
#define _L(x) __L(x)
|
#define _L(x) __L(x)
|
||||||
#define LOG(lvl, msg) (Logger((lvl), _L(__FUNCTION__) L": " msg))
|
#define LOG(lvl, msg) (LoggerLog((lvl), _L(__FUNCTION__) L": " msg))
|
||||||
#define LOG_ERROR(msg, err) (LoggerError(_L(__FUNCTION__) L": " msg, (err)))
|
#define LOG_ERROR(msg, err) (LoggerError(_L(__FUNCTION__) L": " msg, (err)))
|
||||||
#define LOG_LAST_ERROR(msg) (LoggerLastError(_L(__FUNCTION__) L": " msg))
|
#define LOG_LAST_ERROR(msg) (LoggerLastError(_L(__FUNCTION__) L": " msg))
|
||||||
|
123
api/namespace.c
123
api/namespace.c
@ -15,41 +15,48 @@ static BOOL HasInitialized = FALSE;
|
|||||||
static CRITICAL_SECTION Initializing;
|
static CRITICAL_SECTION Initializing;
|
||||||
static BCRYPT_ALG_HANDLE AlgProvider;
|
static BCRYPT_ALG_HANDLE AlgProvider;
|
||||||
|
|
||||||
static WCHAR *
|
static _Return_type_success_(
|
||||||
NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source)
|
return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source)
|
||||||
{
|
{
|
||||||
int Len = NormalizeString(NormForm, Source, -1, NULL, 0);
|
int Len = NormalizeString(NormForm, Source, -1, NULL, 0);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
WCHAR *Str = HeapAlloc(ModuleHeap, 0, sizeof(WCHAR) * Len);
|
WCHAR *Str = HeapAlloc(ModuleHeap, 0, sizeof(WCHAR) * Len);
|
||||||
if (!Str)
|
if (!Str)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), NULL;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
Len = NormalizeString(NormForm, Source, -1, Str, Len);
|
Len = NormalizeString(NormForm, Source, -1, Str, Len);
|
||||||
if (Len > 0)
|
if (Len > 0)
|
||||||
return Str;
|
return Str;
|
||||||
DWORD Result = GetLastError();
|
DWORD LastError = GetLastError();
|
||||||
HeapFree(ModuleHeap, 0, Str);
|
HeapFree(ModuleHeap, 0, Str);
|
||||||
if (Result != ERROR_INSUFFICIENT_BUFFER)
|
if (LastError != ERROR_INSUFFICIENT_BUFFER)
|
||||||
return LOG_ERROR(L"Failed", Result), NULL;
|
{
|
||||||
|
SetLastError(LOG_ERROR(L"Failed", LastError));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
Len = -Len;
|
Len = -Len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINTUN_STATUS
|
static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void)
|
||||||
NamespaceRuntimeInit(void)
|
|
||||||
{
|
{
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
|
|
||||||
EnterCriticalSection(&Initializing);
|
EnterCriticalSection(&Initializing);
|
||||||
if (HasInitialized)
|
if (HasInitialized)
|
||||||
{
|
{
|
||||||
LeaveCriticalSection(&Initializing);
|
LeaveCriticalSection(&Initializing);
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0)))
|
if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0)))
|
||||||
{
|
{
|
||||||
Result = ERROR_GEN_FAILURE;
|
LOG(WINTUN_LOG_ERR, L"Failed to open algorithm provider");
|
||||||
|
LastError = ERROR_GEN_FAILURE;
|
||||||
goto cleanupLeaveCriticalSection;
|
goto cleanupLeaveCriticalSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,19 +64,19 @@ NamespaceRuntimeInit(void)
|
|||||||
DWORD SidSize = MAX_SID_SIZE;
|
DWORD SidSize = MAX_SID_SIZE;
|
||||||
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, Sid, &SidSize))
|
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, Sid, &SidSize))
|
||||||
{
|
{
|
||||||
Result = GetLastError();
|
LastError = LOG_LAST_ERROR(L"Failed to create SID");
|
||||||
goto cleanupBCryptCloseAlgorithmProvider;
|
goto cleanupBCryptCloseAlgorithmProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE Boundary = CreateBoundaryDescriptorW(L"Wintun", 0);
|
HANDLE Boundary = CreateBoundaryDescriptorW(L"Wintun", 0);
|
||||||
if (!Boundary)
|
if (!Boundary)
|
||||||
{
|
{
|
||||||
Result = GetLastError();
|
LastError = LOG_LAST_ERROR(L"Failed to create boundary descriptor");
|
||||||
goto cleanupBCryptCloseAlgorithmProvider;
|
goto cleanupBCryptCloseAlgorithmProvider;
|
||||||
}
|
}
|
||||||
if (!AddSIDToBoundaryDescriptor(&Boundary, Sid))
|
if (!AddSIDToBoundaryDescriptor(&Boundary, Sid))
|
||||||
{
|
{
|
||||||
Result = GetLastError();
|
LastError = LOG_LAST_ERROR(L"Failed to add SID to boundary descriptor");
|
||||||
goto cleanupBCryptCloseAlgorithmProvider;
|
goto cleanupBCryptCloseAlgorithmProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,98 +84,124 @@ NamespaceRuntimeInit(void)
|
|||||||
{
|
{
|
||||||
if (CreatePrivateNamespaceW(&SecurityAttributes, Boundary, L"Wintun"))
|
if (CreatePrivateNamespaceW(&SecurityAttributes, Boundary, L"Wintun"))
|
||||||
break;
|
break;
|
||||||
Result = GetLastError();
|
if ((LastError = GetLastError()) == ERROR_ALREADY_EXISTS)
|
||||||
if (Result == ERROR_ALREADY_EXISTS)
|
|
||||||
{
|
{
|
||||||
if (OpenPrivateNamespaceW(Boundary, L"Wintun"))
|
if (OpenPrivateNamespaceW(Boundary, L"Wintun"))
|
||||||
break;
|
break;
|
||||||
Result = GetLastError();
|
if ((LastError = GetLastError()) == ERROR_PATH_NOT_FOUND)
|
||||||
if (Result == ERROR_PATH_NOT_FOUND)
|
|
||||||
continue;
|
continue;
|
||||||
|
LOG_ERROR(L"Failed to open private namespace", LastError);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
LOG_ERROR(L"Failed to create private namespace", LastError);
|
||||||
goto cleanupBCryptCloseAlgorithmProvider;
|
goto cleanupBCryptCloseAlgorithmProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
HasInitialized = TRUE;
|
HasInitialized = TRUE;
|
||||||
Result = ERROR_SUCCESS;
|
LeaveCriticalSection(&Initializing);
|
||||||
goto cleanupLeaveCriticalSection;
|
return TRUE;
|
||||||
|
|
||||||
cleanupBCryptCloseAlgorithmProvider:
|
cleanupBCryptCloseAlgorithmProvider:
|
||||||
BCryptCloseAlgorithmProvider(AlgProvider, 0);
|
BCryptCloseAlgorithmProvider(AlgProvider, 0);
|
||||||
cleanupLeaveCriticalSection:
|
cleanupLeaveCriticalSection:
|
||||||
LeaveCriticalSection(&Initializing);
|
LeaveCriticalSection(&Initializing);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Check_return_
|
_Check_return_
|
||||||
HANDLE
|
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool)
|
||||||
NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool)
|
|
||||||
{
|
{
|
||||||
HANDLE Mutex = NULL;
|
if (!NamespaceRuntimeInit())
|
||||||
|
|
||||||
if (NamespaceRuntimeInit() != ERROR_SUCCESS)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
BCRYPT_HASH_HANDLE Sha256 = NULL;
|
BCRYPT_HASH_HANDLE Sha256 = NULL;
|
||||||
if (!BCRYPT_SUCCESS(BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0)))
|
if (!BCRYPT_SUCCESS(BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0)))
|
||||||
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to create hash");
|
||||||
|
SetLastError(ERROR_GEN_FAILURE);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
DWORD LastError;
|
||||||
static const WCHAR mutex_label[] = L"Wintun Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com";
|
static const WCHAR mutex_label[] = L"Wintun Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com";
|
||||||
if (!BCRYPT_SUCCESS(BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0)))
|
if (!BCRYPT_SUCCESS(
|
||||||
|
BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0)))
|
||||||
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to hash data");
|
||||||
|
LastError = ERROR_GEN_FAILURE;
|
||||||
goto cleanupSha256;
|
goto cleanupSha256;
|
||||||
|
}
|
||||||
WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
|
WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
|
||||||
if (!PoolNorm)
|
if (!PoolNorm)
|
||||||
|
{
|
||||||
|
LastError = GetLastError();
|
||||||
goto cleanupSha256;
|
goto cleanupSha256;
|
||||||
if (!BCRYPT_SUCCESS(BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0)))
|
}
|
||||||
|
if (!BCRYPT_SUCCESS(
|
||||||
|
BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0)))
|
||||||
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to hash data");
|
||||||
|
LastError = ERROR_GEN_FAILURE;
|
||||||
goto cleanupPoolNorm;
|
goto cleanupPoolNorm;
|
||||||
|
}
|
||||||
BYTE Hash[32];
|
BYTE Hash[32];
|
||||||
if (!BCRYPT_SUCCESS(BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0)))
|
if (!BCRYPT_SUCCESS(BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0)))
|
||||||
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to calculate hash");
|
||||||
|
LastError = ERROR_GEN_FAILURE;
|
||||||
goto cleanupPoolNorm;
|
goto cleanupPoolNorm;
|
||||||
|
}
|
||||||
static const WCHAR MutexNamePrefix[] = L"Wintun\\Wintun-Name-Mutex-";
|
static const WCHAR MutexNamePrefix[] = L"Wintun\\Wintun-Name-Mutex-";
|
||||||
WCHAR MutexName[_countof(MutexNamePrefix) + sizeof(Hash) * 2];
|
WCHAR MutexName[_countof(MutexNamePrefix) + sizeof(Hash) * 2];
|
||||||
memcpy(MutexName, MutexNamePrefix, sizeof(MutexNamePrefix));
|
memcpy(MutexName, MutexNamePrefix, sizeof(MutexNamePrefix));
|
||||||
for (size_t i = 0; i < sizeof(Hash); ++i)
|
for (size_t i = 0; i < sizeof(Hash); ++i)
|
||||||
swprintf_s(&MutexName[_countof(MutexNamePrefix) - 1 + i * 2], 3, L"%02x", Hash[i]);
|
swprintf_s(&MutexName[_countof(MutexNamePrefix) - 1 + i * 2], 3, L"%02x", Hash[i]);
|
||||||
Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName);
|
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName);
|
||||||
if (!Mutex)
|
if (!Mutex)
|
||||||
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to create mutex");
|
||||||
goto cleanupPoolNorm;
|
goto cleanupPoolNorm;
|
||||||
|
}
|
||||||
switch (WaitForSingleObject(Mutex, INFINITE))
|
switch (WaitForSingleObject(Mutex, INFINITE))
|
||||||
{
|
{
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
case WAIT_ABANDONED:
|
case WAIT_ABANDONED:
|
||||||
goto cleanupPoolNorm;
|
HeapFree(ModuleHeap, 0, PoolNorm);
|
||||||
|
BCryptDestroyHash(Sha256);
|
||||||
|
return Mutex;
|
||||||
}
|
}
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to get mutex");
|
||||||
|
LastError = ERROR_GEN_FAILURE;
|
||||||
CloseHandle(Mutex);
|
CloseHandle(Mutex);
|
||||||
Mutex = NULL;
|
|
||||||
cleanupPoolNorm:
|
cleanupPoolNorm:
|
||||||
HeapFree(ModuleHeap, 0, PoolNorm);
|
HeapFree(ModuleHeap, 0, PoolNorm);
|
||||||
cleanupSha256:
|
cleanupSha256:
|
||||||
BCryptDestroyHash(Sha256);
|
BCryptDestroyHash(Sha256);
|
||||||
return Mutex;
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Check_return_
|
_Check_return_
|
||||||
HANDLE
|
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void)
|
||||||
NamespaceTakeDriverInstallationMutex(void)
|
|
||||||
{
|
{
|
||||||
HANDLE Mutex = NULL;
|
if (!NamespaceRuntimeInit())
|
||||||
|
|
||||||
if (NamespaceRuntimeInit() != ERROR_SUCCESS)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex");
|
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex");
|
||||||
if (!Mutex)
|
if (!Mutex)
|
||||||
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to create mutex");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
switch (WaitForSingleObject(Mutex, INFINITE))
|
switch (WaitForSingleObject(Mutex, INFINITE))
|
||||||
{
|
{
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
case WAIT_ABANDONED:
|
case WAIT_ABANDONED:
|
||||||
goto out;
|
return Mutex;
|
||||||
}
|
}
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to get mutex");
|
||||||
CloseHandle(Mutex);
|
CloseHandle(Mutex);
|
||||||
Mutex = NULL;
|
SetLastError(ERROR_GEN_FAILURE);
|
||||||
out:
|
return NULL;
|
||||||
return Mutex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -185,7 +218,7 @@ NamespaceInit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NamespaceCleanup(void)
|
NamespaceDone(void)
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&Initializing);
|
EnterCriticalSection(&Initializing);
|
||||||
if (HasInitialized)
|
if (HasInitialized)
|
||||||
|
@ -8,12 +8,10 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
_Check_return_
|
_Check_return_
|
||||||
HANDLE
|
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool);
|
||||||
NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool);
|
|
||||||
|
|
||||||
_Check_return_
|
_Check_return_
|
||||||
HANDLE
|
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void);
|
||||||
NamespaceTakeDriverInstallationMutex(void);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
NamespaceReleaseMutex(_In_ HANDLE Mutex);
|
NamespaceReleaseMutex(_In_ HANDLE Mutex);
|
||||||
@ -22,4 +20,4 @@ void
|
|||||||
NamespaceInit(void);
|
NamespaceInit(void);
|
||||||
|
|
||||||
void
|
void
|
||||||
NamespaceCleanup(void);
|
NamespaceDone(void);
|
||||||
|
248
api/registry.c
248
api/registry.c
@ -9,42 +9,54 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
static WINTUN_STATUS
|
static _Return_type_success_(return != NULL) HKEY
|
||||||
OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline, _Out_ HKEY *KeyOut)
|
OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline)
|
||||||
{
|
{
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
WCHAR *PathNext = wcschr(Path, L'\\');
|
WCHAR *PathNext = wcschr(Path, L'\\');
|
||||||
if (PathNext)
|
if (PathNext)
|
||||||
*PathNext = 0;
|
*PathNext = 0;
|
||||||
|
|
||||||
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
if (!Event)
|
if (!Event)
|
||||||
return LOG_LAST_ERROR(L"Failed to create event");
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to create event");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE);
|
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (LastError != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_ERROR(L"Failed to setup notification", Result);
|
LOG_ERROR(L"Failed to setup notification", LastError);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
HKEY Subkey;
|
HKEY Subkey;
|
||||||
Result = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey);
|
LastError = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey);
|
||||||
if (Result == ERROR_SUCCESS)
|
if (LastError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (PathNext)
|
if (PathNext)
|
||||||
{
|
{
|
||||||
Result = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline, KeyOut);
|
HKEY KeyOut = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline);
|
||||||
RegCloseKey(Subkey);
|
if (KeyOut)
|
||||||
|
{
|
||||||
|
RegCloseKey(Subkey);
|
||||||
|
CloseHandle(Event);
|
||||||
|
return KeyOut;
|
||||||
|
}
|
||||||
|
LastError = GetLastError();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*KeyOut = Subkey;
|
{
|
||||||
break;
|
CloseHandle(Event);
|
||||||
|
return Subkey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
|
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
|
||||||
{
|
{
|
||||||
LOG_ERROR(L"Failed to open", Result);
|
LOG_ERROR(L"Failed to open", LastError);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,27 +70,35 @@ OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(Event);
|
CloseHandle(Event);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != NULL) HKEY
|
||||||
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut)
|
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout)
|
||||||
{
|
{
|
||||||
WCHAR Buf[MAX_REG_PATH];
|
WCHAR Buf[MAX_REG_PATH];
|
||||||
if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE)
|
if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Registry path too long"), ERROR_INVALID_PARAMETER;
|
{
|
||||||
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout, KeyOut);
|
LOG(WINTUN_LOG_ERR, L"Registry path too long");
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
||||||
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
|
||||||
{
|
{
|
||||||
if (wcsnlen(*Buf, Len) >= Len)
|
if (wcsnlen(*Buf, Len) >= Len)
|
||||||
{
|
{
|
||||||
/* String is missing zero-terminator. */
|
/* String is missing zero-terminator. */
|
||||||
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
||||||
if (!BufZ)
|
if (!BufZ)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
wmemcpy(BufZ, *Buf, Len);
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
BufZ[Len] = 0;
|
BufZ[Len] = 0;
|
||||||
HeapFree(ModuleHeap, 0, *Buf);
|
HeapFree(ModuleHeap, 0, *Buf);
|
||||||
@ -86,25 +106,30 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ValueType != REG_EXPAND_SZ)
|
if (ValueType != REG_EXPAND_SZ)
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
|
|
||||||
/* ExpandEnvironmentStringsW() returns strlen on success or 0 on error. Bail out on empty input strings to
|
/* ExpandEnvironmentStringsW() returns strlen on success or 0 on error. Bail out on empty input strings to
|
||||||
* disambiguate. */
|
* disambiguate. */
|
||||||
if (!(*Buf)[0])
|
if (!(*Buf)[0])
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
|
|
||||||
Len = Len * 2 + 64;
|
Len = Len * 2 + 64;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
WCHAR *Expanded = HeapAlloc(ModuleHeap, 0, Len * sizeof(WCHAR));
|
WCHAR *Expanded = HeapAlloc(ModuleHeap, 0, Len * sizeof(WCHAR));
|
||||||
if (!Expanded)
|
if (!Expanded)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
|
DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
|
||||||
if (!Result)
|
if (!Result)
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to expand environment variables");
|
DWORD LastError = LOG_LAST_ERROR(L"Failed to expand environment variables");
|
||||||
HeapFree(ModuleHeap, 0, Expanded);
|
HeapFree(ModuleHeap, 0, Expanded);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (Result > Len)
|
if (Result > Len)
|
||||||
{
|
{
|
||||||
@ -114,12 +139,12 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
|||||||
}
|
}
|
||||||
HeapFree(ModuleHeap, 0, *Buf);
|
HeapFree(ModuleHeap, 0, *Buf);
|
||||||
*Buf = Expanded;
|
*Buf = Expanded;
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
||||||
{
|
{
|
||||||
if (ValueType == REG_MULTI_SZ)
|
if (ValueType == REG_MULTI_SZ)
|
||||||
{
|
{
|
||||||
@ -130,52 +155,61 @@ RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType
|
|||||||
/* Missing string and list terminators. */
|
/* Missing string and list terminators. */
|
||||||
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 2) * sizeof(WCHAR));
|
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 2) * sizeof(WCHAR));
|
||||||
if (!BufZ)
|
if (!BufZ)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
wmemcpy(BufZ, *Buf, Len);
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
BufZ[Len] = 0;
|
BufZ[Len] = 0;
|
||||||
BufZ[Len + 1] = 0;
|
BufZ[Len + 1] = 0;
|
||||||
HeapFree(ModuleHeap, 0, *Buf);
|
HeapFree(ModuleHeap, 0, *Buf);
|
||||||
*Buf = BufZ;
|
*Buf = BufZ;
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (i == Len)
|
if (i == Len)
|
||||||
{
|
{
|
||||||
/* Missing list terminator. */
|
/* Missing list terminator. */
|
||||||
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
||||||
if (!BufZ)
|
if (!BufZ)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
wmemcpy(BufZ, *Buf, Len);
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
BufZ[Len] = 0;
|
BufZ[Len] = 0;
|
||||||
HeapFree(ModuleHeap, 0, *Buf);
|
HeapFree(ModuleHeap, 0, *Buf);
|
||||||
*Buf = BufZ;
|
*Buf = BufZ;
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (!(*Buf)[i])
|
if (!(*Buf)[i])
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sanitize REG_SZ/REG_EXPAND_SZ and append a list terminator to make a multi-string. */
|
/* Sanitize REG_SZ/REG_EXPAND_SZ and append a list terminator to make a multi-string. */
|
||||||
DWORD Result = RegistryGetString(Buf, Len, ValueType);
|
if (!RegistryGetString(Buf, Len, ValueType))
|
||||||
if (Result != ERROR_SUCCESS)
|
return FALSE;
|
||||||
return Result;
|
|
||||||
Len = (DWORD)wcslen(*Buf) + 1;
|
Len = (DWORD)wcslen(*Buf) + 1;
|
||||||
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
||||||
if (!BufZ)
|
if (!BufZ)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
wmemcpy(BufZ, *Buf, Len);
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
BufZ[Len] = 0;
|
BufZ[Len] = 0;
|
||||||
HeapFree(ModuleHeap, 0, *Buf);
|
HeapFree(ModuleHeap, 0, *Buf);
|
||||||
*Buf = BufZ;
|
*Buf = BufZ;
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINTUN_STATUS
|
static _Return_type_success_(return != NULL) void *RegistryQuery(
|
||||||
RegistryQuery(
|
|
||||||
_In_ HKEY Key,
|
_In_ HKEY Key,
|
||||||
_In_opt_z_ const WCHAR *Name,
|
_In_opt_z_ const WCHAR *Name,
|
||||||
_Out_opt_ DWORD *ValueType,
|
_Out_opt_ DWORD *ValueType,
|
||||||
_Out_ void **Buf,
|
|
||||||
_Inout_ DWORD *BufLen,
|
_Inout_ DWORD *BufLen,
|
||||||
_In_ BOOL Log)
|
_In_ BOOL Log)
|
||||||
{
|
{
|
||||||
@ -183,60 +217,77 @@ RegistryQuery(
|
|||||||
{
|
{
|
||||||
BYTE *p = HeapAlloc(ModuleHeap, 0, *BufLen);
|
BYTE *p = HeapAlloc(ModuleHeap, 0, *BufLen);
|
||||||
if (!p)
|
if (!p)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
|
||||||
LSTATUS Result = RegQueryValueExW(Key, Name, NULL, ValueType, p, BufLen);
|
|
||||||
if (Result == ERROR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
*Buf = p;
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
return ERROR_SUCCESS;
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
LSTATUS LastError = RegQueryValueExW(Key, Name, NULL, ValueType, p, BufLen);
|
||||||
|
if (LastError == ERROR_SUCCESS)
|
||||||
|
return p;
|
||||||
HeapFree(ModuleHeap, 0, p);
|
HeapFree(ModuleHeap, 0, p);
|
||||||
if (Result != ERROR_MORE_DATA)
|
if (LastError != ERROR_MORE_DATA)
|
||||||
return Log ? LOG_ERROR(L"Querying value failed", Result) : Result;
|
{
|
||||||
|
if (Log)
|
||||||
|
LOG_ERROR(L"Querying value failed", LastError);
|
||||||
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(
|
||||||
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **Value, _In_ BOOL Log)
|
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log)
|
||||||
{
|
{
|
||||||
DWORD ValueType, Size = 256 * sizeof(WCHAR);
|
DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR);
|
||||||
DWORD Result = RegistryQuery(Key, Name, &ValueType, Value, &Size, Log);
|
WCHAR *Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (!Value)
|
||||||
return Result;
|
return NULL;
|
||||||
switch (ValueType)
|
switch (ValueType)
|
||||||
{
|
{
|
||||||
case REG_SZ:
|
case REG_SZ:
|
||||||
case REG_EXPAND_SZ:
|
case REG_EXPAND_SZ:
|
||||||
case REG_MULTI_SZ:
|
case REG_MULTI_SZ:
|
||||||
Result = RegistryGetString(Value, Size / sizeof(WCHAR), ValueType);
|
if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType))
|
||||||
if (Result != ERROR_SUCCESS)
|
return Value;
|
||||||
HeapFree(ModuleHeap, 0, *Value);
|
LastError = GetLastError();
|
||||||
return Result;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(WINTUN_LOG_ERR, L"Value is not a string");
|
LOG(WINTUN_LOG_ERR, L"Value is not a string");
|
||||||
HeapFree(ModuleHeap, 0, *Value);
|
LastError = ERROR_INVALID_DATATYPE;
|
||||||
return ERROR_INVALID_DATATYPE;
|
|
||||||
}
|
}
|
||||||
|
HeapFree(ModuleHeap, 0, Value);
|
||||||
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(
|
||||||
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ WCHAR **Value)
|
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout)
|
||||||
{
|
{
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
||||||
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
if (!Event)
|
if (!Event)
|
||||||
return LOG_LAST_ERROR(L"Failed to create event");
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to create event");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
|
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (LastError != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_ERROR(L"Failed to setup notification", Result);
|
LOG_ERROR(L"Failed to setup notification", LastError);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Result = RegistryQueryString(Key, Name, Value, FALSE);
|
WCHAR *Value = RegistryQueryString(Key, Name, FALSE);
|
||||||
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
|
if (Value)
|
||||||
|
{
|
||||||
|
CloseHandle(Event);
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
LastError = GetLastError();
|
||||||
|
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
|
||||||
break;
|
break;
|
||||||
LONGLONG TimeLeft = Deadline - GetTickCount64();
|
LONGLONG TimeLeft = Deadline - GetTickCount64();
|
||||||
if (TimeLeft < 0)
|
if (TimeLeft < 0)
|
||||||
@ -248,51 +299,63 @@ RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(Event);
|
CloseHandle(Event);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log)
|
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log)
|
||||||
{
|
{
|
||||||
DWORD ValueType, Size = sizeof(DWORD);
|
DWORD ValueType, Size = sizeof(DWORD);
|
||||||
DWORD Result = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
|
DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (LastError != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (Log)
|
if (Log)
|
||||||
LOG_ERROR(L"Querying failed", Result);
|
LOG_ERROR(L"Querying failed", LastError);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (ValueType != REG_DWORD)
|
if (ValueType != REG_DWORD)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Value is not a DWORD");
|
LOG(WINTUN_LOG_ERR, L"Value is not a DWORD");
|
||||||
return ERROR_INVALID_DATATYPE;
|
SetLastError(ERROR_INVALID_DATATYPE);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (Size != sizeof(DWORD))
|
if (Size != sizeof(DWORD))
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Value size is not 4 bytes");
|
LOG(WINTUN_LOG_ERR, L"Value size is not 4 bytes");
|
||||||
return ERROR_INVALID_DATA;
|
SetLastError(ERROR_INVALID_DATA);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
return ERROR_SUCCESS;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value)
|
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value)
|
||||||
{
|
{
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
||||||
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
if (!Event)
|
if (!Event)
|
||||||
return LOG_LAST_ERROR(L"Failed to create event");
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to create event");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
|
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (LastError != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_ERROR(L"Failed to setup notification", Result);
|
LOG_ERROR(L"Failed to setup notification", LastError);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Result = RegistryQueryDWORD(Key, Name, Value, FALSE);
|
if (RegistryQueryDWORD(Key, Name, Value, FALSE))
|
||||||
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
|
{
|
||||||
|
CloseHandle(Event);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
LastError = GetLastError();
|
||||||
|
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
|
||||||
break;
|
break;
|
||||||
LONGLONG TimeLeft = Deadline - GetTickCount64();
|
LONGLONG TimeLeft = Deadline - GetTickCount64();
|
||||||
if (TimeLeft < 0)
|
if (TimeLeft < 0)
|
||||||
@ -304,5 +367,6 @@ RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(Event);
|
CloseHandle(Event);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,11 @@
|
|||||||
*
|
*
|
||||||
* @param Timeout Timeout to wait for the value in milliseconds.
|
* @param Timeout Timeout to wait for the value in milliseconds.
|
||||||
*
|
*
|
||||||
* @param KeyOut Pointer to a variable to receive the key handle.
|
* @return Key handle on success. If the function fails, the return value is zero. To get extended error information,
|
||||||
*
|
* call GetLastError.
|
||||||
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; Win32 error code otherwise.
|
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != NULL) HKEY
|
||||||
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut);
|
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates and/or sanitizes string value read from registry.
|
* Validates and/or sanitizes string value read from registry.
|
||||||
@ -42,10 +41,11 @@ RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access,
|
|||||||
* @param ValueType Type of data. Must be either REG_SZ or REG_EXPAND_SZ. REG_MULTI_SZ is treated like REG_SZ; only
|
* @param ValueType Type of data. Must be either REG_SZ or REG_EXPAND_SZ. REG_MULTI_SZ is treated like REG_SZ; only
|
||||||
* the first string of a multi-string is to be used.
|
* the first string of a multi-string is to be used.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates and/or sanitizes multi-string value read from registry.
|
* Validates and/or sanitizes multi-string value read from registry.
|
||||||
@ -58,10 +58,11 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
|||||||
*
|
*
|
||||||
* @param ValueType Type of data. Must be one of REG_MULTI_SZ, REG_SZ or REG_EXPAND_SZ.
|
* @param ValueType Type of data. Must be one of REG_MULTI_SZ, REG_SZ or REG_EXPAND_SZ.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads string value from registry key.
|
* Reads string value from registry key.
|
||||||
@ -79,11 +80,11 @@ RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType
|
|||||||
* errors reduces log clutter when we are using RegistryQueryString() from
|
* errors reduces log clutter when we are using RegistryQueryString() from
|
||||||
* RegistryQueryStringWait() and some errors are expected to occur.
|
* RegistryQueryStringWait() and some errors are expected to occur.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; ERROR_INVALID_DATATYPE when the registry value is not a string; Win32 error code
|
* @return String with registry value on success; If the function fails, the return value is zero. To get extended error
|
||||||
* otherwise.
|
* information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(
|
||||||
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **Value, _In_ BOOL Log);
|
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads string value from registry key. It waits for the registry value to become available.
|
* Reads string value from registry key. It waits for the registry value to become available.
|
||||||
@ -94,16 +95,14 @@ RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **V
|
|||||||
*
|
*
|
||||||
* @param Timeout Timeout to wait for the value in milliseconds.
|
* @param Timeout Timeout to wait for the value in milliseconds.
|
||||||
*
|
*
|
||||||
* @param Value Pointer to string to retrieve registry value. If the value type is REG_EXPAND_SZ the value is
|
* @return Registry value. If the value type is REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings(). If
|
||||||
* expanded using ExpandEnvironmentStrings(). If the value type is REG_MULTI_SZ, only the first
|
* the value type is REG_MULTI_SZ, only the first string from the multi-string is returned. The string must be
|
||||||
* string from the multi-string is returned. The string must be released with
|
* released with HeapFree(ModuleHeap, 0, Value) after use. If the function fails, the return value is zero. To
|
||||||
* HeapFree(ModuleHeap, 0, Value) after use.
|
* get extended error information, call GetLastError. Possible errors include the following:
|
||||||
*
|
* ERROR_INVALID_DATATYPE when the registry value is not a string
|
||||||
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; ERROR_INVALID_DATATYPE when the registry value is not a
|
|
||||||
* string; Win32 error code otherwise.
|
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(
|
||||||
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ WCHAR **Value);
|
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a 32-bit DWORD value from registry key.
|
* Reads a 32-bit DWORD value from registry key.
|
||||||
@ -118,11 +117,11 @@ RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD
|
|||||||
* errors reduces log clutter when we are using RegistryQueryDWORD() from
|
* errors reduces log clutter when we are using RegistryQueryDWORD() from
|
||||||
* RegistryQueryDWORDWait() and some errors are expected to occur.
|
* RegistryQueryDWORDWait() and some errors are expected to occur.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
* ERROR_INVALID_DATA when registry value size is not 4 bytes; Win32 error code otherwise.
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log);
|
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available.
|
* Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available.
|
||||||
@ -135,8 +134,10 @@ RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Val
|
|||||||
*
|
*
|
||||||
* @param Value Pointer to DWORD to retrieve registry value.
|
* @param Value Pointer to DWORD to retrieve registry value.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; ERROR_INVALID_DATATYPE when registry value exist but not
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
* REG_DWORD type; ERROR_INVALID_DATA when registry value size is not 4 bytes; Win32 error code otherwise.
|
* get extended error information, call GetLastError. Possible errors include the following:
|
||||||
|
* ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
|
||||||
|
* ERROR_INVALID_DATA when registry value size is not 4 bytes
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
|
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
|
||||||
|
@ -8,35 +8,47 @@
|
|||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
|
||||||
ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address, _Out_ DWORD *Size)
|
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size)
|
||||||
{
|
{
|
||||||
HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA);
|
HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA);
|
||||||
if (!FoundResource)
|
if (!FoundResource)
|
||||||
return LOG_LAST_ERROR(L"Failed to find resource");
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to find resource");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
*Size = SizeofResource(ResourceModule, FoundResource);
|
*Size = SizeofResource(ResourceModule, FoundResource);
|
||||||
if (!*Size)
|
if (!*Size)
|
||||||
return LOG_LAST_ERROR(L"Failed to query resource size");
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to query resource size");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
|
HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
|
||||||
if (!LoadedResource)
|
if (!LoadedResource)
|
||||||
return LOG_LAST_ERROR(L"Failed to load resource");
|
{
|
||||||
*Address = LockResource(LoadedResource);
|
LOG_LAST_ERROR(L"Failed to load resource");
|
||||||
if (!*Address)
|
return NULL;
|
||||||
|
}
|
||||||
|
BYTE *Address = LockResource(LoadedResource);
|
||||||
|
if (!Address)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Failed to lock resource");
|
LOG(WINTUN_LOG_ERR, L"Failed to lock resource");
|
||||||
return ERROR_LOCK_FAILED;
|
SetLastError(ERROR_LOCK_FAILED);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
return ERROR_SUCCESS;
|
return Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName)
|
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName)
|
||||||
{
|
{
|
||||||
const void *LockedResource;
|
|
||||||
DWORD SizeResource;
|
DWORD SizeResource;
|
||||||
DWORD Result = ResourceGetAddress(ResourceName, &LockedResource, &SizeResource);
|
const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (!LockedResource)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to locate resource");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
HANDLE DestinationHandle = CreateFileW(
|
HANDLE DestinationHandle = CreateFileW(
|
||||||
DestinationPath,
|
DestinationPath,
|
||||||
GENERIC_WRITE,
|
GENERIC_WRITE,
|
||||||
@ -46,15 +58,25 @@ ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *Reso
|
|||||||
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
|
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
|
||||||
NULL);
|
NULL);
|
||||||
if (DestinationHandle == INVALID_HANDLE_VALUE)
|
if (DestinationHandle == INVALID_HANDLE_VALUE)
|
||||||
return LOG_LAST_ERROR(L"Failed to create file");
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to create file");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
DWORD BytesWritten;
|
DWORD BytesWritten;
|
||||||
|
DWORD LastError;
|
||||||
if (!WriteFile(DestinationHandle, LockedResource, SizeResource, &BytesWritten, NULL))
|
if (!WriteFile(DestinationHandle, LockedResource, SizeResource, &BytesWritten, NULL))
|
||||||
Result = LOG_LAST_ERROR(L"Failed to write file");
|
{
|
||||||
|
LastError = LOG_LAST_ERROR(L"Failed to write file");
|
||||||
|
goto cleanupDestinationHandle;
|
||||||
|
}
|
||||||
if (BytesWritten != SizeResource)
|
if (BytesWritten != SizeResource)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Incomplete write");
|
LOG(WINTUN_LOG_ERR, L"Incomplete write");
|
||||||
Result = Result != ERROR_SUCCESS ? Result : ERROR_WRITE_FAULT;
|
LastError = ERROR_WRITE_FAULT;
|
||||||
|
goto cleanupDestinationHandle;
|
||||||
}
|
}
|
||||||
|
LastError = ERROR_SUCCESS;
|
||||||
|
cleanupDestinationHandle:
|
||||||
CloseHandle(DestinationHandle);
|
CloseHandle(DestinationHandle);
|
||||||
return Result;
|
return RET_ERROR(TRUE, LastError);
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,13 @@
|
|||||||
*
|
*
|
||||||
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
||||||
*
|
*
|
||||||
* Address Pointer to a pointer variable to receive resource address.
|
|
||||||
*
|
|
||||||
* Size Pointer to a variable to receive resource size.
|
* Size Pointer to a variable to receive resource size.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return Resource address on success. If the function fails, the return value is NULL. To get extended error
|
||||||
|
* information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
|
||||||
ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address, _Out_ DWORD *Size);
|
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies resource to a file.
|
* Copies resource to a file.
|
||||||
@ -29,7 +28,8 @@ ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address,
|
|||||||
*
|
*
|
||||||
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS
|
_Return_type_success_(return != FALSE) BOOL
|
||||||
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName);
|
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName);
|
||||||
|
@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
#if ACCEPT_WOW64 == 1
|
#if ACCEPT_WOW64 == 1
|
||||||
|
|
||||||
#include "adapter.h"
|
# include "adapter.h"
|
||||||
#include "logger.h"
|
# include "logger.h"
|
||||||
#include "wintun.h"
|
# include "wintun.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
# include <Windows.h>
|
||||||
#include <cfgmgr32.h>
|
# include <cfgmgr32.h>
|
||||||
#include <objbase.h>
|
# include <objbase.h>
|
||||||
#include <assert.h>
|
# include <assert.h>
|
||||||
|
|
||||||
#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
|
# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
|
||||||
|
|
||||||
static DWORD
|
static DWORD
|
||||||
WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...)
|
WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...)
|
||||||
@ -77,7 +77,7 @@ Done(void)
|
|||||||
LocalFree(Argv);
|
LocalFree(Argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning(disable: 4100) /* unreferenced formal parameter */
|
# pragma warning(disable : 4100) /* unreferenced formal parameter */
|
||||||
|
|
||||||
VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
@ -94,18 +94,19 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int
|
|||||||
if (Argc > 4 && FAILED(CLSIDFromString(Argv[4], &RequestedGUID)))
|
if (Argc > 4 && FAILED(CLSIDFromString(Argv[4], &RequestedGUID)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
WINTUN_ADAPTER *Adapter;
|
|
||||||
BOOL RebootRequired;
|
BOOL RebootRequired;
|
||||||
DWORD Result = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &Adapter, &RebootRequired);
|
WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired);
|
||||||
|
DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError();
|
||||||
WCHAR GuidStr[MAX_GUID_STRING_LEN];
|
WCHAR GuidStr[MAX_GUID_STRING_LEN];
|
||||||
WriteFormatted(
|
WriteFormatted(
|
||||||
STD_OUTPUT_HANDLE,
|
STD_OUTPUT_HANDLE,
|
||||||
L"%1!X! %2!.*s! %3!X!",
|
L"%1!X! %2!.*s! %3!X!",
|
||||||
Result,
|
LastError,
|
||||||
StringFromGUID2(Result == ERROR_SUCCESS ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)),
|
StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)),
|
||||||
GuidStr,
|
GuidStr,
|
||||||
RebootRequired);
|
RebootRequired);
|
||||||
WintunFreeAdapter(Adapter);
|
if (Adapter)
|
||||||
|
WintunFreeAdapter(Adapter);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
Done();
|
Done();
|
||||||
@ -124,8 +125,9 @@ VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int
|
|||||||
if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID)))
|
if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
BOOL RebootRequired;
|
BOOL RebootRequired;
|
||||||
WINTUN_STATUS Ret = WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired);
|
DWORD LastError =
|
||||||
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired);
|
WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError();
|
||||||
|
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
Done();
|
Done();
|
||||||
@ -140,8 +142,8 @@ VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, i
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
BOOL RebootRequired;
|
BOOL RebootRequired;
|
||||||
WINTUN_STATUS Ret = WintunDeletePoolDriver(Argv[2], &RebootRequired);
|
DWORD LastError = WintunDeletePoolDriver(Argv[2], &RebootRequired) ? ERROR_SUCCESS : GetLastError();
|
||||||
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired);
|
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
Done();
|
Done();
|
||||||
|
133
api/rundll32.h
133
api/rundll32.h
@ -72,7 +72,7 @@ ProcessStderr(_In_ HANDLE Stderr)
|
|||||||
else if (State == OnMsg && c == L'\n')
|
else if (State == OnMsg && c == L'\n')
|
||||||
{
|
{
|
||||||
Msg[Count] = 0;
|
Msg[Count] = 0;
|
||||||
Logger(Level, Msg);
|
LoggerLog(Level, Msg);
|
||||||
State = OnNone;
|
State = OnNone;
|
||||||
Count = 0;
|
Count = 0;
|
||||||
}
|
}
|
||||||
@ -80,27 +80,35 @@ ProcessStderr(_In_ HANDLE Stderr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINTUN_STATUS
|
static _Return_type_success_(return != FALSE) BOOL ExecuteRunDll32(
|
||||||
ExecuteRunDll32(
|
|
||||||
_In_z_ const WCHAR *Arguments,
|
_In_z_ const WCHAR *Arguments,
|
||||||
_Out_z_cap_c_(ResponseCapacity) WCHAR *Response,
|
_Out_z_cap_c_(ResponseCapacity) WCHAR *Response,
|
||||||
_In_ DWORD ResponseCapacity)
|
_In_ DWORD ResponseCapacity)
|
||||||
{
|
{
|
||||||
WCHAR WindowsDirectory[MAX_PATH];
|
WCHAR WindowsDirectory[MAX_PATH];
|
||||||
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
|
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
|
||||||
return LOG_LAST_ERROR(L"Failed to get Windows folder");
|
{
|
||||||
|
LOG_LAST_ERROR(L"Failed to get Windows folder");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
WCHAR RunDll32Path[MAX_PATH];
|
WCHAR RunDll32Path[MAX_PATH];
|
||||||
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
|
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
|
||||||
return ERROR_BUFFER_OVERFLOW;
|
{
|
||||||
|
SetLastError(ERROR_BUFFER_OVERFLOW);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
WCHAR RandomTempSubDirectory[MAX_PATH];
|
WCHAR RandomTempSubDirectory[MAX_PATH];
|
||||||
if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS)
|
if (!CreateTemporaryDirectory(RandomTempSubDirectory))
|
||||||
return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
WCHAR DllPath[MAX_PATH] = { 0 };
|
WCHAR DllPath[MAX_PATH] = { 0 };
|
||||||
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
|
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
|
||||||
{
|
{
|
||||||
Result = ERROR_BUFFER_OVERFLOW;
|
LastError = ERROR_BUFFER_OVERFLOW;
|
||||||
goto cleanupDirectory;
|
goto cleanupDirectory;
|
||||||
}
|
}
|
||||||
const WCHAR *WintunDllResourceName;
|
const WCHAR *WintunDllResourceName;
|
||||||
@ -114,12 +122,12 @@ ExecuteRunDll32(
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(WINTUN_LOG_ERR, L"Unsupported platform");
|
LOG(WINTUN_LOG_ERR, L"Unsupported platform");
|
||||||
Result = ERROR_NOT_SUPPORTED;
|
LastError = ERROR_NOT_SUPPORTED;
|
||||||
goto cleanupDirectory;
|
goto cleanupDirectory;
|
||||||
}
|
}
|
||||||
if ((Result = ResourceCopyToFile(DllPath, WintunDllResourceName)) != ERROR_SUCCESS)
|
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Failed to copy resource");
|
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource");
|
||||||
goto cleanupDelete;
|
goto cleanupDelete;
|
||||||
}
|
}
|
||||||
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1;
|
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1;
|
||||||
@ -127,14 +135,14 @@ ExecuteRunDll32(
|
|||||||
if (!CommandLine)
|
if (!CommandLine)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
Result = ERROR_OUTOFMEMORY;
|
LastError = ERROR_OUTOFMEMORY;
|
||||||
goto cleanupDelete;
|
goto cleanupDelete;
|
||||||
}
|
}
|
||||||
if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) ==
|
if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) ==
|
||||||
-1)
|
-1)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||||
Result = ERROR_INVALID_PARAMETER;
|
LastError = ERROR_INVALID_PARAMETER;
|
||||||
goto cleanupDelete;
|
goto cleanupDelete;
|
||||||
}
|
}
|
||||||
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
|
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
|
||||||
@ -142,13 +150,13 @@ ExecuteRunDll32(
|
|||||||
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
|
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
|
||||||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
|
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to create pipes");
|
LastError = LOG_LAST_ERROR(L"Failed to create pipes");
|
||||||
goto cleanupPipes;
|
goto cleanupPipes;
|
||||||
}
|
}
|
||||||
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
|
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
|
||||||
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to set handle info");
|
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
|
||||||
goto cleanupPipes;
|
goto cleanupPipes;
|
||||||
}
|
}
|
||||||
if (ResponseCapacity)
|
if (ResponseCapacity)
|
||||||
@ -160,7 +168,7 @@ ExecuteRunDll32(
|
|||||||
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
|
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
|
||||||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
|
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to spawn readers");
|
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
|
||||||
goto cleanupThreads;
|
goto cleanupThreads;
|
||||||
}
|
}
|
||||||
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
|
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
|
||||||
@ -172,14 +180,15 @@ ExecuteRunDll32(
|
|||||||
HANDLE ProcessToken = GetPrimarySystemTokenFromThread();
|
HANDLE ProcessToken = GetPrimarySystemTokenFromThread();
|
||||||
if (!ProcessToken)
|
if (!ProcessToken)
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to get primary system token from thread");
|
LastError = LOG(WINTUN_LOG_ERR, L"Failed to get primary system token from thread");
|
||||||
goto cleanupThreads;
|
goto cleanupThreads;
|
||||||
}
|
}
|
||||||
if (!CreateProcessAsUserW(ProcessToken, RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
if (!CreateProcessAsUserW(ProcessToken, RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to create process");
|
LastError = LOG_LAST_ERROR(L"Failed to create process");
|
||||||
goto cleanupToken;
|
goto cleanupToken;
|
||||||
}
|
}
|
||||||
|
LastError = ERROR_SUCCESS;
|
||||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
@ -198,10 +207,10 @@ cleanupThreads:
|
|||||||
CloseHandle(StreamWStdout);
|
CloseHandle(StreamWStdout);
|
||||||
StreamWStdout = INVALID_HANDLE_VALUE;
|
StreamWStdout = INVALID_HANDLE_VALUE;
|
||||||
WaitForSingleObject(ThreadStdout, INFINITE);
|
WaitForSingleObject(ThreadStdout, INFINITE);
|
||||||
if (!GetExitCodeThread(ThreadStdout, &Result))
|
if (!GetExitCodeThread(ThreadStdout, &LastError))
|
||||||
Result = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
|
LastError = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
|
||||||
else if (Result != ERROR_SUCCESS)
|
else if (LastError != ERROR_SUCCESS)
|
||||||
LOG_ERROR(L"Failed to read process output", Result);
|
LOG_ERROR(L"Failed to read process output", LastError);
|
||||||
CloseHandle(ThreadStdout);
|
CloseHandle(ThreadStdout);
|
||||||
}
|
}
|
||||||
cleanupPipes:
|
cleanupPipes:
|
||||||
@ -214,15 +223,13 @@ cleanupDelete:
|
|||||||
DeleteFileW(DllPath);
|
DeleteFileW(DllPath);
|
||||||
cleanupDirectory:
|
cleanupDirectory:
|
||||||
RemoveDirectoryW(RandomTempSubDirectory);
|
RemoveDirectoryW(RandomTempSubDirectory);
|
||||||
return Result;
|
return RET_ERROR(TRUE, LastError);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINTUN_STATUS
|
static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapterViaRundll32(
|
||||||
CreateAdapterViaRundll32(
|
|
||||||
_In_z_ const WCHAR *Pool,
|
_In_z_ const WCHAR *Pool,
|
||||||
_In_z_ const WCHAR *Name,
|
_In_z_ const WCHAR *Name,
|
||||||
_In_opt_ const GUID *RequestedGUID,
|
_In_opt_ const GUID *RequestedGUID,
|
||||||
_Out_ WINTUN_ADAPTER **Adapter,
|
|
||||||
_Inout_ BOOL *RebootRequired)
|
_Inout_ BOOL *RebootRequired)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||||
@ -237,38 +244,46 @@ CreateAdapterViaRundll32(
|
|||||||
Name,
|
Name,
|
||||||
RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0,
|
RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0,
|
||||||
RequestedGUIDStr) == -1)
|
RequestedGUIDStr) == -1)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
|
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
|
||||||
DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response));
|
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
|
||||||
if (Result != ERROR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
|
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
|
||||||
return Result;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
DWORD LastError;
|
||||||
|
WINTUN_ADAPTER *Adapter = NULL;
|
||||||
int Argc;
|
int Argc;
|
||||||
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
||||||
GUID CfgInstanceID;
|
GUID CfgInstanceID;
|
||||||
if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID)))
|
if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID)))
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
|
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
|
||||||
Result = ERROR_INVALID_PARAMETER;
|
LastError = ERROR_INVALID_PARAMETER;
|
||||||
goto cleanupArgv;
|
goto cleanupArgv;
|
||||||
}
|
}
|
||||||
Result = wcstoul(Argv[0], NULL, 16);
|
LastError = wcstoul(Argv[0], NULL, 16);
|
||||||
if (Result == ERROR_SUCCESS && GetAdapter(Pool, &CfgInstanceID, Adapter) != ERROR_SUCCESS)
|
if (LastError == ERROR_SUCCESS && (Adapter = GetAdapter(Pool, &CfgInstanceID)) == NULL)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Failed to get adapter");
|
LOG(WINTUN_LOG_ERR, L"Failed to get adapter");
|
||||||
Result = ERROR_FILE_NOT_FOUND;
|
LastError = ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
if (wcstoul(Argv[2], NULL, 16))
|
if (wcstoul(Argv[2], NULL, 16))
|
||||||
*RebootRequired = TRUE;
|
*RebootRequired = TRUE;
|
||||||
cleanupArgv:
|
cleanupArgv:
|
||||||
LocalFree(Argv);
|
LocalFree(Argv);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return Adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINTUN_STATUS
|
static _Return_type_success_(return != FALSE) BOOL DeleteAdapterViaRundll32(
|
||||||
DeleteAdapterViaRundll32(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Inout_ BOOL *RebootRequired)
|
_In_ const WINTUN_ADAPTER *Adapter,
|
||||||
|
_In_ BOOL ForceCloseSessions,
|
||||||
|
_Inout_ BOOL *RebootRequired)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||||
WCHAR GuidStr[MAX_GUID_STRING_LEN];
|
WCHAR GuidStr[MAX_GUID_STRING_LEN];
|
||||||
@ -281,57 +296,65 @@ DeleteAdapterViaRundll32(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceClos
|
|||||||
ForceCloseSessions ? 1 : 0,
|
ForceCloseSessions ? 1 : 0,
|
||||||
StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)),
|
StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)),
|
||||||
GuidStr) == -1)
|
GuidStr) == -1)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
WCHAR Response[8 + 1 + 8 + 1];
|
WCHAR Response[8 + 1 + 8 + 1];
|
||||||
DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response));
|
DWORD LastError;
|
||||||
if (Result != ERROR_SUCCESS)
|
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
|
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
|
||||||
return Result;
|
return FALSE;
|
||||||
}
|
}
|
||||||
int Argc;
|
int Argc;
|
||||||
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
||||||
if (Argc < 2)
|
if (Argc < 2)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
|
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
|
||||||
Result = ERROR_INVALID_PARAMETER;
|
LastError = ERROR_INVALID_PARAMETER;
|
||||||
goto cleanupArgv;
|
goto cleanupArgv;
|
||||||
}
|
}
|
||||||
Result = wcstoul(Argv[0], NULL, 16);
|
LastError = wcstoul(Argv[0], NULL, 16);
|
||||||
if (wcstoul(Argv[1], NULL, 16))
|
if (wcstoul(Argv[1], NULL, 16))
|
||||||
*RebootRequired = TRUE;
|
*RebootRequired = TRUE;
|
||||||
cleanupArgv:
|
cleanupArgv:
|
||||||
LocalFree(Argv);
|
LocalFree(Argv);
|
||||||
return Result;
|
return RET_ERROR(TRUE, LastError);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINTUN_STATUS
|
static _Return_type_success_(return != FALSE) BOOL
|
||||||
DeletePoolDriverViaRundll32(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired)
|
DeletePoolDriverViaRundll32(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||||
|
|
||||||
WCHAR Arguments[17 + WINTUN_MAX_POOL + 1];
|
WCHAR Arguments[17 + WINTUN_MAX_POOL + 1];
|
||||||
if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1)
|
if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER;
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
WCHAR Response[8 + 1 + 8 + 1];
|
WCHAR Response[8 + 1 + 8 + 1];
|
||||||
DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response));
|
DWORD LastError;
|
||||||
if (Result != ERROR_SUCCESS)
|
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
|
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
|
||||||
return Result;
|
return FALSE;
|
||||||
}
|
}
|
||||||
int Argc;
|
int Argc;
|
||||||
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
||||||
if (Argc < 2)
|
if (Argc < 2)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
|
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
|
||||||
Result = ERROR_INVALID_PARAMETER;
|
LastError = ERROR_INVALID_PARAMETER;
|
||||||
goto cleanupArgv;
|
goto cleanupArgv;
|
||||||
}
|
}
|
||||||
Result = wcstoul(Argv[0], NULL, 16);
|
LastError = wcstoul(Argv[0], NULL, 16);
|
||||||
if (wcstoul(Argv[1], NULL, 16))
|
if (wcstoul(Argv[1], NULL, 16))
|
||||||
*RebootRequired = TRUE;
|
*RebootRequired = TRUE;
|
||||||
cleanupArgv:
|
cleanupArgv:
|
||||||
LocalFree(Argv);
|
LocalFree(Argv);
|
||||||
return Result;
|
return RET_ERROR(TRUE, LastError);
|
||||||
}
|
}
|
||||||
|
123
api/session.c
123
api/session.c
@ -69,86 +69,87 @@ typedef struct _TUN_SESSION
|
|||||||
HANDLE Handle;
|
HANDLE Handle;
|
||||||
} TUN_SESSION;
|
} TUN_SESSION;
|
||||||
|
|
||||||
WINTUN_STATUS WINAPI
|
_Return_type_success_(return != NULL) TUN_SESSION *WINAPI
|
||||||
WintunStartSession(
|
WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity)
|
||||||
_In_ const WINTUN_ADAPTER *Adapter,
|
|
||||||
_In_ DWORD Capacity,
|
|
||||||
_Out_ TUN_SESSION **Session)
|
|
||||||
{
|
{
|
||||||
TUN_SESSION *s = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(TUN_SESSION));
|
DWORD LastError;
|
||||||
if (!s)
|
TUN_SESSION *Session = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(TUN_SESSION));
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
if (!Session)
|
||||||
|
{
|
||||||
|
LOG(WINTUN_LOG_ERR, L"Out of memory");
|
||||||
|
LastError = ERROR_OUTOFMEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
const ULONG RingSize = TUN_RING_SIZE(Capacity);
|
const ULONG RingSize = TUN_RING_SIZE(Capacity);
|
||||||
DWORD Result;
|
|
||||||
BYTE *AllocatedRegion = VirtualAlloc(0, (size_t)RingSize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
BYTE *AllocatedRegion = VirtualAlloc(0, (size_t)RingSize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
if (!AllocatedRegion)
|
if (!AllocatedRegion)
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to allocate ring memory");
|
LastError = LOG_LAST_ERROR(L"Failed to allocate ring memory");
|
||||||
goto cleanupRings;
|
goto cleanupRings;
|
||||||
}
|
}
|
||||||
if (!ElevateToSystem())
|
if (!ElevateToSystem())
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user");
|
LastError = LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user");
|
||||||
Result = ERROR_ACCESS_DENIED;
|
|
||||||
goto cleanupAllocatedRegion;
|
goto cleanupAllocatedRegion;
|
||||||
}
|
}
|
||||||
s->Descriptor.Send.RingSize = RingSize;
|
Session->Descriptor.Send.RingSize = RingSize;
|
||||||
s->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion;
|
Session->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion;
|
||||||
s->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
|
Session->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
|
||||||
if (!s->Descriptor.Send.TailMoved)
|
if (!Session->Descriptor.Send.TailMoved)
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to create send event");
|
LastError = LOG_LAST_ERROR(L"Failed to create send event");
|
||||||
goto cleanupToken;
|
goto cleanupToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->Descriptor.Receive.RingSize = RingSize;
|
Session->Descriptor.Receive.RingSize = RingSize;
|
||||||
s->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize);
|
Session->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize);
|
||||||
s->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
|
Session->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
|
||||||
if (!s->Descriptor.Receive.TailMoved)
|
if (!Session->Descriptor.Receive.TailMoved)
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to create receive event");
|
LastError = LOG_LAST_ERROR(L"Failed to create receive event");
|
||||||
goto cleanupSendTailMoved;
|
goto cleanupSendTailMoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = WintunOpenAdapterDeviceObject(Adapter, &s->Handle);
|
Session->Handle = WintunOpenAdapterDeviceObject(Adapter);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (Session->Handle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
LOG(WINTUN_LOG_ERR, L"Failed to open adapter device object");
|
LastError = LOG(WINTUN_LOG_ERR, L"Failed to open adapter device object");
|
||||||
goto cleanupReceiveTailMoved;
|
goto cleanupReceiveTailMoved;
|
||||||
}
|
}
|
||||||
DWORD BytesReturned;
|
DWORD BytesReturned;
|
||||||
if (!DeviceIoControl(
|
if (!DeviceIoControl(
|
||||||
s->Handle,
|
Session->Handle,
|
||||||
TUN_IOCTL_REGISTER_RINGS,
|
TUN_IOCTL_REGISTER_RINGS,
|
||||||
&s->Descriptor,
|
&Session->Descriptor,
|
||||||
sizeof(TUN_REGISTER_RINGS),
|
sizeof(TUN_REGISTER_RINGS),
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
&BytesReturned,
|
&BytesReturned,
|
||||||
NULL))
|
NULL))
|
||||||
{
|
{
|
||||||
Result = LOG_LAST_ERROR(L"Failed to register rings");
|
LastError = LOG_LAST_ERROR(L"Failed to register rings");
|
||||||
goto cleanupHandle;
|
goto cleanupHandle;
|
||||||
}
|
}
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
s->Capacity = Capacity;
|
Session->Capacity = Capacity;
|
||||||
(void)InitializeCriticalSectionAndSpinCount(&s->Receive.Lock, LOCK_SPIN_COUNT);
|
(void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
|
||||||
(void)InitializeCriticalSectionAndSpinCount(&s->Send.Lock, LOCK_SPIN_COUNT);
|
(void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
|
||||||
*Session = s;
|
return Session;
|
||||||
return ERROR_SUCCESS;
|
|
||||||
cleanupHandle:
|
cleanupHandle:
|
||||||
CloseHandle(s->Handle);
|
CloseHandle(Session->Handle);
|
||||||
cleanupReceiveTailMoved:
|
cleanupReceiveTailMoved:
|
||||||
CloseHandle(s->Descriptor.Receive.TailMoved);
|
CloseHandle(Session->Descriptor.Receive.TailMoved);
|
||||||
cleanupSendTailMoved:
|
cleanupSendTailMoved:
|
||||||
CloseHandle(s->Descriptor.Send.TailMoved);
|
CloseHandle(Session->Descriptor.Send.TailMoved);
|
||||||
cleanupToken:
|
cleanupToken:
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
cleanupAllocatedRegion:
|
cleanupAllocatedRegion:
|
||||||
VirtualFree(AllocatedRegion, 0, MEM_RELEASE);
|
VirtualFree(AllocatedRegion, 0, MEM_RELEASE);
|
||||||
cleanupRings:
|
cleanupRings:
|
||||||
HeapFree(ModuleHeap, 0, s);
|
HeapFree(ModuleHeap, 0, Session);
|
||||||
return Result;
|
out:
|
||||||
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WINAPI
|
void WINAPI
|
||||||
@ -170,53 +171,55 @@ WintunGetReadWaitEvent(_In_ TUN_SESSION *Session)
|
|||||||
return Session->Descriptor.Send.TailMoved;
|
return Session->Descriptor.Send.TailMoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS WINAPI
|
_Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI
|
||||||
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_bytecapcount_(*PacketSize) BYTE **Packet, _Out_ DWORD *PacketSize)
|
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize)
|
||||||
{
|
{
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
EnterCriticalSection(&Session->Send.Lock);
|
EnterCriticalSection(&Session->Send.Lock);
|
||||||
if (Session->Send.Head >= Session->Capacity)
|
if (Session->Send.Head >= Session->Capacity)
|
||||||
{
|
{
|
||||||
Result = ERROR_HANDLE_EOF;
|
LastError = ERROR_HANDLE_EOF;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
const ULONG BuffTail = ReadULongAcquire(&Session->Descriptor.Send.Ring->Tail);
|
const ULONG BuffTail = ReadULongAcquire(&Session->Descriptor.Send.Ring->Tail);
|
||||||
if (BuffTail >= Session->Capacity)
|
if (BuffTail >= Session->Capacity)
|
||||||
{
|
{
|
||||||
Result = ERROR_HANDLE_EOF;
|
LastError = ERROR_HANDLE_EOF;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (Session->Send.Head == BuffTail)
|
if (Session->Send.Head == BuffTail)
|
||||||
{
|
{
|
||||||
Result = ERROR_NO_MORE_ITEMS;
|
LastError = ERROR_NO_MORE_ITEMS;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
const ULONG BuffContent = TUN_RING_WRAP(BuffTail - Session->Send.Head, Session->Capacity);
|
const ULONG BuffContent = TUN_RING_WRAP(BuffTail - Session->Send.Head, Session->Capacity);
|
||||||
if (BuffContent < sizeof(TUN_PACKET))
|
if (BuffContent < sizeof(TUN_PACKET))
|
||||||
{
|
{
|
||||||
Result = ERROR_INVALID_DATA;
|
LastError = ERROR_INVALID_DATA;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.Head];
|
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.Head];
|
||||||
if (BuffPacket->Size > WINTUN_MAX_IP_PACKET_SIZE)
|
if (BuffPacket->Size > WINTUN_MAX_IP_PACKET_SIZE)
|
||||||
{
|
{
|
||||||
Result = ERROR_INVALID_DATA;
|
LastError = ERROR_INVALID_DATA;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
|
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
|
||||||
if (AlignedPacketSize > BuffContent)
|
if (AlignedPacketSize > BuffContent)
|
||||||
{
|
{
|
||||||
Result = ERROR_INVALID_DATA;
|
LastError = ERROR_INVALID_DATA;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
*PacketSize = BuffPacket->Size;
|
*PacketSize = BuffPacket->Size;
|
||||||
*Packet = BuffPacket->Data;
|
BYTE *Packet = BuffPacket->Data;
|
||||||
Session->Send.Head = TUN_RING_WRAP(Session->Send.Head + AlignedPacketSize, Session->Capacity);
|
Session->Send.Head = TUN_RING_WRAP(Session->Send.Head + AlignedPacketSize, Session->Capacity);
|
||||||
Session->Send.PacketsToRelease++;
|
Session->Send.PacketsToRelease++;
|
||||||
Result = ERROR_SUCCESS;
|
LeaveCriticalSection(&Session->Send.Lock);
|
||||||
|
return Packet;
|
||||||
cleanup:
|
cleanup:
|
||||||
LeaveCriticalSection(&Session->Send.Lock);
|
LeaveCriticalSection(&Session->Send.Lock);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WINAPI
|
void WINAPI
|
||||||
@ -238,38 +241,40 @@ WintunReceiveRelease(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
|
|||||||
LeaveCriticalSection(&Session->Send.Lock);
|
LeaveCriticalSection(&Session->Send.Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS WINAPI
|
_Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI
|
||||||
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize, _Out_bytecapcount_(PacketSize) BYTE **Packet)
|
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize)
|
||||||
{
|
{
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
EnterCriticalSection(&Session->Receive.Lock);
|
EnterCriticalSection(&Session->Receive.Lock);
|
||||||
if (Session->Receive.Tail >= Session->Capacity)
|
if (Session->Receive.Tail >= Session->Capacity)
|
||||||
{
|
{
|
||||||
Result = ERROR_HANDLE_EOF;
|
LastError = ERROR_HANDLE_EOF;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
|
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
|
||||||
const ULONG BuffHead = ReadULongAcquire(&Session->Descriptor.Receive.Ring->Head);
|
const ULONG BuffHead = ReadULongAcquire(&Session->Descriptor.Receive.Ring->Head);
|
||||||
if (BuffHead >= Session->Capacity)
|
if (BuffHead >= Session->Capacity)
|
||||||
{
|
{
|
||||||
Result = ERROR_HANDLE_EOF;
|
LastError = ERROR_HANDLE_EOF;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
const ULONG BuffSpace = TUN_RING_WRAP(BuffHead - Session->Receive.Tail - TUN_ALIGNMENT, Session->Capacity);
|
const ULONG BuffSpace = TUN_RING_WRAP(BuffHead - Session->Receive.Tail - TUN_ALIGNMENT, Session->Capacity);
|
||||||
if (AlignedPacketSize > BuffSpace)
|
if (AlignedPacketSize > BuffSpace)
|
||||||
{
|
{
|
||||||
Result = ERROR_BUFFER_OVERFLOW;
|
LastError = ERROR_BUFFER_OVERFLOW;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.Tail];
|
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.Tail];
|
||||||
BuffPacket->Size = PacketSize | TUN_PACKET_RELEASE;
|
BuffPacket->Size = PacketSize | TUN_PACKET_RELEASE;
|
||||||
*Packet = BuffPacket->Data;
|
BYTE *Packet = BuffPacket->Data;
|
||||||
Session->Receive.Tail = TUN_RING_WRAP(Session->Receive.Tail + AlignedPacketSize, Session->Capacity);
|
Session->Receive.Tail = TUN_RING_WRAP(Session->Receive.Tail + AlignedPacketSize, Session->Capacity);
|
||||||
Session->Receive.PacketsToRelease++;
|
Session->Receive.PacketsToRelease++;
|
||||||
Result = ERROR_SUCCESS;
|
LeaveCriticalSection(&Session->Receive.Lock);
|
||||||
|
return Packet;
|
||||||
cleanup:
|
cleanup:
|
||||||
LeaveCriticalSection(&Session->Receive.Lock);
|
LeaveCriticalSection(&Session->Receive.Lock);
|
||||||
return Result;
|
SetLastError(LastError);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WINAPI
|
void WINAPI
|
||||||
|
131
api/wintun.h
131
api/wintun.h
@ -13,8 +13,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef _Return_type_success_(return == ERROR_SUCCESS) DWORD WINTUN_STATUS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handle representing Wintun adapter
|
* A handle representing Wintun adapter
|
||||||
*/
|
*/
|
||||||
@ -33,24 +31,20 @@ typedef void *WINTUN_ADAPTER_HANDLE;
|
|||||||
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
|
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
|
||||||
* characters.
|
* characters.
|
||||||
*
|
*
|
||||||
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation
|
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically.
|
||||||
* deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence
|
* If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is
|
||||||
* a new NLA entry is created for each new adapter. It is called "requested" GUID because the API
|
* created for each new adapter. It is called "requested" GUID because the API it uses is
|
||||||
* it uses is completely undocumented, and so there could be minor interesting complications with
|
* completely undocumented, and so there could be minor interesting complications with its usage.
|
||||||
* its usage.
|
|
||||||
*
|
|
||||||
* @param Adapter Pointer to a handle to receive the adapter handle. Must be released with
|
|
||||||
* WintunFreeAdapter.
|
|
||||||
*
|
*
|
||||||
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
|
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. If
|
||||||
|
* the function fails, the return value is NULL. To get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
|
typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE *(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
|
||||||
_In_z_ const WCHAR *Pool,
|
_In_z_ const WCHAR *Pool,
|
||||||
_In_z_ const WCHAR *Name,
|
_In_z_ const WCHAR *Name,
|
||||||
_In_opt_ const GUID *RequestedGUID,
|
_In_opt_ const GUID *RequestedGUID,
|
||||||
_Out_ WINTUN_ADAPTER_HANDLE *Adapter,
|
|
||||||
_Out_opt_ BOOL *RebootRequired);
|
_Out_opt_ BOOL *RebootRequired);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,9 +58,10 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
|
|||||||
*
|
*
|
||||||
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
|
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success or the adapter was not found; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
|
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
|
||||||
_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
||||||
_In_ BOOL ForceCloseSessions,
|
_In_ BOOL ForceCloseSessions,
|
||||||
_Out_opt_ BOOL *RebootRequired);
|
_Out_opt_ BOOL *RebootRequired);
|
||||||
@ -79,11 +74,11 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
|
|||||||
*
|
*
|
||||||
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
|
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(
|
typedef _Return_type_success_(return != FALSE)
|
||||||
_In_z_ const WCHAR Pool[WINTUN_MAX_POOL],
|
BOOL(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
|
||||||
_Out_opt_ BOOL *RebootRequired);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by WintunEnumAdapters for each adapter in the pool.
|
* Called by WintunEnumAdapters for each adapter in the pool.
|
||||||
@ -106,9 +101,10 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ada
|
|||||||
*
|
*
|
||||||
* @param Param An application-defined value to be passed to the callback function.
|
* @param Param An application-defined value to be passed to the callback function.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(
|
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(
|
||||||
_In_z_ const WCHAR *Pool,
|
_In_z_ const WCHAR *Pool,
|
||||||
_In_ WINTUN_ENUM_CALLBACK_FUNC Callback,
|
_In_ WINTUN_ENUM_CALLBACK_FUNC Callback,
|
||||||
_In_ LPARAM Param);
|
_In_ LPARAM Param);
|
||||||
@ -127,27 +123,26 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte
|
|||||||
*
|
*
|
||||||
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
|
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
|
||||||
*
|
*
|
||||||
* @param Adapter Pointer to a handle to receive the adapter handle. Must be released with WintunFreeAdapter.
|
* @return 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
|
||||||
* @return ERROR_SUCCESS on success; ERROR_FILE_NOT_FOUND if adapter with given name is not found; ERROR_ALREADY_EXISTS
|
* errors include the following:
|
||||||
* if adapter is found but not a Wintun-class or not a member of the pool; Win32 error code otherwise
|
* ERROR_FILE_NOT_FOUND if adapter with given name is not found;
|
||||||
|
* ERROR_ALREADY_EXISTS if adapter is found but not a Wintun-class or not a member of the pool
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_FUNC)(
|
typedef _Return_type_success_(return != NULL)
|
||||||
_In_z_ const WCHAR *Pool,
|
WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_GET_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name);
|
||||||
_In_z_ const WCHAR *Name,
|
|
||||||
_Out_ WINTUN_ADAPTER_HANDLE *Adapter);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a handle to the adapter device object.
|
* Returns a handle to the adapter device object.
|
||||||
*
|
*
|
||||||
* @param Adapter Adapter handle obtained with WintunGetAdapter or WintunCreateAdapter.
|
* @param Adapter Adapter handle obtained with WintunGetAdapter or WintunCreateAdapter.
|
||||||
*
|
*
|
||||||
* @param Handle Pointer to receive the adapter device object handle. Must be released with CloseHandle.
|
* @return 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 ERROR_SUCCESS on success; Win32 error code otherwise.
|
* information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(
|
typedef _Return_type_success_(return != INVALID_HANDLE_VALUE)
|
||||||
WINAPI *WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ HANDLE *Handle);
|
HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the LUID of the adapter.
|
* Returns the LUID of the adapter.
|
||||||
@ -165,9 +160,10 @@ typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ad
|
|||||||
*
|
*
|
||||||
* @param Name Pointer to a string to receive adapter name
|
* @param Name Pointer to a string to receive adapter name
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)(
|
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)(
|
||||||
_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
||||||
_Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name);
|
_Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name);
|
||||||
|
|
||||||
@ -178,15 +174,19 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)(
|
|||||||
*
|
*
|
||||||
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
|
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
|
||||||
*
|
*
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||||
|
* get extended error information, call GetLastError.
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(
|
typedef _Return_type_success_(return != FALSE)
|
||||||
WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name);
|
BOOL(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the version of the Wintun driver currently loaded.
|
* Determines the version of the Wintun driver currently loaded.
|
||||||
*
|
*
|
||||||
* @return The version number on success, or 0 if failure or Wintun not loaded.
|
* @return If the function succeeds, the return value is the version number. If the function fails, the return value is
|
||||||
|
* zero. To get extended error information, call GetLastError. Possible errors include the following:
|
||||||
|
* ERROR_FILE_NOT_FOUND Wintun not loaded;
|
||||||
|
* ERROR_GEN_FAILURE Enumerating drivers failed
|
||||||
*/
|
*/
|
||||||
typedef DWORD(WINAPI *WINTUN_GET_VERSION_FUNC)(void);
|
typedef DWORD(WINAPI *WINTUN_GET_VERSION_FUNC)(void);
|
||||||
|
|
||||||
@ -240,14 +240,11 @@ typedef void *WINTUN_SESSION_HANDLE;
|
|||||||
* @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.)
|
* @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.)
|
||||||
* Must be a power of two.
|
* Must be a power of two.
|
||||||
*
|
*
|
||||||
* @param Session Pointer to a variable to receive 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.
|
||||||
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
|
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_START_SESSION_FUNC)(
|
typedef _Return_type_success_(return != NULL)
|
||||||
_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
|
||||||
_In_ DWORD Capacity,
|
|
||||||
_Out_ WINTUN_SESSION_HANDLE *Session);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ends Wintun session.
|
* Ends Wintun session.
|
||||||
@ -279,22 +276,17 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND
|
|||||||
*
|
*
|
||||||
* @param Session Wintun session handle obtained with WintunStartSession
|
* @param Session Wintun session handle obtained with WintunStartSession
|
||||||
*
|
*
|
||||||
* @param Packet Pointer to receive pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at
|
* @param PacketSize Pointer to receive packet size.
|
||||||
* will.
|
|
||||||
*
|
*
|
||||||
* @param PacketSize Pointer to receive Packet size.
|
* @return Pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at will. If the function fails, the
|
||||||
*
|
* return value is NULL. To get extended error information, call GetLastError. Possible errors include the
|
||||||
* @return Returns one of the following values:
|
* following:
|
||||||
* ERROR_HANDLE_EOF Wintun adapter is terminating;
|
* ERROR_HANDLE_EOF Wintun adapter is terminating;
|
||||||
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
|
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
|
||||||
* ERROR_INVALID_DATA Wintun buffer is corrupt;
|
* ERROR_INVALID_DATA Wintun buffer is corrupt
|
||||||
* ERROR_SUCCESS on success.
|
|
||||||
* Regardless, if the error was returned, some packets might have been read nevertheless.
|
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(
|
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *(
|
||||||
_In_ WINTUN_SESSION_HANDLE *Session,
|
WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _Out_ DWORD *PacketSize);
|
||||||
_Out_bytecapcount_(*PacketSize) BYTE **Packet,
|
|
||||||
_Out_ DWORD *PacketSize);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
|
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
|
||||||
@ -314,17 +306,14 @@ typedef void(WINAPI *WINTUN_RECEIVE_RELEASE_FUNC)(_In_ WINTUN_SESSION_HANDLE *Se
|
|||||||
*
|
*
|
||||||
* @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
|
* @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
|
||||||
*
|
*
|
||||||
* @param Packet Pointer to receive pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending.
|
* @return Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails,
|
||||||
*
|
* the return value is NULL. To get extended error information, call GetLastError. Possible errors include the
|
||||||
* @return Returns one of the following values:
|
* following:
|
||||||
* ERROR_HANDLE_EOF Wintun adapter is terminating;
|
* ERROR_HANDLE_EOF Wintun adapter is terminating;
|
||||||
* ERROR_BUFFER_OVERFLOW Wintun buffer is full;
|
* ERROR_BUFFER_OVERFLOW Wintun buffer is full;
|
||||||
* ERROR_SUCCESS on success.
|
|
||||||
*/
|
*/
|
||||||
typedef WINTUN_STATUS(WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(
|
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *(
|
||||||
_In_ WINTUN_SESSION_HANDLE *Session,
|
WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _In_ DWORD PacketSize);
|
||||||
_In_ DWORD PacketSize,
|
|
||||||
_Out_bytecapcount_(PacketSize) BYTE **Packet);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
|
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
|
||||||
|
@ -100,6 +100,15 @@ LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error)
|
|||||||
return Error;
|
return Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD
|
||||||
|
LogLastError(_In_z_ const WCHAR *Prefix)
|
||||||
|
{
|
||||||
|
DWORD LastError = GetLastError();
|
||||||
|
LogError(Prefix, LastError);
|
||||||
|
SetLastError(LastError);
|
||||||
|
return LastError;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
|
Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
|
||||||
{
|
{
|
||||||
@ -206,22 +215,26 @@ ReceivePackets(_Inout_ DWORD_PTR SessionPtr)
|
|||||||
|
|
||||||
while (!HaveQuit)
|
while (!HaveQuit)
|
||||||
{
|
{
|
||||||
BYTE *Packet;
|
|
||||||
DWORD PacketSize;
|
DWORD PacketSize;
|
||||||
DWORD Result = WintunReceivePacket(Session, &Packet, &PacketSize);
|
BYTE *Packet = WintunReceivePacket(Session, &PacketSize);
|
||||||
switch (Result)
|
if (Packet)
|
||||||
{
|
{
|
||||||
case ERROR_SUCCESS:
|
|
||||||
PrintPacket(Packet, PacketSize);
|
PrintPacket(Packet, PacketSize);
|
||||||
WintunReceiveRelease(Session, Packet);
|
WintunReceiveRelease(Session, Packet);
|
||||||
continue;
|
}
|
||||||
case ERROR_NO_MORE_ITEMS:
|
else
|
||||||
if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
|
{
|
||||||
continue;
|
DWORD LastError = GetLastError();
|
||||||
return ERROR_SUCCESS;
|
switch (LastError)
|
||||||
default:
|
{
|
||||||
LogError(L"Packet read failed", Result);
|
case ERROR_NO_MORE_ITEMS:
|
||||||
return Result;
|
if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
|
||||||
|
continue;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
default:
|
||||||
|
LogError(L"Packet read failed", LastError);
|
||||||
|
return LastError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
@ -233,8 +246,9 @@ SendPackets(_Inout_ DWORD_PTR SessionPtr)
|
|||||||
WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr;
|
WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr;
|
||||||
while (!HaveQuit)
|
while (!HaveQuit)
|
||||||
{
|
{
|
||||||
BYTE *Packet;
|
BYTE *Packet = WintunAllocateSendPacket(Session, 28);
|
||||||
WintunAllocateSendPacket(Session, 28, &Packet);
|
if (!Packet)
|
||||||
|
return LogLastError(L"Packet write failed");
|
||||||
MakeICMP(Packet);
|
MakeICMP(Packet);
|
||||||
WintunSendPacket(Session, Packet);
|
WintunSendPacket(Session, Packet);
|
||||||
|
|
||||||
@ -269,9 +283,9 @@ InitializeWintun(void)
|
|||||||
X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
|
X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
|
||||||
#undef X
|
#undef X
|
||||||
{
|
{
|
||||||
DWORD Result = GetLastError();
|
DWORD LastError = GetLastError();
|
||||||
FreeLibrary(Wintun);
|
FreeLibrary(Wintun);
|
||||||
SetLastError(Result);
|
SetLastError(LastError);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
SetLastError(ERROR_SUCCESS);
|
SetLastError(ERROR_SUCCESS);
|
||||||
@ -287,29 +301,31 @@ main(void)
|
|||||||
WintunSetLogger(ConsoleLogger);
|
WintunSetLogger(ConsoleLogger);
|
||||||
Log(WINTUN_LOG_INFO, L"Wintun library loaded");
|
Log(WINTUN_LOG_INFO, L"Wintun library loaded");
|
||||||
|
|
||||||
DWORD Result;
|
DWORD LastError;
|
||||||
HaveQuit = FALSE;
|
HaveQuit = FALSE;
|
||||||
QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||||
if (!QuitEvent)
|
if (!QuitEvent)
|
||||||
{
|
{
|
||||||
Result = LogError(L"Failed to create event", GetLastError());
|
LastError = LogError(L"Failed to create event", GetLastError());
|
||||||
goto cleanupWintun;
|
goto cleanupWintun;
|
||||||
}
|
}
|
||||||
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
|
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
|
||||||
{
|
{
|
||||||
Result = LogError(L"Failed to set console handler", GetLastError());
|
LastError = LogError(L"Failed to set console handler", GetLastError());
|
||||||
goto cleanupQuit;
|
goto cleanupQuit;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
|
GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
|
||||||
WINTUN_ADAPTER_HANDLE Adapter;
|
WINTUN_ADAPTER_HANDLE Adapter = WintunGetAdapter(L"Example", L"Demo");
|
||||||
Result = WintunGetAdapter(L"Example", L"Demo", &Adapter);
|
if (!Adapter)
|
||||||
if (Result != ERROR_SUCCESS)
|
|
||||||
Result = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, &Adapter, NULL);
|
|
||||||
if (Result != ERROR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
LogError(L"Failed to create adapter", Result);
|
Adapter = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, NULL);
|
||||||
goto cleanupQuit;
|
if (!Adapter)
|
||||||
|
{
|
||||||
|
LastError = GetLastError();
|
||||||
|
LogError(L"Failed to create adapter", LastError);
|
||||||
|
goto cleanupQuit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD Version = WintunGetVersion();
|
DWORD Version = WintunGetVersion();
|
||||||
@ -321,18 +337,17 @@ main(void)
|
|||||||
AddressRow.Address.Ipv4.sin_family = AF_INET;
|
AddressRow.Address.Ipv4.sin_family = AF_INET;
|
||||||
AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
|
AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
|
||||||
AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
|
AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
|
||||||
Result = CreateUnicastIpAddressEntry(&AddressRow);
|
LastError = CreateUnicastIpAddressEntry(&AddressRow);
|
||||||
if (Result != ERROR_SUCCESS && Result != ERROR_OBJECT_ALREADY_EXISTS)
|
if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
|
||||||
{
|
{
|
||||||
LogError(L"Failed to set IP address", Result);
|
LogError(L"Failed to set IP address", LastError);
|
||||||
goto cleanupAdapter;
|
goto cleanupAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_SESSION_HANDLE Session;
|
WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x40000);
|
||||||
Result = WintunStartSession(Adapter, 0x40000, &Session);
|
if (!Session)
|
||||||
if (Result != ERROR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
LogError(L"Failed to create adapter", Result);
|
LastError = LogLastError(L"Failed to create adapter");
|
||||||
goto cleanupAdapter;
|
goto cleanupAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,11 +357,11 @@ main(void)
|
|||||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };
|
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };
|
||||||
if (!Workers[0] || !Workers[1])
|
if (!Workers[0] || !Workers[1])
|
||||||
{
|
{
|
||||||
Result = LogError(L"Failed to create threads", GetLastError());
|
LastError = LogError(L"Failed to create threads", GetLastError());
|
||||||
goto cleanupWorkers;
|
goto cleanupWorkers;
|
||||||
}
|
}
|
||||||
WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);
|
WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);
|
||||||
Result = ERROR_SUCCESS;
|
LastError = ERROR_SUCCESS;
|
||||||
|
|
||||||
cleanupWorkers:
|
cleanupWorkers:
|
||||||
HaveQuit = TRUE;
|
HaveQuit = TRUE;
|
||||||
@ -368,5 +383,5 @@ cleanupQuit:
|
|||||||
CloseHandle(QuitEvent);
|
CloseHandle(QuitEvent);
|
||||||
cleanupWintun:
|
cleanupWintun:
|
||||||
FreeLibrary(Wintun);
|
FreeLibrary(Wintun);
|
||||||
return Result;
|
return LastError;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user