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