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.
581 lines
16 KiB
581 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
registry.c
|
|
|
|
Abstract:
|
|
|
|
(This file has been copied from the temporary hack that BryanWi and
|
|
ScottBi did in kernel mode. I saw no need to have it be in kernel
|
|
mode and it had many bugs caused as a result of being in kernel mode,
|
|
so I made it caller mode. Jim Kelly).
|
|
|
|
|
|
|
|
This module represents a quick and dirty Nt level registry. Each key
|
|
in the Registry is implemented as a file directory within a directory
|
|
tree whose root is the directory "\Registry" on the system disk.
|
|
A key's data is stored within a file called "Data.Reg" in the key's
|
|
directory, and a key's attributes is stored as the file "Attr.Reg"
|
|
within the directory.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Author:
|
|
|
|
Bryan M. Willman (bryanwi) 30-Apr-1991
|
|
Scott Birrell (ScottBi) 6-Jun-1991
|
|
|
|
Environment:
|
|
|
|
callable from Kernel or user mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ntrtlp.h"
|
|
|
|
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
|
|
#pragma alloc_text(PAGE,RtlpNtOpenKey)
|
|
#pragma alloc_text(PAGE,RtlpNtCreateKey)
|
|
#pragma alloc_text(PAGE,RtlpNtQueryValueKey)
|
|
#pragma alloc_text(PAGE,RtlpNtSetValueKey)
|
|
#pragma alloc_text(PAGE,RtlpNtMakeTemporaryKey)
|
|
#pragma alloc_text(PAGE,RtlpNtEnumerateSubKey)
|
|
#endif
|
|
|
|
#define REG_INVALID_ATTRIBUTES (OBJ_EXCLUSIVE | OBJ_PERMANENT)
|
|
|
|
|
|
|
|
//
|
|
// Temporary Registry User APIs.
|
|
//
|
|
// NOTE: These are temporary implementations. Although there is no code
|
|
// within that requires these API to be implemented as system services, the
|
|
// eventual replacements for these routines will use the Object Manager and
|
|
// hence require to be system services.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
RtlpNtOpenKey(
|
|
OUT PHANDLE KeyHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN ULONG Options
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens a key in the Registry. The key must already exist.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Receives a value called a Handle which is used to access
|
|
the specified key in the Registration Database.
|
|
|
|
DesiredAccess - Specifies the Accesses desired
|
|
|
|
REG_KEY_READ - Generic Read access to key
|
|
REG_KEY_QUERY_VALUE - Query Key's value
|
|
REG_KEY_WRITE - Generic Write access to key
|
|
REG_KEY_SET_VALUE - Set Key's value
|
|
|
|
ObjectAttributes - Specifies the attributes of the key being opened.
|
|
Note that a key name must be specified. If a Root Directory
|
|
is specified, the name is relative to the root. The name of the
|
|
object must be within the name space allocated to the Registry, that
|
|
is, all names beginning "\Registry". RootHandle, if present, must
|
|
be a handle to "\", or "\Registry", or a key under "\Registry".
|
|
|
|
Options - REG_OPTION_READ_FUZZY - Allow Read access on handle even if
|
|
it is open for Read/Write access.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call. The following are returned
|
|
|
|
STATUS_SUCCESS - The open was successful.
|
|
|
|
STATUS_INVALID_PARAMETER - A parameter other that object name was
|
|
invalid.
|
|
|
|
STATUS_OBJECT_NAME_INVALID - The key name has invalid syntax
|
|
|
|
STATUS_OBJECT_NAME_NOT_FOUND - No key of the given name exists
|
|
|
|
STATUS_ACCESS_DENIED - Caller does not have the requested access
|
|
to the specified key.
|
|
--*/
|
|
|
|
{
|
|
RTL_PAGED_CODE();
|
|
|
|
if (ARGUMENT_PRESENT(ObjectAttributes)) {
|
|
ObjectAttributes->Attributes &= ~(REG_INVALID_ATTRIBUTES);
|
|
}
|
|
|
|
return( NtOpenKey( KeyHandle,
|
|
DesiredAccess,
|
|
ObjectAttributes
|
|
) );
|
|
|
|
DBG_UNREFERENCED_PARAMETER( Options );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RtlpNtCreateKey(
|
|
OUT PHANDLE KeyHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN ULONG Options,
|
|
IN PUNICODE_STRING Provider,
|
|
OUT OPTIONAL PULONG Disposition
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates or opens the specified key in the Registry. If
|
|
the key does not exist, it is created. If the key already exists, it
|
|
is opened.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Receives a value called a Handle which is used to access
|
|
the specified key in the Registration Database.
|
|
|
|
DesiredAccess - Specifies the Accesses desired
|
|
|
|
REG_KEY_READ - Generic Read access to key
|
|
REG_KEY_QUERY_VALUE - Query Key's value
|
|
REG_KEY_WRITE - Generic Write access to key
|
|
REG_KEY_SET_VALUE - Set Key's value
|
|
|
|
ObjectAttributes - Specifies the attributes of the key being opened.
|
|
Note that a key name must be specified. If a Root Directory
|
|
is specified, the name is relative to the root. The name of the
|
|
object must be within the name space allocated to the Registry, that
|
|
is, all names beginning "\Registry". RootHandle, if present, must
|
|
be a handle to "\", or "\Registry", or a key under "\Registry".
|
|
|
|
|
|
Options - REG_OPTION_READ_FUZZY - Allow Read access on handle even if it is
|
|
open for READ_WRITE access.
|
|
|
|
REG_OPTION_VOLATILE - Object is not to be stored across boots.
|
|
|
|
Provider - This parameter is reserved for future use and must currently
|
|
be set to NULL. It will be used in the future to specify the name of
|
|
the provider to be used for operations on this node and its descendant
|
|
nodes.
|
|
|
|
Disposition - This optional parameter is a pointer to a variable that
|
|
will receive a value indicating whether a new Registry key was
|
|
created or an existing one opened.
|
|
|
|
REG_CREATED_NEW_KEY - A new Registry Key was created
|
|
REG_OPENED_EXISTING_KEY - An existing Registry Key was opened
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call. The following are returned
|
|
|
|
STATUS_SUCCESS - The open was successful.
|
|
|
|
STATUS_INVALID_PARAMETER - A parameter other that object name was
|
|
--*/
|
|
|
|
{
|
|
RTL_PAGED_CODE();
|
|
|
|
if (ARGUMENT_PRESENT(ObjectAttributes)) {
|
|
ObjectAttributes->Attributes &= ~(REG_INVALID_ATTRIBUTES);
|
|
}
|
|
|
|
|
|
return(NtCreateKey( KeyHandle,
|
|
DesiredAccess,
|
|
ObjectAttributes,
|
|
0, //TitleIndex
|
|
NULL, //Class OPTIONAL,
|
|
REG_OPTION_NON_VOLATILE, //CreateOptions,
|
|
Disposition
|
|
) );
|
|
|
|
DBG_UNREFERENCED_PARAMETER( Options );
|
|
DBG_UNREFERENCED_PARAMETER( Provider );
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RtlpNtQueryValueKey(
|
|
IN HANDLE KeyHandle,
|
|
OUT OPTIONAL PULONG KeyValueType,
|
|
OUT OPTIONAL PVOID KeyValue,
|
|
IN OUT OPTIONAL PULONG KeyValueLength,
|
|
OUT OPTIONAL PLARGE_INTEGER LastWriteTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function queries the value of a key.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of a key opened for GENERIC_READ access via NtOpenKey.
|
|
|
|
KeyValueType - Optional pointer to variable that will receive the
|
|
client-defined type of the key value (if any). If no value has been
|
|
set for the key, 0 is returned.
|
|
|
|
KeyValue - Optional pointer to buffer in which part or all of the key's
|
|
value (as set on the most recent call to NtSetValueKey) will be
|
|
returned. If the key's value is too large to fit into the supplied
|
|
buffer, as much of the value as will fit into the buffer will be
|
|
returned and the warning STATUS_BUFFER_OVERFLOW is returned. If no
|
|
value has ever been set, nothing is returned. If NULL is specified
|
|
for this parameter, no Key Value is returned.
|
|
|
|
KeyValueLength - On input, this optional parameter points to a variable
|
|
that contains the length in bytes of the KeyValue buffer (if any). If
|
|
no KeyValue buffer is specified, the variable content on entry is
|
|
ignored. On return, the referenced variable (if any) receives the
|
|
FULL length in bytes of the key value. If the key's value is too
|
|
large to fit into the supplied buffer, as much of the value as will
|
|
fit into the buffer will be returned and the warning
|
|
STATUS_BUFFER_OVERFLOW is returned.
|
|
|
|
The returned length is intended for use by calling code in allocating
|
|
a buffer of sufficient size to hold the key's value. After receiving
|
|
STATUS_BUFFER_OVERFLOW from NtQueryValueKey, calling code may make a
|
|
subsequent call to NtQueryValueKey with a buffer of size equal to the
|
|
length returned by the prior call.
|
|
|
|
If no value has been set for the key, 0 is returned.
|
|
|
|
LastWriteTime - Optional parameter to variable which receives a time stamp
|
|
specifying the last time that the key was written.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code
|
|
|
|
STATUS_SUCCESS - Call was successful
|
|
|
|
STATUS_INVALID_PARAMETER - Invalid parameter
|
|
|
|
STATUS_ACCESS_DENIED - Caller does not have GENERIC_READ access to
|
|
the specified key
|
|
|
|
STATUS_BUFFER_OVERFLOW - This is a warning that the key's value
|
|
is too large for the buffer specified by the KeyValue and
|
|
KeyValueLength parameters. Use the length returned to
|
|
determine the size of buffer to allocate for a subsequent
|
|
call of NtQueryValueKey.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UNICODE_STRING NullName;
|
|
NTSTATUS Status;
|
|
PKEY_VALUE_PARTIAL_INFORMATION ValueInformation;
|
|
ULONG ValueLength;
|
|
|
|
RTL_PAGED_CODE();
|
|
|
|
//
|
|
// Compute the size of the buffer needed to hold the key value information.
|
|
//
|
|
|
|
ValueLength = 0;
|
|
if (ARGUMENT_PRESENT(KeyValueLength)) {
|
|
ValueLength = *KeyValueLength;
|
|
}
|
|
|
|
ValueLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
|
ValueInformation = RtlAllocateHeap(RtlProcessHeap(), 0, ValueLength);
|
|
if (ValueInformation == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Query the key value.
|
|
//
|
|
|
|
NullName.Length = 0;
|
|
Status = NtQueryValueKey(KeyHandle,
|
|
&NullName,
|
|
KeyValuePartialInformation,
|
|
ValueInformation,
|
|
ValueLength,
|
|
&ValueLength);
|
|
|
|
//
|
|
// Temporary hack to allow query of "" attribute when it hasn't
|
|
// yet been set.
|
|
//
|
|
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
Status = STATUS_SUCCESS;
|
|
ValueInformation->DataLength = 0;
|
|
ValueInformation->Type = 0;
|
|
}
|
|
|
|
//
|
|
// If requested return the key value length and the key type.
|
|
//
|
|
|
|
if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW)) {
|
|
if (ARGUMENT_PRESENT(KeyValueLength)) {
|
|
*KeyValueLength = ValueInformation->DataLength;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(KeyValueType)) {
|
|
*KeyValueType = ValueInformation->Type;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the query was successful and buffer overflow did not occur, then
|
|
// return the key value information.
|
|
//
|
|
|
|
if (NT_SUCCESS(Status) && ARGUMENT_PRESENT(KeyValue)) {
|
|
RtlCopyMemory(KeyValue,
|
|
&ValueInformation->Data[0],
|
|
ValueInformation->DataLength);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, ValueInformation);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RtlpNtSetValueKey(
|
|
IN HANDLE KeyHandle,
|
|
IN ULONG KeyValueType,
|
|
IN OPTIONAL PVOID KeyValue,
|
|
IN ULONG KeyValueLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the type and value of a key.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Specifies a handle of the key whose type and value are to
|
|
be set. The key must have been opened with GENERIC_WRITE access.
|
|
|
|
KeyValueType - This is a value that the client of the registry defines to
|
|
distinguish different client-defined types of data value stored
|
|
with the key. When setting the value of a key that has previously
|
|
had a Type and Value stored, the Type may be changed.
|
|
|
|
KeyValue - Optional pointer to the data to be optionally stored as the
|
|
value of the key. If NULL is specified for this parameter, only
|
|
the value type will be written.
|
|
|
|
KeyValueLength - Specifies the length in bytes of the data to be stored as
|
|
the key's value. A zero value indicates that no data is being stored:
|
|
if zero is specified, the Value parameter will be ignored.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code. The following values are returned
|
|
|
|
STATUS_SUCCESS - The call was successful
|
|
|
|
STATUS_INVALID_PARAMETER - Invalid Parameter(s)
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING NullName;
|
|
NullName.Length = 0;
|
|
|
|
RTL_PAGED_CODE();
|
|
|
|
return( NtSetValueKey( KeyHandle,
|
|
&NullName, // ValueName
|
|
0, // TitleIndex
|
|
KeyValueType,
|
|
KeyValue,
|
|
KeyValueLength
|
|
) );
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RtlpNtMakeTemporaryKey(
|
|
IN HANDLE KeyHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function makes a Registry key temporary. The key will be deleted
|
|
when the last handle to it is closed.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Specifies the handle of the Key. This is also the handle
|
|
of the key's directory.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_INVALID_HANDLE - The specified handle is invalid.
|
|
|
|
STATUS_ACCESS_DENIED - The specified handle does not specify delet
|
|
access.
|
|
|
|
--*/
|
|
|
|
{
|
|
RTL_PAGED_CODE();
|
|
|
|
return( NtDeleteKey(KeyHandle) );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RtlpNtEnumerateSubKey(
|
|
IN HANDLE KeyHandle,
|
|
OUT PUNICODE_STRING SubKeyName,
|
|
IN ULONG Index,
|
|
OUT PLARGE_INTEGER LastWriteTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function finds the name of the next sub key of a given key. By
|
|
making successive calls, all of the sub keys of a key can be determined.
|
|
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key whose sub keys are to be enumerated.
|
|
|
|
SubKeyName - Pointer to a Unicode String in which the name of the sub
|
|
key will be returned.
|
|
|
|
Index - Specifies the (ZERO-based) number of the sub key to be returned.
|
|
|
|
|
|
LastWriteTime - Receives the time stamp that specifies when the key
|
|
was last written.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code
|
|
|
|
STATUS_SUCCESS - The call succeeded
|
|
|
|
STATUS_INVALID_PARAMETER - Invalid parameter
|
|
|
|
STATUS_NO_MORE_ENTRIES - There is no key having the specified index
|
|
|
|
STATUS_BUFFER_OVERFLOW - The buffer of the output string was not
|
|
large enough to hold the next sub-key name. SubKeyName->Length
|
|
contains the number of bytes required.
|
|
|
|
STATUS_NO_MEMORY - There was not sufficient heap to perform the
|
|
requested operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PKEY_BASIC_INFORMATION KeyInformation = NULL;
|
|
ULONG LocalBufferLength, ResultLength;
|
|
|
|
RTL_PAGED_CODE();
|
|
|
|
LocalBufferLength = 0;
|
|
if (SubKeyName->MaximumLength > 0) {
|
|
|
|
LocalBufferLength = SubKeyName->MaximumLength +
|
|
FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);
|
|
KeyInformation = RtlAllocateHeap( RtlProcessHeap(), 0,
|
|
LocalBufferLength
|
|
);
|
|
if (KeyInformation == NULL) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
}
|
|
|
|
Status = NtEnumerateKey( KeyHandle,
|
|
Index,
|
|
KeyBasicInformation, //KeyInformationClass
|
|
(PVOID)KeyInformation,
|
|
LocalBufferLength,
|
|
&ResultLength
|
|
);
|
|
|
|
if (NT_SUCCESS(Status) && (KeyInformation != NULL)) {
|
|
|
|
if ( SubKeyName->MaximumLength >= KeyInformation->NameLength) {
|
|
|
|
SubKeyName->Length = (USHORT)KeyInformation->NameLength;
|
|
|
|
RtlCopyMemory( SubKeyName->Buffer,
|
|
&KeyInformation->Name[0],
|
|
SubKeyName->Length
|
|
);
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the length required if we failed due to a small buffer
|
|
//
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
SubKeyName->Length = (USHORT)(ResultLength -
|
|
FIELD_OFFSET(KEY_BASIC_INFORMATION, Name));
|
|
}
|
|
|
|
|
|
//
|
|
// Free up any memory we allocated
|
|
//
|
|
|
|
if (KeyInformation != NULL) {
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0,
|
|
KeyInformation
|
|
);
|
|
}
|
|
|
|
|
|
return(Status);
|
|
|
|
DBG_UNREFERENCED_PARAMETER( LastWriteTime );
|
|
|
|
}
|