[ADVAPI32]

- Implement RegOpenKeyEx for HKEY_CLASSES_ROOT subkeys
CORE-8582

svn path=/trunk/; revision=64418
This commit is contained in:
Jérôme Gardou 2014-09-30 20:00:23 +00:00
parent ccc1a83dca
commit 0bcdd836f1
4 changed files with 285 additions and 1 deletions

View file

@ -28,6 +28,7 @@ list(APPEND SOURCE
misc/msi.c
misc/shutdown.c
misc/sysfunc.c
reg/hkcr.c
reg/reg.c
sec/ac.c
sec/audit.c

View file

@ -0,0 +1,269 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/advapi32/reg/hkcr.c
* PURPOSE: Registry functions - HKEY_CLASSES_ROOT abstraction
* PROGRAMMER: Jerôme Gardou (jerome.gardou@reactos.org)
*/
#include <advapi32.h>
#include <ndk/cmfuncs.h>
#include <pseh/pseh2.h>
#include "reg.h"
WINE_DEFAULT_DEBUG_CHANNEL(reg);
static const UNICODE_STRING HKLM_ClassesPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes");
static
LONG
GetKeyName(HKEY hKey, PUNICODE_STRING KeyName)
{
UNICODE_STRING InfoName;
PKEY_NAME_INFORMATION NameInformation;
ULONG InfoLength;
NTSTATUS Status;
/* Get info length */
InfoLength = 0;
Status = NtQueryKey(hKey, KeyNameInformation, NULL, 0, &InfoLength);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
ERR("NtQueryKey returned unexpected Status: 0x%08x\n", Status);
return RtlNtStatusToDosError(Status);
}
/* Get it for real */
NameInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength);
if (NameInformation == NULL)
{
ERR("Failed to allocate %lu bytes", InfoLength);
return ERROR_NOT_ENOUGH_MEMORY;
}
Status = NtQueryKey(hKey, KeyNameInformation, NameInformation, InfoLength, &InfoLength);
if (!NT_SUCCESS(Status))
{
ERR("NtQueryKey failed: 0x%08x\n", Status);
return RtlNtStatusToDosError(Status);
}
/* Make it a proper UNICODE_STRING */
InfoName.Length = NameInformation->NameLength;
InfoName.MaximumLength = NameInformation->NameLength;
InfoName.Buffer = NameInformation->Name;
Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &InfoName, KeyName);
if (!NT_SUCCESS(Status))
{
ERR("RtlDuplicateUnicodeString failed: 0x%08x\n", Status);
return RtlNtStatusToDosError(Status);
}
RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation);
return ERROR_SUCCESS;
}
static
LONG
GetKeySam(
_In_ HKEY hKey,
_Out_ REGSAM* RegSam)
{
NTSTATUS Status;
OBJECT_BASIC_INFORMATION ObjectInfo;
Status = NtQueryObject(hKey, ObjectBasicInformation, &ObjectInfo, sizeof(ObjectInfo), NULL);
if (!NT_SUCCESS(Status))
{
ERR("NtQueryObject failed, Status %x08x\n", Status);
return RtlNtStatusToDosError(Status);
}
*RegSam = ObjectInfo.GrantedAccess;
return ERROR_SUCCESS;
}
/*
* Gets a HKLM key from an HKCU key.
*/
static
LONG
GetFallbackHKCRKey(
_In_ HKEY hKey,
_Out_ HKEY* MachineKey)
{
UNICODE_STRING KeyName;
LPWSTR SubKeyName;
LONG ErrorCode;
REGSAM SamDesired;
/* Get the key name */
ErrorCode = GetKeyName(hKey, &KeyName);
if (ErrorCode != ERROR_SUCCESS)
return ErrorCode;
/* See if we really need a conversion */
if (RtlPrefixUnicodeString(&HKLM_ClassesPath, &KeyName, TRUE))
{
RtlFreeUnicodeString(&KeyName);
*MachineKey = hKey;
return ERROR_SUCCESS;
}
SubKeyName = KeyName.Buffer + 15; /* 15 == wcslen(L"\\Registry\\User\\") */
/* Skip the user token */
while (*SubKeyName++ != L'\\')
{
if (!*SubKeyName)
{
ERR("Key name %S is invalid!\n", KeyName.Buffer);
return ERROR_INTERNAL_ERROR;
}
}
/* Use the same access mask than the original key */
ErrorCode = GetKeySam(hKey, &SamDesired);
if (ErrorCode != ERROR_SUCCESS)
{
RtlFreeUnicodeString(&KeyName);
return ErrorCode;
}
/* Open the key. */
ErrorCode = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
SubKeyName,
0,
SamDesired,
MachineKey);
RtlFreeUnicodeString(&KeyName);
return ErrorCode;
}
/* Get the HKCU key (if it exists) from an HKCR key */
static
LONG
GetPreferredHKCRKey(
_In_ HKEY hKey,
_Out_ HKEY* PreferredKey)
{
UNICODE_STRING KeyName;
LPWSTR SubKeyName;
LONG ErrorCode;
REGSAM SamDesired;
/* Get the key name */
ErrorCode = GetKeyName(hKey, &KeyName);
if (ErrorCode != ERROR_SUCCESS)
return ErrorCode;
/* See if we really need a conversion */
if (!RtlPrefixUnicodeString(&HKLM_ClassesPath, &KeyName, TRUE))
{
RtlFreeUnicodeString(&KeyName);
*PreferredKey = hKey;
return ERROR_SUCCESS;
}
/* 18 == wcslen(L"\\Registry\\Machine\\") */
SubKeyName = KeyName.Buffer + 18;
/* Use the same access mask than the original key */
ErrorCode = GetKeySam(hKey, &SamDesired);
if (ErrorCode != ERROR_SUCCESS)
{
RtlFreeUnicodeString(&KeyName);
return ErrorCode;
}
/* Open the key. */
ErrorCode = RegOpenKeyExW(
HKEY_CURRENT_USER,
SubKeyName,
0,
SamDesired,
PreferredKey);
RtlFreeUnicodeString(&KeyName);
return ErrorCode;
}
/* Same as RegOpenKeyExW, but for HKEY_CLASSES_ROOT subkeys */
LONG
WINAPI
OpenHKCRKey(
_In_ HKEY hKey,
_In_ LPCWSTR lpSubKey,
_In_ DWORD ulOptions,
_In_ REGSAM samDesired,
_In_ PHKEY phkResult)
{
HKEY QueriedKey;
LONG ErrorCode;
ASSERT(IsHKCRKey(hKey));
/* Remove the HKCR flag while we're working */
hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
if (ErrorCode == ERROR_FILE_NOT_FOUND)
{
/* The key doesn't exist on HKCU side, no chance for a subkey */
ErrorCode = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
if (ErrorCode == ERROR_SUCCESS)
MakeHKCRKey(phkResult);
return ErrorCode;
}
if (ErrorCode != ERROR_SUCCESS)
{
/* Somehow we failed for another reason (maybe deleted key or whatever) */
return ErrorCode;
}
/* Try on the HKCU side */
ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, ulOptions, samDesired, phkResult);
if (ErrorCode == ERROR_SUCCESS)
MakeHKCRKey(phkResult);
/* Close it if we must */
if (QueriedKey != hKey)
{
/* The original key is on the machine view */
RegCloseKey(QueriedKey);
}
/* Anything else than ERROR_FILE_NOT_FOUND means that we found it, even if it is with failures. */
if (ErrorCode != ERROR_FILE_NOT_FOUND)
return ErrorCode;
/* If we're here, we must open from HKLM key. */
ErrorCode = GetFallbackHKCRKey(hKey, &QueriedKey);
if (ErrorCode != ERROR_SUCCESS)
{
/* Maybe the key doesn't exist in the HKLM view */
return ErrorCode;
}
ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, ulOptions, samDesired, phkResult);
if (ErrorCode == ERROR_SUCCESS)
MakeHKCRKey(phkResult);
/* Close it if we must */
if (QueriedKey != hKey)
{
/* The original key is on the machine view */
RegCloseKey(QueriedKey);
}
return ErrorCode;
}

View file

@ -3483,6 +3483,9 @@ RegOpenKeyExW(HKEY hKey,
return RtlNtStatusToDosError(Status);
}
if (IsHKCRKey(KeyHandle))
return OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
if (ulOptions & REG_OPTION_OPEN_LINK)
Attributes |= OBJ_OPENLINK;
@ -3500,11 +3503,13 @@ RegOpenKeyExW(HKEY hKey,
Status = NtOpenKey((PHANDLE)phkResult,
samDesired,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError(Status);
}
ClosePredefKey(KeyHandle);
return ErrorCode;

View file

@ -19,5 +19,14 @@ FORCEINLINE
void
MakeHKCRKey(_Inout_ HKEY* hKey)
{
*hKey = (HKEY)((ULONG_PTR)*hKey | 0x2);
*hKey = (HKEY)((ULONG_PTR)(*hKey) | 0x2);
}
LONG
WINAPI
OpenHKCRKey(
_In_ HKEY hKey,
_In_ LPCWSTR lpSubKey,
_In_ DWORD ulOptions,
_In_ REGSAM samDesired,
_In_ PHKEY phkResult);