/*++



Copyright (c) 1992-2000  Microsoft Corporation

Module Name:

    Regkey.c

Abstract:

    This module contains the client side wrappers for the Win32 Registry
    APIs to open, create, flush and close keys.  That is:

        - RegCloseKey
        - RegCreateKeyA
        - RegCreateKeyW
        - RegCreateKeyExA
        - RegCreateKeyExW
        - RegFlushKey
        - RegOpenKeyA
        - RegOpenKeyW
        - RegOpenKeyExA
        - RegOpenKeyExW
        - RegOverridePredefKey
        - RegOpenCurrentUser

Author:

    David J. Gilman (davegi) 15-Nov-1991

Notes:

    See the notes in server\regkey.c.

--*/

#include <rpc.h>
#include "regrpc.h"
#include "client.h"
#include <wow64reg.h>

#if defined(LEAK_TRACK)
NTSTATUS TrackObject(HKEY hKey);
#endif // defined(LEAK_TRACK)

NTSTATUS DisablePredefinedHandleTable(HKEY Handle);


LONG
APIENTRY
RegCloseKey (
    IN HKEY hKey
    )

/*++

Routine Description:

    Win32 RPC wrapper for closeing a key handle.

--*/

{

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    if( hKey == NULL ) {
        return ERROR_INVALID_HANDLE;
    }

    if( IsPredefinedRegistryHandle( hKey )) {
        return( ClosePredefinedHandle( hKey ) );
    }

    if( IsLocalHandle( hKey )) {

#if defined(_WIN64)
        Wow64RegCloseKey (hKey);
#endif
        return ( LONG ) LocalBaseRegCloseKey( &hKey );

    } else {

        hKey = DereferenceRemoteHandle( hKey );
        return ( LONG ) BaseRegCloseKey( &hKey );
    }
}

LONG
APIENTRY
RegOverridePredefKey (
    IN HKEY hKey,
	IN HKEY hNewKey
    )

/*++

Routine Description:

    Win32 wrapper to override the normal value for a predefined key.

--*/

{

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    if( hKey == NULL ) {
        return ERROR_INVALID_HANDLE;
    }

    if( !IsPredefinedRegistryHandle( hKey )) {
        return ERROR_INVALID_HANDLE;
    }

    {
	NTSTATUS Status;

	Status = RemapPredefinedHandle( hKey, hNewKey );

	return RtlNtStatusToDosError( Status );
    }
}

LONG
APIENTRY
RegCreateKeyA (
    HKEY hKey,
    LPCSTR lpSubKey,
    PHKEY phkResult
    )

/*++

Routine Description:

    Win 3.1 ANSI RPC wrapper for opening an existing key or creating a new one.

--*/

{
    LONG    Error;

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    //
    // Win3.1ism - Win 3.1 allows the predefined handle to be opened by
    // specifying a pointer to an empty or NULL string for the sub-key.
    //

    //
    // If the subkey is NULL or points to a NUL string and the handle is
    // predefined, just return the predefined handle (a virtual open)
    // otherwise it's an error.
    //

    if(( lpSubKey == NULL ) || ( *lpSubKey == '\0' )) {

        if( IsPredefinedRegistryHandle( hKey )) {

            *phkResult = hKey;
            return ERROR_SUCCESS;

        } else {

            return ERROR_BADKEY;
        }
    }

    Error = (LONG)RegCreateKeyExA(
                            hKey,
                            lpSubKey,
                            0,
                            WIN31_CLASS,
                            REG_OPTION_NON_VOLATILE,
                            WIN31_REGSAM,
                            NULL,
                            phkResult,
                            NULL
                            );

    return Error;

}

LONG
APIENTRY
RegCreateKeyW (
    HKEY hKey,
    LPCWSTR lpSubKey,
    PHKEY phkResult
    )

/*++

Routine Description:

    Win 3.1 Unicode RPC wrapper for opening an existing key or creating a
    new one.

--*/

{
    LONG    Error;

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    Error =  (LONG)RegCreateKeyExW(
                            hKey,
                            lpSubKey,
                            0,
                            WIN31_CLASS,
                            REG_OPTION_NON_VOLATILE,
                            WIN31_REGSAM,
                            NULL,
                            phkResult,
                            NULL
                            );

    return Error;

}

