/*++


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


