513 lines
16 KiB
C
513 lines
16 KiB
C
/*++
|
||
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Regeval.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the server side implementation for the Win32
|
||
Registry API to enumerate values. That is:
|
||
|
||
- BaseRegEnumValue
|
||
|
||
Author:
|
||
|
||
David J. Gilman (davegi) 23-Dec-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
|
||
BaseRegEnumValue(
|
||
IN HKEY hKey,
|
||
IN DWORD dwIndex,
|
||
OUT PUNICODE_STRING lpValueName,
|
||
OUT LPDWORD lpType OPTIONAL,
|
||
OUT LPBYTE lpData OPTIONAL,
|
||
IN OUT LPDWORD lpcbData OPTIONAL,
|
||
IN OUT LPDWORD lpcbLen OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Used to enumerate the ValueNames of an open key. This function copies
|
||
the dwIndex-th ValueName of hKey. This function is guaranteed to
|
||
operate correctly only if dwIndex starts at 0 and is incremented on
|
||
successive calls without intervening calls to other registration APIs
|
||
that will change the key. The ValueName (only the ValueName, not the
|
||
full path) is copied to lpBuffer. The size of lpBuffer is specified
|
||
by dwBufferSize.
|
||
|
||
Arguments:
|
||
|
||
hKey - 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.
|
||
|
||
dwIndex - The index of the ValueName to return. Note that this is for
|
||
convenience, ValueNames are not ordered (a new ValueName has an
|
||
arbitrary index). Indexes start at 0.
|
||
|
||
lpValueName - Provides a pointer to a buffer to receive the name of
|
||
the value (it's Id)
|
||
|
||
lpType - If present, supplies pointer to variable to receive the type
|
||
code of value entry.
|
||
|
||
lpData - If present, provides a pointer to a buffer to receive the
|
||
data of the value entry.
|
||
|
||
lpcbData - Must be present if lpDatais. Provides pointer to a
|
||
variable which on input contains the size of the buffer lpDatapoints
|
||
to. On output, the variable will receive the number of bytes returned
|
||
in lpData.
|
||
|
||
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.
|
||
|
||
Notes:
|
||
|
||
hKey must have been opened for KEY_QUERY_VALUE access.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG BufferLength;
|
||
KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;
|
||
PVOID KeyValueInformation;
|
||
ULONG ResultLength;
|
||
|
||
BYTE PrivateKeyValueInformation[ sizeof( KEY_VALUE_FULL_INFORMATION ) +
|
||
DEFAULT_VALUE_NAME_SIZE +
|
||
sizeof(UNICODE_NULL) +
|
||
DEFAULT_VALUE_SIZE +
|
||
sizeof(UNICODE_NULL) ];
|
||
HKEY hkEnum;
|
||
#ifdef LOCAL
|
||
ValueState* pValState;
|
||
|
||
pValState = NULL;
|
||
#endif // LOCAL
|
||
hkEnum = 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 )) {
|
||
|
||
return (error_status_t)PerfRegEnumValue (
|
||
hKey,
|
||
dwIndex,
|
||
lpValueName,
|
||
NULL,
|
||
lpType,
|
||
lpData,
|
||
lpcbData,
|
||
lpcbLen
|
||
);
|
||
}
|
||
|
||
#ifdef LOCAL
|
||
//
|
||
// If we are in HKEY_CLASSES_ROOT, then we need to remap
|
||
// the key / index pair to take into account merging
|
||
//
|
||
|
||
if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
|
||
|
||
//
|
||
// Find a key state for this key
|
||
//
|
||
Status = BaseRegGetClassKeyValueState(
|
||
hKey,
|
||
dwIndex,
|
||
&pValState);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return (error_status_t)RtlNtStatusToDosError(Status);
|
||
}
|
||
|
||
//
|
||
// Now remap to the appropriate key / index
|
||
//
|
||
ValStateGetPhysicalIndexFromLogical(
|
||
pValState,
|
||
hKey,
|
||
dwIndex,
|
||
&hkEnum,
|
||
&dwIndex);
|
||
|
||
}
|
||
#endif // LOCAL
|
||
|
||
//
|
||
// First we assume that the information we want will fit on
|
||
// PrivateKeyValueInformattion
|
||
//
|
||
|
||
KeyValueInformationClass = ( ARGUMENT_PRESENT( lpcbData ))?
|
||
KeyValueFullInformation :
|
||
KeyValueBasicInformation;
|
||
|
||
|
||
KeyValueInformation = PrivateKeyValueInformation;
|
||
BufferLength = sizeof( PrivateKeyValueInformation );
|
||
|
||
//
|
||
// Query for the necessary information about the supplied value.
|
||
//
|
||
|
||
Status = NtEnumerateValueKey( hkEnum,
|
||
dwIndex,
|
||
KeyValueInformationClass,
|
||
KeyValueInformation,
|
||
BufferLength,
|
||
&ResultLength
|
||
);
|
||
|
||
//
|
||
// 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 ) {
|
||
//
|
||
// The buffer defined in the stack wasn't big enough to hold
|
||
// the Value information.
|
||
// If the caller's buffer are big enough to hold the value name
|
||
// and value data, then allocate a new buffer, and call the
|
||
// NT API again.
|
||
//
|
||
if( ( ( KeyValueInformationClass == KeyValueBasicInformation ) &&
|
||
( (ULONG)(lpValueName->MaximumLength) >=
|
||
(( PKEY_VALUE_BASIC_INFORMATION )
|
||
KeyValueInformation )->NameLength + sizeof(UNICODE_NULL)
|
||
)
|
||
) ||
|
||
( ( KeyValueInformationClass == KeyValueFullInformation ) &&
|
||
( (ULONG)(lpValueName->MaximumLength) >=
|
||
(( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->NameLength + sizeof(UNICODE_NULL)
|
||
) &&
|
||
( !ARGUMENT_PRESENT( lpData ) ||
|
||
( ARGUMENT_PRESENT( lpData ) &&
|
||
ARGUMENT_PRESENT( lpcbData ) &&
|
||
( *lpcbData >= (( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->DataLength
|
||
)
|
||
)
|
||
)
|
||
)
|
||
) {
|
||
BufferLength = ResultLength;
|
||
|
||
KeyValueInformation = RtlAllocateHeap( RtlProcessHeap( ), 0,
|
||
BufferLength
|
||
);
|
||
//
|
||
// If the memory allocation fails, return a Registry error.
|
||
//
|
||
|
||
if( ! KeyValueInformation ) {
|
||
#ifdef LOCAL
|
||
ValStateRelease(pValState);
|
||
#endif // LOCAL
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
//
|
||
// Query for the necessary information about the supplied value. This
|
||
// may or may not include the data depending on lpcbData as determined
|
||
// above.
|
||
//
|
||
|
||
Status = NtEnumerateValueKey( hkEnum,
|
||
dwIndex,
|
||
KeyValueInformationClass,
|
||
KeyValueInformation,
|
||
BufferLength,
|
||
&ResultLength
|
||
);
|
||
}
|
||
}
|
||
|
||
#ifdef LOCAL
|
||
ValStateRelease(pValState);
|
||
#endif // LOCAL
|
||
|
||
//
|
||
// If the API succeeded, try to copy the value name to the client's buffer
|
||
//
|
||
|
||
if( NT_SUCCESS( Status ) ) {
|
||
//
|
||
// Copy value name
|
||
//
|
||
|
||
if( KeyValueInformationClass == KeyValueBasicInformation ) {
|
||
//
|
||
// Return the name length and the name of the value.
|
||
// Note that the NUL byte is included so that RPC copies the
|
||
// correct number of bytes. It is decremented on the client
|
||
// side.
|
||
//
|
||
|
||
if( (ULONG)(lpValueName->MaximumLength) >=
|
||
(( PKEY_VALUE_BASIC_INFORMATION )
|
||
KeyValueInformation )->NameLength + sizeof( UNICODE_NULL )) {
|
||
|
||
//
|
||
// If client's buffer is big enough for the name,
|
||
// copy the value name and NUL terminate it
|
||
//
|
||
lpValueName->Length = ( USHORT )
|
||
(( PKEY_VALUE_BASIC_INFORMATION )
|
||
KeyValueInformation )->NameLength;
|
||
|
||
RtlMoveMemory( lpValueName->Buffer,
|
||
(( PKEY_VALUE_BASIC_INFORMATION )
|
||
KeyValueInformation )->Name,
|
||
lpValueName->Length
|
||
);
|
||
|
||
lpValueName->Buffer[ lpValueName->Length >> 1 ] = UNICODE_NULL;
|
||
|
||
//
|
||
// Value name length must include size of UNICODE_NULL.
|
||
// It will be decremented in the client side
|
||
//
|
||
|
||
lpValueName->Length += sizeof( UNICODE_NULL );
|
||
|
||
} else {
|
||
//
|
||
// If the client's buffer for the value name is not big
|
||
// enough, then set status to STATUS_BUFFER_OVERFLOW.
|
||
//
|
||
// Note that in the remote case, RPC will transmit garbage
|
||
// in the buffer back to the client.
|
||
// We cannot set the buffer to prevent this transmission,
|
||
// because in the local case we would be destroying the
|
||
// buffer in the &NtCurrectTeb->StaticUnicodeString.
|
||
//
|
||
|
||
Status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// Here if KeyValueInformation == KeyValueFullInformation
|
||
//
|
||
// Return the name length and the name of the value.
|
||
// Note that the NUL byte is included so that RPC copies the
|
||
// correct number of bytes. It is decremented on the client
|
||
// side.
|
||
//
|
||
|
||
if( (ULONG)(lpValueName->MaximumLength) >=
|
||
(( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->NameLength + sizeof( UNICODE_NULL )) {
|
||
|
||
//
|
||
// If client's buffer is big enough for the name,
|
||
// copy the value name and NUL terminate it
|
||
//
|
||
lpValueName->Length = ( USHORT )
|
||
(( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->NameLength;
|
||
|
||
RtlMoveMemory( lpValueName->Buffer,
|
||
(( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->Name,
|
||
lpValueName->Length
|
||
);
|
||
|
||
lpValueName->Buffer[ lpValueName->Length >> 1 ] = UNICODE_NULL;
|
||
|
||
//
|
||
// Value name length must include size of UNICODE_NULL.
|
||
// It will be decremented in the client side
|
||
//
|
||
|
||
lpValueName->Length += sizeof( UNICODE_NULL );
|
||
|
||
} else {
|
||
//
|
||
// If the client's buffer for the value name is not big
|
||
// enough, then set status to STATUS_BUFFER_OVERFLOW.
|
||
//
|
||
// Note that in the remote case, RPC will transmit garbage
|
||
// in the buffer back to the client.
|
||
// We cannot set the buffer to prevent this transmission,
|
||
// because in the local case we would be destroying the
|
||
// buffer in the &NtCurrectTeb->StaticUnicodeString.
|
||
//
|
||
|
||
Status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
|
||
if( NT_SUCCESS( Status ) &&
|
||
ARGUMENT_PRESENT( lpData ) ) {
|
||
|
||
//
|
||
// If we were able to copy the value name to the client's buffer
|
||
// and the value data is also requested, then try to copy it
|
||
// to the client's buffer
|
||
//
|
||
|
||
if( *lpcbData >= (( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->DataLength ) {
|
||
//
|
||
// If the buffer is big enough to hold the data, copy the data
|
||
//
|
||
RtlMoveMemory( lpData,
|
||
( PBYTE ) KeyValueInformation
|
||
+ (( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->DataOffset,
|
||
(( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->DataLength
|
||
);
|
||
} else {
|
||
//
|
||
// If buffer is not big enough to hold the data, then return
|
||
// STATUS_BUFFER_OVERFLOW.
|
||
//
|
||
// Note that in the remote case, RPC will transmit garbage
|
||
// in the buffer back to the client.
|
||
// We cannot set the buffer to prevent this transmission,
|
||
// because in the local case we would be destroying the
|
||
// buffer in the &NtCurrectTeb->StaticUnicodeString.
|
||
//
|
||
Status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Certain information is returned on success or in the case of
|
||
// NtEnumerateValueKey returning STATUS_BUFFER_OVERFLOW. This information
|
||
// is always available because we always pass the minimum size required for
|
||
// the NtEnumerateValueKey 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;
|
||
}
|
||
|
||
// lpValueName->Length
|
||
// = ( USHORT ) ((( PKEY_VALUE_BASIC_INFORMATION )
|
||
// KeyValueInformation )->NameLength + sizeof( UNICODE_NULL ) );
|
||
|
||
} else {
|
||
//
|
||
// Here if KeyValueInformationClass == KeyValueFullInformation
|
||
//
|
||
|
||
//
|
||
// If requested, return the value type.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpType )) {
|
||
|
||
*lpType = (( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->Type;
|
||
}
|
||
|
||
// lpValueName->Length
|
||
// = ( USHORT ) ((( PKEY_VALUE_FULL_INFORMATION )
|
||
// KeyValueInformation )->NameLength + sizeof( UNICODE_NULL ) );
|
||
|
||
*lpcbData = (( PKEY_VALUE_FULL_INFORMATION )
|
||
KeyValueInformation )->DataLength;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Transmit all of the value data back to the client.
|
||
//
|
||
|
||
if( NT_SUCCESS( Status ) ) {
|
||
if( ARGUMENT_PRESENT( lpcbLen ) &&
|
||
ARGUMENT_PRESENT( lpcbData ) ) {
|
||
*lpcbLen = *lpcbData;
|
||
}
|
||
} else {
|
||
//
|
||
// If something failed, don't transmit any data back to the client
|
||
//
|
||
if( ARGUMENT_PRESENT( lpcbLen ) ) {
|
||
*lpcbLen = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Free memory if it was allocated
|
||
//
|
||
if( KeyValueInformation != PrivateKeyValueInformation ) {
|
||
|
||
RtlFreeHeap( RtlProcessHeap( ), 0, KeyValueInformation );
|
||
|
||
}
|
||
|
||
return (error_status_t)RtlNtStatusToDosError( Status );
|
||
}
|
||
|