LONG
APIENTRY
RegCreateKeyExA (
    HKEY hKey,
    LPCSTR lpSubKey,
    DWORD Reserved,
    LPSTR lpClass,
    DWORD dwOptions,
    REGSAM samDesired,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    PHKEY phkResult,
    LPDWORD lpdwDisposition
    )

/*++

Routine Description:

    Win32 ANSI RPC wrapper for opening an existing key or creating a new one.

    RegCreateKeyExA converts the LPSECURITY_ATTRIBUTES argument to a
    RPC_SECURITY_ATTRIBUTES argument and calls BaseRegCreateKeyExA.

--*/

{
    UNICODE_STRING              SubKey;
    UNICODE_STRING              ClassUnicode;
    PUNICODE_STRING             Class;
    ANSI_STRING                 AnsiString;
    PRPC_SECURITY_ATTRIBUTES    pRpcSA;
    RPC_SECURITY_ATTRIBUTES     RpcSA;
    NTSTATUS                    Status;
    LONG                        Error;
    HKEY                        TempHandle = NULL;


#if DBG
    if ( BreakPointOnEntry ) {
        OutputDebugString( "In RegCreateKeyExA\n" );
        DbgBreakPoint();
    }
#endif

    //
    // Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
    //

    if(( hKey == HKEY_PERFORMANCE_DATA ) ||
       ( hKey == HKEY_PERFORMANCE_TEXT ) ||
       ( hKey == HKEY_PERFORMANCE_NLSTEXT )) {

        return ERROR_INVALID_HANDLE;
    }

    //
    // Ensure Reserved is zero to avoid future compatability problems.
    //

    if( Reserved != 0 ) {
            return ERROR_INVALID_PARAMETER;
    }

    //
    // Validate that the sub key is not NULL.
    //
    if( ! lpSubKey ) {
        return ERROR_BADKEY;
    }

    hKey = MapPredefinedHandle( hKey, &TempHandle );
    if( hKey == NULL ) {
        Error = ERROR_INVALID_HANDLE;
        goto ExitCleanup;
    }

    //
    // Convert the subkey to a counted Unicode string 
    //
    if( !RtlCreateUnicodeStringFromAsciiz(&SubKey,lpSubKey) ) {
        Status = STATUS_NO_MEMORY;
        Error = RtlNtStatusToDosError( Status );
        goto ExitCleanup;
    }

    //
    //  Add size of NULL so that RPC transmits the right
    //  stuff.
    //
    SubKey.Length += sizeof( UNICODE_NULL );

    if (ARGUMENT_PRESENT( lpClass )) {

        //
        // Convert the class name to a counted Unicode string using a counted
        // Unicode string dynamically allocated by RtlAnsiStringToUnicodeString.
        //

        RtlInitAnsiString( &AnsiString, lpClass );
        Status = RtlAnsiStringToUnicodeString(
                    &ClassUnicode,
                    &AnsiString,
                    TRUE
                    );

        if( ! NT_SUCCESS( Status )) {
            Error = RtlNtStatusToDosError( Status );
            RtlFreeUnicodeString( &SubKey );
            goto ExitCleanup;
        }

        Class = &ClassUnicode;
        Class->Length += sizeof( UNICODE_NULL );

    } else {

        Class = &ClassUnicode;

        Class->Length        = 0;
        Class->MaximumLength = 0;
        Class->Buffer        = NULL;
    }

    //
    // If the caller supplied a LPSECURITY_ATTRIBUTES argument, map
    // it to the RPCable version.
    //

    if( ARGUMENT_PRESENT( lpSecurityAttributes )) {

        pRpcSA = &RpcSA;

        Error = MapSAToRpcSA( lpSecurityAttributes, pRpcSA );

        if( Error != ERROR_SUCCESS ) {
            RtlFreeUnicodeString( &SubKey );
            goto ExitCleanup;
        }

    } else {

        //
        // No PSECURITY_ATTRIBUTES argument, therefore no mapping was done.
        //

        pRpcSA = NULL;
    }

    //
    // Call the Base API, passing it the supplied parameters and the
    // counted Unicode strings.
    //

    if( IsLocalHandle( hKey )) {

#if defined(_WIN64)
        DWORD dwTempDisposition = 0;
        if ( lpdwDisposition == NULL )
            lpdwDisposition = &dwTempDisposition;

        //
        //  if wow64 reserve field is set in the access mask, call
        //  wow64 function to handle the scenario.
        //

        if ( samDesired & KEY_WOW64_RES ) {

            Error = (LONG)Wow64RegCreateKeyEx (
                            hKey,
                            SubKey.Buffer,
                            0, //reserved
                            Class->Buffer,
                            dwOptions,
                            samDesired,
                            lpSecurityAttributes,
                            phkResult,
                            lpdwDisposition
                            );

        } else
#endif

        Error = (LONG)LocalBaseRegCreateKey (
                            hKey,
                            &SubKey,
                            Class,
                            dwOptions,
                            samDesired,
                            pRpcSA,
                            phkResult,
                            lpdwDisposition
                            );
#if defined(_WIN64)

        if ( ( Error == 0) && ( REG_CREATED_NEW_KEY & *lpdwDisposition) ) //only set dirty if its a newly created key
                    Wow64RegSetKeyDirty (*phkResult);
#endif
    } else {

        Error = (LONG)BaseRegCreateKey (
                            DereferenceRemoteHandle( hKey ),
                            &SubKey,
                            Class,
                            dwOptions,
                            samDesired,
                            pRpcSA,
                            phkResult,
                            lpdwDisposition
                            );

        if( Error == ERROR_SUCCESS) {

            TagRemoteHandle( phkResult );
        }
    }

    //
    // Free the counted Unicode string allocated by
    // RtlAnsiStringToUnicodeString.
    //

    if (Class != NULL) {
        RtlFreeUnicodeString( Class );
    }

    //
    // Free the RPC_SECURITY_DESCRIPTOR buffer and return the
    // Registry return value.
    //

    if( pRpcSA != NULL ) {

        RtlFreeHeap(
            RtlProcessHeap( ), 0,
            pRpcSA->RpcSecurityDescriptor.lpSecurityDescriptor
            );
    }
    
    RtlFreeUnicodeString( &SubKey );

ExitCleanup:

    CLOSE_LOCAL_HANDLE(TempHandle);
    return Error;
}

