520 lines
14 KiB
C
520 lines
14 KiB
C
/*++
|
||
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Regqval.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the server side implementation for the Win32
|
||
Registry query value API. That is:
|
||
|
||
- BaseRegQueryValue
|
||
- BaseRegQueryMultipleValues
|
||
|
||
Author:
|
||
|
||
David J. Gilman (davegi) 27-Nov-1991
|
||
|
||
Notes:
|
||
|
||
See the Notes in Regkey.c.
|
||
|
||
--*/
|
||
|
||
#include <rpc.h>
|
||
#include "regrpc.h"
|
||
#include "localreg.h"
|
||
#include "regclass.h"
|
||
#include "regvcls.h"
|
||
|
||
|
||
#define DEFAULT_VALUE_SIZE 128
|
||
#define DEFAULT_VALUE_NAME_SIZE 64
|
||
|
||
|
||
error_status_t
|
||
BaseRegQueryValue(
|
||
IN HKEY hKey,
|
||
IN PUNICODE_STRING lpValueName,
|
||
OUT LPDWORD lpType OPTIONAL,
|
||
OUT LPBYTE lpData OPTIONAL,
|
||
OUT LPDWORD lpcbData OPTIONAL,
|
||
IN OUT LPDWORD lpcbLen OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For an open key, given the ID of the value to query, return
|
||
the type, and value.
|
||
|
||
Arguments:
|
||
|
||
hKey - Supplies a handle to the open key. The value entries returned
|
||
are contained in the key pointed to by this key handle. Any of the
|
||
predefined reserved handles or a previously opened key handle may be
|
||
used for hKey.
|
||
|
||
lpValueName - Supplies a pointer to the name of the value.
|
||
|
||
lpType - If present, supplies a pointer to variable to receive the
|
||
type code of value entry.
|
||
|
||
lpData -If present, supplies a pointer to a buffer to receive the
|
||
data of the value entry.
|
||
|
||
lpcbData - Supplies a pointer to a variable which on input contains
|
||
the size of the buffer lpData points to. On output, the variable will
|
||
receive the number of bytes returned in lpData. It must be supplied
|
||
if lpData is, it is ignored otherwise.
|
||
|
||
lpcbLen - Return the number of bytes to transmit to the client (used
|
||
by RPC).
|
||
|
||
Return Value:
|
||
|
||
Returns ERROR_SUCCESS (0) for success; error-code for failure.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG BufferLength;
|
||
KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;
|
||
PVOID KeyValueInformation;
|
||
ULONG ResultLength;
|
||
HKEY hkQueryKey;
|
||
|
||
BYTE PrivateKeyValueInformation[ sizeof( KEY_VALUE_PARTIAL_INFORMATION ) +
|
||
DEFAULT_VALUE_SIZE ];
|
||
#ifdef LOCAL
|
||
HKEY hkUserClasses;
|
||
HKEY hkMachineClasses;
|
||
|
||
hkUserClasses = NULL;
|
||
hkMachineClasses = NULL;
|
||
#endif LOCAL
|
||
hkQueryKey = hKey;
|
||
|
||
//
|
||
// If the client gave us a bogus size, patch it.
|
||
//
|
||
if ( ARGUMENT_PRESENT( lpcbData ) && !ARGUMENT_PRESENT( lpData ) ) {
|
||
*lpcbData = 0;
|
||
}
|
||
|
||
|
||
//
|
||
// Call out to Perflib if the HKEY is HKEY_PERFOMANCE_DATA.
|
||
//
|
||
|
||
if(( hKey == HKEY_PERFORMANCE_DATA ) ||
|
||
( hKey == HKEY_PERFORMANCE_TEXT ) ||
|
||
( hKey == HKEY_PERFORMANCE_NLSTEXT)) {
|
||
error_status_t Error;
|
||
|
||
//
|
||
// Impersonate the client.
|
||
//
|
||
|
||
RPC_IMPERSONATE_CLIENT( NULL );
|
||
|
||
Error = (error_status_t)PerfRegQueryValue (
|
||
hKey,
|
||
lpValueName,
|
||
NULL,
|
||
lpType,
|
||
lpData,
|
||
lpcbData,
|
||
lpcbLen
|
||
);
|
||
RPC_REVERT_TO_SELF();
|
||
return(Error);
|
||
}
|
||
|
||
ASSERT( IsPredefinedRegistryHandle( hKey ) == FALSE );
|
||
|
||
//
|
||
// Subtract the NULL from the Length. This was added on
|
||
// the client side so that RPC would transmit it.
|
||
//
|
||
if ( lpValueName->Length > 0 ) {
|
||
lpValueName->Length -= sizeof( UNICODE_NULL );
|
||
}
|
||
|
||
//
|
||
// First we assume that the information we want will fit on
|
||
// PrivateKeyValueInformattion
|
||
//
|
||
|
||
KeyValueInformationClass = ( ARGUMENT_PRESENT( lpcbData ))?
|
||
KeyValuePartialInformation :
|
||
KeyValueBasicInformation;
|
||
|
||
|
||
KeyValueInformation = PrivateKeyValueInformation;
|
||
BufferLength = sizeof( PrivateKeyValueInformation );
|
||
|
||
//
|
||
// Query for the necessary information about the supplied value. This
|
||
// may or may not include the data depending on lpcbData as determined
|
||
// above.
|
||
//
|
||
#ifdef LOCAL
|
||
if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
|
||
|
||
Status = BaseRegGetUserAndMachineClass(
|
||
NULL,
|
||
hKey,
|
||
MAXIMUM_ALLOWED,
|
||
&hkMachineClasses,
|
||
&hkUserClasses);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return (error_status_t) RtlNtStatusToDosError(Status);
|
||
}
|
||
}
|
||
|
||
if (hkUserClasses && hkMachineClasses) {
|
||
hkQueryKey = hkUserClasses;
|
||
}
|
||
|
||
for (;;) {
|
||
#endif
|
||
|
||
Status = NtQueryValueKey( hkQueryKey,
|
||
lpValueName,
|
||
KeyValueInformationClass,
|
||
KeyValueInformation,
|
||
BufferLength,
|
||
&ResultLength
|
||
);
|
||
#ifdef LOCAL
|
||
//
|
||
// If we don't have two classes keys to worry about,
|
||
// just continue as we normally would
|
||
//
|
||
if (!hkUserClasses || !hkMachineClasses) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// If we're using machine, then we don't want to repeat
|
||
// since machine is the last resort
|
||
//
|
||
if (hkQueryKey == hkMachineClasses) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// If the key doesn't exist in user, then let's try
|
||
// again in machine
|
||
//
|
||
if (STATUS_OBJECT_NAME_NOT_FOUND == Status) {
|
||
hkQueryKey = hkMachineClasses;
|
||
continue;
|
||
}
|
||
|
||
break;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// A return value of STATUS_BUFFER_TOO_SMALL would mean that there
|
||
// was not enough room for even the known (i.e. fixed length portion)
|
||
// of the structure.
|
||
//
|
||
|
||
ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
|
||
|
||
if( ( Status == STATUS_BUFFER_OVERFLOW ) &&
|
||
( !ARGUMENT_PRESENT( lpData ) ) ) {
|
||
//
|
||
// STATUS_BUFFER_OVERFLOW means that the API returned all the
|
||
// information in the fixed portion of the structure
|
||
// KEY_VALUE_BASIC_INFORMATION or KEY_VALUE_PARTIAL_INFORMATION,
|
||
// but not the value name or the value data.
|
||
//
|
||
// If KeyValueInformationClass is equal to KeyValueBasicInformation
|
||
// then the API would return the value name. But since we are not
|
||
// interested in the value name (it was supplied by the client), we
|
||
// can assume that the API succeeded.
|
||
//
|
||
// If KeyValueInformationClass is equal to KeyValuePartialInformation
|
||
// then the API would return the value data. But lpData == NULL
|
||
// means that the client is not interested on the value data, but
|
||
// just on its size. For this reason, we can also assume that the
|
||
// API succeeded.
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
if( Status == STATUS_BUFFER_OVERFLOW ) {
|
||
//
|
||
// The buffer defined in the stack wasn't big enough to hold
|
||
// the Value information.
|
||
// If the caller's buffer is big enough to hold the value data
|
||
// then allocate a new buffer, and call the NT API again.
|
||
//
|
||
if( ( ( KeyValueInformationClass == KeyValuePartialInformation ) &&
|
||
( ARGUMENT_PRESENT( lpData ) ) &&
|
||
( *lpcbData >=
|
||
(( PKEY_VALUE_PARTIAL_INFORMATION )
|
||
KeyValueInformation )->DataLength
|
||
)
|
||
)
|
||
) {
|
||
BufferLength = ResultLength;
|
||
|
||
KeyValueInformation = RtlAllocateHeap( RtlProcessHeap( ), 0,
|
||
BufferLength
|
||
);
|
||
//
|
||
// If the memory allocation fails, return a Registry error.
|
||
//
|
||
|
||
if( ! KeyValueInformation ) {
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
//
|
||
// Query for the necessary information about the supplied value.
|
||
//
|
||
|
||
Status = NtQueryValueKey( hkQueryKey,
|
||
lpValueName,
|
||
KeyValueInformationClass,
|
||
KeyValueInformation,
|
||
BufferLength,
|
||
&ResultLength
|
||
);
|
||
}
|
||
}
|
||
|
||
#ifdef LOCAL
|
||
if (hkUserClasses && hkMachineClasses) {
|
||
if (hkUserClasses != hKey) {
|
||
NtClose(hkUserClasses);
|
||
} else {
|
||
NtClose(hkMachineClasses);
|
||
}
|
||
}
|
||
#endif // LOCAL
|
||
|
||
if( NT_SUCCESS( Status ) &&
|
||
ARGUMENT_PRESENT( lpData ) ) {
|
||
//
|
||
// If requested, copy the value data
|
||
//
|
||
if( *lpcbData >= (( PKEY_VALUE_PARTIAL_INFORMATION )
|
||
KeyValueInformation )->DataLength ) {
|
||
|
||
RtlMoveMemory( lpData,
|
||
(( PKEY_VALUE_PARTIAL_INFORMATION )
|
||
KeyValueInformation )->Data,
|
||
(( PKEY_VALUE_PARTIAL_INFORMATION )
|
||
KeyValueInformation )->DataLength
|
||
);
|
||
} else {
|
||
Status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Certain information is returned on success or in the case of
|
||
// NtQueryValueKey returning STATUS_BUFFER_OVERFLOW. This information
|
||
// is always available because we always pass the minimum size required for
|
||
// the NtQueryValueKey API.
|
||
//
|
||
|
||
if( NT_SUCCESS( Status ) ||
|
||
( Status == STATUS_BUFFER_OVERFLOW ) ) {
|
||
|
||
if( KeyValueInformationClass == KeyValueBasicInformation ) {
|
||
|
||
//
|
||
// If requested, return the value type.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpType )) {
|
||
|
||
*lpType = (( PKEY_VALUE_BASIC_INFORMATION )
|
||
KeyValueInformation )->Type;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// If requested, return the value type.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpType )) {
|
||
|
||
*lpType = (( PKEY_VALUE_PARTIAL_INFORMATION )
|
||
KeyValueInformation )->Type;
|
||
}
|
||
|
||
//
|
||
// Return the value data size
|
||
//
|
||
*lpcbData = (( PKEY_VALUE_PARTIAL_INFORMATION )
|
||
KeyValueInformation )->DataLength;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Transmit all of the data back to the client.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpcbLen ) ) {
|
||
if( NT_SUCCESS( Status ) &&
|
||
ARGUMENT_PRESENT( lpData ) ) {
|
||
*lpcbLen = (( PKEY_VALUE_PARTIAL_INFORMATION )
|
||
KeyValueInformation )->DataLength;
|
||
} else {
|
||
//
|
||
// The API failed, so make sure that no data is transmitted back
|
||
// to the client. This ensures that the client stub will not
|
||
// attempt to unmarshall data that doesn't exist.
|
||
//
|
||
|
||
*lpcbLen = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If memory was allocated, then free it
|
||
//
|
||
if( KeyValueInformation != PrivateKeyValueInformation ) {
|
||
|
||
RtlFreeHeap( RtlProcessHeap( ), 0, KeyValueInformation );
|
||
}
|
||
return (error_status_t)RtlNtStatusToDosError( Status );
|
||
}
|
||
|
||
error_status_t
|
||
BaseRegQueryMultipleValues(
|
||
IN HKEY hKey,
|
||
IN OUT PRVALENT val_list,
|
||
IN DWORD num_vals,
|
||
OUT LPSTR lpvalueBuf,
|
||
IN OUT LPDWORD ldwTotsize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For an open key, atomically queries a set of values.
|
||
|
||
Arguments:
|
||
|
||
hKey - Supplies a handle to the open key. The value entries returned
|
||
are contained in the key pointed to by this key handle. Any of
|
||
the predefined reserved handles or a previously opened key handle
|
||
may be used for hKey.
|
||
|
||
val_list - Supplies a pointer to an array of RVALENT structures, one for
|
||
each value to be queried.
|
||
|
||
num_vals - Supplies the size in bytes of the val_list array.
|
||
|
||
lpValueBuf - Returns the data for each value
|
||
|
||
ldwTotsize - Supplies the length of lpValueBuf. Returns the number of bytes
|
||
written into lpValueBuf. If lpValueBuf is not large enough to
|
||
contain all the data, returns the size of lpValueBuf required
|
||
to return all the requested data.
|
||
|
||
Return Value:
|
||
|
||
Returns ERROR_SUCCESS (0) for success; error-code for failure.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG RequiredLength;
|
||
ULONG i;
|
||
|
||
//
|
||
// Call out to Perflib if the HKEY is HKEY_PERFOMANCE_DATA.
|
||
//
|
||
|
||
if(( hKey == HKEY_PERFORMANCE_DATA ) ||
|
||
( hKey == HKEY_PERFORMANCE_TEXT ) ||
|
||
( hKey == HKEY_PERFORMANCE_NLSTEXT)) {
|
||
|
||
return((error_status_t)ERROR_CALL_NOT_IMPLEMENTED);
|
||
}
|
||
|
||
//
|
||
// Subtract the NULLs from the Length. This was added on
|
||
// the client side so that RPC would transmit it.
|
||
//
|
||
for (i=0; i<num_vals; i++) {
|
||
if (val_list[i].rv_valuename->Length > 0) {
|
||
val_list[i].rv_valuename->Length -= sizeof( UNICODE_NULL );
|
||
}
|
||
}
|
||
|
||
#ifdef LOCAL
|
||
|
||
//
|
||
// For class keys in hkcr, we need to merge the data
|
||
//
|
||
if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
|
||
|
||
Status = BaseRegQueryMultipleClassKeyValues(
|
||
hKey,
|
||
val_list,
|
||
num_vals,
|
||
lpvalueBuf,
|
||
ldwTotsize,
|
||
&RequiredLength);
|
||
|
||
} else {
|
||
|
||
#endif // LOCAL
|
||
|
||
Status = NtQueryMultipleValueKey(hKey,
|
||
(PKEY_VALUE_ENTRY)val_list,
|
||
num_vals,
|
||
lpvalueBuf,
|
||
ldwTotsize,
|
||
&RequiredLength);
|
||
|
||
#ifdef LOCAL
|
||
|
||
}
|
||
|
||
#endif // LOCAL
|
||
|
||
if (Status == STATUS_BUFFER_OVERFLOW) {
|
||
*ldwTotsize = RequiredLength;
|
||
} else if (!NT_SUCCESS(Status)) {
|
||
//
|
||
// The API failed, so make sure that no data is transmitted back
|
||
// to the client. This ensures that the client stub will not
|
||
// attempt to unmarshall data that doesn't exist.
|
||
//
|
||
|
||
*ldwTotsize = 0;
|
||
}
|
||
|
||
return(error_status_t)RtlNtStatusToDosError(Status);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|