646 lines
16 KiB
C
646 lines
16 KiB
C
//
|
|
// REGKYLST.C
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995
|
|
//
|
|
// Declares the predefined key structures and manages dynamic HKEY structures.
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include <limits.h>
|
|
|
|
// We would rather just have one definition a
|
|
#ifdef WANT_DYNKEY_SUPPORT
|
|
#define INITED_PREDEFINED_KEY(index, flags) \
|
|
{ \
|
|
KEY_SIGNATURE, \
|
|
KEYF_PREDEFINED | KEYF_INVALID | (flags), \
|
|
0, \
|
|
NULL, \
|
|
REG_NULL, \
|
|
REG_NULL, \
|
|
0, \
|
|
0, \
|
|
(index), \
|
|
NULL, \
|
|
NULL, \
|
|
(UINT) -1, \
|
|
REG_NULL, \
|
|
NULL \
|
|
}
|
|
#else
|
|
#define INITED_PREDEFINED_KEY(index, flags) \
|
|
{ \
|
|
KEY_SIGNATURE, \
|
|
KEYF_PREDEFINED | KEYF_INVALID | (flags), \
|
|
0, \
|
|
NULL, \
|
|
REG_NULL, \
|
|
REG_NULL, \
|
|
0, \
|
|
0, \
|
|
(index), \
|
|
NULL, \
|
|
NULL, \
|
|
(UINT) -1, \
|
|
REG_NULL \
|
|
}
|
|
#endif
|
|
|
|
KEY g_RgLocalMachineKey =
|
|
INITED_PREDEFINED_KEY(INDEX_LOCAL_MACHINE, KEYF_HIVESALLOWED);
|
|
KEY g_RgUsersKey = INITED_PREDEFINED_KEY(INDEX_USERS, KEYF_HIVESALLOWED);
|
|
#ifdef WANT_DYNKEY_SUPPORT
|
|
KEY g_RgDynDataKey = INITED_PREDEFINED_KEY(INDEX_DYN_DATA, 0);
|
|
#endif
|
|
|
|
HKEY g_RgPredefinedKeys[] = {
|
|
NULL, // HKEY_CLASSES_ROOT
|
|
NULL, // HKEY_CURRENT_USER
|
|
&g_RgLocalMachineKey, // HKEY_LOCAL_MACHINE
|
|
&g_RgUsersKey, // HKEY_USERS
|
|
NULL, // HKEY_PERFORMANCE_DATA
|
|
NULL, // HKEY_CURRENT_CONFIG
|
|
#ifdef WANT_DYNKEY_SUPPORT
|
|
&g_RgDynDataKey, // HKEY_DYN_DATA
|
|
#endif
|
|
};
|
|
|
|
#define NUMBER_PREDEF_KEYS (sizeof(g_RgPredefinedKeys) / sizeof(HKEY))
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
#define NUMBER_STATIC_KEYS 32
|
|
HKEY g_RgStaticKeyArray = NULL;
|
|
#endif
|
|
|
|
// List of all dynamically allocated keys.
|
|
HKEY g_RgDynamicKeyList = NULL;
|
|
|
|
const char g_RgClassesRootSubKey[] = "SOFTWARE\\CLASSES";
|
|
const char g_RgCurrentUserSubKey[] = ".DEFAULT";
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
//
|
|
// RgAllocKeyHandleStructures
|
|
//
|
|
|
|
BOOL
|
|
INTERNAL
|
|
RgAllocKeyHandleStructures(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
UINT Index;
|
|
HKEY hKey;
|
|
|
|
ASSERT(IsNullPtr(g_RgStaticKeyArray));
|
|
ASSERT(IsNullPtr(g_RgDynamicKeyList));
|
|
|
|
//
|
|
// Allocate and initialize the static key table.
|
|
//
|
|
|
|
g_RgStaticKeyArray = RgSmAllocMemory(NUMBER_STATIC_KEYS * sizeof(KEY));
|
|
|
|
if (IsNullPtr(g_RgStaticKeyArray))
|
|
return FALSE;
|
|
|
|
for (Index = NUMBER_STATIC_KEYS, hKey = g_RgStaticKeyArray; Index > 0;
|
|
Index--, hKey++) {
|
|
hKey-> Signature = KEY_SIGNATURE;
|
|
hKey-> Flags = KEYF_STATIC | KEYF_INVALID;
|
|
hKey-> ReferenceCount = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
#endif
|
|
|
|
#ifdef WANT_FULL_MEMORY_CLEANUP
|
|
//
|
|
// RgFreeKeyHandleStructures
|
|
//
|
|
// Releases resources allocated by RgAllocKeyHandleStructures.
|
|
//
|
|
|
|
VOID
|
|
INTERNAL
|
|
RgFreeKeyHandleStructures(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HKEY hTempKey;
|
|
HKEY hKey;
|
|
|
|
//
|
|
// Delete all of the dynamically allocated keys.
|
|
//
|
|
|
|
hKey = g_RgDynamicKeyList;
|
|
|
|
if (!IsNullPtr(hKey)) {
|
|
do {
|
|
hTempKey = hKey;
|
|
hKey = hKey-> lpNext;
|
|
#ifdef WANT_DYNKEY_SUPPORT
|
|
if (!IsNullPtr(hTempKey-> pProvider))
|
|
RgSmFreeMemory(hTempKey-> pProvider);
|
|
#endif
|
|
RgSmFreeMemory(hTempKey);
|
|
} while (hKey != g_RgDynamicKeyList);
|
|
}
|
|
|
|
g_RgDynamicKeyList = NULL;
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
//
|
|
// Delete the static key table.
|
|
//
|
|
|
|
if (!IsNullPtr(g_RgStaticKeyArray)) {
|
|
RgSmFreeMemory(g_RgStaticKeyArray);
|
|
g_RgStaticKeyArray = NULL;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// RgCreateKeyHandle
|
|
//
|
|
// Allocates one KEY structure, initializes some of its members, and links it
|
|
// to the list of open key handles.
|
|
//
|
|
|
|
HKEY
|
|
INTERNAL
|
|
RgCreateKeyHandle(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
UINT Index;
|
|
#endif
|
|
HKEY hKey;
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
//
|
|
// Check if any keys are available in the static pool.
|
|
//
|
|
|
|
if (!IsNullPtr(g_RgStaticKeyArray)) {
|
|
|
|
for (Index = NUMBER_STATIC_KEYS, hKey = g_RgStaticKeyArray; Index > 0;
|
|
Index--, hKey++) {
|
|
if (hKey-> Flags & KEYF_INVALID) {
|
|
ASSERT(hKey-> ReferenceCount == 0);
|
|
hKey-> Flags &= ~(KEYF_INVALID | KEYF_DELETED |
|
|
KEYF_ENUMKEYCACHED);
|
|
return hKey;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Must allocate a dynamic key. Initialize it and add it to our list.
|
|
//
|
|
|
|
hKey = (HKEY) RgSmAllocMemory(sizeof(KEY));
|
|
|
|
if (!IsNullPtr(hKey)) {
|
|
|
|
hKey-> Signature = KEY_SIGNATURE;
|
|
hKey-> Flags = 0;
|
|
hKey-> ReferenceCount = 0;
|
|
#ifdef WANT_DYNKEY_SUPPORT
|
|
hKey-> pProvider = NULL;
|
|
#endif
|
|
|
|
if (IsNullPtr(g_RgDynamicKeyList)) {
|
|
hKey-> lpPrev = hKey;
|
|
hKey-> lpNext = hKey;
|
|
}
|
|
|
|
else if (hKey != g_RgDynamicKeyList) {
|
|
hKey-> lpNext = g_RgDynamicKeyList;
|
|
hKey-> lpPrev = g_RgDynamicKeyList-> lpPrev;
|
|
hKey-> lpPrev-> lpNext = hKey;
|
|
g_RgDynamicKeyList-> lpPrev = hKey;
|
|
}
|
|
|
|
g_RgDynamicKeyList = hKey;
|
|
|
|
}
|
|
|
|
return hKey;
|
|
|
|
}
|
|
|
|
//
|
|
// RgDeleteKeyHandle
|
|
//
|
|
// Decrements the reference count on the given key handle. If the count
|
|
// reaches zero and the key was dynamically allocated, then the key is unlinked
|
|
// from the key list and the key is freed.
|
|
//
|
|
|
|
VOID
|
|
INTERNAL
|
|
RgDestroyKeyHandle(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
|
|
ASSERT(!IsNullPtr(hKey));
|
|
|
|
// Don't allow the reference count to underflow for predefined keys or
|
|
// keys marked "never delete".
|
|
if (hKey-> ReferenceCount > 0)
|
|
hKey-> ReferenceCount--;
|
|
|
|
if (hKey-> ReferenceCount == 0) {
|
|
|
|
if (!(hKey-> Flags & (KEYF_PREDEFINED | KEYF_NEVERDELETE))) {
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
if (hKey-> Flags & KEYF_STATIC) {
|
|
hKey-> Flags |= KEYF_INVALID;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (hKey == hKey-> lpNext)
|
|
g_RgDynamicKeyList = NULL;
|
|
|
|
else {
|
|
|
|
hKey-> lpPrev-> lpNext = hKey-> lpNext;
|
|
hKey-> lpNext-> lpPrev = hKey-> lpPrev;
|
|
|
|
if (hKey == g_RgDynamicKeyList)
|
|
g_RgDynamicKeyList = hKey-> lpNext;
|
|
|
|
}
|
|
|
|
#ifdef WANT_DYNKEY_SUPPORT
|
|
if (!IsNullPtr(hKey-> pProvider))
|
|
RgSmFreeMemory(hKey-> pProvider);
|
|
#endif
|
|
|
|
hKey-> Signature = 0;
|
|
RgSmFreeMemory(hKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// RgValidateAndConvertKeyHandle
|
|
//
|
|
// Verifies the the given key handle is valid. If the handle is one of the
|
|
// special predefined constants, then it is converted to the handle of the
|
|
// real KEY structure.
|
|
//
|
|
|
|
int
|
|
INTERNAL
|
|
RgValidateAndConvertKeyHandle(
|
|
LPHKEY lphKey
|
|
)
|
|
{
|
|
|
|
HKEY hKey;
|
|
UINT Index;
|
|
HKEY hRootKey;
|
|
LPCSTR lpSubKey;
|
|
|
|
hKey = *lphKey;
|
|
|
|
//
|
|
// Check if this is one of the predefined key handles.
|
|
//
|
|
|
|
if ((DWORD) HKEY_CLASSES_ROOT <= (DWORD) hKey &&
|
|
(DWORD) hKey < (DWORD) HKEY_CLASSES_ROOT + NUMBER_PREDEF_KEYS) {
|
|
|
|
Index = (UINT) ((DWORD) hKey - (DWORD) HKEY_CLASSES_ROOT);
|
|
hKey = g_RgPredefinedKeys[Index];
|
|
|
|
// If the predefined handle is not valid, we'll try to (re)open it for
|
|
// use. This isn't pretty, but in the typical case, this code path is
|
|
// only executed once per handle.
|
|
if (IsNullPtr(hKey) || (hKey-> Flags & KEYF_DELETED)) {
|
|
|
|
if (Index == INDEX_CLASSES_ROOT) {
|
|
hRootKey = &g_RgLocalMachineKey;
|
|
lpSubKey = g_RgClassesRootSubKey;
|
|
}
|
|
|
|
else if (Index == INDEX_CURRENT_USER) {
|
|
hRootKey = &g_RgUsersKey;
|
|
lpSubKey = g_RgCurrentUserSubKey;
|
|
}
|
|
|
|
else if (Index == INDEX_USERS) {
|
|
goto ReturnKeyAndSuccess;
|
|
}
|
|
|
|
else
|
|
return ERROR_BADKEY;
|
|
|
|
// Extremely rare case: somebody has deleted one of the predefined
|
|
// key paths. We'll clear the predefined bit on this key and throw
|
|
// it away.
|
|
if (!IsNullPtr(hKey)) {
|
|
g_RgPredefinedKeys[Index] = NULL;
|
|
hKey-> Flags &= ~KEYF_PREDEFINED;
|
|
RgDestroyKeyHandle(hKey);
|
|
}
|
|
|
|
// If the base root key for this predefined key is valid, attempt
|
|
// to open the key. Mark the key as predefined so that bad apps
|
|
// can't close a key more times then it has opened it.
|
|
if (!(hRootKey-> Flags & KEYF_INVALID) && RgLookupKey(hRootKey,
|
|
lpSubKey, &hKey, LK_CREATE) == ERROR_SUCCESS) {
|
|
g_RgPredefinedKeys[Index] = hKey;
|
|
hKey-> Flags |= KEYF_PREDEFINED;
|
|
hKey-> PredefinedKeyIndex = (BYTE) Index;
|
|
goto ReturnKeyAndSuccess;
|
|
}
|
|
|
|
return ERROR_BADKEY;
|
|
|
|
}
|
|
|
|
ReturnKeyAndSuccess:
|
|
*lphKey = hKey;
|
|
return (hKey-> Flags & KEYF_INVALID) ? ERROR_BADKEY : ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (IsBadHugeReadPtr(hKey, sizeof(KEY)) || hKey-> Signature !=
|
|
KEY_SIGNATURE || (hKey-> Flags & KEYF_INVALID))
|
|
return ERROR_BADKEY;
|
|
|
|
return (hKey-> Flags & KEYF_DELETED) ? ERROR_KEY_DELETED :
|
|
ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// RgIncrementKeyReferenceCount
|
|
//
|
|
// Safely increments the reference count of the specified KEY. If the count
|
|
// overflows, then the key is marked as "never delete" since the usage count
|
|
// is now unknown.
|
|
//
|
|
|
|
VOID
|
|
INTERNAL
|
|
RgIncrementKeyReferenceCount(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
|
|
if (hKey-> ReferenceCount != UINT_MAX)
|
|
hKey-> ReferenceCount++;
|
|
else {
|
|
if (!(hKey-> Flags & KEYF_NEVERDELETE)) {
|
|
TRACE(("RgIncrementKeyReferenceCount: handle %lx has overflowed\n",
|
|
hKey));
|
|
}
|
|
hKey-> Flags |= KEYF_NEVERDELETE;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// RgFindOpenKeyHandle
|
|
//
|
|
// Searches the list of currently opened keys for a key that refers to the same
|
|
// FILE_INFO structure and keynode offset. If found, the HKEY is returned, or
|
|
// if not, NULL.
|
|
//
|
|
|
|
HKEY
|
|
INTERNAL
|
|
RgFindOpenKeyHandle(
|
|
LPFILE_INFO lpFileInfo,
|
|
DWORD KeynodeIndex
|
|
)
|
|
{
|
|
|
|
UINT Index;
|
|
LPHKEY lphKey;
|
|
HKEY hKey;
|
|
|
|
ASSERT(!IsNullKeynodeIndex(KeynodeIndex));
|
|
|
|
//
|
|
// Check if this is one of the predefined key handles.
|
|
//
|
|
|
|
for (Index = NUMBER_PREDEF_KEYS, lphKey = g_RgPredefinedKeys; Index > 0;
|
|
Index--, lphKey++) {
|
|
|
|
hKey = *lphKey;
|
|
|
|
if (!IsNullPtr(hKey) && hKey-> lpFileInfo == lpFileInfo && hKey->
|
|
KeynodeIndex == KeynodeIndex && !(hKey-> Flags & (KEYF_DELETED |
|
|
KEYF_INVALID)))
|
|
return hKey;
|
|
|
|
}
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
//
|
|
// Check if this is one of the static key handles.
|
|
//
|
|
|
|
if (!IsNullPtr(g_RgStaticKeyArray)) {
|
|
|
|
for (Index = NUMBER_STATIC_KEYS, hKey = g_RgStaticKeyArray; Index > 0;
|
|
Index--, hKey++) {
|
|
if (hKey-> lpFileInfo == lpFileInfo && hKey-> KeynodeIndex ==
|
|
KeynodeIndex && !(hKey-> Flags & (KEYF_DELETED | KEYF_INVALID)))
|
|
return hKey;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Check if this is one of the dynamic key handles.
|
|
//
|
|
|
|
if (!IsNullPtr((hKey = g_RgDynamicKeyList))) {
|
|
|
|
do {
|
|
|
|
if (hKey-> KeynodeIndex == KeynodeIndex && hKey-> lpFileInfo ==
|
|
lpFileInfo && !(hKey-> Flags & KEYF_DELETED))
|
|
return hKey;
|
|
|
|
hKey = hKey-> lpNext;
|
|
|
|
} while (hKey != g_RgDynamicKeyList);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// RgInvalidateKeyHandles
|
|
//
|
|
// Generic routine to invalidate key handles based on a set of criteria.
|
|
// If any key handle meets any of the given criteria, then it's marked invalid.
|
|
//
|
|
|
|
VOID
|
|
INTERNAL
|
|
RgInvalidateKeyHandles(
|
|
LPFILE_INFO lpFileInfo,
|
|
UINT PredefinedKeyIndex
|
|
)
|
|
{
|
|
|
|
UINT Index;
|
|
LPHKEY lphKey;
|
|
HKEY hKey;
|
|
|
|
//
|
|
// Invalidate predefined key handles.
|
|
//
|
|
|
|
for (Index = NUMBER_PREDEF_KEYS, lphKey = g_RgPredefinedKeys; Index > 0;
|
|
Index--, lphKey++) {
|
|
|
|
hKey = *lphKey;
|
|
|
|
if (!IsNullPtr(hKey)) {
|
|
if (hKey-> lpFileInfo == lpFileInfo || hKey-> PredefinedKeyIndex ==
|
|
(BYTE) PredefinedKeyIndex)
|
|
hKey-> Flags |= (KEYF_DELETED | KEYF_INVALID);
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef WANT_STATIC_KEYS
|
|
//
|
|
// Invalidate static key handles.
|
|
//
|
|
|
|
if (!IsNullPtr(g_RgStaticKeyArray)) {
|
|
|
|
for (Index = NUMBER_STATIC_KEYS, hKey = g_RgStaticKeyArray; Index > 0;
|
|
Index--, hKey++) {
|
|
if (hKey-> lpFileInfo == lpFileInfo || hKey-> PredefinedKeyIndex ==
|
|
PredefinedKeyIndex)
|
|
hKey-> Flags |= (KEYF_DELETED | KEYF_INVALID);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Invalidate dynamic key handles.
|
|
//
|
|
|
|
if (!IsNullPtr((hKey = g_RgDynamicKeyList))) {
|
|
|
|
do {
|
|
|
|
if (hKey-> lpFileInfo == lpFileInfo || hKey-> PredefinedKeyIndex ==
|
|
(BYTE) PredefinedKeyIndex)
|
|
hKey-> Flags |= (KEYF_DELETED | KEYF_INVALID);
|
|
|
|
hKey = hKey-> lpNext;
|
|
|
|
} while (hKey != g_RgDynamicKeyList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef VXD
|
|
#pragma VxD_RARE_CODE_SEG
|
|
#endif
|
|
|
|
//
|
|
// VMMRegMapPredefKeyToKey
|
|
//
|
|
|
|
LONG
|
|
REGAPI
|
|
VMMRegMapPredefKeyToKey(
|
|
HKEY hTargetKey,
|
|
HKEY hPredefKey
|
|
)
|
|
{
|
|
|
|
int ErrorCode;
|
|
UINT PredefinedKeyIndex;
|
|
HKEY hOldKey;
|
|
|
|
if (!RgLockRegistry())
|
|
return ERROR_LOCK_FAILED;
|
|
|
|
if ((ErrorCode = RgValidateAndConvertKeyHandle(&hTargetKey)) ==
|
|
ERROR_SUCCESS) {
|
|
|
|
if ((hPredefKey == HKEY_CURRENT_USER && hTargetKey->
|
|
PredefinedKeyIndex == INDEX_USERS) || (hPredefKey ==
|
|
HKEY_CURRENT_CONFIG && hTargetKey-> PredefinedKeyIndex ==
|
|
INDEX_LOCAL_MACHINE)) {
|
|
|
|
PredefinedKeyIndex = (UINT) ((DWORD) hPredefKey - (DWORD)
|
|
HKEY_CLASSES_ROOT);
|
|
|
|
hOldKey = g_RgPredefinedKeys[PredefinedKeyIndex];
|
|
|
|
if (!IsNullPtr(hOldKey)) {
|
|
|
|
// Invalidate open handles based off the existing predefined
|
|
// key handle. Win95 behavior.
|
|
RgInvalidateKeyHandles((LPFILE_INFO) -1L, (BYTE)
|
|
PredefinedKeyIndex);
|
|
|
|
hOldKey-> Flags &= ~KEYF_PREDEFINED;
|
|
RgDestroyKeyHandle(hOldKey);
|
|
|
|
}
|
|
|
|
hTargetKey-> Flags |= KEYF_PREDEFINED;
|
|
RgIncrementKeyReferenceCount(hTargetKey);
|
|
g_RgPredefinedKeys[PredefinedKeyIndex] = hTargetKey;
|
|
|
|
}
|
|
|
|
else {
|
|
DEBUG_OUT(("VMMRegMapPredefKeyToKey: invalid hTargetKey\n"));
|
|
ErrorCode = ERROR_BADKEY;
|
|
}
|
|
|
|
}
|
|
|
|
RgUnlockRegistry();
|
|
|
|
return ErrorCode;
|
|
|
|
}
|