LONG
APIENTRY
RegCreateKeyExW (
    HKEY hKey,
    LPCWSTR lpSubKey,
    DWORD Reserved,
    LPWSTR lpClass,
    DWORD dwOptions,
    REGSAM samDesired,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    PHKEY phkResult,
    LPDWORD lpdwDisposition
    )

/*++

Routine Description:

    Win32 Unicode RPC wrapper for opening an existing key or creating a new one.

    RegCreateKeyExW converts the LPSECURITY_ATTRIBUTES argument to a
    RPC_SECURITY_ATTRIBUTES argument and calls BaseRegCreateKeyExW.

--*/

{
    UNICODE_STRING              SubKey;
    UNICODE_STRING              ClassUnicode;
    PUNICODE_STRING             Class;
    PRPC_SECURITY_ATTRIBUTES    pRpcSA;
    RPC_SECURITY_ATTRIBUTES     RpcSA;
    LONG                        Error;
    PWSTR                       AuxBuffer;
    HKEY                        TempHandle = NULL;


#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    //
    // Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
    //

    if(( hKey == HKEY_PERFORMANCE_DATA ) ||
       ( hKey == HKEY_PERFORMANCE_TEXT ) ||
       ( hKey == HKEY_PERFORMANCE_NLSTEXT )) {
        return ERROR_INVALID_HANDLE;
    }

    //
    // Ensure Reserved is zero to avoid future compatability problems.
    //

    if( Reserved != 0 ) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Validate that the sub key is not NULL.
    //

    if( ! lpSubKey ) {
        return ERROR_BADKEY;
    }

    hKey = MapPredefinedHandle( hKey, &TempHandle );
    if( hKey == NULL ) {
        Error = ERROR_INVALID_HANDLE;
        goto ExitCleanup;
    }

    //
    // Convert the subkey to a counted Unicode string.
    //

    RtlInitUnicodeString( &SubKey, lpSubKey );

    //
    //  Add terminating NULL to Length so that RPC transmits it.
    //
    SubKey.Length += sizeof( UNICODE_NULL );
    if( SubKey.Length == 0 ) {
        //
        // overflow in RtlInitUnicodeString
        //
        Error = ERROR_INVALID_PARAMETER;
        goto ExitCleanup;
    }

    if (ARGUMENT_PRESENT( lpClass )) {

        //
        // Convert the class name to a counted Unicode string.
        //

        RtlInitUnicodeString( &ClassUnicode, lpClass );
        Class = &ClassUnicode;
        Class->Length += sizeof( UNICODE_NULL );

    } else {

        Class = &ClassUnicode;

        Class->Length        = 0;
        Class->MaximumLength = 0;
        Class->Buffer        = NULL;
    }


    //
    // If the caller supplied a LPSECURITY_ATTRIBUTES argument, map
    // it and call the private version of the create key API.
    //

    if( ARGUMENT_PRESENT( lpSecurityAttributes )) {

        pRpcSA = &RpcSA;

        Error = MapSAToRpcSA( lpSecurityAttributes, pRpcSA );

        if( Error != ERROR_SUCCESS ) {
            goto ExitCleanup;
        }

    } else {

        //
        // No PSECURITY_ATTRIBUTES argument, therefore no mapping was done.
        //

        pRpcSA = NULL;
    }

    //
    // Call the Base API, passing it the supplied parameters and the
    // counted Unicode strings.
    //

    if( IsLocalHandle( hKey )) {

#if defined(_WIN64)
        DWORD dwTempDisposition = 0;
        if ( lpdwDisposition == NULL )
            lpdwDisposition = &dwTempDisposition;

        //
        //  if wow64 reserve field is set in the access mask, call
        //  wow64 function to handle the scenario.
        //

        if ( samDesired & KEY_WOW64_RES ) {

            Error = (LONG)Wow64RegCreateKeyEx (
                            hKey,
                            SubKey.Buffer,
                            0, //reserved
                            Class->Buffer,
                            dwOptions,
                            samDesired,
                            lpSecurityAttributes,
                            phkResult,
                            lpdwDisposition
                            );
        } else
#endif
        Error = (LONG)LocalBaseRegCreateKey (
                            hKey,
                            &SubKey,
                            Class,
                            dwOptions,
                            samDesired,
                            pRpcSA,
                            phkResult,
                            lpdwDisposition
                            );
#if defined(_WIN64)

        if ( ( Error == 0) && ( REG_CREATED_NEW_KEY & *lpdwDisposition) ) //only set dirty if its a newly created key
                    Wow64RegSetKeyDirty (*phkResult);
#endif
    } else {

        Error = (LONG)BaseRegCreateKey (
                            DereferenceRemoteHandle( hKey ),
                            &SubKey,
                            Class,
                            dwOptions,
                            samDesired,
                            pRpcSA,
                            phkResult,
                            lpdwDisposition
                            );

        if( Error == ERROR_SUCCESS) {

            TagRemoteHandle( phkResult );
        }
    }

    //
    // Free the RPC_SECURITY_DESCRIPTOR buffer and return the
    // Registry return value.
    //

    if( pRpcSA != NULL ) {

        RtlFreeHeap(
            RtlProcessHeap( ), 0,
            pRpcSA->RpcSecurityDescriptor.lpSecurityDescriptor
            );
    }

ExitCleanup:

    CLOSE_LOCAL_HANDLE(TempHandle);
    return Error;
}

