Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1064 lines
26 KiB

/*++
Copyright (c) 1991-2000 Microsoft Corporation
Module Name:
ntreg.c
Abstract:
This source file contains the routines to to access the NT Registry for
configuration info.
Author:
Mike Massa (mikemas) September 3, 1993
(taken from routines by jballard)
Revision History:
--*/
#include "precomp.h"
#include "internaldef.h"
#define WORK_BUFFER_SIZE 512
//
// Local function prototypes
//
NTSTATUS
OpenRegKey(
PHANDLE HandlePtr,
PWCHAR KeyName
);
NTSTATUS
GetRegDWORDValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG ValueData
);
NTSTATUS
GetRegLARGEINTValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PLARGE_INTEGER ValueData
);
NTSTATUS
SetRegDWORDValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG ValueData
);
NTSTATUS
SetRegMultiSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData
);
NTSTATUS
SetRegMultiSZValueNew(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING_NEW ValueData
);
NTSTATUS
GetRegStringValueNew(
HANDLE KeyHandle,
PWCHAR ValueName,
PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
PULONG ValueSize
);
NTSTATUS
GetRegStringValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
PUSHORT ValueSize
);
NTSTATUS
GetRegSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData,
PULONG ValueType
);
NTSTATUS
GetRegMultiSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData
);
NTSTATUS
GetRegMultiSZValueNew(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING_NEW ValueData
);
NTSTATUS
InitRegDWORDParameter(
HANDLE RegKey,
PWCHAR ValueName,
ULONG * Value,
ULONG DefaultValue
);
#if !MILLEN
#ifdef ALLOC_PRAGMA
//
// All of the init code can be discarded
//
#pragma alloc_text(PAGE, GetRegDWORDValue)
#pragma alloc_text(PAGE, GetRegLARGEINTValue)
#pragma alloc_text(PAGE, SetRegDWORDValue)
#pragma alloc_text(PAGE, InitRegDWORDParameter)
//
// This code is pagable.
//
#pragma alloc_text(PAGE, OpenRegKey)
#pragma alloc_text(PAGE, GetRegStringValue)
#pragma alloc_text(PAGE, GetRegStringValueNew)
#pragma alloc_text(PAGE, GetRegSZValue)
#pragma alloc_text(PAGE, GetRegMultiSZValue)
#pragma alloc_text(PAGE, GetRegMultiSZValueNew)
#endif // ALLOC_PRAGMA
#endif // !MILLEN
#if DBG
ULONG IPDebug = 0;
#endif
//
// Function definitions
//
NTSTATUS
OpenRegKey(
PHANDLE HandlePtr,
PWCHAR KeyName
)
/*++
Routine Description:
Opens a Registry key and returns a handle to it.
Arguments:
HandlePtr - The varible into which to write the opened handle.
KeyName - The name of the Registry key to open.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UKeyName;
PAGED_CODE();
RtlInitUnicodeString(&UKeyName, KeyName);
memset(&ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
InitializeObjectAttributes(&ObjectAttributes,
&UKeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(HandlePtr,
KEY_READ,
&ObjectAttributes);
return Status;
}
#if MILLEN
ulong
ConvertDecimalString(PWCHAR pString)
{
ulong dwTemp = 0;
while (*pString)
{
if (*pString >= L'0' && *pString <= L'9')
dwTemp = dwTemp * 10 + (*pString - L'0');
else
break;
pString++;
}
return(dwTemp);
}
#endif // MILLEN
NTSTATUS
GetRegDWORDValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG ValueData
)
/*++
Routine Description:
Reads a REG_DWORD value from the registry into the supplied variable.
Arguments:
KeyHandle - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
ValueData - The variable into which to read the data.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
ULONG resultLength;
PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
UCHAR keybuf[WORK_BUFFER_SIZE];
UNICODE_STRING UValueName;
PAGED_CODE();
RtlInitUnicodeString(&UValueName, ValueName);
keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION) keybuf;
RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
status = ZwQueryValueKey(KeyHandle,
&UValueName,
KeyValueFullInformation,
keyValueFullInformation,
WORK_BUFFER_SIZE,
&resultLength);
if (NT_SUCCESS(status)) {
if (keyValueFullInformation->Type == REG_DWORD) {
*ValueData = *((ULONG UNALIGNED *) ((PCHAR) keyValueFullInformation +
keyValueFullInformation->DataOffset));
#if MILLEN
} else if (keyValueFullInformation->Type == REG_SZ) {
PWCHAR Data;
Data = (PWCHAR) ((PCHAR) keyValueFullInformation +
keyValueFullInformation->DataOffset);
// On Millennium, we need to support legacy of reading registry
// keys as strings and converting to a DWORD.
*ValueData = ConvertDecimalString(Data);
#endif // !MILLEN
} else {
status = STATUS_INVALID_PARAMETER_MIX;
}
}
return status;
}
NTSTATUS
GetRegLARGEINTValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PLARGE_INTEGER ValueData
)
/*++
Routine Description:
Reads a REG_DWORD value from the registry into the supplied variable.
Arguments:
KeyHandle - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
ValueData - The variable into which to read the data.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
ULONG resultLength;
PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
UCHAR keybuf[WORK_BUFFER_SIZE];
UNICODE_STRING UValueName;
PAGED_CODE();
RtlInitUnicodeString(&UValueName, ValueName);
keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION) keybuf;
RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
status = ZwQueryValueKey(KeyHandle,
&UValueName,
KeyValueFullInformation,
keyValueFullInformation,
WORK_BUFFER_SIZE,
&resultLength);
if (NT_SUCCESS(status)) {
if (keyValueFullInformation->Type != REG_BINARY) {
status = STATUS_INVALID_PARAMETER_MIX;
} else {
*ValueData = *((LARGE_INTEGER UNALIGNED *) ((PCHAR) keyValueFullInformation +
keyValueFullInformation->DataOffset));
}
}
return status;
}
NTSTATUS
SetRegDWORDValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG ValueData
)
/*++
Routine Description:
Writes the contents of a variable to a REG_DWORD value.
Arguments:
KeyHandle - Open handle to the parent key of the value to write.
ValueName - The name of the value to write.
ValueData - The variable from which to write the data.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
UNICODE_STRING UValueName;
PAGED_CODE();
RtlInitUnicodeString(&UValueName, ValueName);
status = ZwSetValueKey(KeyHandle,
&UValueName,
0,
REG_DWORD,
ValueData,
sizeof(ULONG));
return status;
}
NTSTATUS
SetRegMultiSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData
)
/*++
Routine Description:
Writes the contents of a variable to a REG_DWORD value.
Arguments:
KeyHandle - Open handle to the parent key of the value to write.
ValueName - The name of the value to write.
ValueData - The variable from which to write the data.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
UNICODE_STRING UValueName;
#if MILLEN
LONG i;
PWCHAR Buf = ValueData->Buffer;
#endif // MILLEN
PAGED_CODE();
#if MILLEN
// Convert it to a SZ string
while (*Buf != UNICODE_NULL) {
while (*Buf++ != UNICODE_NULL);
if (*Buf != UNICODE_NULL) {
*(Buf-1) = L',';
}
}
#endif // MILLEN
RtlInitUnicodeString(&UValueName, ValueName);
status = ZwSetValueKey(KeyHandle,
&UValueName,
0,
#if MILLEN
REG_SZ,
#else // MILLEN
REG_MULTI_SZ,
#endif // !MILLEN
ValueData->Buffer,
ValueData->Length);
return status;
}
NTSTATUS
SetRegMultiSZValueNew(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING_NEW ValueData
)
/*++
Routine Description:
Writes the contents of a variable to a REG_DWORD value, using a structure
which accommodates >64K bytes.
Arguments:
KeyHandle - Open handle to the parent key of the value to write.
ValueName - The name of the value to write.
ValueData - The variable from which to write the data.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
UNICODE_STRING UValueName;
#if MILLEN
LONG i;
PWCHAR Buf = ValueData->Buffer;
#endif // MILLEN
PAGED_CODE();
#if MILLEN
// Convert it to a SZ string
while (*Buf != UNICODE_NULL) {
while (*Buf++ != UNICODE_NULL);
if (*Buf != UNICODE_NULL) {
*(Buf-1) = L',';
}
}
#endif // MILLEN
RtlInitUnicodeString(&UValueName, ValueName);
status = ZwSetValueKey(KeyHandle,
&UValueName,
0,
#if MILLEN
REG_SZ,
#else // MILLEN
REG_MULTI_SZ,
#endif // !MILLEN
ValueData->Buffer,
ValueData->Length);
return status;
}
NTSTATUS
GetRegStringValueNew(
HANDLE KeyHandle,
PWCHAR ValueName,
PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
PULONG ValueSize
)
/*++
Routine Description:
Reads a REG_*_SZ string value from the Registry into the supplied
key value buffer. If the buffer string buffer is not large enough,
it is reallocated.
Arguments:
KeyHandle - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
ValueData - Destination for the read data.
ValueSize - Size of the ValueData buffer. Updated on output.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
ULONG resultLength;
UNICODE_STRING UValueName;
PAGED_CODE();
RtlInitUnicodeString(&UValueName, ValueName);
status = ZwQueryValueKey(
KeyHandle,
&UValueName,
KeyValuePartialInformation,
*ValueData,
(ULONG) * ValueSize,
&resultLength
);
if ((status == STATUS_BUFFER_OVERFLOW) ||
(status == STATUS_BUFFER_TOO_SMALL)
) {
PVOID temp;
//
// Free the old buffer and allocate a new one of the
// appropriate size.
//
ASSERT(resultLength > *ValueSize);
temp = ExAllocatePoolWithTag(NonPagedPool, resultLength, 'iPCT');
if (temp != NULL) {
if (*ValueData != NULL) {
CTEFreeMem(*ValueData);
}
*ValueData = temp;
*ValueSize = resultLength;
status = ZwQueryValueKey(KeyHandle,
&UValueName,
KeyValuePartialInformation,
*ValueData,
*ValueSize,
&resultLength
);
ASSERT((status != STATUS_BUFFER_OVERFLOW) &&
(status != STATUS_BUFFER_TOO_SMALL)
);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
return (status);
}
NTSTATUS
GetRegStringValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PKEY_VALUE_PARTIAL_INFORMATION * ValueData,
PUSHORT ValueSize
)
/*++
Routine Description:
Reads a REG_*_SZ string value from the Registry into the supplied
key value buffer. If the buffer string buffer is not large enough,
it is reallocated.
Arguments:
KeyHandle - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
ValueData - Destination for the read data.
ValueSize - Size of the ValueData buffer. Updated on output.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
ULONG resultLength;
UNICODE_STRING UValueName;
PAGED_CODE();
RtlInitUnicodeString(&UValueName, ValueName);
status = ZwQueryValueKey(
KeyHandle,
&UValueName,
KeyValuePartialInformation,
*ValueData,
(ULONG) * ValueSize,
&resultLength
);
if ((status == STATUS_BUFFER_OVERFLOW) ||
(status == STATUS_BUFFER_TOO_SMALL)
) {
PVOID temp;
//
// Free the old buffer and allocate a new one of the
// appropriate size.
//
ASSERT(resultLength > (ULONG) * ValueSize);
if (resultLength <= 0xFFFF) {
//temp = CTEAllocMem(resultLength);
temp = ExAllocatePoolWithTag(NonPagedPool, resultLength, 'iPCT');
if (temp != NULL) {
if (*ValueData != NULL) {
CTEFreeMem(*ValueData);
}
*ValueData = temp;
*ValueSize = (USHORT) resultLength;
status = ZwQueryValueKey(KeyHandle,
&UValueName,
KeyValuePartialInformation,
*ValueData,
resultLength,
&resultLength
);
ASSERT((status != STATUS_BUFFER_OVERFLOW) &&
(status != STATUS_BUFFER_TOO_SMALL)
);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
}
return (status);
}
NTSTATUS
GetRegMultiSZValueNew(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING_NEW ValueData
)
/*++
Routine Description:
Reads a REG_MULTI_SZ string value from the Registry into the supplied
Unicode string. If the Unicode string buffer is not large enough,
it is reallocated.
Arguments:
KeyHandle - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
ValueData - Destination Unicode string for the value data.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
ULONG resultLength;
PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
UNICODE_STRING UValueName;
PAGED_CODE();
ValueData->Length = 0;
status = GetRegStringValueNew(
KeyHandle,
ValueName,
(PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
&(ValueData->MaximumLength)
);
DEBUGMSG(DBG_ERROR && !NT_SUCCESS(status),
(DTEXT("GetRegStringValueNew failure %x\n"), status));
if (NT_SUCCESS(status)) {
keyValuePartialInformation =
(PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
DEBUGMSG(DBG_INFO && DBG_REG,
(DTEXT("GetRegMultiSZValueNew - retrieved string -- type %x = %s\n"),
keyValuePartialInformation->Type,
keyValuePartialInformation->Type == REG_MULTI_SZ ? TEXT("MULTI-SZ") :
keyValuePartialInformation->Type == REG_SZ ? TEXT("SZ") :
TEXT("OTHER")));
if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
ValueData->Length = keyValuePartialInformation->DataLength;
RtlCopyMemory(
ValueData->Buffer,
&(keyValuePartialInformation->Data),
ValueData->Length
);
#if MILLEN
} else if (keyValuePartialInformation->Type == REG_SZ) {
// Convert it to a MULTI-SZ string
LONG i;
PWCHAR Buf = ValueData->Buffer;
ValueData->Length = keyValuePartialInformation->DataLength;
RtlCopyMemory(
ValueData->Buffer,
&(keyValuePartialInformation->Data),
ValueData->Length
);
for (i = 0; Buf[i] != L'\0'; i++) {
if (L',' == Buf[i]) {
Buf[i] = L'\0';
}
}
// Need an extra NULL at the end.
Buf[++i] = L'\0';
#endif // MILLEN
} else {
status = STATUS_INVALID_PARAMETER_MIX;
}
}
return status;
} // GetRegMultiSZValueNew
NTSTATUS
GetRegMultiSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData
)
/*++
Routine Description:
Reads a REG_MULTI_SZ string value from the Registry into the supplied
Unicode string. If the Unicode string buffer is not large enough,
it is reallocated.
Arguments:
KeyHandle - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
ValueData - Destination Unicode string for the value data.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
ULONG resultLength;
PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
UNICODE_STRING UValueName;
PAGED_CODE();
ValueData->Length = 0;
status = GetRegStringValue(
KeyHandle,
ValueName,
(PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
&(ValueData->MaximumLength)
);
if (NT_SUCCESS(status)) {
keyValuePartialInformation =
(PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
ValueData->Length = (USHORT)
keyValuePartialInformation->DataLength;
RtlCopyMemory(
ValueData->Buffer,
&(keyValuePartialInformation->Data),
ValueData->Length
);
#if MILLEN
} else if (keyValuePartialInformation->Type == REG_SZ) {
// Convert it to a MULTI-SZ string
LONG i;
PWCHAR Buf = ValueData->Buffer;
ValueData->Length = (USHORT) keyValuePartialInformation->DataLength;
RtlCopyMemory(
ValueData->Buffer,
&(keyValuePartialInformation->Data),
ValueData->Length
);
for (i = 0; Buf[i] != L'\0'; i++) {
if (L',' == Buf[i]) {
Buf[i] = L'\0';
}
}
// Need an extra NULL at the end.
Buf[++i] = L'\0';
#endif // MILLEN
} else {
status = STATUS_INVALID_PARAMETER_MIX;
}
}
return status;
} // GetRegMultiSZValue
NTSTATUS
GetRegSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData,
PULONG ValueType
)
/*++
Routine Description:
Reads a REG_SZ string value from the Registry into the supplied
Unicode string. If the Unicode string buffer is not large enough,
it is reallocated.
Arguments:
KeyHandle - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
ValueData - Destination Unicode string for the value data.
ValueType - On return, contains the Registry type of the value read.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
ULONG resultLength;
PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
UNICODE_STRING UValueName;
PAGED_CODE();
ValueData->Length = 0;
status = GetRegStringValue(
KeyHandle,
ValueName,
(PKEY_VALUE_PARTIAL_INFORMATION *) & (ValueData->Buffer),
&(ValueData->MaximumLength)
);
if (NT_SUCCESS(status)) {
keyValuePartialInformation =
(PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
if ((keyValuePartialInformation->Type == REG_SZ) ||
(keyValuePartialInformation->Type == REG_EXPAND_SZ)
) {
WCHAR *src;
WCHAR *dst;
ULONG dataLength;
*ValueType = keyValuePartialInformation->Type;
dataLength = keyValuePartialInformation->DataLength;
ASSERT(dataLength <= ValueData->MaximumLength);
dst = ValueData->Buffer;
src = (PWCHAR) & (keyValuePartialInformation->Data);
while (ValueData->Length <= dataLength) {
if ((*dst++ = *src++) == UNICODE_NULL) {
break;
}
ValueData->Length += sizeof(WCHAR);
}
if (ValueData->Length < (ValueData->MaximumLength - 1)) {
ValueData->Buffer[ValueData->Length / sizeof(WCHAR)] =
UNICODE_NULL;
}
} else {
status = STATUS_INVALID_PARAMETER_MIX;
}
}
return status;
}
NTSTATUS
InitRegDWORDParameter(
HANDLE RegKey,
PWCHAR ValueName,
ULONG * Value,
ULONG DefaultValue
)
/*++
Routine Description:
Reads a REG_DWORD parameter from the Registry into a variable. If the
read fails, the variable is initialized to a default.
Arguments:
RegKey - Open handle to the parent key of the value to read.
ValueName - The name of the value to read.
Value - Destination variable into which to read the data.
DefaultValue - Default to assign if the read fails.
Return Value:
STATUS_SUCCESS or an appropriate failure code.
--*/
{
NTSTATUS status;
PAGED_CODE();
status = GetRegDWORDValue(
RegKey,
ValueName,
Value
);
if (!NT_SUCCESS(status)) {
//
// These registry parameters override the defaults, so their
// absence is not an error.
//
*Value = DefaultValue;
}
return (status);
}
PWCHAR
EnumRegMultiSz(
IN PWCHAR MszString,
IN ULONG MszStringLength,
IN ULONG StringIndex
)
/*++
Routine Description:
Parses a REG_MULTI_SZ string and returns the specified substring.
Arguments:
MszString - A pointer to the REG_MULTI_SZ string.
MszStringLength - The length of the REG_MULTI_SZ string, including the
terminating null character.
StringIndex - Index number of the substring to return. Specifiying
index 0 retrieves the first substring.
Return Value:
A pointer to the specified substring.
Notes:
This code is called at raised IRQL. It is not pageable.
--*/
{
PWCHAR string = MszString;
if (MszStringLength < (2 * sizeof(WCHAR))) {
return (NULL);
}
//
// Find the start of the desired string.
//
while (StringIndex) {
while (MszStringLength >= sizeof(WCHAR)) {
MszStringLength -= sizeof(WCHAR);
if (*string++ == UNICODE_NULL) {
break;
}
}
//
// Check for index out of range.
//
if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
return (NULL);
}
StringIndex--;
}
if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
return (NULL);
}
return (string);
}