mirror of https://github.com/tongzx/nt5src
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.
525 lines
15 KiB
525 lines
15 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1992, Microsoft Corporation
|
|
//
|
|
// File: regsups.c
|
|
//
|
|
// Contents: Support routines for registry - mainly wrappers for NtAPI.
|
|
// The native NT registry API deal with unweildy OBJECT_ATTRIBUTES
|
|
// structures to simply name a registry entry, and also deal
|
|
// with open-ended structures. This module wraps around the native
|
|
// NT api and presents a more logical interface tot the registry.
|
|
//
|
|
// The routines all have a uniform theme:
|
|
//
|
|
// o Declare a KEY_XXX (NT defined) structure on the stack,
|
|
// with an "arbitrary guess" for size of data.
|
|
//
|
|
// o Make the NT call.
|
|
//
|
|
// o If NT call returns STATUS_BUFFER_OVERFLOW, allocate a
|
|
// KEY_XXX structure of the correct size from heap, and make
|
|
// NT call again.
|
|
//
|
|
// o If success, copy data to caller's data buffer, and free
|
|
// anything we allocated on the heap.
|
|
//
|
|
// With a generous initial guess for data buffer size, most of
|
|
// the time these calls will make a single NT call. Only for
|
|
// large data will we pay the overhead of memory allocation.
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions: KRegpAttributes
|
|
// KRegpGetValueByName
|
|
// KRegpGetKeyInfo
|
|
// KRegpEnumKeyValues
|
|
// KRegpEnumSubKeys
|
|
//
|
|
// History: 18 Sep 92 Milans created.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "registry.h"
|
|
#include "regsups.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, KRegpAttributes )
|
|
#pragma alloc_text( PAGE, KRegpGetValueByName )
|
|
#pragma alloc_text( PAGE, KRegpGetKeyInfo )
|
|
#pragma alloc_text( PAGE, KRegpEnumKeyValues )
|
|
#pragma alloc_text( PAGE, KRegpEnumSubKeys )
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// The NT Reg API uses a few open ended structs for info related calls. This
|
|
// defines the max size of our structs.
|
|
//
|
|
// This is just an "optimization". When the NT API's want an open ended data
|
|
// buffer, we will initially supply one of MAX_INFO_LENGTH. If this is not
|
|
// sufficient, the NT API will return STATUS_BUFFER_OVERFLOW. At that point,
|
|
// we will allocate on the heap the proper size buffer, and call again.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#define MAX_INFO_LENGTH 512 // Maximum length of info bufs
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Struct for Value information (ie, value name, data, etc.)
|
|
//
|
|
|
|
typedef struct tag_KEY_VALUE_INFORMATION {
|
|
KEY_VALUE_FULL_INFORMATION vi;
|
|
BYTE buffer[MAX_INFO_LENGTH];
|
|
} KEY_VALUE_INFORMATION;
|
|
|
|
#define KEY_VALUE_INFORMATION_LENGTH sizeof(KEY_VALUE_FULL_INFORMATION) + \
|
|
MAX_INFO_LENGTH
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Struct for Key information (ie, # of subkeys, # of values, etc.)
|
|
//
|
|
|
|
typedef struct tag_KEY_INFORMATION {
|
|
KEY_FULL_INFORMATION ki;
|
|
BYTE buffer[MAX_INFO_LENGTH];
|
|
} KEY_INFORMATION;
|
|
|
|
#define KEY_INFORMATION_LENGTH sizeof(KEY_FULL_INFORMATION) + MAX_INFO_LENGTH
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Struct for a particular subkey's information
|
|
//
|
|
|
|
typedef struct tag_KEY_SUBKEY_INFORMATION {
|
|
KEY_NODE_INFORMATION ni;
|
|
BYTE buffer[MAX_INFO_LENGTH];
|
|
} KEY_SUBKEY_INFORMATION;
|
|
|
|
#define KEY_SUBKEY_INFORMATION_LENGTH sizeof(KEY_NODE_INFORMATION) + \
|
|
MAX_INFO_LENGTH
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegpAttributes
|
|
//
|
|
// Synopsis: The NT reg API often calls for an Object Attributes structure
|
|
// for things like names etc. This routine bundles a name and its
|
|
// parent into such a structure.
|
|
//
|
|
// Arguments: [hParent] Handle to parent of object
|
|
// [wszName] Name of object
|
|
//
|
|
// Returns: Address of initialized object attributes structure.
|
|
//
|
|
// Notes: Return value is address to static variable.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
OBJECT_ATTRIBUTES *
|
|
KRegpAttributes(
|
|
IN HANDLE hParent,
|
|
IN PWSTR wszName)
|
|
{
|
|
static OBJECT_ATTRIBUTES objAttributes;
|
|
static UNICODE_STRING usName;
|
|
|
|
RtlInitUnicodeString(&usName, wszName);
|
|
InitializeObjectAttributes(
|
|
&objAttributes, // Destination
|
|
&usName, // Name
|
|
OBJ_CASE_INSENSITIVE, // Attributes
|
|
hParent, // Parent
|
|
NULL); // Security
|
|
|
|
return(&objAttributes);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegpGetValueByName
|
|
//
|
|
// Synopsis: Given a Value Name, returns the value's data.
|
|
//
|
|
// Arguments: [hkey] Handle of key
|
|
// [wszValueName] Value Name to query
|
|
// [pbData] Pointer to data buffer
|
|
// [pcbSize] Pointer to ULONG. On entry, it must show size of
|
|
// data buffer. On successful exit, it will be set to
|
|
// actual length of data retrieved.
|
|
//
|
|
// Returns: STATUS_BUFFER_TOO_SMALL, Status from NT Reg API.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegpGetValueByName(
|
|
IN HKEY hKey,
|
|
IN PWSTR wszValueName,
|
|
OUT PBYTE pbData,
|
|
IN OUT PULONG pcbSize)
|
|
{
|
|
KEY_VALUE_INFORMATION viValue, *pviValue;
|
|
UNICODE_STRING ustrValueName;
|
|
ULONG cbActualLength, cbRequiredSize;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&ustrValueName, wszValueName);
|
|
pviValue = &viValue;
|
|
Status = NtQueryValueKey(
|
|
hKey,
|
|
&ustrValueName,
|
|
KeyValueFullInformation,
|
|
(PVOID) pviValue,
|
|
KEY_VALUE_INFORMATION_LENGTH,
|
|
&cbActualLength
|
|
);
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
|
|
//
|
|
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
|
|
// Forced to allocate from heap and make call again.
|
|
//
|
|
|
|
pviValue = (KEY_VALUE_INFORMATION *) ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
cbActualLength,
|
|
' sfD');
|
|
if (!pviValue) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
Status = NtQueryValueKey(
|
|
hKey,
|
|
&ustrValueName,
|
|
KeyValueFullInformation,
|
|
(PVOID) pviValue,
|
|
cbActualLength,
|
|
&cbActualLength);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (pviValue->vi.Type == REG_SZ) {
|
|
cbRequiredSize = pviValue->vi.DataLength + sizeof(UNICODE_NULL);
|
|
} else {
|
|
cbRequiredSize = pviValue->vi.DataLength;
|
|
}
|
|
|
|
if (cbRequiredSize > *pcbSize) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
RtlMoveMemory(pbData, ((BYTE *) pviValue) + pviValue->vi.DataOffset,
|
|
pviValue->vi.DataLength);
|
|
|
|
if (pviValue->vi.Type == REG_SZ) {
|
|
((PWSTR) pbData)[cbRequiredSize/sizeof(WCHAR) - 1] = UNICODE_NULL;
|
|
}
|
|
|
|
*pcbSize = cbRequiredSize;
|
|
|
|
|
|
Cleanup:
|
|
if (pviValue != &viValue) {
|
|
|
|
//
|
|
// Must have had to allocate from heap, so free the heap
|
|
//
|
|
|
|
DfsFree(pviValue);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegpGetKeyInfo
|
|
//
|
|
// Synopsis: Given a key, return the number of subkeys, values, and their
|
|
// max sizes.
|
|
//
|
|
// Arguments: [hkey] Handle to key.
|
|
// [pcNumSubKeys] Receives # of subkeys that hkey has
|
|
// [pcbMaxSubKeyLength] Receives max length of subkey name
|
|
// [pcNumValues] Receives # of values that hkey has
|
|
// [pcbMaxValueLength] Receives max length of value name
|
|
// [pcbMaxValueData] Receives max length of value data
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegpGetKeyInfo(
|
|
IN HKEY hKey,
|
|
OUT PULONG pcNumSubKeys,
|
|
OUT PULONG pcbMaxSubKeyLength,
|
|
OUT PULONG pcNumValues,
|
|
OUT PULONG pcbMaxValueName,
|
|
OUT PULONG pcbMaxValueData)
|
|
{
|
|
KEY_INFORMATION kiInfo, *pkiInfo;
|
|
ULONG lActualLength;
|
|
NTSTATUS Status;
|
|
|
|
pkiInfo = &kiInfo;
|
|
Status = NtQueryKey(
|
|
hKey,
|
|
KeyFullInformation,
|
|
pkiInfo,
|
|
KEY_INFORMATION_LENGTH,
|
|
&lActualLength);
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
|
|
//
|
|
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
|
|
// Forced to allocate from heap and make call again.
|
|
//
|
|
|
|
pkiInfo = (KEY_INFORMATION *) ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
lActualLength,
|
|
' sfD');
|
|
if (!pkiInfo) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
Status = NtQueryKey(
|
|
hKey,
|
|
KeyFullInformation,
|
|
pkiInfo,
|
|
lActualLength,
|
|
&lActualLength);
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
*pcNumSubKeys = pkiInfo->ki.SubKeys;
|
|
*pcbMaxSubKeyLength = pkiInfo->ki.MaxNameLen;
|
|
*pcNumValues = pkiInfo->ki.Values;
|
|
*pcbMaxValueName = pkiInfo->ki.MaxValueNameLen;
|
|
*pcbMaxValueData = pkiInfo->ki.MaxValueDataLen;
|
|
}
|
|
|
|
if (pkiInfo != &kiInfo) {
|
|
DfsFree(pkiInfo);
|
|
}
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegpEnumKeyValues
|
|
//
|
|
// Synopsis: Given a key, return the name and data of the i'th value, where
|
|
// the first value has an index of 0.
|
|
//
|
|
// Arguments: [hkey] -- Handle to key
|
|
// [i] -- Index of value to get
|
|
// [wszValueName] -- Pointer to buffer to hold value name.
|
|
// [pcbMaxValueName] -- on entry, size in bytes of wszValueName.
|
|
// On exit, will hold size of wszValueName.
|
|
// [pbData] -- pointer to buffer to hold value data.
|
|
// [pcbMaxDataSize] -- on entry, size of pbData. On successful
|
|
// return, size of pbData.
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegpEnumKeyValues(
|
|
HKEY hKey,
|
|
ULONG iValue,
|
|
PWSTR wszValueName,
|
|
PULONG pcbMaxValueName,
|
|
PBYTE pbData,
|
|
PULONG pcbMaxDataSize)
|
|
{
|
|
KEY_VALUE_INFORMATION viValue, *pviValue;
|
|
ULONG dwActualLength;
|
|
NTSTATUS Status;
|
|
|
|
pviValue = &viValue;
|
|
Status = NtEnumerateValueKey(
|
|
hKey,
|
|
iValue,
|
|
KeyValueFullInformation,
|
|
pviValue,
|
|
KEY_VALUE_INFORMATION_LENGTH,
|
|
&dwActualLength);
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
|
|
//
|
|
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
|
|
// Forced to allocate from heap and make call again.
|
|
//
|
|
|
|
pviValue = (KEY_VALUE_INFORMATION *) ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
dwActualLength,
|
|
' sfD');
|
|
if (!pviValue) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
Status = NtEnumerateValueKey(
|
|
hKey,
|
|
iValue,
|
|
KeyValueFullInformation,
|
|
pviValue,
|
|
dwActualLength,
|
|
&dwActualLength);
|
|
}
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if ( (*pcbMaxValueName < pviValue->vi.NameLength) ||
|
|
(*pcbMaxDataSize < pviValue->vi.DataLength) ) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*pcbMaxValueName = pviValue->vi.NameLength;
|
|
|
|
RtlMoveMemory(
|
|
(BYTE *) wszValueName,
|
|
(BYTE *) pviValue->vi.Name,
|
|
pviValue->vi.NameLength
|
|
);
|
|
wszValueName[pviValue->vi.NameLength / sizeof(WCHAR)] = L'\0';
|
|
|
|
RtlMoveMemory(
|
|
pbData,
|
|
((BYTE *) &viValue) + pviValue->vi.DataOffset,
|
|
pviValue->vi.DataLength
|
|
);
|
|
*pcbMaxDataSize = pviValue->vi.DataLength;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
if (pviValue != &viValue) {
|
|
DfsFree(pviValue);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: KRegpEnumSubKeys
|
|
//
|
|
// Synopsis: Retrieve the i'th subkey name of a key.
|
|
//
|
|
// Arguments: [hKey] -- Parent key
|
|
// [iSubKey] -- index of the subkey
|
|
// [wszSubKeyName] Buffer to hold name of subkey
|
|
// [pcbMaxNameSize] On entry, size in bytes of wszSubKeyName
|
|
// On exit, size of name.
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
KRegpEnumSubKeys(
|
|
HKEY hKey,
|
|
ULONG iSubKey,
|
|
PWSTR wszSubKeyName,
|
|
PULONG pcbMaxNameSize
|
|
)
|
|
{
|
|
KEY_SUBKEY_INFORMATION si, *psi;
|
|
ULONG dwActualLength;
|
|
NTSTATUS Status;
|
|
|
|
psi = &si;
|
|
Status = NtEnumerateKey(
|
|
hKey,
|
|
iSubKey,
|
|
KeyNodeInformation,
|
|
psi,
|
|
KEY_SUBKEY_INFORMATION_LENGTH,
|
|
&dwActualLength
|
|
);
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
|
|
//
|
|
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
|
|
// Forced to allocate from heap and make call again.
|
|
//
|
|
|
|
psi = (KEY_SUBKEY_INFORMATION *) ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
dwActualLength,
|
|
' sfD');
|
|
if (!psi) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
Status = NtEnumerateKey(
|
|
hKey,
|
|
iSubKey,
|
|
KeyNodeInformation,
|
|
psi,
|
|
dwActualLength,
|
|
&dwActualLength
|
|
);
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (*pcbMaxNameSize < si.ni.NameLength) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
(BYTE *) wszSubKeyName,
|
|
(BYTE *) psi->ni.Name,
|
|
psi->ni.NameLength
|
|
);
|
|
wszSubKeyName[psi->ni.NameLength / sizeof(WCHAR)] = UNICODE_NULL;
|
|
*pcbMaxNameSize = psi->ni.NameLength;
|
|
}
|
|
|
|
Cleanup:
|
|
if (psi != &si) {
|
|
DfsFree(psi);
|
|
}
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|