/*++ 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 #include #include #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); }