LONG
APIENTRY
RegFlushKey (
    IN HKEY hKey
    )

/*++

Routine Description:

    Win32 RPC wrapper for flushing changes to backing store.

--*/

{
    LONG                        Error;
    HKEY                        TempHandle = NULL;

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    //
    // Flush is a NO-OP for HKEY_PERFORMANCE_DATA.
    //

    if(( hKey == HKEY_PERFORMANCE_DATA ) ||
       ( hKey == HKEY_PERFORMANCE_TEXT ) ||
       ( hKey == HKEY_PERFORMANCE_NLSTEXT )) {
        return ERROR_SUCCESS;
    }

    hKey = MapPredefinedHandle( hKey, &TempHandle );
    if( hKey == NULL ) {
        Error = ERROR_INVALID_HANDLE;
        goto ExitCleanup;
    }

    if( IsLocalHandle( hKey )) {

        Error = (LONG)LocalBaseRegFlushKey( hKey );

    } else {

        Error = (LONG)BaseRegFlushKey( DereferenceRemoteHandle( hKey ));
    }

ExitCleanup:

    CLOSE_LOCAL_HANDLE(TempHandle);
    return Error;
}

LONG
APIENTRY
RegOpenKeyA (
    HKEY hKey,
    LPCSTR lpSubKey,
    PHKEY phkResult
    )

/*++

Routine Description:

    Win 3.1 ANSI RPC wrapper for opening an existing key.

--*/

