/*++ Copyright (c) 1989-2001 Microsoft Corporation Module Name: registry.c Abstract: Implement registry functions Author: Jiandong Ruan Revision History: --*/ #include "precomp.h" #include "registry.tmh" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SmbQueryValueKey) #pragma alloc_text(PAGE, SmbReadULong) #endif PKEY_VALUE_FULL_INFORMATION SmbQueryValueKey( HANDLE hKey, LPWSTR ValueStringName ) /*++ Routine Description: This function retrieves the full information for the specified key. It allocates local memory for the returned information. Arguments: Key : registry handle to the key where the value is. ValueStringName : name of the value string. Return Value: NULL if out of resource or error. Otherwise, the pointer to the full information --*/ { DWORD BytesNeeded, BytesAllocated; NTSTATUS status; UNICODE_STRING KeyName; PKEY_VALUE_FULL_INFORMATION Buffer; PAGED_CODE(); RtlInitUnicodeString(&KeyName, ValueStringName); Buffer = NULL; BytesAllocated = 0; BytesNeeded = 240; while(1) { ASSERT(Buffer == NULL); Buffer = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(PagedPool, BytesNeeded, SMB_POOL_REGISTRY); if (Buffer == NULL) { SmbTrace(SMB_TRACE_REGISTRY, ("(Out of memory)")); return NULL; } BytesAllocated = BytesNeeded; status = ZwQueryValueKey( hKey, &KeyName, KeyValueFullInformation, Buffer, BytesAllocated, &BytesNeeded ); if (status == STATUS_SUCCESS) { break; } ASSERT(Buffer); ExFreePool(Buffer); Buffer = NULL; if (BytesNeeded == 0 || (status != STATUS_BUFFER_TOO_SMALL && status != STATUS_BUFFER_OVERFLOW)) { SmbTrace(SMB_TRACE_REGISTRY, ("return %!status! BytesAllocated=%d BytsNeeded=%d %ws", status, BytesAllocated, BytesNeeded, ValueStringName)); SmbPrint(SMB_TRACE_REGISTRY, ("SmbQueryValueKey return 0x%08lx BytesAllocated=%d BytsNeeded=%d %ws\n", status, BytesAllocated, BytesNeeded, ValueStringName)); return NULL; } } ASSERT (status == STATUS_SUCCESS); ASSERT (Buffer); return Buffer; } LONG SmbReadLong( IN HANDLE hKey, IN WCHAR *KeyName, IN LONG DefaultValue, IN LONG MinimumValue ) { PKEY_VALUE_FULL_INFORMATION KeyInfo; LONG Value; PAGED_CODE(); ASSERT (DefaultValue >= MinimumValue); Value = DefaultValue; if (Value < MinimumValue) { Value = MinimumValue; } KeyInfo = SmbQueryValueKey(hKey, KeyName); if (KeyInfo == NULL) { return Value; } if (KeyInfo->Type == REG_DWORD && KeyInfo->DataLength == sizeof(ULONG)) { RtlCopyMemory(&Value, (PCHAR)KeyInfo + KeyInfo->DataOffset, sizeof(ULONG)); if (Value < MinimumValue) { Value = MinimumValue; } } ExFreePool(KeyInfo); return Value; } ULONG SmbReadULong( IN HANDLE hKey, IN WCHAR *KeyName, IN ULONG DefaultValue, IN ULONG MinimumValue ) { PKEY_VALUE_FULL_INFORMATION KeyInfo; ULONG Value; PAGED_CODE(); ASSERT (DefaultValue >= MinimumValue); Value = DefaultValue; if (Value < MinimumValue) { Value = MinimumValue; } KeyInfo = SmbQueryValueKey(hKey, KeyName); if (KeyInfo == NULL) { return Value; } if (KeyInfo->Type == REG_DWORD && KeyInfo->DataLength == sizeof(ULONG)) { RtlCopyMemory(&Value, (PCHAR)KeyInfo + KeyInfo->DataOffset, sizeof(ULONG)); if (Value < MinimumValue) { Value = MinimumValue; } } ExFreePool(KeyInfo); return Value; } NTSTATUS SmbReadRegistry( IN HANDLE Key, IN LPWSTR ValueStringName, IN OUT DWORD *Type, IN OUT DWORD *Size, IN OUT PVOID *Buffer ) /*++ Routine Description: Read a regisry value Arguments: Key The registry handle under which the registry key resides. ValueStringName The name of registry key Type The data type of the registry key Type == NULL The caller is not interested in the data type Type != NULL The caller want to receive the data type *Type != REG_NONE The caller can receive the value as any data type. Size The size (# of bytes) of the registry value. Size == NULL The caller is not interested in the data size Size != NULL The caller want to know the data size. Size != NULL && *Buffer != NULL The caller has provided a buffer. *Size is the size of caller-supplied buffer. Buffer The output buffer *Buffer == NULL The caller doesn't provide any buffer. This function should allocate a buffer. The caller is responsible to free the buffer. *Buffer != NULL The caller provides a buffer. The size of buffer is specified in *Size; Return Value: STATUS_SUCCESS success other failure --*/ { PKEY_VALUE_FULL_INFORMATION KeyInfo; ASSERT (Buffer); if (Buffer == NULL) { return STATUS_INVALID_PARAMETER; } // ASSERT (*Buffer ==> Size && *Size); ASSERT (!(*Buffer) || (Size && *Size)); if ((*Buffer) && !(Size && *Size)) { return STATUS_INVALID_PARAMETER; } if ((NULL == *Buffer) && Size && *Size) { ASSERT(0); return STATUS_INVALID_PARAMETER; } KeyInfo = SmbQueryValueKey( Key, ValueStringName ); if (NULL == KeyInfo) { return STATUS_UNSUCCESSFUL; } if (Type && *Type != REG_NONE) { if (KeyInfo->Type != *Type) { ExFreePool(KeyInfo); return STATUS_UNSUCCESSFUL; } } if (NULL == *Buffer) { *Buffer = ExAllocatePoolWithTag(PagedPool, KeyInfo->DataLength, SMB_POOL_REGISTRY); if (NULL == *Buffer) { ExFreePool(KeyInfo); return STATUS_NO_MEMORY; } } else { if (*Size < KeyInfo->DataLength) { ExFreePool(KeyInfo); *Size = KeyInfo->DataLength; return STATUS_BUFFER_TOO_SMALL; } } // // From now on, we cannot fail // if (Size) { *Size = KeyInfo->DataLength; } if (Type) { *Type = KeyInfo->Type; } RtlCopyMemory(*Buffer, ((PUCHAR)KeyInfo) + KeyInfo->DataOffset, KeyInfo->DataLength); ExFreePool(KeyInfo); return STATUS_SUCCESS; }