api: finish porting from wireguard-go
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
		
							parent
							
								
									c8bf62ac19
								
							
						
					
					
						commit
						7e3740018d
					
				
							
								
								
									
										70
									
								
								api/api.h
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								api/api.h
									
									
									
									
									
								
							@ -6,6 +6,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					#include <IPExport.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef _Return_type_success_(return == ERROR_SUCCESS) DWORD WINSTATUS;
 | 
					typedef _Return_type_success_(return == ERROR_SUCCESS) DWORD WINSTATUS;
 | 
				
			||||||
extern HINSTANCE ResourceModule;
 | 
					extern HINSTANCE ResourceModule;
 | 
				
			||||||
@ -37,6 +38,42 @@ NciInit();
 | 
				
			|||||||
void
 | 
					void
 | 
				
			||||||
NciCleanup();
 | 
					NciCleanup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryOpenKeyWait(
 | 
				
			||||||
 | 
					    _In_ HKEY Key,
 | 
				
			||||||
 | 
					    _In_z_count_c_(MAX_PATH) LPCWSTR Path,
 | 
				
			||||||
 | 
					    _In_ DWORD Access,
 | 
				
			||||||
 | 
					    _In_ DWORD Timeout,
 | 
				
			||||||
 | 
					    _Out_ HKEY *KeyOut);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryWaitForKey(_In_ HKEY Key, _In_z_count_c_(MAX_PATH) LPCWSTR Path, _In_ DWORD Timeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryGetMultiString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ LPWSTR *Value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ LPWSTR *Value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
 | 
					WintunGetVersion(
 | 
				
			||||||
 | 
					    _Out_ DWORD *DriverVersionMaj,
 | 
				
			||||||
 | 
					    _Out_ DWORD *DriverVersionMin,
 | 
				
			||||||
 | 
					    _Out_ DWORD *NdisVersionMaj,
 | 
				
			||||||
 | 
					    _Out_ DWORD *NdisVersionMin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_POOL 256
 | 
					#define MAX_POOL 256
 | 
				
			||||||
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
 | 
					#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,4 +90,35 @@ VOID WINAPI
 | 
				
			|||||||
WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
 | 
					WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WINSTATUS WINAPI
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
WintunGetAdapter(_In_z_count_c_(MAX_POOL) LPCWSTR Pool, _In_z_ LPCWSTR IfName, _Out_ WINTUN_ADAPTER **Adapter);
 | 
					WintunGetAdapter(_In_z_count_c_(MAX_POOL) LPCWSTR Pool, _In_z_ LPCWSTR Name, _Out_ WINTUN_ADAPTER **Adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
 | 
					WintunGetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_ADAPTER_NAME) LPWSTR Name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
 | 
					WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_count_c_(MAX_ADAPTER_NAME) LPCWSTR Name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void WINAPI
 | 
				
			||||||
 | 
					WintunGetAdapterGUID(_In_ const WINTUN_ADAPTER *Adapter, _Out_ GUID *Guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void WINAPI
 | 
				
			||||||
 | 
					WintunGetAdapterLUID(_In_ const WINTUN_ADAPTER *Adapter, _Out_ LUID *Luid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
 | 
					WintunGetAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
 | 
					WintunCreateAdapter(
 | 
				
			||||||
 | 
					    _In_z_count_c_(MAX_POOL) LPCWSTR Pool,
 | 
				
			||||||
 | 
					    _In_z_ LPCWSTR Name,
 | 
				
			||||||
 | 
					    _In_opt_ const GUID *RequestedGUID,
 | 
				
			||||||
 | 
					    _Out_ WINTUN_ADAPTER **Adapter,
 | 
				
			||||||
 | 
					    _Inout_ BOOL *RebootRequired);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
 | 
					WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequired);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef BOOL(CALLBACK *WINTUN_ENUMPROC)(_In_ const WINTUN_ADAPTER *Adapter, _In_ LPARAM Param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS WINAPI
 | 
				
			||||||
 | 
					WintunEnumAdapters(_In_z_count_c_(MAX_POOL) LPCWSTR Pool, _In_ WINTUN_ENUMPROC Func, _In_ LPARAM Param);
 | 
				
			||||||
 | 
				
			|||||||
@ -120,7 +120,7 @@
 | 
				
			|||||||
      <AdditionalIncludeDirectories>..\$(WintunPlatform)\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 | 
					      <AdditionalIncludeDirectories>..\$(WintunPlatform)\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
 | 
				
			||||||
    </ResourceCompile>
 | 
					    </ResourceCompile>
 | 
				
			||||||
    <Link>
 | 
					    <Link>
 | 
				
			||||||
      <AdditionalDependencies>Bcrypt.lib;Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
					      <AdditionalDependencies>Bcrypt.lib;Cfgmgr32.lib;Iphlpapi.lib;Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
				
			||||||
      <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
 | 
					      <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
 | 
				
			||||||
      <SubSystem>Windows</SubSystem>
 | 
					      <SubSystem>Windows</SubSystem>
 | 
				
			||||||
    </Link>
 | 
					    </Link>
 | 
				
			||||||
@ -162,6 +162,7 @@
 | 
				
			|||||||
    <ClCompile Include="devmgmt.c" />
 | 
					    <ClCompile Include="devmgmt.c" />
 | 
				
			||||||
    <ClCompile Include="namespace.c" />
 | 
					    <ClCompile Include="namespace.c" />
 | 
				
			||||||
    <ClCompile Include="nci.c" />
 | 
					    <ClCompile Include="nci.c" />
 | 
				
			||||||
 | 
					    <ClCompile Include="registry.c" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 | 
					  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 | 
				
			||||||
  <ImportGroup Label="ExtensionTargets">
 | 
					  <ImportGroup Label="ExtensionTargets">
 | 
				
			||||||
 | 
				
			|||||||
@ -42,5 +42,8 @@
 | 
				
			|||||||
    <ClCompile Include="nci.c">
 | 
					    <ClCompile Include="nci.c">
 | 
				
			||||||
      <Filter>Source Files</Filter>
 | 
					      <Filter>Source Files</Filter>
 | 
				
			||||||
    </ClCompile>
 | 
					    </ClCompile>
 | 
				
			||||||
 | 
					    <ClCompile Include="registry.c">
 | 
				
			||||||
 | 
					      <Filter>Source Files</Filter>
 | 
				
			||||||
 | 
					    </ClCompile>
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										1084
									
								
								api/devmgmt.c
									
									
									
									
									
								
							
							
						
						
									
										1084
									
								
								api/devmgmt.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,3 +1,12 @@
 | 
				
			|||||||
EXPORTS
 | 
					EXPORTS
 | 
				
			||||||
	WintunFreeAdapter
 | 
						WintunFreeAdapter
 | 
				
			||||||
	WintunGetAdapter
 | 
						WintunGetAdapter
 | 
				
			||||||
 | 
						WintunGetAdapterName
 | 
				
			||||||
 | 
						WintunSetAdapterName
 | 
				
			||||||
 | 
						WintunGetAdapterGUID
 | 
				
			||||||
 | 
						WintunGetAdapterLUID
 | 
				
			||||||
 | 
						WintunGetAdapterDeviceObject
 | 
				
			||||||
 | 
						WintunGetVersion
 | 
				
			||||||
 | 
						WintunCreateAdapter
 | 
				
			||||||
 | 
						WintunDeleteAdapter
 | 
				
			||||||
 | 
						WintunEnumAdapters
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										411
									
								
								api/registry.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										411
									
								
								api/registry.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,411 @@
 | 
				
			|||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "api.h"
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static WINSTATUS
 | 
				
			||||||
 | 
					OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline, _Out_ HKEY *KeyOut)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DWORD Result;
 | 
				
			||||||
 | 
					    LPWSTR PathNext = wcschr(Path, L'\\');
 | 
				
			||||||
 | 
					    if (PathNext)
 | 
				
			||||||
 | 
					        *PathNext = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
 | 
				
			||||||
 | 
					    if (!Event)
 | 
				
			||||||
 | 
					        return GetLastError();
 | 
				
			||||||
 | 
					    for (;;)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE);
 | 
				
			||||||
 | 
					        if (Result != ERROR_SUCCESS)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        HKEY Subkey;
 | 
				
			||||||
 | 
					        Result = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey);
 | 
				
			||||||
 | 
					        if (Result == ERROR_SUCCESS)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (PathNext)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Result = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline, KeyOut);
 | 
				
			||||||
 | 
					                RegCloseKey(Subkey);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                *KeyOut = Subkey;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        LONGLONG TimeLeft = Deadline - GetTickCount64();
 | 
				
			||||||
 | 
					        if (TimeLeft < 0)
 | 
				
			||||||
 | 
					            TimeLeft = 0;
 | 
				
			||||||
 | 
					        if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CloseHandle(Event);
 | 
				
			||||||
 | 
					    return Result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @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
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param KeyOut        Pointer to a variable to receive the key handle
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; error code otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryOpenKeyWait(
 | 
				
			||||||
 | 
					    _In_ HKEY Key,
 | 
				
			||||||
 | 
					    _In_z_count_c_(MAX_PATH) LPCWSTR Path,
 | 
				
			||||||
 | 
					    _In_ DWORD Access,
 | 
				
			||||||
 | 
					    _In_ DWORD Timeout,
 | 
				
			||||||
 | 
					    _Out_ HKEY *KeyOut)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WCHAR Buf[MAX_PATH];
 | 
				
			||||||
 | 
					    wcscpy_s(Buf, _countof(Buf), Path);
 | 
				
			||||||
 | 
					    return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout, KeyOut);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryWaitForKey(_In_ HKEY Key, _In_z_count_c_(MAX_PATH) LPCWSTR Path, _In_ DWORD Timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HKEY k;
 | 
				
			||||||
 | 
					    DWORD Result = RegistryOpenKeyWait(Key, Path, KEY_NOTIFY, Timeout, &k);
 | 
				
			||||||
 | 
					    if (Result != ERROR_SUCCESS)
 | 
				
			||||||
 | 
					        return Result;
 | 
				
			||||||
 | 
					    RegCloseKey(k);
 | 
				
			||||||
 | 
					    return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Validate and/or sanitize string value read from registry.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Buf           On input, it contains pointer to pointer where the data is stored. The data must be
 | 
				
			||||||
 | 
					 *                      allocated using HeapAlloc(GetProcessHeap(), 0).
 | 
				
			||||||
 | 
					 *                      On output, it contains pointer to pointer where the sanitized data is stored. It must be
 | 
				
			||||||
 | 
					 *                      released with HeapFree(GetProcessHeap(), 0, *Buf) after use.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Len           Length of data string in wide characters
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HANDLE Heap = GetProcessHeap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (wcsnlen(*Buf, Len) >= Len)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /* String is missing zero-terminator. */
 | 
				
			||||||
 | 
					        LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
 | 
				
			||||||
 | 
					        if (!BufZ)
 | 
				
			||||||
 | 
					            return ERROR_OUTOFMEMORY;
 | 
				
			||||||
 | 
					        wmemcpy(BufZ, *Buf, Len);
 | 
				
			||||||
 | 
					        BufZ[Len] = 0;
 | 
				
			||||||
 | 
					        HeapFree(Heap, 0, *Buf);
 | 
				
			||||||
 | 
					        *Buf = BufZ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ValueType != REG_EXPAND_SZ)
 | 
				
			||||||
 | 
					        return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* ExpandEnvironmentStringsW() returns strlen on success or 0 on error. Bail out on empty input strings to
 | 
				
			||||||
 | 
					     * disambiguate. */
 | 
				
			||||||
 | 
					    if (!(*Buf)[0])
 | 
				
			||||||
 | 
					        return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Len = Len * 2 + 64;
 | 
				
			||||||
 | 
					    for (;;)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LPWSTR Expanded = HeapAlloc(Heap, 0, Len * sizeof(WCHAR));
 | 
				
			||||||
 | 
					        if (!Expanded)
 | 
				
			||||||
 | 
					            return ERROR_OUTOFMEMORY;
 | 
				
			||||||
 | 
					        DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
 | 
				
			||||||
 | 
					        if (!Result)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Result = GetLastError();
 | 
				
			||||||
 | 
					            HeapFree(Heap, 0, Expanded);
 | 
				
			||||||
 | 
					            return Result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (Result > Len)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            HeapFree(Heap, 0, Expanded);
 | 
				
			||||||
 | 
					            Len = Result;
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        HeapFree(Heap, 0, *Buf);
 | 
				
			||||||
 | 
					        *Buf = Expanded;
 | 
				
			||||||
 | 
					        return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Validate and/or sanitize multi-string value read from registry.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Buf           On input, it contains pointer to pointer where the data is stored. The data must be
 | 
				
			||||||
 | 
					 *                      allocated using HeapAlloc(GetProcessHeap(), 0).
 | 
				
			||||||
 | 
					 *                      On output, it contains pointer to pointer where the sanitized data is stored. It must be
 | 
				
			||||||
 | 
					 *                      released with HeapFree(GetProcessHeap(), 0, *Buf) after use.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Len           Length of data string in wide characters
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryGetMultiString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HANDLE Heap = GetProcessHeap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ValueType == REG_MULTI_SZ)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (size_t i = 0;; i += wcsnlen(*Buf + i, Len - i) + 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (i > Len)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                /* Missing string and list terminators. */
 | 
				
			||||||
 | 
					                LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 2) * sizeof(WCHAR));
 | 
				
			||||||
 | 
					                if (!BufZ)
 | 
				
			||||||
 | 
					                    return ERROR_OUTOFMEMORY;
 | 
				
			||||||
 | 
					                wmemcpy(BufZ, *Buf, Len);
 | 
				
			||||||
 | 
					                BufZ[Len] = 0;
 | 
				
			||||||
 | 
					                BufZ[Len + 1] = 0;
 | 
				
			||||||
 | 
					                HeapFree(Heap, 0, *Buf);
 | 
				
			||||||
 | 
					                *Buf = BufZ;
 | 
				
			||||||
 | 
					                return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (i == Len)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                /* Missing list terminator. */
 | 
				
			||||||
 | 
					                LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
 | 
				
			||||||
 | 
					                if (!BufZ)
 | 
				
			||||||
 | 
					                    return ERROR_OUTOFMEMORY;
 | 
				
			||||||
 | 
					                wmemcpy(BufZ, *Buf, Len);
 | 
				
			||||||
 | 
					                BufZ[Len] = 0;
 | 
				
			||||||
 | 
					                HeapFree(Heap, 0, *Buf);
 | 
				
			||||||
 | 
					                *Buf = BufZ;
 | 
				
			||||||
 | 
					                return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!(*Buf)[i])
 | 
				
			||||||
 | 
					                return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 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;
 | 
				
			||||||
 | 
					    Len = (DWORD)wcslen(*Buf) + 1;
 | 
				
			||||||
 | 
					    LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
 | 
				
			||||||
 | 
					    if (!BufZ)
 | 
				
			||||||
 | 
					        return ERROR_OUTOFMEMORY;
 | 
				
			||||||
 | 
					    wmemcpy(BufZ, *Buf, Len);
 | 
				
			||||||
 | 
					    BufZ[Len] = 0;
 | 
				
			||||||
 | 
					    HeapFree(Heap, 0, *Buf);
 | 
				
			||||||
 | 
					    *Buf = BufZ;
 | 
				
			||||||
 | 
					    return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Retrieves the type and data for the specified value name associated with an open registry key.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @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 ValueType     A pointer to a variable that receives a code indicating the type of data stored in the specified
 | 
				
			||||||
 | 
					 *                      value.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Buf           Pointer to a pointer to retrieve registry value. The buffer must be released with
 | 
				
			||||||
 | 
					 *                      HeapFree(GetProcessHeap(), 0, *Buf) after use.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param BufLen        On input, a hint of expected registry value size in bytes; on output, actual registry value size
 | 
				
			||||||
 | 
					 *                      in bytes.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return ERROR_SUCCESS on success; Win32 error code otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static WINSTATUS
 | 
				
			||||||
 | 
					RegistryQuery(
 | 
				
			||||||
 | 
					    _In_ HKEY Key,
 | 
				
			||||||
 | 
					    _In_opt_z_ LPCWSTR Name,
 | 
				
			||||||
 | 
					    _Out_opt_ DWORD *ValueType,
 | 
				
			||||||
 | 
					    _Out_ void **Buf,
 | 
				
			||||||
 | 
					    _Inout_ DWORD *BufLen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HANDLE Heap = GetProcessHeap();
 | 
				
			||||||
 | 
					    for (;;)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        *Buf = HeapAlloc(Heap, 0, *BufLen);
 | 
				
			||||||
 | 
					        if (!*Buf)
 | 
				
			||||||
 | 
					            return ERROR_OUTOFMEMORY;
 | 
				
			||||||
 | 
					        LSTATUS Result = RegQueryValueExW(Key, Name, NULL, ValueType, (BYTE *)*Buf, BufLen);
 | 
				
			||||||
 | 
					        if (Result == ERROR_SUCCESS)
 | 
				
			||||||
 | 
					            return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					        HeapFree(Heap, 0, *Buf);
 | 
				
			||||||
 | 
					        if (Result != ERROR_MORE_DATA)
 | 
				
			||||||
 | 
					            return Result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reads string value from registry key.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @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 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(GetProcessHeap(), 0, Value) after use.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return ERROR_SUCCESS on success; Win32 error code otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ LPWSTR *Value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DWORD ValueType, Size = 256 * sizeof(WCHAR);
 | 
				
			||||||
 | 
					    DWORD Result = RegistryQuery(Key, Name, &ValueType, Value, &Size);
 | 
				
			||||||
 | 
					    if (Result != ERROR_SUCCESS)
 | 
				
			||||||
 | 
					        return Result;
 | 
				
			||||||
 | 
					    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(GetProcessHeap(), 0, *Value);
 | 
				
			||||||
 | 
					        return Result;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        HeapFree(GetProcessHeap(), 0, *Value);
 | 
				
			||||||
 | 
					        return ERROR_INVALID_DATATYPE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Value         Pointer to string to retrieve registry value. If the value type is
 | 
				
			||||||
 | 
					 *                      REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings().
 | 
				
			||||||
 | 
					 *                      The string must be released with HeapFree(GetProcessHeap(), 0, Value)
 | 
				
			||||||
 | 
					 *                      after use.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return ERROR_SUCCESS on success; Win32 error code otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ LPWSTR *Value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DWORD Result;
 | 
				
			||||||
 | 
					    ULONGLONG Deadline = GetTickCount64() + Timeout;
 | 
				
			||||||
 | 
					    HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
 | 
				
			||||||
 | 
					    if (!Event)
 | 
				
			||||||
 | 
					        return GetLastError();
 | 
				
			||||||
 | 
					    for (;;)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
 | 
				
			||||||
 | 
					        if (Result != ERROR_SUCCESS)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        Result = RegistryQueryString(Key, Name, Value);
 | 
				
			||||||
 | 
					        if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        LONGLONG TimeLeft = Deadline - GetTickCount64();
 | 
				
			||||||
 | 
					        if (TimeLeft < 0)
 | 
				
			||||||
 | 
					            TimeLeft = 0;
 | 
				
			||||||
 | 
					        if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CloseHandle(Event);
 | 
				
			||||||
 | 
					    return Result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Name          Name of the value to read
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param Value         Pointer to DWORD to retrieve registry value
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return ERROR_SUCCESS on success; Win32 error code otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DWORD ValueType, Size = sizeof(DWORD);
 | 
				
			||||||
 | 
					    DWORD Result = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
 | 
				
			||||||
 | 
					    if (Result != ERROR_SUCCESS)
 | 
				
			||||||
 | 
					        return Result;
 | 
				
			||||||
 | 
					    if (ValueType != REG_DWORD)
 | 
				
			||||||
 | 
					        return ERROR_INVALID_DATATYPE;
 | 
				
			||||||
 | 
					    if (Size != sizeof(DWORD))
 | 
				
			||||||
 | 
					        return ERROR_INVALID_DATA;
 | 
				
			||||||
 | 
					    return ERROR_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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 ERROR_SUCCESS on success; Win32 error code otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					WINSTATUS
 | 
				
			||||||
 | 
					RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DWORD Result;
 | 
				
			||||||
 | 
					    ULONGLONG Deadline = GetTickCount64() + Timeout;
 | 
				
			||||||
 | 
					    HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
 | 
				
			||||||
 | 
					    if (!Event)
 | 
				
			||||||
 | 
					        return GetLastError();
 | 
				
			||||||
 | 
					    for (;;)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
 | 
				
			||||||
 | 
					        if (Result != ERROR_SUCCESS)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        Result = RegistryQueryDWORD(Key, Name, Value);
 | 
				
			||||||
 | 
					        if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        LONGLONG TimeLeft = Deadline - GetTickCount64();
 | 
				
			||||||
 | 
					        if (TimeLeft < 0)
 | 
				
			||||||
 | 
					            TimeLeft = 0;
 | 
				
			||||||
 | 
					        if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CloseHandle(Event);
 | 
				
			||||||
 | 
					    return Result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user