{
    LONG    Error;

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    if( phkResult == NULL ) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Win3.1ism - Win 3.1 allows the predefined handle to be opened by
    // specifying a pointer to an empty or NULL string for the sub-key.
    //

    //
    // If the subkey is NULL or points to a NUL string and the handle is
    // predefined, just return the predefined handle (a virtual open)
    // otherwise return the same handle that was passed in.
    //

    if(( lpSubKey == NULL ) || ( *lpSubKey == '\0' )) {
        if( !IsPredefinedRegistryHandle( hKey )) {
            *phkResult = hKey;
            return ERROR_SUCCESS;
        }

/*
        if( IsPredefinedRegistryHandle( hKey )) {

            *phkResult = hKey;
            return ERROR_SUCCESS;

        } else {

            return ERROR_BADKEY;
        }
*/
    }

    Error = (LONG)RegOpenKeyExA(
                        hKey,
                        lpSubKey,
                        REG_OPTION_RESERVED,
                        WIN31_REGSAM,
                        phkResult
                        );

    return Error;

}

LONG
APIENTRY
RegOpenKeyW (
    HKEY hKey,
    LPCWSTR lpSubKey,
    PHKEY phkResult
    )

/*++

Routine Description:

    Win 3.1 Unicode RPC wrapper for opening an existing key.

--*/

{

    LONG    Error;

#if DBG
    if ( BreakPointOnEntry ) {
        OutputDebugString( "In RegOpenKeyW\n" );
        DbgBreakPoint();
    }
#endif

    if( phkResult == NULL ) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Win3.1ism - Win 3.1 allows the predefined handle to be opened by
    // specifying a pointer to an empty or NULL string for the sub-key.
    //

    //
    // If the subkey is NULL or points to a NUL string and the handle is
    // predefined, just return the predefined handle (a virtual open)
    // otherwise return the handle passed in.
    //

    if(( lpSubKey == NULL ) || ( *lpSubKey == '\0' )) {
        if( !IsPredefinedRegistryHandle( hKey )) {
            *phkResult = hKey;
            return ERROR_SUCCESS;
        }

/*
        if( IsPredefinedRegistryHandle( hKey )) {

            *phkResult = hKey;
            return ERROR_SUCCESS;

        } else {

            return ERROR_BADKEY;
        }
*/
    }

    Error = (LONG)RegOpenKeyExW(
                         hKey,
                         lpSubKey,
                         REG_OPTION_RESERVED,
                         WIN31_REGSAM,
                         phkResult
                         );

    return Error;

}

LONG
APIENTRY
RegOpenKeyExA (
    HKEY hKey,
    LPCSTR lpSubKey,
    DWORD dwOptions,
    REGSAM samDesired,
    PHKEY phkResult
    )

/*++

Routine Description:

    Win32 ANSI RPC wrapper for opening an existing key.

    RegOpenKeyExA converts the lpSubKey argument to a counted Unicode string
    and then calls BaseRegOpenKey.

--*/

