359 lines
8.4 KiB
C
359 lines
8.4 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Regnccls.c
|
||
|
||
Abstract:
|
||
|
||
This file contains functions needed for handling
|
||
change notifications in the classes portion of the registry
|
||
|
||
Author:
|
||
|
||
Adam P. Edwards (adamed) 14-Nov-1997
|
||
|
||
Key Functions:
|
||
|
||
BaseRegNotifyClassKey
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
|
||
#ifdef LOCAL
|
||
|
||
#include <rpc.h>
|
||
#include <string.h>
|
||
#include <wchar.h>
|
||
#include "regrpc.h"
|
||
#include "localreg.h"
|
||
#include "regclass.h"
|
||
#include "regnccls.h"
|
||
#include <malloc.h>
|
||
|
||
NTSTATUS BaseRegNotifyClassKey(
|
||
IN HKEY hKey,
|
||
IN HANDLE hEvent,
|
||
IN PIO_STATUS_BLOCK pLocalIoStatusBlock,
|
||
IN DWORD dwNotifyFilter,
|
||
IN BOOLEAN fWatchSubtree,
|
||
IN BOOLEAN fAsynchronous)
|
||
{
|
||
NTSTATUS Status;
|
||
HKEY hkUser;
|
||
HKEY hkMachine;
|
||
SKeySemantics KeyInfo;
|
||
UNICODE_STRING EmptyString = {0, 0, 0};
|
||
BYTE rgNameBuf[REG_MAX_CLASSKEY_LEN + REG_CHAR_SIZE + sizeof(OBJECT_NAME_INFORMATION)];
|
||
OBJECT_ATTRIBUTES Obja;
|
||
BOOL fAllocatedPath;
|
||
|
||
//
|
||
// Set buffer to store info about this key
|
||
//
|
||
KeyInfo._pFullPath = (PKEY_NAME_INFORMATION) rgNameBuf;
|
||
KeyInfo._cbFullPath = sizeof(rgNameBuf);
|
||
KeyInfo._fAllocedNameBuf = FALSE;
|
||
|
||
//
|
||
// get information about this key
|
||
//
|
||
Status = BaseRegGetKeySemantics(hKey, &EmptyString, &KeyInfo);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Initialize conditionally freed resources
|
||
//
|
||
hkUser = NULL;
|
||
hkMachine = NULL;
|
||
|
||
fAllocatedPath = FALSE;
|
||
Obja.ObjectName = NULL;
|
||
|
||
//
|
||
// Now get handles for both user and machine versions of the key
|
||
//
|
||
Status = BaseRegGetUserAndMachineClass(
|
||
&KeyInfo,
|
||
hKey,
|
||
KEY_NOTIFY,
|
||
&hkUser,
|
||
&hkMachine);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
if (fWatchSubtree || (hkUser && hkMachine)) {
|
||
|
||
//
|
||
// This will return the closest ancestor to the
|
||
// nonexistent translated key -- note that it allocates memory
|
||
// to the Obja.ObjectName member, so we need to free that on
|
||
// success
|
||
//
|
||
Status = BaseRegGetBestAncestor(
|
||
&KeyInfo,
|
||
hkUser,
|
||
hkMachine,
|
||
&Obja);
|
||
|
||
fAllocatedPath = Obja.ObjectName != NULL;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Ask for the notify on both user and machine keys (or
|
||
// the closest approximation). Note that we pass a full path --
|
||
// if we used an relative path with an object handle instead, we
|
||
// would never have an opportunity to close the object, so we would
|
||
// leak objects
|
||
//
|
||
//
|
||
Status = NtNotifyChangeMultipleKeys(
|
||
hKey,
|
||
1,
|
||
&Obja,
|
||
hEvent,
|
||
NULL,
|
||
NULL,
|
||
pLocalIoStatusBlock,
|
||
dwNotifyFilter,
|
||
fWatchSubtree,
|
||
NULL,
|
||
0,
|
||
fAsynchronous
|
||
);
|
||
|
||
} else {
|
||
|
||
Status = NtNotifyChangeKey(
|
||
hkUser ? hkUser : hkMachine,
|
||
hEvent,
|
||
NULL,
|
||
NULL,
|
||
pLocalIoStatusBlock,
|
||
dwNotifyFilter,
|
||
fWatchSubtree,
|
||
NULL,
|
||
0,
|
||
fAsynchronous
|
||
);
|
||
}
|
||
|
||
cleanup:
|
||
|
||
//if (!NT_SUCCESS(Status)) {
|
||
|
||
if (hkUser && (hkUser != hKey)) {
|
||
NtClose(hkUser);
|
||
}
|
||
|
||
if (hkMachine && (hkMachine != hKey)) {
|
||
NtClose(hkMachine);
|
||
}
|
||
//}
|
||
|
||
if (fAllocatedPath) {
|
||
RegClassHeapFree(Obja.ObjectName);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS BaseRegGetBestAncestor(
|
||
IN SKeySemantics* pKeySemantics,
|
||
IN HKEY hkUser,
|
||
IN HKEY hkMachine,
|
||
IN POBJECT_ATTRIBUTES pObja)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Finds a full object path for the closest ancestor for a key
|
||
described by a key semantics structure
|
||
|
||
|
||
Arguments:
|
||
|
||
pKeySemantics - contains information about a registry key
|
||
hkUser - handle to a user class version of the key above
|
||
hkMachine - handle to a machine class version of the key above
|
||
pObja - Object Attributes structure to initialize with a full
|
||
object path for the closest ancestor -- not that memory
|
||
is allocated for the ObjectName member of the structure
|
||
which must be freed by the caller -- caller should
|
||
check this member to see if it's non-NULL, regardless
|
||
of success code returned by function
|
||
|
||
Return Value:
|
||
|
||
Returns ERROR_SUCCESS (0) for success; error-code for failure.
|
||
|
||
--*/
|
||
{
|
||
USHORT PrefixLen;
|
||
NTSTATUS Status;
|
||
PUNICODE_STRING pKeyPath;
|
||
USHORT uMaxLen;
|
||
|
||
//
|
||
// Allocate memory for the Obja's ObjectName member
|
||
//
|
||
uMaxLen = (USHORT) pKeySemantics->_pFullPath->NameLength + REG_CLASSES_SUBTREE_PADDING;
|
||
|
||
pKeyPath = RegClassHeapAlloc(uMaxLen + sizeof(*pKeyPath));
|
||
|
||
if (!(pKeyPath)) {
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
//
|
||
// Now initialize the structure
|
||
//
|
||
pKeyPath->MaximumLength = uMaxLen;
|
||
pKeyPath->Buffer = (WCHAR*) (((PBYTE) pKeyPath) + sizeof(*pKeyPath));
|
||
|
||
//
|
||
// Now form a version of this key path in the opposite tree
|
||
//
|
||
if (pKeySemantics->_fUser) {
|
||
|
||
Status = BaseRegTranslateToMachineClassKey(
|
||
pKeySemantics,
|
||
pKeyPath,
|
||
&PrefixLen);
|
||
|
||
} else {
|
||
|
||
Status = BaseRegTranslateToUserClassKey(
|
||
pKeySemantics,
|
||
pKeyPath,
|
||
&PrefixLen);
|
||
}
|
||
|
||
//
|
||
// Make sure the caller has a reference to allocated memory
|
||
//
|
||
pObja->ObjectName = pKeyPath;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Set up the object attributes with this translated key so
|
||
// we can use the structure to notify keys
|
||
//
|
||
InitializeObjectAttributes(
|
||
pObja,
|
||
pKeyPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL, // using absolute path, no hkey
|
||
NULL);
|
||
|
||
//
|
||
// If we were supplied both keys, then they both exist,
|
||
// so we can simply use the translated path above
|
||
//
|
||
if (hkUser && hkMachine) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// At this point, we know the translated path doesn't exist,
|
||
// since we only have a handle for one of the paths. Therefore
|
||
// we will attempt to find an approximation. Note that the
|
||
// manipulation of KeyPath below affects the Obja passed in since
|
||
// the Obja struct references KeyPath
|
||
//
|
||
do
|
||
{
|
||
WCHAR* pBufferEnd;
|
||
HKEY hkExistingKey;
|
||
|
||
//
|
||
// Find the last pathsep in the current key path
|
||
//
|
||
pBufferEnd = wcsrchr(pKeyPath->Buffer, L'\\');
|
||
|
||
//
|
||
// We should never get NULL here, because all keys
|
||
// have the ancestory \Registry\User or \Registry\Machine,
|
||
// each which have two pathseps to spare -- the loop
|
||
// terminates once that path is shorter than those prefixes,
|
||
// so we should never encounter this situation
|
||
//
|
||
ASSERT(pBufferEnd);
|
||
|
||
//
|
||
// Now truncate the string
|
||
//
|
||
*pBufferEnd = L'\0';
|
||
|
||
//
|
||
// Adjust the unicode string structure to conform
|
||
// to the truncated string
|
||
//
|
||
RtlInitUnicodeString(pKeyPath, pKeyPath->Buffer);
|
||
|
||
//
|
||
// Now attempt to open with this truncated path
|
||
//
|
||
Status = NtOpenKey(
|
||
&hkExistingKey,
|
||
KEY_NOTIFY,
|
||
pObja);
|
||
|
||
//
|
||
// If we do open it, we will close it and not pass this object
|
||
// since we want our obja to use a full path and not a relative
|
||
// path off a kernel object
|
||
//
|
||
if (NT_SUCCESS(Status)) {
|
||
NtClose(hkExistingKey);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// If we get any error besides a key not found error, then our reason
|
||
// for failing the open is not because the key did not exist, but because
|
||
// of some other error, most likely access denied.
|
||
//
|
||
if (STATUS_OBJECT_NAME_NOT_FOUND != Status) {
|
||
break;
|
||
}
|
||
|
||
} while (pKeyPath->Length > PrefixLen);
|
||
|
||
cleanup:
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
#endif // defined ( LOCAL )
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|