990 lines
24 KiB
C
990 lines
24 KiB
C
|
/*++
|
|||
|
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Predefh.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the client side support for managing the Win32
|
|||
|
Registry API's predefined handles. This support is supplied via a
|
|||
|
table, which maps (a) predefined handles to real handles and (b)
|
|||
|
the server side routine which opens the handle.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David J. Gilman (davegi) 15-Nov-1991
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
See the notes in server\predefh.c.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <rpc.h>
|
|||
|
#include "regrpc.h"
|
|||
|
#include "client.h"
|
|||
|
|
|||
|
#if defined(LEAK_TRACK)
|
|||
|
NTSTATUS TrackObject(HKEY hKey);
|
|||
|
#endif // LEAK_TRACK
|
|||
|
|
|||
|
RTL_CRITICAL_SECTION PredefinedHandleTableCriticalSection;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// For each predefined handle an entry is maintained in an array. Each of
|
|||
|
// these structures contains a real (context) handle and a pointer to a
|
|||
|
// function that knows how to map the predefined handle to the Registry name
|
|||
|
// space.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to function to open predefined handles.
|
|||
|
//
|
|||
|
|
|||
|
typedef
|
|||
|
error_status_t
|
|||
|
( *OPEN_FUNCTION ) (
|
|||
|
PREGISTRY_SERVER_NAME,
|
|||
|
REGSAM,
|
|||
|
PRPC_HKEY
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Table entry for a predefined handle.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _PRDEFINED_HANDLE {
|
|||
|
|
|||
|
RPC_HKEY Handle;
|
|||
|
OPEN_FUNCTION OpenFunc;
|
|||
|
BOOLEAN Disabled; // tells whether the handle should be cached or not.
|
|||
|
|
|||
|
#if DBG
|
|||
|
ULONG Callers;
|
|||
|
PVOID CallerAddress[10];
|
|||
|
#endif
|
|||
|
|
|||
|
} PREDEFINED_HANDLE, *PPREDEFINED_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize predefined handle table.
|
|||
|
//
|
|||
|
PREDEFINED_HANDLE PredefinedHandleTable[ ] = {
|
|||
|
|
|||
|
NULL, LocalOpenClassesRoot, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenCurrentUser, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenLocalMachine, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenUsers, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenPerformanceData, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenPerformanceText, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenPerformanceNlsText, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenCurrentConfig, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
,
|
|||
|
NULL, LocalOpenDynData, FALSE
|
|||
|
#if DBG
|
|||
|
, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|||
|
#endif
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
#define MAX_PREDEFINED_HANDLES \
|
|||
|
( sizeof( PredefinedHandleTable ) / sizeof( PREDEFINED_HANDLE ))
|
|||
|
|
|||
|
//
|
|||
|
// Predefined HKEY values are defined in Winreg.x. They MUST be kept in
|
|||
|
// synch with the following constants and macros.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Mark Registry handles so that we can recognize predefined handles.
|
|||
|
//
|
|||
|
|
|||
|
#define PREDEFINED_REGISTRY_HANDLE_SIGNATURE ( 0x80000000 )
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SetHandleProtection(
|
|||
|
IN HANDLE Handle,
|
|||
|
IN LONG Index,
|
|||
|
IN BOOLEAN Protect
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Changes the handle ProtectFromClose attribute. To be used for predefined handles,
|
|||
|
to prevent abnormal closure.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - Supplies the handle who's protection to be changed.
|
|||
|
|
|||
|
Index - Index in the predefined handle table
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the NtSetInformationObject call
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
OBJECT_HANDLE_FLAG_INFORMATION Ohfi = { FALSE,
|
|||
|
FALSE
|
|||
|
};
|
|||
|
ULONG PredefHandle;
|
|||
|
|
|||
|
PredefHandle = ((ULONG)Index) | PREDEFINED_REGISTRY_HANDLE_SIGNATURE;
|
|||
|
|
|||
|
switch (PredefHandle) {
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_CLASSES_ROOT):
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_CURRENT_USER):
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_LOCAL_MACHINE):
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_USERS):
|
|||
|
//
|
|||
|
// go change the protection
|
|||
|
//
|
|||
|
break;
|
|||
|
default:
|
|||
|
//
|
|||
|
// The supplied handle might not be a real handle
|
|||
|
//
|
|||
|
return STATUS_INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Ohfi.ProtectFromClose = Protect;
|
|||
|
|
|||
|
Status = NtSetInformationObject(Handle,
|
|||
|
ObjectHandleFlagInformation,
|
|||
|
&Ohfi,
|
|||
|
sizeof (OBJECT_HANDLE_FLAG_INFORMATION));
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
DbgPrint( "WINREG: SetHandleProtection (%u) on %lx failed. Status = %lx \n",Protect, Handle, Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
LONG
|
|||
|
MapPredefinedRegistryHandleToIndex(
|
|||
|
IN ULONG Handle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Maps a predefined handle to an index into the predefined handle table.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - Supplies the handle to be mapped.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
An index into the predefined handle table
|
|||
|
-1 if the handle is not a predefined handle
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LONG Index;
|
|||
|
|
|||
|
switch (Handle) {
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_CLASSES_ROOT):
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_CURRENT_USER):
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_LOCAL_MACHINE):
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_USERS):
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_PERFORMANCE_DATA):
|
|||
|
Index = (Handle & ~PREDEFINED_REGISTRY_HANDLE_SIGNATURE);
|
|||
|
break;
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_PERFORMANCE_TEXT):
|
|||
|
Index = 5;
|
|||
|
break;
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT):
|
|||
|
Index = 6;
|
|||
|
break;
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_CURRENT_CONFIG):
|
|||
|
Index = 7;
|
|||
|
break;
|
|||
|
case (ULONG)((ULONG_PTR)HKEY_DYN_DATA):
|
|||
|
Index = 8;
|
|||
|
break;
|
|||
|
default:
|
|||
|
//
|
|||
|
// The supplied handle is not predefined, so return it.
|
|||
|
//
|
|||
|
Index = -1;
|
|||
|
break;
|
|||
|
}
|
|||
|
return(Index);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RemapPredefinedHandle(
|
|||
|
IN RPC_HKEY Handle,
|
|||
|
IN RPC_HKEY NewHandle
|
|||
|
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Override the current predefined handle. If it is already open, close it,
|
|||
|
then set the new handle
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - Supplies a handle which must be a predefined handle
|
|||
|
NewHandle - an already open registry key to override the special key
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS - no problems
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONG Index;
|
|||
|
LONG Error;
|
|||
|
NTSTATUS Status;
|
|||
|
HANDLE hCurrentProcess;
|
|||
|
HKEY hkTableHandle = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// If the high bit is not set, we know it's not a predefined handle
|
|||
|
// so take a quick out.
|
|||
|
//
|
|||
|
if (((ULONG_PTR)Handle & 0x80000000) == 0) {
|
|||
|
return(STATUS_INVALID_HANDLE);
|
|||
|
}
|
|||
|
|
|||
|
Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
#if DBG
|
|||
|
DbgPrint( "WINREG: RtlEnterCriticalSection() on RemapPredefinedHandle() failed. Status = %lx \n", Status );
|
|||
|
#endif
|
|||
|
Status = ERROR_INVALID_HANDLE;
|
|||
|
goto cleanup_and_exit;
|
|||
|
}
|
|||
|
|
|||
|
Index = MapPredefinedRegistryHandleToIndex((ULONG)(ULONG_PTR)Handle);
|
|||
|
|
|||
|
if (Index == -1) {
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
goto leave_crit_sect;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
|
|||
|
|
|||
|
if( PredefinedHandleTable[ Index ].Disabled == TRUE ) {
|
|||
|
//
|
|||
|
// predefined table is disabled for this key
|
|||
|
//
|
|||
|
|
|||
|
// nobody is allowed to write here
|
|||
|
ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
|
|||
|
|
|||
|
// refuse the request
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
goto leave_crit_sect;
|
|||
|
}
|
|||
|
|
|||
|
hCurrentProcess = NtCurrentProcess();
|
|||
|
|
|||
|
//
|
|||
|
// see if we can duplicate this handle so we can place it
|
|||
|
// in the table
|
|||
|
//
|
|||
|
if (NewHandle && !NT_SUCCESS(Status = NtDuplicateObject (hCurrentProcess,
|
|||
|
NewHandle,
|
|||
|
hCurrentProcess,
|
|||
|
&hkTableHandle,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
DUPLICATE_SAME_ACCESS))) {
|
|||
|
goto leave_crit_sect;
|
|||
|
}
|
|||
|
|
|||
|
if (NewHandle && IsSpecialClassesHandle(NewHandle)) {
|
|||
|
TagSpecialClassesHandle( &hkTableHandle );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the predefined handle has already been opened try
|
|||
|
// and close the key now.
|
|||
|
//
|
|||
|
if( PredefinedHandleTable[ Index ].Handle != NULL ) {
|
|||
|
|
|||
|
// make sure the handle CAN be closed.
|
|||
|
SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,FALSE);
|
|||
|
|
|||
|
#if DBG
|
|||
|
PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
|
|||
|
#endif
|
|||
|
|
|||
|
Error = (LONG) RegCloseKey( PredefinedHandleTable[ Index ].Handle );
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ( Error != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
DbgPrint( "Winreg.dll: Cannot close predefined handle\n" );
|
|||
|
DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
|
|||
|
Handle, Index, Error );
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
PredefinedHandleTable[ Index ].Handle = hkTableHandle;
|
|||
|
|
|||
|
// make sure the handle CANNOT be closed.
|
|||
|
SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,TRUE);
|
|||
|
|
|||
|
leave_crit_sect:
|
|||
|
|
|||
|
#if DBG
|
|||
|
{
|
|||
|
NTSTATUS Status =
|
|||
|
#endif DBG
|
|||
|
RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlLeaveCriticalSection() on RemapPredefinedHandle() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
cleanup_and_exit:
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status) && hkTableHandle)
|
|||
|
{
|
|||
|
RegCloseKey(hkTableHandle);
|
|||
|
}
|
|||
|
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_HKEY
|
|||
|
MapPredefinedHandle(
|
|||
|
IN RPC_HKEY Handle,
|
|||
|
OUT PRPC_HKEY HandleToClose
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Attempt to map a predefined handle to a RPC context handle. This in
|
|||
|
turn will map to a real Nt Registry handle.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - Supplies a handle which may be a predefined handle or a handle
|
|||
|
returned from a previous call to any flavour of RegCreateKey,
|
|||
|
RegOpenKey or RegConnectRegistry.
|
|||
|
|
|||
|
HandleToClose - When not NULL, this is the same as the result.
|
|||
|
Used to implement the DisablePredefinedCache feature.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_HKEY- Returns the supplied handle argument if it not predefined,
|
|||
|
a RPC context handle if possible (i.e. it was previously
|
|||
|
opened or can be opened now), NULL otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONG Index;
|
|||
|
LONG Error;
|
|||
|
NTSTATUS Status;
|
|||
|
HANDLE ResultHandle;
|
|||
|
|
|||
|
*HandleToClose = NULL;
|
|||
|
|
|||
|
// reject outrageous calls
|
|||
|
if( Handle == INVALID_HANDLE_VALUE ) {
|
|||
|
return( NULL );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the high bit is not set, we know it's not a predefined handle
|
|||
|
// so take a quick out.
|
|||
|
//
|
|||
|
if (((ULONG_PTR)Handle & 0x80000000) == 0) {
|
|||
|
return(Handle);
|
|||
|
}
|
|||
|
Index = MapPredefinedRegistryHandleToIndex((ULONG)(ULONG_PTR)Handle);
|
|||
|
if (Index == -1) {
|
|||
|
return(Handle);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
|
|||
|
|
|||
|
Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
#if DBG
|
|||
|
DbgPrint( "WINREG: RtlEnterCriticalSection() on MapPredefinedHandle() failed. Status = %lx \n", Status );
|
|||
|
#endif
|
|||
|
return( NULL );
|
|||
|
}
|
|||
|
|
|||
|
if( PredefinedHandleTable[ Index ].Disabled == TRUE ) {
|
|||
|
//
|
|||
|
// for this handle the predefined feature has been disabled
|
|||
|
//
|
|||
|
|
|||
|
// nobody is allowed to write here
|
|||
|
ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
|
|||
|
|
|||
|
//
|
|||
|
// open a new handle for this request and store it in "toClose"
|
|||
|
// argument so the caller knows that should close it
|
|||
|
//
|
|||
|
( *PredefinedHandleTable[ Index ].OpenFunc )(
|
|||
|
NULL,
|
|||
|
MAXIMUM_ALLOWED,
|
|||
|
HandleToClose
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
// return the new handle to the caller
|
|||
|
ResultHandle = *HandleToClose;
|
|||
|
} else {
|
|||
|
//
|
|||
|
// If the predefined handle has not already been openend try
|
|||
|
// and open the key now.
|
|||
|
//
|
|||
|
if( PredefinedHandleTable[ Index ].Handle == NULL ) {
|
|||
|
|
|||
|
Error = (LONG)( *PredefinedHandleTable[ Index ].OpenFunc )(
|
|||
|
NULL,
|
|||
|
MAXIMUM_ALLOWED,
|
|||
|
&PredefinedHandleTable[ Index ].Handle
|
|||
|
);
|
|||
|
|
|||
|
if( Error == ERROR_SUCCESS ) {
|
|||
|
// make sure the handle CANNOT be closed.
|
|||
|
SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,TRUE);
|
|||
|
}
|
|||
|
|
|||
|
#if defined(LEAK_TRACK)
|
|||
|
|
|||
|
if (g_RegLeakTraceInfo.bEnableLeakTrack) {
|
|||
|
(void) TrackObject(PredefinedHandleTable[ Index ].Handle);
|
|||
|
}
|
|||
|
|
|||
|
#endif // defined(LEAK_TRACK)
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ( Error != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
DbgPrint( "Winreg.dll: Cannot map predefined handle\n" );
|
|||
|
DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
|
|||
|
Handle, Index, Error );
|
|||
|
} else {
|
|||
|
ASSERT( IsLocalHandle( PredefinedHandleTable[ Index ].Handle ));
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
}
|
|||
|
//
|
|||
|
// Map the predefined handle to a real handle (may be NULL
|
|||
|
// if key could not be opened).
|
|||
|
//
|
|||
|
ResultHandle = PredefinedHandleTable[ Index ].Handle;
|
|||
|
|
|||
|
ASSERT(*HandleToClose == NULL);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlLeaveCriticalSection() on MapPredefinedHandle() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
return( ResultHandle );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
CleanupPredefinedHandles(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Runs down the list of predefined handles and closes any that have been opened.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - success
|
|||
|
|
|||
|
FALSE - failure
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONG i;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlEnterCriticalSection() on CleanupPredefinedHandles() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
for (i=0;i<sizeof(PredefinedHandleTable)/sizeof(PREDEFINED_HANDLE);i++) {
|
|||
|
//
|
|||
|
// consistency check
|
|||
|
//
|
|||
|
if( PredefinedHandleTable[ i ].Disabled == TRUE ) {
|
|||
|
//
|
|||
|
// predefined table is disabled for this key
|
|||
|
//
|
|||
|
|
|||
|
// nobody is allowed to write here
|
|||
|
ASSERT( PredefinedHandleTable[ i ].Handle == NULL );
|
|||
|
} else if (PredefinedHandleTable[i].Handle != NULL) {
|
|||
|
// make sure the handle CAN be closed.
|
|||
|
SetHandleProtection(PredefinedHandleTable[ i ].Handle,i,FALSE);
|
|||
|
#if DBG
|
|||
|
PredefinedHandleTable[ i ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ i ].CallerAddress[0]), 10, 0);
|
|||
|
#endif
|
|||
|
LocalBaseRegCloseKey(&PredefinedHandleTable[i].Handle);
|
|||
|
PredefinedHandleTable[i].Handle = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlLeaveCriticalSection() on CleanupPredefinedHandles() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LONG
|
|||
|
ClosePredefinedHandle(
|
|||
|
IN RPC_HKEY Handle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Zero out the predefined handles entry in the predefined handle table
|
|||
|
so that subsequent opens will call the server.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - Supplies a predefined handle.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
HKEY hKey1;
|
|||
|
LONG Error;
|
|||
|
LONG Index;
|
|||
|
|
|||
|
ASSERT( IsPredefinedRegistryHandle( Handle ));
|
|||
|
|
|||
|
Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlEnterCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
|
|||
|
ASSERT( Index != -1 );
|
|||
|
|
|||
|
hKey1 = PredefinedHandleTable[ Index ].Handle;
|
|||
|
if( hKey1 == NULL ) {
|
|||
|
//
|
|||
|
// If the handle was already closed, then return ERROR_SUCCESS.
|
|||
|
// This is because an application may already have called RegCloseKey
|
|||
|
// on a predefined key, and is now callig RegOpenKey on the same
|
|||
|
// predefined key. RegOpenKeyEx will try to close the predefined handle
|
|||
|
// and open a new one, in order to re-impersonate the client. If we don't
|
|||
|
// return ERROR_SUCCESS, then RegOpenKeyEx will not open a new predefined
|
|||
|
// handle, and the API will fail.
|
|||
|
//
|
|||
|
Error = ERROR_SUCCESS;
|
|||
|
} else {
|
|||
|
|
|||
|
// if there is a handle here, the predefined handle is not disabled.
|
|||
|
ASSERT(PredefinedHandleTable[ Index ].Disabled == FALSE);
|
|||
|
|
|||
|
PredefinedHandleTable[ Index ].Handle = NULL;
|
|||
|
#if DBG
|
|||
|
PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlLeaveCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if( hKey1 != NULL ) {
|
|||
|
//
|
|||
|
// close the key now (after leaving critical region to prevent deadlock
|
|||
|
// with dumb heads calling reg apis from DllInit.
|
|||
|
//
|
|||
|
|
|||
|
// make sure the handle CAN be closed.
|
|||
|
SetHandleProtection(hKey1,Index,FALSE);
|
|||
|
|
|||
|
Error = ( LONG ) LocalBaseRegCloseKey( &hKey1 );
|
|||
|
}
|
|||
|
return( Error );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
LONG
|
|||
|
OpenPredefinedKeyForSpecialAccess(
|
|||
|
IN RPC_HKEY Handle,
|
|||
|
IN REGSAM AccessMask,
|
|||
|
OUT PRPC_HKEY pKey
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Attempt to open a predefined key with SYSTEM_SECURITY_ACCESS.
|
|||
|
Such an access is not included on MAXIMUM_ALLOWED, and is needed
|
|||
|
by RegGetKeySecurity and RegSetKeySecurity, in order to retrieve
|
|||
|
and save the SACL of a predefined key.
|
|||
|
|
|||
|
WHEN USING A HANDLE WITH SPECIAL ACCESS, IT IS IMPORTANT TO FOLLOW
|
|||
|
THE RULES BELOW:
|
|||
|
|
|||
|
- HANDLES OPENED FOR SPECIAL ACCESS ARE NEVER SAVED ON THE
|
|||
|
PredefinedHandleTable.
|
|||
|
|
|||
|
- SUCH HANDLES SHOULD BE USED ONLY INTERNALY TO THE CLIENT
|
|||
|
SIDE OF WINREG APIs.
|
|||
|
THEY SHOULD NEVER BE RETURNED TO THE OUTSIDE WORLD.
|
|||
|
|
|||
|
- IT IS THE RESPONSIBILITY OF THE CALLER OF THIS FUNCTION TO CLOSE
|
|||
|
THE HANDLES OPENED BY THIS FUNCTION.
|
|||
|
RegCloseKey() SHOULD BE USED TO CLOSE SUCH HANDLES.
|
|||
|
|
|||
|
|
|||
|
This function should be called only by the following APIs:
|
|||
|
|
|||
|
RegGetKeySecurity -> So that it can retrieve the SACL of a predefined key
|
|||
|
RegSetKeySecurity -> So that it can save the SACL of a predefined key
|
|||
|
RegOpenKeyEx -> So that it can determine wheteher or not the caller of
|
|||
|
RegOpenKeyEx is able to save and restore SACL of
|
|||
|
predefined keys.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - Supplies one of the predefined handle of the local machine.
|
|||
|
|
|||
|
AccessMask - Suplies an access mask that contains the special access
|
|||
|
desired (the ones not included in MAXIMUM_ALLOWED).
|
|||
|
On NT 1.0, ACCESS_SYSTEM_SECURITY is the only one of such
|
|||
|
access.
|
|||
|
|
|||
|
pKey - Pointer to the variable that will contain the handle opened with
|
|||
|
the special access.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
LONG - Returns a DosErrorCode (ERROR_SUCCESS if the operation succeeds).
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONG Index;
|
|||
|
LONG Error;
|
|||
|
|
|||
|
|
|||
|
ASSERT( pKey );
|
|||
|
ASSERT( AccessMask & ACCESS_SYSTEM_SECURITY );
|
|||
|
ASSERT( IsPredefinedRegistryHandle( Handle ) );
|
|||
|
|
|||
|
//
|
|||
|
// Check if the Handle is a predefined handle.
|
|||
|
//
|
|||
|
|
|||
|
if( IsPredefinedRegistryHandle( Handle )) {
|
|||
|
|
|||
|
if( ( ( AccessMask & ACCESS_SYSTEM_SECURITY ) == 0 ) ||
|
|||
|
( pKey == NULL ) ) {
|
|||
|
return( ERROR_INVALID_PARAMETER );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the handle to an index.
|
|||
|
//
|
|||
|
|
|||
|
Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
|
|||
|
ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
|
|||
|
|
|||
|
//
|
|||
|
// If the predefined handle has not already been openend try
|
|||
|
// and open the key now.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
Error = (LONG)( *PredefinedHandleTable[ Index ].OpenFunc )(
|
|||
|
NULL,
|
|||
|
AccessMask,
|
|||
|
pKey
|
|||
|
);
|
|||
|
|
|||
|
/*
|
|||
|
#if DBG
|
|||
|
if ( Error != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
DbgPrint( "Winreg.dll: Cannot map predefined handle\n" );
|
|||
|
DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
|
|||
|
Handle, Index, Error );
|
|||
|
} else {
|
|||
|
ASSERT( IsLocalHandle( PredefinedHandleTable[ Index ].Handle ));
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
*/
|
|||
|
|
|||
|
return Error;
|
|||
|
} else {
|
|||
|
return( ERROR_BADKEY );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
// #endif
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
InitializePredefinedHandlesTable(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize the critical section used by the functions that access
|
|||
|
PredefinedHandleTable.
|
|||
|
This critical section is needed to avoid that a thread closes a predefined
|
|||
|
key, while other threads are accessing the predefined key
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE if the initialization succeeds.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
|
|||
|
NtStatus = RtlInitializeCriticalSection(
|
|||
|
&PredefinedHandleTableCriticalSection
|
|||
|
);
|
|||
|
ASSERT( NT_SUCCESS( NtStatus ) );
|
|||
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
return( TRUE );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
CleanupPredefinedHandlesTable(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Delete the critical section used by the functions that access the
|
|||
|
PredefinedHandleTable.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE if the cleanup succeeds.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Delete the critical section
|
|||
|
//
|
|||
|
NtStatus = RtlDeleteCriticalSection(
|
|||
|
&PredefinedHandleTableCriticalSection
|
|||
|
);
|
|||
|
|
|||
|
ASSERT( NT_SUCCESS( NtStatus ) );
|
|||
|
|
|||
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DisablePredefinedHandleTable(
|
|||
|
HKEY Handle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Disables the predefined handle table for the current user
|
|||
|
key. Eventually closes the handle in predefined handle, if already open
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - predefined handle for which to disable (now only current user)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
LONG Index;
|
|||
|
|
|||
|
if( Handle != HKEY_CURRENT_USER ) {
|
|||
|
//
|
|||
|
// feature enabled only for current user at this time
|
|||
|
//
|
|||
|
return STATUS_INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlEnterCriticalSection() on DisablePredefinedHandleTable() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
|
|||
|
ASSERT( Index != -1 );
|
|||
|
|
|||
|
if(PredefinedHandleTable[ Index ].Disabled == TRUE) {
|
|||
|
// already called
|
|||
|
ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
|
|||
|
} else {
|
|||
|
if( PredefinedHandleTable[ Index ].Handle != NULL ) {
|
|||
|
|
|||
|
// make sure the handle CAN be closed.
|
|||
|
SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,FALSE);
|
|||
|
|
|||
|
#if DBG
|
|||
|
PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
|
|||
|
#endif
|
|||
|
LocalBaseRegCloseKey( &(PredefinedHandleTable[ Index ].Handle) );
|
|||
|
}
|
|||
|
PredefinedHandleTable[ Index ].Handle = NULL;
|
|||
|
PredefinedHandleTable[ Index ].Disabled = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ( !NT_SUCCESS( Status ) ) {
|
|||
|
DbgPrint( "WINREG: RtlLeaveCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
|
|||
|
}
|
|||
|
#endif
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|