2020-09-30 17:12:29 +02:00

582 lines
14 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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"
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
);
error_status_t
LocalOpenPerformanceText(
IN PREGISTRY_SERVER_NAME ServerName,
IN REGSAM samDesired,
OUT PRPC_HKEY phKey
);
error_status_t
LocalOpenPerformanceNlsText(
IN PREGISTRY_SERVER_NAME ServerName,
IN REGSAM samDesired,
OUT PRPC_HKEY phKey
);
//
// Table entry for a predefined handle.
//
typedef struct _PRDEFINED_HANDLE {
RPC_HKEY Handle;
OPEN_FUNCTION OpenFunc;
} PREDEFINED_HANDLE, *PPREDEFINED_HANDLE;
//
// Initialize predefined handle table.
//
PREDEFINED_HANDLE PredefinedHandleTable[ ] = {
NULL, LocalOpenClassesRoot,
NULL, LocalOpenCurrentUser,
NULL, LocalOpenLocalMachine,
NULL, LocalOpenUsers,
NULL, LocalOpenPerformanceData,
NULL, LocalOpenPerformanceText,
NULL, LocalOpenPerformanceNlsText,
NULL, LocalOpenCurrentConfig,
NULL, LocalOpenDynData
};
#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 )
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 ((ULONG)Handle) {
case (ULONG)HKEY_CLASSES_ROOT:
case (ULONG)HKEY_CURRENT_USER:
case (ULONG)HKEY_LOCAL_MACHINE:
case (ULONG)HKEY_USERS:
case (ULONG)HKEY_PERFORMANCE_DATA:
Index = ((DWORD)Handle &= ~PREDEFINED_REGISTRY_HANDLE_SIGNATURE);
break;
case (ULONG)HKEY_PERFORMANCE_TEXT:
Index = 5;
break;
case (ULONG)HKEY_PERFORMANCE_NLSTEXT:
Index = 6;
break;
case (ULONG)HKEY_CURRENT_CONFIG:
Index = 7;
break;
case (ULONG)HKEY_DYN_DATA:
Index = 8;
break;
default:
//
// The supplied handle is not predefined, so return it.
//
Index = -1;
break;
}
return(Index);
}
RPC_HKEY
MapPredefinedHandle(
IN RPC_HKEY Handle
)
/*++
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.
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;
//
// If the high bit is not set, we know it's not a predefined handle
// so take a quick out.
//
if (((ULONG)Handle & 0x80000000) == 0) {
return(Handle);
}
Index = MapPredefinedRegistryHandleToIndex((ULONG)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 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 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;
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++) {
if (PredefinedHandleTable[i].Handle != NULL) {
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;
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
hKey1 = PredefinedHandleTable[ MapPredefinedRegistryHandleToIndex( (ULONG)Handle ) ].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 {
PredefinedHandleTable[ MapPredefinedRegistryHandleToIndex( (ULONG)Handle ) ]
.Handle = NULL;
Error = ( LONG ) LocalBaseRegCloseKey( &hKey1 );
}
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( 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)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 );
}