You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1355 lines
31 KiB
1355 lines
31 KiB
/*++
|
|
|
|
|
|
|
|
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( phkResult == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
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 || !phkResult ) {
|
|
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( Class );
|
|
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;
|
|
NTSTATUS Status;
|
|
|
|
|
|
#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 || !phkResult) {
|
|
return ERROR_BADKEY;
|
|
}
|
|
|
|
hKey = MapPredefinedHandle( hKey, &TempHandle );
|
|
if( hKey == NULL ) {
|
|
Error = ERROR_INVALID_HANDLE;
|
|
goto ExitCleanup;
|
|
}
|
|
|
|
//
|
|
// Convert the subkey to a counted Unicode string.
|
|
// This also acounts for the NULL we are adding at the end
|
|
//
|
|
Status = RtlInitUnicodeStringEx(&SubKey, lpSubKey);
|
|
if( !NT_SUCCESS(Status) ) {
|
|
Error = RtlNtStatusToDosError( Status );
|
|
goto ExitCleanup;
|
|
}
|
|
//
|
|
// Add terminating NULL to Length so that RPC transmits it.
|
|
//
|
|
SubKey.Length += sizeof( UNICODE_NULL );
|
|
|
|
if (ARGUMENT_PRESENT( lpClass )) {
|
|
//
|
|
// Convert the class name to a counted Unicode string.
|
|
// This also acounts for the NULL we are adding at the end
|
|
//
|
|
Status = RtlInitUnicodeStringEx(&ClassUnicode, lpClass);
|
|
if( !NT_SUCCESS(Status) ) {
|
|
Error = RtlNtStatusToDosError( Status );
|
|
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 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;
|
|
NTSTATUS Status;
|
|
|
|
#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.
|
|
// This also acounts for the NULL we are adding at the end
|
|
//
|
|
Status = RtlInitUnicodeStringEx(&SubKey, lpSubKey);
|
|
if( !NT_SUCCESS(Status) ) {
|
|
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 );
|
|
}
|
|
}
|
|
|
|
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 ;
|
|
|
|
if( phkResult == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|