{
    UNICODE_STRING      SubKey;
    NTSTATUS            Status;
    LONG                Error;
    CHAR                NullString;
    HKEY                TempHandle = NULL;

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    //
    // Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
    //

    if(( hKey == HKEY_PERFORMANCE_DATA ) ||
       ( hKey == HKEY_PERFORMANCE_TEXT ) ||
       ( hKey == HKEY_PERFORMANCE_NLSTEXT )) {
        return ERROR_INVALID_HANDLE;
    }

    //
    //  Caller must pass pointer to the variable where the opened handle
    //  will be returned
    //

    if( phkResult == NULL ) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    //  If lpSubKey is NULL, then assume NUL-string as subkey name
    //

    if( lpSubKey == NULL ) {
        NullString = ( CHAR )'\0';
        lpSubKey = &NullString;
    }

    //
    //  If hKey is a predefined key, and lpSubKey is either a NULL pointer or
    //  a NUL string, close the predefined key and clear the associated entry
    //  in the PredefinedHandleTable  (RegCloseKey will do the job).
    //
    if( IsPredefinedRegistryHandle( hKey ) && (!( samDesired & KEY_WOW64_RES )) &&
        ( ( lpSubKey == NULL ) || ( *lpSubKey == '\0' ) ) ) {

        if ( HKEY_CLASSES_ROOT != hKey ) {
            Error = RegCloseKey( hKey );
            if( Error != ERROR_SUCCESS ) {
                return( Error );
            }
            //
            //  Create a handle and save it in the appropriate entry  in
            //  PredefinedHandleTable.
            //  Notice that the client will be impersonated.
            //  (MapPredefinedHandle will do all this stuff).
            //
            if( MapPredefinedHandle( hKey, &TempHandle ) == NULL ) {
                Error = ERROR_INVALID_HANDLE;
                goto ExitCleanup;
            }
        }

        //
        //  Return to the user the handle passed in
        //
        *phkResult = hKey;
        Error = ERROR_SUCCESS;
        goto ExitCleanup;
    }


    //
    // Validate that the sub key is not NULL.
    //

    ASSERT( lpSubKey != NULL );
    if( ! lpSubKey ) {
        Error = ERROR_BADKEY;
        goto ExitCleanup;
    }

    hKey = MapPredefinedHandle( hKey, &TempHandle );
    if( hKey == NULL ) {
        Error = ERROR_INVALID_HANDLE;
        goto ExitCleanup;
    }

    //
    // Convert the subkey to a counted Unicode string 
    //
    if( !RtlCreateUnicodeStringFromAsciiz(&SubKey,lpSubKey) ) {
        Status = STATUS_NO_MEMORY;
        Error = RtlNtStatusToDosError( Status );
        goto ExitCleanup;
    }

    //
    //  Add terminating NULL to Length so that RPC transmits it.
    //
    SubKey.Length += sizeof( UNICODE_NULL );


    //
    // Call the Base API, passing it the supplied parameters and the
    // counted Unicode strings.
    //

    if( IsLocalHandle( hKey )) {
#if defined(_WIN64)

        //
        //  if wow64 reserve field is set in the access mask, call
        //  wow64 function to handle the scenario.
        //

        if ( samDesired & KEY_WOW64_RES ) {

            Error = (LONG)Wow64RegOpenKeyEx (
                            hKey,
                            SubKey.Buffer,
                            dwOptions,
                            samDesired,
                            phkResult
                            );
        } else
#endif

        Error = (LONG)LocalBaseRegOpenKey (
                            hKey,
                            &SubKey,
                            dwOptions,
                            samDesired,
                            phkResult
                            );
    } else {

        Error = (LONG)BaseRegOpenKey (
                            DereferenceRemoteHandle( hKey ),
                            &SubKey,
                            dwOptions,
                            samDesired,
                            phkResult
                            );

        if( Error == ERROR_SUCCESS) {

            TagRemoteHandle( phkResult );
        }
    }

    // free the allocated unicode string
    RtlFreeUnicodeString( &SubKey );

ExitCleanup:

    CLOSE_LOCAL_HANDLE(TempHandle);
    return Error;
}

LONG
APIENTRY
RegOpenKeyExW (
    HKEY hKey,
    LPCWSTR lpSubKey,
    DWORD dwOptions,
    REGSAM samDesired,
    PHKEY phkResult
    )

/*++

Routine Description:

    Win32 Unicode RPC wrapper for opening an existing key.

    RegOpenKeyExW converts the lpSubKey argument to a counted Unicode string
    and then calls BaseRegOpenKey.

--*/

