diff options
author | 2021-10-04 00:54:24 +0000 | |
---|---|---|
committer | 2021-10-06 05:16:14 +0000 | |
commit | c8ee696db51b70ef87386f083dbdf99e7051c85f (patch) | |
tree | f4d045e5d81b1acadb5e334cd700d959db236302 | |
parent | api: logger: remove function prefixes (diff) | |
download | wireguard-nt-c8ee696db51b70ef87386f083dbdf99e7051c85f.tar.xz wireguard-nt-c8ee696db51b70ef87386f083dbdf99e7051c85f.zip |
api: adapter: get rid of registry polling on Win8+
Wait for the device to come up as enabled instead using the proper Win8+
API. Fall back to polling for Win7.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | api/adapter.c | 258 | ||||
-rw-r--r-- | api/api.vcxproj | 4 | ||||
-rw-r--r-- | api/main.c | 7 | ||||
-rw-r--r-- | api/main.h | 2 | ||||
-rw-r--r-- | api/ntdll.h | 1 | ||||
-rw-r--r-- | api/registry.c | 199 | ||||
-rw-r--r-- | api/registry.h | 62 |
7 files changed, 190 insertions, 343 deletions
diff --git a/api/adapter.c b/api/adapter.c index 42b191f..0775e12 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -18,6 +18,15 @@ #include <initguid.h> /* Keep these two at bottom in this order, so that we only generate extra GUIDs for devpkey. The other keys we'll get from uuid.lib like usual. */ #include <devpkey.h> +/* We pretend we're Windows 8, and then hack around the limitation in Windows 7 below. */ +#if NTDDI_VERSION == NTDDI_WIN7 +# undef NTDDI_VERSION +# define NTDDI_VERSION NTDDI_WIN8 +# include <devquery.h> +# undef NTDDI_VERSION +# define NTDDI_VERSION NTDDI_WIN7 +#endif + #include "../driver/ioctl.h" #include "adapter.h" #include "logger.h" @@ -32,7 +41,6 @@ #pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ -#define WAIT_FOR_REGISTRY_TIMEOUT 10000 /* ms */ #define MAX_POOL_DEVICE_TYPE (WIREGUARD_MAX_POOL + 8) /* Should accommodate a pool name with " Tunnel" appended */ static const DEVPROPKEY DEVPKEY_WireGuard_Pool = { @@ -1339,6 +1347,147 @@ cleanup: return RET_ERROR(Adapter, LastError); } +typedef struct _WAIT_FOR_INTERFACE_CTX +{ + HANDLE Event; + DWORD LastError; +} WAIT_FOR_INTERFACE_CTX; + +static VOID WINAPI +WaitForInterfaceCallback( + _In_ HDEVQUERY DevQuery, + _Inout_ PVOID Context, + _In_ const DEV_QUERY_RESULT_ACTION_DATA *ActionData) +{ + WAIT_FOR_INTERFACE_CTX *Ctx = Context; + Ctx->LastError = ERROR_SUCCESS; + if (ActionData->Action == DevQueryResultStateChange) + { + if (ActionData->Data.State != DevQueryStateAborted) + return; + Ctx->LastError = ERROR_DEVICE_NOT_AVAILABLE; + } + else if (ActionData->Action == DevQueryResultRemove) + return; + SetEvent(Ctx->Event); +} + +#if NTDDI_VERSION == NTDDI_WIN7 +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +WaitForInterfaceWin7(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +{ + ULONG Status, Number; + DWORD ValType, Zero; + HKEY Key = INVALID_HANDLE_VALUE; + BOOLEAN Ret = FALSE; + for (int i = 0; i < 1500; ++i) + { + if (i) + Sleep(10); + if (Key == INVALID_HANDLE_VALUE) + { + Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + if (Key == INVALID_HANDLE_VALUE) + continue; + } + _Analysis_assume_(Key); + Zero = 0; + if (RegQueryValueExW(Key, L"NetCfgInstanceId", NULL, &ValType, NULL, &Zero) != ERROR_MORE_DATA && + CM_Get_DevNode_Status(&Status, &Number, DevInfoData->DevInst, 0) == CR_SUCCESS && + !(Status & DN_HAS_PROBLEM) && !Number) + { + Ret = TRUE; + break; + } + } + if (Key != INVALID_HANDLE_VALUE) + RegCloseKey(Key); + return Ret; +} +#endif + +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +WaitForInterface(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) +{ +#if NTDDI_VERSION == NTDDI_WIN7 + if (IsWindows7) + return WaitForInterfaceWin7(DevInfo, DevInfoData); +#endif + + DWORD LastError = ERROR_SUCCESS, Size; + WCHAR InstanceId[MAX_INSTANCE_ID]; + if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, _countof(InstanceId), &Size)) + { + LastError = LOG_LAST_ERROR(L"Failed to get adapter %u instance ID", DevInfoData->DevInst); + goto cleanup; + } + + static const DEVPROP_BOOLEAN DevPropTrue = DEVPROP_TRUE; + const DEVPROP_FILTER_EXPRESSION Filters[] = { { .Operator = DEVPROP_OPERATOR_EQUALS_IGNORE_CASE, + .Property.CompKey.Key = DEVPKEY_Device_InstanceId, + .Property.CompKey.Store = DEVPROP_STORE_SYSTEM, + .Property.Type = DEVPROP_TYPE_STRING, + .Property.Buffer = InstanceId, + .Property.BufferSize = + (ULONG)((wcslen(InstanceId) + 1) * sizeof(InstanceId[0])) }, + { .Operator = DEVPROP_OPERATOR_EQUALS, + .Property.CompKey.Key = DEVPKEY_DeviceInterface_Enabled, + .Property.CompKey.Store = DEVPROP_STORE_SYSTEM, + .Property.Type = DEVPROP_TYPE_BOOLEAN, + .Property.Buffer = (PVOID)&DevPropTrue, + .Property.BufferSize = sizeof(DevPropTrue) }, + { .Operator = DEVPROP_OPERATOR_EQUALS, + .Property.CompKey.Key = DEVPKEY_DeviceInterface_ClassGuid, + .Property.CompKey.Store = DEVPROP_STORE_SYSTEM, + .Property.Type = DEVPROP_TYPE_GUID, + .Property.Buffer = (PVOID)&GUID_DEVINTERFACE_NET, + .Property.BufferSize = sizeof(GUID_DEVINTERFACE_NET) } }; + WAIT_FOR_INTERFACE_CTX Ctx = { .Event = CreateEventW(NULL, FALSE, FALSE, NULL) }; + if (!Ctx.Event) + { + LastError = LOG_LAST_ERROR(L"Failed to create event"); + goto cleanup; + } + HDEVQUERY Query; + HRESULT HRet = DevCreateObjectQuery( + DevObjectTypeDeviceInterface, + DevQueryFlagUpdateResults, + 0, + NULL, + _countof(Filters), + Filters, + WaitForInterfaceCallback, + &Ctx, + &Query); + if (HRet < 0) + { + LastError = LOG_ERROR(HRet, L"Failed to create device query"); + goto cleanupEvent; + } + LastError = WaitForSingleObject(Ctx.Event, 15000); + if (LastError != WAIT_OBJECT_0) + { + if (LastError == WAIT_FAILED) + LastError = LOG_LAST_ERROR(L"Failed to wait for device query"); + else + LastError = LOG_ERROR(LastError, L"Timed out waiting for device query"); + goto cleanupQuery; + } + LastError = Ctx.LastError; + if (LastError != ERROR_SUCCESS) + LastError = LOG_ERROR(LastError, L"Failed to get enabled device"); +cleanupQuery: + DevCloseObjectQuery(Query); +cleanupEvent: + CloseHandle(Ctx.Event); +cleanup: + return RET_ERROR(TRUE, LastError); +} + _Use_decl_annotations_ WIREGUARD_ADAPTER_HANDLE WINAPI WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) @@ -1441,51 +1590,51 @@ WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, Adapter->DevInfo, &Adapter->DevInfoData)) LOG_LAST_ERROR(L"Failed to register adapter %u coinstallers", Adapter->DevInfoData.DevInst); - HKEY NetDevRegKey = INVALID_HANDLE_VALUE; - const int PollTimeout = 50 /* ms */; - for (int i = 0; NetDevRegKey == INVALID_HANDLE_VALUE && i < WAIT_FOR_REGISTRY_TIMEOUT / PollTimeout; ++i) - { - if (i) - Sleep(PollTimeout); - NetDevRegKey = SetupDiOpenDevRegKey( - Adapter->DevInfo, - &Adapter->DevInfoData, - DICS_FLAG_GLOBAL, - 0, - DIREG_DRV, - KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY); - } - if (NetDevRegKey == INVALID_HANDLE_VALUE) - { - LastError = - LOG_LAST_ERROR(L"Failed to open adapter %u device-specific registry key", Adapter->DevInfoData.DevInst); - goto cleanupDevice; - } if (RequestedGUID) { + HKEY NetDevRegKey = INVALID_HANDLE_VALUE; + for (int i = 0; NetDevRegKey == INVALID_HANDLE_VALUE && i < 1000; ++i) + { + if (i) + Sleep(10); + NetDevRegKey = SetupDiOpenDevRegKey( + Adapter->DevInfo, + &Adapter->DevInfoData, + DICS_FLAG_GLOBAL, + 0, + DIREG_DRV, + KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY); + } + if (NetDevRegKey == INVALID_HANDLE_VALUE) + { + LastError = + LOG_LAST_ERROR(L"Failed to open adapter %u device-specific registry key", Adapter->DevInfoData.DevInst); + goto cleanupDevice; + } LastError = RegSetValueExW( NetDevRegKey, L"SuggestedInstanceId", 0, REG_BINARY, (const BYTE *)RequestedGUID, sizeof(*RequestedGUID)); + RegCloseKey(NetDevRegKey); if (LastError != ERROR_SUCCESS) { WCHAR RegPath[MAX_REG_PATH]; LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); LOG_ERROR(LastError, L"Failed to set %.*s\\SuggestedInstanceId", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; + goto cleanupDevice; } } if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, Adapter->DevInfo, &Adapter->DevInfoData)) LOG_LAST_ERROR(L"Failed to install adapter %u interfaces", Adapter->DevInfoData.DevInst); - if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, Adapter->DevInfo, &Adapter->DevInfoData)) { LastError = LOG_LAST_ERROR(L"Failed to install adapter %u device", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; + goto cleanupDevice; } + if (CheckReboot(Adapter->DevInfo, &Adapter->DevInfoData)) { LastError = ERROR_PNP_REBOOT_REQUIRED; - goto cleanupNetDevRegKey; + goto cleanupDevice; } if (!SetupDiSetDevicePropertyW( @@ -1499,7 +1648,7 @@ WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) 0)) { LastError = LOG_LAST_ERROR(L"Failed to set adapter %u pool", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; + goto cleanupDevice; } if (!SetupDiSetDeviceRegistryPropertyW( Adapter->DevInfo, @@ -1509,15 +1658,14 @@ WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) (DWORD)((wcslen(PoolDeviceTypeName) + 1) * sizeof(*PoolDeviceTypeName)))) { LastError = LOG_LAST_ERROR(L"Failed to set adapter %u description", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; + goto cleanupDevice; } - for (int Tries = 0; Tries < 1000; ++Tries) + if (!WaitForInterface(Adapter->DevInfo, &Adapter->DevInfoData)) { DEVPROPTYPE PropertyType = 0; NTSTATUS NtStatus = 0; INT32 ProblemCode = 0; - if (!SetupDiGetDevicePropertyW( Adapter->DevInfo, &Adapter->DevInfoData, @@ -1540,72 +1688,32 @@ WireGuardCreateAdapter(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID) 0) || (PropertyType != DEVPROP_TYPE_INT32 && PropertyType != DEVPROP_TYPE_UINT32)) ProblemCode = 0; - if (NtStatus == STATUS_PNP_DEVICE_CONFIGURATION_PENDING && Tries < 999) - { - Sleep(10); - continue; - } - if (NT_SUCCESS(NtStatus) && !ProblemCode) - break; LastError = RtlNtStatusToDosError(NtStatus); if (LastError == ERROR_SUCCESS) - LastError = ERROR_NOT_READY; - LOG_ERROR( - LastError, - L"Failed to setup adapter (problem code: 0x%x, ntstatus: 0x%x)", - ProblemCode, - NtStatus); - goto cleanupNetDevRegKey; - } - - /* DIF_INSTALLDEVICE returns almost immediately, while the device installation continues in the background. It might - * take a while, before all registry keys and values are populated. */ - LPWSTR DummyStr = RegistryQueryStringWait(NetDevRegKey, L"NetCfgInstanceId", WAIT_FOR_REGISTRY_TIMEOUT); - if (!DummyStr) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to get %.*s\\NetCfgInstanceId", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; - } - Free(DummyStr); - DWORD DummyDWORD; - if (!RegistryQueryDWORDWait(NetDevRegKey, L"NetLuidIndex", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD)) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to get %.*s\\NetLuidIndex", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; - } - if (!RegistryQueryDWORDWait(NetDevRegKey, L"*IfType", WAIT_FOR_REGISTRY_TIMEOUT, &DummyDWORD)) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(NetDevRegKey, RegPath); - LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to get %.*s\\*IfType", MAX_REG_PATH, RegPath); - goto cleanupNetDevRegKey; + LastError = ERROR_DEVICE_NOT_AVAILABLE; + LOG_ERROR(LastError, L"Failed to setup adapter (problem code: 0x%x, ntstatus: 0x%x)", ProblemCode, NtStatus); + goto cleanupDevice; } if (!PopulateAdapterData(Adapter, Pool)) { LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to populate adapter %u data", Adapter->DevInfoData.DevInst); - goto cleanupNetDevRegKey; + goto cleanupDevice; } if (!WireGuardSetAdapterName(Adapter, Name)) { LastError = LOG(WIREGUARD_LOG_ERR, L"Failed to set adapter name %s", Name); - goto cleanupNetDevRegKey; + goto cleanupDevice; } if (!EnsureDeviceObject(Adapter->DevInstanceID)) { LastError = LOG_LAST_ERROR(L"Device object file did not appear"); - goto cleanupNetDevRegKey; + goto cleanupDevice; } LastError = ERROR_SUCCESS; -cleanupNetDevRegKey: - RegCloseKey(NetDevRegKey); cleanupDevice: if (LastError != ERROR_SUCCESS) { diff --git a/api/api.vcxproj b/api/api.vcxproj index d805826..0c75dc8 100644 --- a/api/api.vcxproj +++ b/api/api.vcxproj @@ -34,8 +34,8 @@ <PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Link> - <DelayLoadDLLs>advapi32.dll;bcrypt.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll</DelayLoadDLLs> - <AdditionalDependencies>Bcrypt.lib;Cfgmgr32.lib;Iphlpapi.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies> + <DelayLoadDLLs>advapi32.dll;api-ms-win-devices-query-l1-1-0.dll;bcrypt.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll</DelayLoadDLLs> + <AdditionalDependencies>Bcrypt.lib;Cfgmgr32.lib;Iphlpapi.lib;onecore.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies> <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> <SubSystem>Windows</SubSystem> </Link> @@ -21,7 +21,7 @@ HANDLE ModuleHeap; SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) }; BOOL IsLocalSystem; USHORT NativeMachine = IMAGE_FILE_PROCESS; -BOOL IsWindows10; +BOOL IsWindows10, IsWindows7; static FARPROC WINAPI DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) @@ -72,9 +72,10 @@ cleanupProcessToken: static void EnvInit(VOID) { - DWORD MajorVersion; - RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL); + DWORD MajorVersion, MinorVersion; + RtlGetNtVersionNumbers(&MajorVersion, &MinorVersion, NULL); IsWindows10 = MajorVersion >= 10; + IsWindows7 = MajorVersion == 6 && MinorVersion == 1; #ifdef MAYBE_WOW64 typedef BOOL(WINAPI * IsWow64Process2_t)( @@ -24,4 +24,4 @@ extern HANDLE ModuleHeap; extern SECURITY_ATTRIBUTES SecurityAttributes; extern BOOL IsLocalSystem; extern USHORT NativeMachine; -extern BOOL IsWindows10;
\ No newline at end of file +extern BOOL IsWindows10, IsWindows7;
\ No newline at end of file diff --git a/api/ntdll.h b/api/ntdll.h index 3782a30..2eb2786 100644 --- a/api/ntdll.h +++ b/api/ntdll.h @@ -39,7 +39,6 @@ typedef struct _KEY_NAME_INFORMATION } KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION; #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) // TODO: #include <ntstatus.h> instead of this -#define STATUS_PNP_DEVICE_CONFIGURATION_PENDING ((NTSTATUS)0xC0000495L) /* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista * when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers. diff --git a/api/registry.c b/api/registry.c index 05a62a6..245d72f 100644 --- a/api/registry.c +++ b/api/registry.c @@ -10,100 +10,6 @@ #include <stdlib.h> #include <strsafe.h> -_Must_inspect_result_ -static _Return_type_success_(return != NULL) -_Post_maybenull_ -HKEY -OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline) -{ - DWORD LastError; - LPWSTR PathNext = wcschr(Path, L'\\'); - if (PathNext) - *PathNext = 0; - - HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!Event) - { - LOG_LAST_ERROR(L"Failed to create event"); - return NULL; - } - for (;;) - { - LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE); - if (LastError != ERROR_SUCCESS) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); - break; - } - - HKEY Subkey; - LastError = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey); - if (LastError == ERROR_SUCCESS) - { - if (PathNext) - { - HKEY KeyOut = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline); - if (KeyOut) - { - RegCloseKey(Subkey); - CloseHandle(Event); - return KeyOut; - } - LastError = GetLastError(); - break; - } - else - { - CloseHandle(Event); - return Subkey; - } - } - if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to open registry key %.*s\\%s", MAX_REG_PATH, RegPath, Path); - break; - } - - LONGLONG TimeLeft = Deadline - GetTickCount64(); - if (TimeLeft < 0) - TimeLeft = 0; - DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft); - if (Result != WAIT_OBJECT_0) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG(WIREGUARD_LOG_ERR, - L"Timeout waiting for registry key %.*s\\%s (status: 0x%x)", - MAX_REG_PATH, - RegPath, - Path, - Result); - break; - } - } - CloseHandle(Event); - SetLastError(LastError); - return NULL; -} - -_Use_decl_annotations_ -HKEY -RegistryOpenKeyWait(HKEY Key, LPCWSTR Path, DWORD Access, DWORD Timeout) -{ - WCHAR Buf[MAX_REG_PATH]; - if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE) - { - LOG(WIREGUARD_LOG_ERR, L"Registry path too long: %s", Path); - SetLastError(ERROR_INVALID_PARAMETER); - return NULL; - } - return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout); -} - _Use_decl_annotations_ BOOL RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType) @@ -257,59 +163,6 @@ RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log) } _Use_decl_annotations_ -LPWSTR -RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout) -{ - DWORD LastError; - ULONGLONG Deadline = GetTickCount64() + Timeout; - HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!Event) - { - LOG_LAST_ERROR(L"Failed to create event"); - return NULL; - } - for (;;) - { - LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); - if (LastError != ERROR_SUCCESS) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); - break; - } - LPWSTR 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) - TimeLeft = 0; - DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft); - if (Result != WAIT_OBJECT_0) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG(WIREGUARD_LOG_ERR, - L"Timeout waiting for registry value %.*s\\%s (status: 0x%x)", - MAX_REG_PATH, - RegPath, - Name, - Result); - break; - } - } - CloseHandle(Event); - SetLastError(LastError); - return NULL; -} - -_Use_decl_annotations_ BOOL RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log) { @@ -344,55 +197,3 @@ RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log) } return TRUE; } - -_Use_decl_annotations_ -BOOL -RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value) -{ - DWORD LastError; - ULONGLONG Deadline = GetTickCount64() + Timeout; - HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!Event) - { - LOG_LAST_ERROR(L"Failed to create event"); - return FALSE; - } - for (;;) - { - LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE); - if (LastError != ERROR_SUCCESS) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath); - break; - } - 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) - TimeLeft = 0; - DWORD Result = WaitForSingleObject(Event, (DWORD)TimeLeft); - if (Result != WAIT_OBJECT_0) - { - WCHAR RegPath[MAX_REG_PATH]; - LoggerGetRegistryKeyPath(Key, RegPath); - LOG(WIREGUARD_LOG_ERR, - L"Timeout waiting registry value %.*s\\%s (status: 0x%x)", - MAX_REG_PATH, - RegPath, - Name, - Result); - break; - } - } - CloseHandle(Event); - SetLastError(LastError); - return FALSE; -} diff --git a/api/registry.h b/api/registry.h index 40fc7c7..9f9429d 100644 --- a/api/registry.h +++ b/api/registry.h @@ -13,26 +13,6 @@ https://support.microsoft.com/en-us/help/256986/windows-registry-information-for-advanced-users */ /** - * Opens the specified registry key. It waits for the registry key to become available. - * - * @param Key Handle of the parent registry key. Must be opened with notify access. - * - * @param Path Subpath of the registry key to open. Zero-terminated string of up to MAX_REG_PATH-1 characters. - * - * @param Access A mask that specifies the desired access rights to the key to be opened. - * - * @param Timeout Timeout to wait for the value in milliseconds. - * - * @return Key handle on success. If the function fails, the return value is zero. To get extended error information, - * call GetLastError. - */ -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -HKEY -RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ LPCWSTR Path, _In_ DWORD Access, _In_ DWORD Timeout); - -/** * Validates and/or sanitizes string value read from registry. * * @param Buf On input, it contains a pointer to pointer where the data is stored. The data must be allocated @@ -97,27 +77,6 @@ LPWSTR RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ BOOL Log); /** - * Reads string value from registry key. It waits for the registry value to become available. - * - * @param Key Handle of the registry key to read from. Must be opened with read and notify access. - * - * @param Name Name of the value to read. - * - * @param Timeout Timeout to wait for the value in milliseconds. - * - * @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 - */ -_Must_inspect_result_ -_Return_type_success_(return != NULL) -_Post_maybenull_ -LPWSTR -RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout); - -/** * Reads a 32-bit DWORD value from registry key. * * @param Key Handle of the registry key to read from. Must be opened with read access. @@ -137,24 +96,3 @@ _Must_inspect_result_ _Return_type_success_(return != FALSE) BOOL RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log); - -/** - * Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available. - * - * @param Key Handle of the registry key to read from. Must be opened with read access. - * - * @param Name Name of the value to read. - * - * @param Timeout Timeout to wait for the value in milliseconds. - * - * @param Value Pointer to DWORD to retrieve registry value. - * - * @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 - */ -_Must_inspect_result_ -_Return_type_success_(return != FALSE) -BOOL -RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value); |