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;
|
||
}
|
||
|
||
|