mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
12 KiB
415 lines
12 KiB
/*++
|
|
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
regclass.h
|
|
|
|
Abstract:
|
|
|
|
This file contains declarations needed for manipulating
|
|
the portion of the registry that contains class registrations
|
|
|
|
Author:
|
|
|
|
Adam Edwards (adamed) 14-Nov-1997
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#if defined( LOCAL )
|
|
|
|
//
|
|
// Declarations
|
|
//
|
|
|
|
#define LENGTH( str ) ( sizeof( str ) - sizeof( UNICODE_NULL ))
|
|
#define INIT_SPECIALKEY(x) {LENGTH(x), LENGTH(x), x}
|
|
|
|
#define REG_CLASSES_FIRST_DISTINCT_ICH 10
|
|
|
|
#define REG_CHAR_SIZE sizeof(WCHAR)
|
|
|
|
#define REG_USER_HIVE_NAME L"\\Registry\\User"
|
|
#define REG_USER_HIVE_NAMELEN LENGTH(REG_USER_HIVE_NAME)
|
|
#define REG_USER_HIVE_NAMECCH (REG_USER_HIVE_NAMELEN / REG_CHAR_SIZE)
|
|
|
|
#define REG_USER_HIVE_CLASSES_SUFFIX L"_Classes"
|
|
#define REG_USER_HIVE_CLASSES_SUFFIXLEN LENGTH(REG_USER_HIVE_CLASSES_SUFFIX)
|
|
#define REG_USER_HIVE_CLASSES_SUFFIXCCH (REG_USER_HIVE_CLASSES_SUFFIXLEN / REG_CHAR_SIZE)
|
|
|
|
#define REG_MACHINE_CLASSES_HIVE_NAME L"\\Registry\\Machine\\Software\\Classes"
|
|
#define REG_MACHINE_CLASSES_HIVE_NAMELEN LENGTH(REG_MACHINE_CLASSES_HIVE_NAME)
|
|
#define REG_MACHINE_CLASSES_HIVE_NAMECCH (REG_MACHINE_CLASSES_HIVE_NAMELEN / REG_CHAR_SIZE)
|
|
|
|
#define REG_USER_HIVE_LINK_TREE L"\\Software\\Classes"
|
|
|
|
#define REG_CLASSES_HIVE_MIN_NAMELEN REG_USER_HIVE_CLASSES_SUFFIXLEN + REG_USER_HIVE_NAMELEN
|
|
|
|
//
|
|
// The difference between these two paths
|
|
// \Registry\User\<sid>_Classes and
|
|
// \Registry\User\<siid>\Software\Classes
|
|
//
|
|
// plus extra for the translation from machine to user -- take into account the sid
|
|
//
|
|
#define REG_CLASSES_SUBTREE_PADDING 128
|
|
|
|
#define REG_MAX_CLASSKEY_LEN 384
|
|
#define REG_MAX_CLASSKEY_CCH (REG_MAX_CLASSKEY_LEN / REG_CHAR_SIZE)
|
|
|
|
#define REG_MAX_KEY_LEN 512
|
|
#define REG_MAX_KEY_CCH (REG_MAX_KEY_LEN / REG_CHAR_SIZE)
|
|
|
|
#define REG_MAX_KEY_PATHLEN 65535
|
|
|
|
|
|
//
|
|
// HKCR Handle Tags for Per-user Class Registration.
|
|
//
|
|
// Subkeys of HKCR up to and including a class registration parent key are tagged
|
|
// by setting two free bits in their handle value (the lower two bits of a handle
|
|
// are free to be used as tags). This makes it easy to tell if a key is in
|
|
// HKCR and needs special treatment. After the class registration part of a path,
|
|
// this marker is not needed since such keys do not require special treatment
|
|
// for enumeration, opening, and deletion.
|
|
//
|
|
|
|
//
|
|
// Note that for the sake of speed we are using 1 bit instead of a specific pattern of
|
|
// two bits. Currently, bit 0 is used to mark remote handles. Bit 2 is used in the
|
|
// server only to mark restricted keys. Locally, we use it to mark hkcr keys. More
|
|
// Here is a list of valid combinations -- unused bits must be 0. Invalid means that
|
|
// in the current implementation, you should never see it in that part of the registry.
|
|
//
|
|
|
|
//
|
|
// Local Server Client (application sees these)
|
|
// 00 (non HKCR, unused) 00 (unrestricted, unused) 00 (non HKCR, local)
|
|
// 01 Invalid (HKCR, unused) 01 Invalid (unrestricted, unused) 01 (non HKCR, remote)
|
|
// 10 (HKCR, unused) 10 (restricted, unused) 10 (HKCR, local)
|
|
// 11 Invalid (HKCR, unused) 11 Invalid (restricted, unused) 11 Invalid (HKCR, remote)
|
|
//
|
|
|
|
//
|
|
// Note that we could use either 10 or 11 to mark HKCR handles -- we chose 10 for simplicity's
|
|
// sake since it simply involves oring in a bit. This can be changed in the future
|
|
// if yet another bit pattern is needed. Otherwise, clients never see 11 -- they only see
|
|
// 00, 01, and 10. Note that these bits must be propagated to the local portion. This is done
|
|
// simply by leaving the bits as-is, because local doesn't use any of the bits. Note that
|
|
// we would be broken if the bits needed to propagate to server for some reason, since it
|
|
// is using bit 2 already. We do not allow HKCR as a remote handle, however, so this is
|
|
// not a problem.
|
|
//
|
|
|
|
#define REG_CLASS_HANDLE_MASK 0x3
|
|
|
|
#define REG_CLASS_HANDLE_VALUE 0x2
|
|
#define REG_CLASS_IS_SPECIAL_KEY( Handle ) ( (LONG) ( ( (ULONG_PTR) (Handle) ) & REG_CLASS_HANDLE_VALUE ) )
|
|
#define REG_CLASS_SET_SPECIAL_KEY( Handle ) ( (HANDLE) ( ( (ULONG_PTR) (Handle) ) | \
|
|
REG_CLASS_HANDLE_VALUE ) )
|
|
|
|
#define REG_CLASS_RESET_SPECIAL_KEY( Handle ) ( (HANDLE) ( ( ( (ULONG_PTR) (Handle) ) & ~REG_CLASS_HANDLE_MASK )))
|
|
|
|
#if defined(_REGCLASS_MALLOC_INSTRUMENTED_)
|
|
|
|
extern RTL_CRITICAL_SECTION gRegClassHeapCritSect;
|
|
extern DWORD gcbAllocated;
|
|
extern DWORD gcAllocs;
|
|
extern DWORD gcbMaxAllocated;
|
|
extern DWORD gcMaxAllocs;
|
|
extern PVOID gpvAllocs;
|
|
|
|
__inline PVOID RegClassHeapAlloc(SIZE_T cbSize)
|
|
{
|
|
PVOID pvAllocation;
|
|
|
|
pvAllocation = RtlAllocateHeap(RtlProcessHeap(), 0, cbSize + sizeof(SIZE_T));
|
|
|
|
RtlEnterCriticalSection(&gRegClassHeapCritSect);
|
|
|
|
if (pvAllocation) {
|
|
gcbAllocated += cbSize;
|
|
gcAllocs ++;
|
|
(ULONG_PTR) gpvAllocs ^= (ULONG_PTR) pvAllocation;
|
|
|
|
if (gcAllocs > gcMaxAllocs) {
|
|
gcMaxAllocs = gcAllocs;
|
|
}
|
|
|
|
if (gcbAllocated > gcbMaxAllocated) {
|
|
gcbMaxAllocated = gcbAllocated;
|
|
}
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&gRegClassHeapCritSect);
|
|
|
|
*((SIZE_T*) pvAllocation) = cbSize;
|
|
|
|
((SIZE_T*) pvAllocation) ++;
|
|
|
|
return pvAllocation;
|
|
}
|
|
|
|
__inline BOOLEAN RegClassHeapFree(PVOID pvAllocation)
|
|
{
|
|
BOOLEAN bRetVal;
|
|
SIZE_T cbSize;
|
|
|
|
((SIZE_T*) pvAllocation) --;
|
|
|
|
cbSize = *((SIZE_T*) pvAllocation);
|
|
|
|
bRetVal = RtlFreeHeap(RtlProcessHeap(), 0, pvAllocation);
|
|
|
|
RtlEnterCriticalSection(&gRegClassHeapCritSect);
|
|
|
|
gcbAllocated -= cbSize;
|
|
gcAllocs --;
|
|
|
|
(ULONG_PTR) gpvAllocs ^= (ULONG_PTR) pvAllocation;
|
|
|
|
RtlLeaveCriticalSection(&gRegClassHeapCritSect);
|
|
|
|
if (!bRetVal) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
#else // defined(_REGCLASS_MALLOC_INSTRUMENTED_)
|
|
|
|
#define RegClassHeapAlloc(x) RtlAllocateHeap(RtlProcessHeap(), 0, x)
|
|
#define RegClassHeapFree(x) RtlFreeHeap(RtlProcessHeap(), 0, x)
|
|
|
|
#endif // defined(_REGCLASS_MALLOC_INSTRUMENTED_)
|
|
|
|
enum
|
|
{
|
|
LOCATION_MACHINE = 0x1,
|
|
LOCATION_USER = 0x2,
|
|
LOCATION_BOTH = 0x3
|
|
};
|
|
|
|
|
|
//
|
|
// SKeySemantics
|
|
//
|
|
// This structure is the result of parsing a registry key full path
|
|
//
|
|
// ATTENTION: This structure, along with the current parsing code, needs to
|
|
// be overhauled. Originally, it was designed to do one thing. Now, it
|
|
// identifies several parts of keys. The original goal was speed --
|
|
// we attempted to touch the least amount of string (memory) possible.
|
|
// As more functionality was added to the parser, this became more complex.
|
|
// A better solution would pay more attention to a generic, straightforward
|
|
// way of parsing the key -- things have become far too convoluted in
|
|
// an attempt to be fast.
|
|
//
|
|
|
|
typedef struct _SKeySemantics
|
|
{
|
|
/* out */ unsigned _fUser : 1; // this key is rooted in the user hive
|
|
/* out */ unsigned _fMachine : 1; // this key is rooted in the machine hive
|
|
/* out */ unsigned _fCombinedClasses : 1; // this key is rooted in the combined classes hive
|
|
/* out */ unsigned _fClassRegistration : 1; // this key is a class registration key
|
|
/* out */ unsigned _fClassRegParent : 1; // this key is a special key (parent of a class reg key)
|
|
/* out */ unsigned _fAllocedNameBuf : 1; // nonzero if _pFullPath was realloc'd and needs to be freed
|
|
/* out */ USHORT _ichKeyStart; // index to start of a class reg after
|
|
// \\software\\classes in the returned full path
|
|
/* out */ USHORT _cbPrefixLen; // length of prefix
|
|
/* out */ USHORT _cbSpecialKey; // length of special key
|
|
/* out */ USHORT _cbClassRegKey; // length of class reg key name
|
|
/* in, out */ ULONG _cbFullPath; // size of the KEY_NAME_INFORMATION passed in
|
|
/* out */ PKEY_NAME_INFORMATION _pFullPath; // address of an OBJECT_NAME_INFORMATION structure
|
|
} SKeySemantics;
|
|
|
|
|
|
//
|
|
// External Prototypes
|
|
//
|
|
|
|
//
|
|
// Opens the HKCR predefined handle with the combined view
|
|
//
|
|
error_status_t OpenCombinedClassesRoot(
|
|
IN REGSAM samDesired,
|
|
OUT HANDLE * phKey);
|
|
|
|
//
|
|
// Parses a registry key and returns results
|
|
//
|
|
NTSTATUS BaseRegGetKeySemantics(
|
|
HKEY hkParent,
|
|
PUNICODE_STRING pSubKey,
|
|
SKeySemantics* pKeySemantics);
|
|
//
|
|
// Frees resources associated with an SKeySemantics structure
|
|
//
|
|
void BaseRegReleaseKeySemantics(SKeySemantics* pKeySemantics);
|
|
|
|
//
|
|
// Opens a class key that exists in either
|
|
// HKLM or HKCU
|
|
//
|
|
NTSTATUS BaseRegOpenClassKey(
|
|
HKEY hKey,
|
|
PUNICODE_STRING lpSubKey,
|
|
DWORD dwOptions,
|
|
REGSAM samDesired,
|
|
PHKEY phkResult);
|
|
|
|
//
|
|
// Opens a class key from a specified set
|
|
// of locations
|
|
//
|
|
NTSTATUS BaseRegOpenClassKeyFromLocation(
|
|
SKeySemantics* pKeyInfo,
|
|
HKEY hKey,
|
|
PUNICODE_STRING lpSubKey,
|
|
REGSAM samDesired,
|
|
DWORD dwLocation,
|
|
HKEY* phkResult);
|
|
|
|
//
|
|
// Returns key objects for the user and machine
|
|
// versions of a key
|
|
//
|
|
NTSTATUS BaseRegGetUserAndMachineClass(
|
|
SKeySemantics* pKeySemantics,
|
|
HKEY Key,
|
|
REGSAM samDesired,
|
|
PHKEY phkMachine,
|
|
PHKEY phkUser);
|
|
|
|
|
|
//
|
|
// Internal Prototypes
|
|
//
|
|
|
|
USHORT BaseRegGetUserPrefixLength(
|
|
PUNICODE_STRING pFullPath);
|
|
|
|
USHORT BaseRegCchSpecialKeyLen(
|
|
PUNICODE_STRING pFullPath,
|
|
USHORT ichSpecialKeyStart,
|
|
SKeySemantics* pKeySemantics);
|
|
|
|
NTSTATUS BaseRegTranslateToMachineClassKey(
|
|
SKeySemantics* pKeyInfo,
|
|
PUNICODE_STRING pMachineClassKey,
|
|
USHORT* pPrefixLen);
|
|
|
|
NTSTATUS BaseRegTranslateToUserClassKey(
|
|
SKeySemantics* pKeyInfo,
|
|
PUNICODE_STRING pUserClassKey,
|
|
USHORT* pPrefixLen);
|
|
|
|
NTSTATUS BaseRegOpenClassKeyRoot(
|
|
SKeySemantics* pKeyInfo,
|
|
PHKEY phkClassRoot,
|
|
PUNICODE_STRING pClassKeyPath,
|
|
BOOL fMachine);
|
|
|
|
NTSTATUS BaseRegMapClassRegistrationKey(
|
|
HKEY hKey,
|
|
PUNICODE_STRING pSubKey,
|
|
SKeySemantics* pKeyInfo,
|
|
PUNICODE_STRING pDestSubKey,
|
|
BOOL* pfRetryOnAccessDenied,
|
|
PHKEY phkDestResult,
|
|
PUNICODE_STRING* ppSubKeyResult);
|
|
|
|
NTSTATUS BaseRegMapClassOnAccessDenied(
|
|
SKeySemantics* pKeySemantics,
|
|
PHKEY phkDest,
|
|
PUNICODE_STRING pDestSubKey,
|
|
BOOL* pfRetryOnAccessDenied);
|
|
|
|
NTSTATUS CreateMultipartUserClassKey(
|
|
IN HKEY hKey,
|
|
OUT PHKEY phkResult);
|
|
|
|
NTSTATUS GetFixedKeyInfo(
|
|
HKEY hkUser,
|
|
HKEY hkMachine,
|
|
LPDWORD pdwUserValues,
|
|
LPDWORD pdwMachineValues,
|
|
LPDWORD pdwUserMaxDataLen,
|
|
LPDWORD pdwMachineMaxDataLen,
|
|
LPDWORD pdwMaxValueNameLen);
|
|
|
|
BOOL InitializeClassesNameSpace();
|
|
|
|
extern BOOL gbCombinedClasses;
|
|
|
|
|
|
//
|
|
// Inline functions
|
|
//
|
|
|
|
enum
|
|
{
|
|
REMOVEPREFIX_DISCARD_INITIAL_PATHSEP = 0,
|
|
REMOVEPREFIX_KEEP_INITIAL_PATHSEP = 1
|
|
};
|
|
|
|
__inline void KeySemanticsRemovePrefix(
|
|
SKeySemantics* pKeyInfo,
|
|
PUNICODE_STRING pDestination,
|
|
DWORD dwFlags)
|
|
{
|
|
BOOL fMoveBack;
|
|
|
|
fMoveBack = (dwFlags & REMOVEPREFIX_KEEP_INITIAL_PATHSEP) &&
|
|
(pKeyInfo->_pFullPath->Name[pKeyInfo->_ichKeyStart]);
|
|
|
|
pDestination->Buffer = &(pKeyInfo->_pFullPath->Name[pKeyInfo->_ichKeyStart -
|
|
(fMoveBack ? 1 : 0)]);
|
|
|
|
pDestination->Length = (USHORT) pKeyInfo->_pFullPath->NameLength -
|
|
((pKeyInfo->_ichKeyStart - (fMoveBack ? 1 : 0)) * REG_CHAR_SIZE);
|
|
}
|
|
|
|
__inline void KeySemanticsGetSid(
|
|
SKeySemantics* pKeyInfo,
|
|
PUNICODE_STRING pSidString)
|
|
{
|
|
pSidString->Buffer = &(pKeyInfo->_pFullPath->Name[REG_USER_HIVE_NAMECCH]);
|
|
|
|
pSidString->Length = pKeyInfo->_cbPrefixLen -
|
|
(REG_USER_HIVE_CLASSES_SUFFIXLEN + REG_USER_HIVE_NAMELEN);
|
|
}
|
|
|
|
__inline void KeySemanticsTruncatePrefixToClassReg(
|
|
SKeySemantics* pKeyInfo,
|
|
USHORT PrefixLen,
|
|
PUNICODE_STRING pDestination)
|
|
{
|
|
pDestination->Length = PrefixLen + (pKeyInfo->_fClassRegistration ? REG_CHAR_SIZE : 0) +
|
|
pKeyInfo->_cbSpecialKey + pKeyInfo->_cbClassRegKey;
|
|
}
|
|
|
|
BOOL
|
|
ExtractClassKey(
|
|
IN OUT HKEY *phKey,
|
|
IN OUT PUNICODE_STRING lpSubKey);
|
|
|
|
#else // LOCAL
|
|
|
|
#define REG_CLASS_IS_SPECIAL_KEY( Handle ) 0
|
|
#define REG_CLASS_SET_SPECIAL_KEY( Handle ) (Handle)
|
|
#define REG_CLASS_RESET_SPECIAL_KEY( Handle ) (Handle)
|
|
|
|
#endif // LOCAL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|