windows-nt/Source/XPSP1/NT/ds/security/base/lsa/uclient/ctreg.c

808 lines
20 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
ctreg.c
Abstract:
Configuration Registry component test
Needs to move from here
Author:
Scott Birrell (ScottBi) June 5, 1991
Environment:
Revision History:
--*/
#include <string.h>
#include <nt.h>
#include <ntrtl.h>
#define CT_REG_INITIAL_KEY_COUNT 8L
#define CT_REG_INITIAL_LEVEL_COUNT 4L
#define CT_REG_KEY_VALUE_MAX_LENGTH 0x00000100L
//
// List of initial Registry keys to be set up. The list must be
// kept so that moving linearly through it visits key nodes with top
// to bottom key traversal taking precedence over left-to-right.
//
typedef struct _CT_TEST_REGISTRY_KEY {
ULONG KeyLevel;
PUCHAR KeyName;
ULONG KeyValueType;
PUCHAR KeyValue;
ULONG KeyValueLengthToQuery;
ULONG KeyValueLengthToSet;
NTSTATUS ExpectedStatus;
HANDLE KeyHandle;
HANDLE ParentKeyHandle;
} CT_TEST_REGISTRY_KEY, *PCT_TEST_REGISTRY_KEY;
CT_TEST_REGISTRY_KEY RegistryKeys[ CT_REG_INITIAL_KEY_COUNT ];
UCHAR KeyValue[CT_REG_KEY_VALUE_MAX_LENGTH];
ULONG KeyValueLengthToQuery;
ULONG KeyValueType;
LARGE_INTEGER LastWriteTime;
HANDLE ParentKeyHandle[CT_REG_INITIAL_LEVEL_COUNT + 1] =
{ NULL, NULL, NULL, NULL, NULL };
VOID
InitTestKey(
IN ULONG KeyNumber,
IN ULONG KeyLevel,
IN PUCHAR KeyName,
IN ULONG KeyNameLength,
IN ULONG KeyValueType,
IN PUCHAR KeyValue,
IN ULONG KeyValueLengthToQuery,
IN ULONG KeyValueLengthToSet,
IN NTSTATUS ExpectedStatus
);
VOID
CtRegExamineResult(
IN ULONG KeyNumber,
IN ULONG KeyValueType,
IN PUCHAR KeyValue,
IN ULONG KeyValueLength,
IN NTSTATUS ReturnedStatus
);
VOID
CtCreateSetQueryKey();
VOID
CtOpenMakeTempCloseKey();
VOID
main ()
{
CtCreateSetQueryKey();
CtOpenMakeTempCloseKey();
}
VOID
CtCreateSetQueryKey(
)
/*++
Routine Description:
This function tests the RtlpNtOpenKey RtlpNtCreateKey and NtClose API.
Arguments:
None.
Return Value:
None.
--*/
{
NTSTATUS Status;
//
// Set up a test hierarchy of keys
//
ULONG KeyNumber;
ULONG ZeroLength;
STRING Name;
UNICODE_STRING UnicodeName;
OBJECT_ATTRIBUTES ObjectAttributes;
ZeroLength = 0L;
DbgPrint("Start of Create, Set, Query Registry Key Test\n");
//
// Initialize the test array. I did it this way because a statically
// initialized table is harder to read.
//
InitTestKey(
0,
0,
"\\Registry\\RLM",
sizeof ("\\Registry\\RLM"),
0,
"Level 0 - RLM",
sizeof ("\\Registry\\RLM") - 1,
sizeof ("\\Registry\\RLM") - 1,
STATUS_SUCCESS
);
InitTestKey(
1,
1,
"Test",
sizeof ("Test"),
1,
"Keyname Test - this value too big",
6,
sizeof ("Keyname Test - this value too big") -1,
STATUS_BUFFER_OVERFLOW
);
InitTestKey(
2,
2,
"SubTestA",
sizeof("SubTestA"),
2,
"Keyname SubTestA - value small",
30,
sizeof ("Keyname SubTestA - value small") - 1,
STATUS_SUCCESS
);
InitTestKey(
3,
3,
"SSTestA",
sizeof("SSTestA"),
3,
"Keyname SSTestA - zero length buffer",
30,
sizeof("Keyname SSTestA - zero length buffer") - 1,
STATUS_BUFFER_OVERFLOW
);
InitTestKey(
4,
3,
"SSTestB",
sizeof("SSTestB"),
4,
"Keyname SSTestB - value exact fit",
sizeof ("Keyname SSTestB - value exact fit") -1,
sizeof ("Keyname SSTestB - value exact fit") -1,
STATUS_SUCCESS
);
InitTestKey(
5,
3,
"SSTestC",
sizeof("SSTestC"),
5,
"Keyname SSTestC - value small",
40,
sizeof ("Keyname SSTestC - value small") -1,
STATUS_SUCCESS
);
InitTestKey(
6,
3,
"SSTestD",
sizeof("SSTestD"),
6,
"Keyname SSTestD - value small",
40,
sizeof ("Keyname SSTestD - value small") -1,
STATUS_SUCCESS
);
InitTestKey(
7,
3,
"SSTestE",
sizeof("SSTestD"),
0,
"Keyname SSTestD - no value set",
40,
0,
STATUS_SUCCESS
);
DbgPrint("Start of Registry Test\n");
//
// Create all of the initial test registry keys
//
for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) {
RtlInitString(
&Name,
RegistryKeys[KeyNumber].KeyName
);
Status = RtlAnsiStringToUnicodeString(
&UnicodeName,
&Name,
TRUE );
if (!NT_SUCCESS(Status)) {
DbgPrint("Security: Registry Init Ansi to Unicode failed 0x%lx\n",
Status);
return;
}
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeName,
OBJ_CASE_INSENSITIVE,
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel],
NULL
);
//
// Remember the Parent Key handle
//
RegistryKeys[KeyNumber].ParentKeyHandle =
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel];
//
// Create the key if it does not already exist. If key does exist,
// continue trying to create all of the other keys needed (for now).
// Store the returned key handle as the parent key handle for the
// next higher (child) level.
//
Status = RtlpNtCreateKey(
&RegistryKeys[KeyNumber].KeyHandle,
(KEY_READ | KEY_WRITE),
&ObjectAttributes,
0L, // No options
NULL, // Default provider
NULL
);
//
// Save the Key's handle as the next level's parent handle.
//
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1] =
RegistryKeys[KeyNumber].KeyHandle;
//
// Free the memory allocated for the Unicode name
//
RtlFreeUnicodeString( &UnicodeName );
if (NT_SUCCESS(Status) || Status == STATUS_OBJECT_NAME_COLLISION) {
//
// Set the key's value unless the length to set is zero.
//
if (RegistryKeys[KeyNumber].KeyValueLengthToSet != 0) {
Status=RtlpNtSetValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel+1],
RegistryKeys[KeyNumber].KeyValueType,
RegistryKeys[KeyNumber].KeyValue,
RegistryKeys[KeyNumber].KeyValueLengthToSet
);
}
//
// Read the key's value back
//
KeyValueLengthToQuery =
RegistryKeys[KeyNumber].KeyValueLengthToQuery;
Status = RtlpNtQueryValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1],
&KeyValueType,
KeyValue,
&KeyValueLengthToQuery,
&LastWriteTime
);
//
// Verify that the expected KeyValue, KeyLength and Status
// were returned.
//
CtRegExamineResult(
KeyNumber,
KeyValueType,
KeyValue,
KeyValueLengthToQuery,
Status
);
//
// Test null pointer cases don't crash NtQueryValueKey
//
Status = RtlpNtQueryValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1],
NULL, // No type
KeyValue,
&KeyValueLengthToQuery,
&LastWriteTime
);
Status = RtlpNtQueryValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1],
&KeyValueType,
NULL, // No value
&KeyValueLengthToQuery,
&LastWriteTime
);
Status = RtlpNtQueryValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1],
&KeyValueType,
KeyValue,
NULL, // No length
&LastWriteTime
);
Status = RtlpNtQueryValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1],
&KeyValueType,
KeyValue,
&ZeroLength, // Zero length
&LastWriteTime
);
Status = RtlpNtQueryValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1],
&KeyValueType,
KeyValue,
&KeyValueLengthToQuery,
NULL // No time
);
//
// Test null pointer cases don't crash NtSetValueKey
//
Status = RtlpNtSetValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel+1],
RegistryKeys[KeyNumber].KeyValueType,
NULL, // No value, setting type only
RegistryKeys[KeyNumber].KeyValueLengthToSet
);
} else {
DbgPrint(
"Key number %d creation failed 0x%lx\n",
KeyNumber,
Status
);
}
}
//
// Close all the keys in the table
//
for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) {
Status = NtClose(
RegistryKeys[KeyNumber].KeyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint("Closing KeyNumber %d failed 0x%lx\n", Status);
}
}
DbgPrint("End of Create, Set, Query Registry Key Test\n");
}
VOID
CtRegExamineResult(
IN ULONG KeyNumber,
IN ULONG KeyValueType,
IN PUCHAR KeyValue,
IN ULONG KeyValueLengthReturned,
IN NTSTATUS ReturnedStatus
)
{
ULONG KeyValueLengthToCompare;
//
// Check the status. If bad, skip the other checks.
//
if (ReturnedStatus != RegistryKeys[KeyNumber].ExpectedStatus) {
DbgPrint(
"KeyNumber %d: RtlpNtQueryValueKey returned 0x%lx, expected 0x%lx\n",
KeyNumber,
ReturnedStatus,
RegistryKeys[KeyNumber].ExpectedStatus
);
} else {
//
// Check that the Key Type is as expected.
//
if (KeyValueType != RegistryKeys[KeyNumber].KeyValueType) {
DbgPrint(
"KeyNumber %d: RtlpNtQueryValueKey returned KeyValueType 0x%lx, \
expected 0x%lx\n",
KeyNumber,
KeyValueType,
RegistryKeys[KeyNumber].KeyValueType
);
}
//
// Check that the Key Length is as expected.
//
if (KeyValueLengthReturned !=
RegistryKeys[KeyNumber].KeyValueLengthToSet) {
DbgPrint(
"KeyNumber %d: RtlpNtQueryValueKey returned ValLength 0x%lx, \
expected 0x%lx\n",
KeyNumber,
KeyValueLengthReturned,
RegistryKeys[KeyNumber].KeyValueLengthToSet
);
}
//
// Check that the Key Value is as expected. Distinguish between
// Buffer truncated cases and regular cases.
//
if (RegistryKeys[KeyNumber].KeyValueLengthToSet != 0L) {
//
// Determine the length of returned key value to compare. This is
// the min of the set length and and the size of the return
// buffer.
//
KeyValueLengthToCompare =
RegistryKeys[KeyNumber].KeyValueLengthToSet;
if (KeyValueLengthToCompare >
RegistryKeys[KeyNumber].KeyValueLengthToQuery) {
KeyValueLengthToCompare =
RegistryKeys[KeyNumber].KeyValueLengthToQuery;
}
if (strncmp(
KeyValue,
RegistryKeys[KeyNumber].KeyValue,
KeyValueLengthToCompare
) != 0) {
//
// Output approriate error message. Message contains
// "truncated.." if key value should have been truncated
//
if (RegistryKeys[KeyNumber].KeyValueLengthToSet >
RegistryKeys[KeyNumber].KeyValueLengthToQuery) {
DbgPrint(
"KeyNumber %d: RtlpNtQueryValueKey returned KeyValue %s, \
expected %s truncated to %d characters\n",
KeyNumber,
KeyValue,
RegistryKeys[KeyNumber].KeyValue,
RegistryKeys[KeyNumber].KeyValueLengthToQuery
);
} else {
DbgPrint(
"KeyNumber %d: RtlpNtQueryValueKey returned KeyValue %s, \
expected %s\n",
KeyNumber,
KeyValue,
RegistryKeys[KeyNumber].KeyValue
);
}
}
}
}
}
VOID
CtOpenMakeTempCloseKey()
/*++
Routine Description:
This function tests NtDeleteKey by deleting the CT configuration
Arguments:
None.
Return Value:
None
--*/
{
ULONG KeyNumber;
ULONG KeyLevel;
STRING Name;
UNICODE_STRING UnicodeName;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
//
// Open all of the initial test registry keys for write and delete
// access, set, query and delete each key.
//
DbgPrint("Start of Open Make Temp and Close Delete Registry Key Test\n");
//
// First, set all of the Parent handles to NULL
//
for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) {
RegistryKeys[KeyNumber].ParentKeyHandle = NULL;
}
for (KeyLevel = 0; KeyLevel < CT_REG_INITIAL_LEVEL_COUNT; KeyLevel++) {
ParentKeyHandle[KeyLevel] = NULL;
}
for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) {
RtlInitString(
&Name,
RegistryKeys[KeyNumber].KeyName
);
Status = RtlAnsiStringToUnicodeString(
&UnicodeName,
&Name,
TRUE );
if (!NT_SUCCESS(Status)) {
DbgPrint("Security: Registry Init Ansi to Unicode failed 0x%lx\n",
Status);
return;
}
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeName,
OBJ_CASE_INSENSITIVE,
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel],
NULL
);
//
// Open the key and store the returned key handle as the parent key
// handle for the next higher (child) level.
//
Status = RtlpNtOpenKey(
&RegistryKeys[KeyNumber].KeyHandle,
(KEY_READ | KEY_WRITE | DELETE),
&ObjectAttributes,
0L // No options
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"NtOpenKey - KeyNumber %d failed 0x%lx\n",
KeyNumber,
Status
);
}
//
// Save the Key's handle as the next level's parent handle.
//
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1] =
RegistryKeys[KeyNumber].KeyHandle;
//
// Free the memory allocated for the Unicode name
//
RtlFreeUnicodeString( &UnicodeName );
if (NT_SUCCESS(Status) || Status == STATUS_OBJECT_NAME_COLLISION) {
//
// Set the key's value unless the length to set is zero.
//
if (RegistryKeys[KeyNumber].KeyValueLengthToSet != 0) {
Status=RtlpNtSetValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel+1],
RegistryKeys[KeyNumber].KeyValueType,
RegistryKeys[KeyNumber].KeyValue,
RegistryKeys[KeyNumber].KeyValueLengthToSet
);
}
//
// Read the key's value back
//
KeyValueLengthToQuery =
RegistryKeys[KeyNumber].KeyValueLengthToQuery;
Status = RtlpNtQueryValueKey(
ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1],
&KeyValueType,
KeyValue,
&KeyValueLengthToQuery,
&LastWriteTime
);
//
// Verify that the expected KeyValue, KeyLength and Status
// were returned.
//
CtRegExamineResult(
KeyNumber,
KeyValueType,
KeyValue,
KeyValueLengthToQuery,
Status
);
} else {
DbgPrint(
"Key number %d open failed 0x%lx\n",
KeyNumber,
Status
);
}
}
//
// Make Temporary and Close all the keys in the table
//
for (KeyNumber = CT_REG_INITIAL_KEY_COUNT-1; KeyNumber != 0L; KeyNumber--) {
Status = RtlpNtMakeTemporaryKey( RegistryKeys[KeyNumber].KeyHandle );
if (!NT_SUCCESS(Status)) {
DbgPrint(
"Making Temporary KeyNumber %d failed 0x%lx\n",
KeyNumber,
Status
);
}
Status = NtClose(
RegistryKeys[KeyNumber].KeyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"Closing KeyNumber %d failed 0x%lx\n",
KeyNumber,
Status
);
}
}
DbgPrint("End of Open Mk Temp and Close Registry Key Test\n");
}
VOID
InitTestKey(
IN ULONG KeyNumber,
IN ULONG KeyLevel,
IN PUCHAR KeyName,
IN ULONG KeyNameLength,
IN ULONG KeyValueType,
IN PUCHAR KeyValue,
IN ULONG KeyValueLengthToQuery,
IN ULONG KeyValueLengthToSet,
IN NTSTATUS ExpectedStatus
)
/*++
Routine Description:
This function initializes an entry in the array of test keys
Arguments:
TBS.
Return Value:
--*/
{
RegistryKeys[KeyNumber].KeyLevel = KeyLevel;
RegistryKeys[KeyNumber].KeyName = KeyName;
RegistryKeys[KeyNumber].KeyValueType = KeyValueType;
RegistryKeys[KeyNumber].KeyValue = KeyValue;
RegistryKeys[KeyNumber].KeyValueLengthToSet = KeyValueLengthToSet;
RegistryKeys[KeyNumber].KeyValueLengthToQuery = KeyValueLengthToQuery;
RegistryKeys[KeyNumber].ExpectedStatus = ExpectedStatus;
RegistryKeys[KeyNumber].KeyHandle = NULL;
RegistryKeys[KeyNumber].ParentKeyHandle = NULL;
DBG_UNREFERENCED_PARAMETER (KeyNameLength);
}