{
    UNICODE_STRING      SubKey;
    LONG                Error;
    WCHAR               NullString;
    HKEY                TempHandle = NULL;

#if DBG
    if ( BreakPointOnEntry ) {
        DbgBreakPoint();
    }
#endif

    //
    // Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
    //

    if(( hKey == HKEY_PERFORMANCE_DATA ) ||
       ( hKey == HKEY_PERFORMANCE_TEXT ) ||
       ( hKey == HKEY_PERFORMANCE_NLSTEXT )) {
        return ERROR_INVALID_HANDLE;
    }

    //
    //  Caller must pass pointer to the variable where the opened handle
    //  will be returned
    //

    if( phkResult == NULL ) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    //  If lpSubKey is NULL, then assume NUL-string as subkey name
    //

    if( lpSubKey == NULL ) {
        NullString = UNICODE_NULL;
        lpSubKey = &NullString;
    }

    //
    //  If hKey is a predefined key, and lpSubKey is either a NULL pointer or
    //  a NUL string, close the predefined key and clear the associated entry
    //  in the PredefinedHandleTable  (RegCloseKey will do the job).
    //
    if( IsPredefinedRegistryHandle( hKey ) && (!( samDesired & KEY_WOW64_RES )) &&
        ( ( lpSubKey == NULL ) || ( *lpSubKey == ( WCHAR )'\0' ) ) ) {

        if ( HKEY_CLASSES_ROOT != hKey ) {
            Error = RegCloseKey( hKey );
            if( Error != ERROR_SUCCESS ) {
                return( Error );
            }
            //
            //  Create a handle and save it in the appropriate entry  in
            //  PredefinedHandleTable.
            //  Notice that the client will be impersonated.
            //  (MapPredefinedHandle will do all this stuff).
            //
            if( MapPredefinedHandle( hKey, &TempHandle ) == NULL ) {
                Error = ERROR_INVALID_HANDLE;
                goto ExitCleanup;
            }
        }

        //
        //  Return to the user the handle passed in
        //
        *phkResult = hKey;
        Error = ERROR_SUCCESS;
        goto ExitCleanup;
    }

    //
    // Validate that the sub key is not NULL.
    //

    ASSERT( lpSubKey != NULL );
    if( ! lpSubKey ) {
        Error = ERROR_BADKEY;
        goto ExitCleanup;
    }


    hKey = MapPredefinedHandle( hKey, &TempHandle );
    if( hKey == NULL ) {
        Error = ERROR_INVALID_HANDLE;
        goto ExitCleanup;
    }

    //
    // Convert the subkey to a counted Unicode string.
    //

    RtlInitUnicodeString( &SubKey, lpSubKey );

    //
    //  Add terminating NULL to Length so that RPC transmits it
    //
    SubKey.Length += sizeof (UNICODE_NULL );

    //
    // Call the Base API, passing it the supplied parameters and the
    // counted Unicode strings.
    //

    if( IsLocalHandle( hKey )) {

#if defined(_WIN64)
        //
        //  if wow64 reserve field is set in the access mask, call
        //  wow64 function to handle the scenario. 
        //

        if ( samDesired & KEY_WOW64_RES ) {

            Error = (LONG)Wow64RegOpenKeyEx (
                            hKey,
                            SubKey.Buffer,
                            dwOptions,
                            samDesired,
                            phkResult
                            );
        } else
#endif
        Error =  (LONG)LocalBaseRegOpenKey (
                            hKey,
                            &SubKey,
                            dwOptions,
                            samDesired,
                            phkResult
                            );
    } else {

        Error =  (LONG)BaseRegOpenKey (
                            DereferenceRemoteHandle( hKey ),
                            &SubKey,
                            dwOptions,
                            samDesired,
                            phkResult
                            );

        if( Error == ERROR_SUCCESS) {

            TagRemoteHandle( phkResult );
        }
    }

ExitCleanup:

    CLOSE_LOCAL_HANDLE(TempHandle);
    return Error;
}

LONG
APIENTRY
RegOpenCurrentUser(
    REGSAM samDesired,
    PHKEY phkResult
    )
/*++

Routine Description:

    Win32 Client-Only function to open the key for HKEY_CURRENT_USER
    for the user that the thread is currently impersonating.  Since
    HKEY_CURRENT_USER is cached for all threads in a process, if the
    process is impersonating multiple users, this allows access to
    the appropriate key.

Arguments:

    samDesired - Supplies the requested security access mask.

    phkResult - Returns an open handle to the key.

Return Value:

    Returns 0 (ERROR_SUCCESS) for success, otherwise a windows error code.

--*/
{
    NTSTATUS Status ;

    Status = RtlOpenCurrentUser( samDesired, phkResult );

#if defined(LEAK_TRACK)

    if (NT_SUCCESS(Status)) {
        if (g_RegLeakTraceInfo.bEnableLeakTrack) {
            (void) TrackObject(*phkResult);
        }
    }

#endif // (LEAK_TRACK)

    return RtlNtStatusToDosError( Status );

}

LONG
APIENTRY
RegDisablePredefinedCache(
    )
/*++

Routine Description:

    Win32 Client-Only function to disable the predefined handle table
    for HKEY_CURRENT_USER for the calling process
    All references to HKEY_CURRENT_USER after this function is called
    will result in a open/close on HKU\<sid>

Arguments:


Return Value:

    Returns 0 (ERROR_SUCCESS) for success, otherwise a windows error code.

--*/
{
    NTSTATUS Status ;

    Status = DisablePredefinedHandleTable( HKEY_CURRENT_USER );

    return RtlNtStatusToDosError( Status );
}

