1 /* 2 * PROJECT: ReactOS API Tests 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Test for NtSetValueKey 5 * COPYRIGHT: Copyright 2016-2019 Thomas Faber (thomas.faber@reactos.org) 6 */ 7 8 #include "precomp.h" 9 10 #include <winreg.h> 11 12 START_TEST(NtSetValueKey) 13 { 14 NTSTATUS Status; 15 HANDLE ParentKeyHandle; 16 HANDLE KeyHandle; 17 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SOFTWARE\\ntdll-apitest-NtSetValueKey"); 18 OBJECT_ATTRIBUTES ObjectAttributes; 19 UNICODE_STRING ValueName; 20 WCHAR Default[] = L"Default"; 21 WCHAR Hello[] = L"Hello"; 22 WCHAR Empty[] = L""; 23 NTSTATUS QueryStatus; 24 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; 25 ULONG PartialInfoLength; 26 ULONG ResultLength; 27 ULONG DataLength; 28 PWCHAR LargeBuffer; 29 ULONG LargeBufferLength; 30 const struct 31 { 32 ULONG Type; 33 PVOID Data; 34 ULONG DataSize; 35 NTSTATUS StatusExisting; 36 NTSTATUS StatusNew; 37 NTSTATUS StatusExisting2; 38 NTSTATUS StatusNew2; 39 } Tests[] = 40 { 41 { REG_NONE, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty REG_NONE value */ 42 { REG_SZ, Hello, sizeof(Hello), STATUS_SUCCESS, STATUS_SUCCESS }, /* Regular string */ 43 { REG_SZ, Empty, sizeof(Empty), STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty string */ 44 { REG_SZ, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length */ 45 { REG_SZ, Hello, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, non-null data */ 46 { REG_SZ, (PVOID)(LONG_PTR)-4, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, kernel data */ 47 { REG_SZ, NULL, 1, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (odd), null data */ 48 { REG_SZ, NULL, 2, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (even), null data */ 49 { REG_SZ, NULL, 4, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* CM_KEY_VALUE_SMALL, null data */ 50 { REG_SZ, NULL, 5, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+1, null data */ 51 STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */ 52 { REG_SZ, NULL, 6, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+2, null data */ 53 STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */ 54 { REG_SZ, NULL, 0x7fff0000, STATUS_INVALID_PARAMETER, STATUS_INSUFFICIENT_RESOURCES, /* MI_USER_PROBE_ADDRESS, null data */ 55 STATUS_INSUFFICIENT_RESOURCES, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */ 56 { REG_SZ, NULL, 0x7fff0001, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* MI_USER_PROBE_ADDRESS+1, null data */ 57 STATUS_INSUFFICIENT_RESOURCES, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */ 58 { REG_SZ, NULL, 0x7fffffff, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* <2GB, null data */ 59 STATUS_INVALID_PARAMETER, STATUS_INVALID_PARAMETER }, /* win7 */ 60 { REG_SZ, NULL, 0x80000000, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* 2GB, null data */ 61 STATUS_INVALID_PARAMETER, STATUS_INVALID_PARAMETER }, /* win7 */ 62 { REG_BINARY, NULL, 5, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* ROSTESTS-200 */ 63 STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */ 64 }; 65 ULONG i; 66 67 Status = RtlOpenCurrentUser(READ_CONTROL, &ParentKeyHandle); 68 ok(Status == STATUS_SUCCESS, "RtlOpenCurrentUser returned %lx\n", Status); 69 if (!NT_SUCCESS(Status)) 70 { 71 skip("No user key handle\n"); 72 return; 73 } 74 75 InitializeObjectAttributes(&ObjectAttributes, 76 &KeyName, 77 OBJ_CASE_INSENSITIVE, 78 ParentKeyHandle, 79 NULL); 80 Status = NtCreateKey(&KeyHandle, 81 KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE, 82 &ObjectAttributes, 83 0, 84 NULL, 85 REG_OPTION_VOLATILE, 86 NULL); 87 ok(Status == STATUS_SUCCESS, "NtCreateKey returned %lx\n", Status); 88 if (!NT_SUCCESS(Status)) 89 { 90 NtClose(ParentKeyHandle); 91 skip("No key handle\n"); 92 return; 93 } 94 95 LargeBufferLength = 0x20000; 96 LargeBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, LargeBufferLength); 97 98 PartialInfoLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[LargeBufferLength]); 99 PartialInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, PartialInfoLength); 100 101 if (LargeBuffer == NULL || PartialInfo == NULL) 102 { 103 RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer); 104 RtlFreeHeap(GetProcessHeap(), 0, PartialInfo); 105 NtDeleteKey(KeyHandle); 106 NtClose(KeyHandle); 107 NtClose(ParentKeyHandle); 108 skip("Could not allocate buffers\n"); 109 return; 110 } 111 112 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 113 { 114 /* 115 * Existing value 116 */ 117 /* Make sure it exists */ 118 RtlInitUnicodeString(&ValueName, L"ExistingValue"); 119 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, Default, sizeof(Default)); 120 ok(Status == STATUS_SUCCESS, "[%lu] NtSetValueKey failed with %lx", i, Status); 121 122 /* Set it */ 123 Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 124 if (Status == Tests[i].StatusExisting2) 125 ok(Status == Tests[i].StatusExisting || Status == Tests[i].StatusExisting2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n", 126 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting, Tests[i].StatusExisting2); 127 else 128 ok(Status == Tests[i].StatusExisting, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n", 129 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting); 130 131 /* Check it */ 132 RtlZeroMemory(PartialInfo, PartialInfoLength); 133 QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength); 134 ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n", 135 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus); 136 if (NT_SUCCESS(QueryStatus)) 137 { 138 if (NT_SUCCESS(Status)) 139 { 140 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n", 141 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex); 142 ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n", 143 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type); 144 ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n", 145 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength); 146 ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n", 147 Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 148 } 149 else 150 { 151 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n", 152 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex); 153 ok(PartialInfo->Type == REG_SZ, "[%lu, %p, %lu] Type = %lu\n", 154 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type); 155 ok(PartialInfo->DataLength == sizeof(Default), "[%lu, %p, %lu] DataLength = %lu\n", 156 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength); 157 ok(!memcmp(PartialInfo->Data, Default, sizeof(Default)), "[%lu, %p, %lu] Data does not match default\n", 158 Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 159 } 160 } 161 162 /* 163 * New value 164 */ 165 /* Make sure it doesn't exist */ 166 RtlInitUnicodeString(&ValueName, L"NewValue"); 167 Status = NtDeleteValueKey(KeyHandle, &ValueName); 168 ok(Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND, 169 "[%lu] NtDeleteValueKey failed with %lx", i, Status); 170 171 /* Set it */ 172 Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 173 if (Tests[i].StatusNew2) 174 ok(Status == Tests[i].StatusNew || Status == Tests[i].StatusNew2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n", 175 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew, Tests[i].StatusNew2); 176 else 177 ok(Status == Tests[i].StatusNew, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n", 178 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew); 179 180 /* Check it */ 181 RtlZeroMemory(PartialInfo, PartialInfoLength); 182 QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength); 183 if (NT_SUCCESS(Status)) 184 { 185 ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n", 186 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus); 187 if (NT_SUCCESS(QueryStatus)) 188 { 189 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n", 190 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex); 191 ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n", 192 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type); 193 ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n", 194 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength); 195 ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n", 196 Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 197 } 198 } 199 else 200 { 201 ok(QueryStatus == STATUS_OBJECT_NAME_NOT_FOUND, "[%lu, %p, %lu] QueryStatus = %lx\n", 202 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus); 203 } 204 } 205 206 /* String value larger than MAXUSHORT */ 207 { 208 const ULONG DataLengths[] = { 0x10000, 0x10002, 0x20000 }; 209 210 RtlInitUnicodeString(&ValueName, L"ExistingValue"); 211 for (i = 0; i < RTL_NUMBER_OF(DataLengths); i++) 212 { 213 DataLength = DataLengths[i]; 214 RtlFillMemoryUlong(LargeBuffer, DataLength, '\0B\0A'); 215 LargeBuffer[DataLength / sizeof(WCHAR) - 2] = L'C'; 216 LargeBuffer[DataLength / sizeof(WCHAR) - 1] = UNICODE_NULL; 217 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, LargeBuffer, DataLength); 218 ok(Status == STATUS_SUCCESS, "[0x%lx] NtSetValueKey failed with %lx", DataLength, Status); 219 220 RtlZeroMemory(PartialInfo, PartialInfoLength); 221 Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength); 222 ok(Status == STATUS_SUCCESS, "[0x%lx] NtQueryValueKey failed with %lx\n", DataLength, Status); 223 ok(PartialInfo->TitleIndex == 0, "[0x%lx] TitleIndex = %lu\n", DataLength, PartialInfo->TitleIndex); 224 ok(PartialInfo->Type == REG_SZ, "[0x%lx] Type = %lu\n", DataLength, PartialInfo->Type); 225 ok(PartialInfo->DataLength == DataLength, "[0x%lx] DataLength = %lu\n", DataLength, PartialInfo->DataLength); 226 ok(!memcmp(PartialInfo->Data, LargeBuffer, DataLength), "[0x%lx] Data does not match set value\n", DataLength); 227 } 228 } 229 230 RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer); 231 RtlFreeHeap(GetProcessHeap(), 0, PartialInfo); 232 Status = NtDeleteKey(KeyHandle); 233 ok(Status == STATUS_SUCCESS, "NtDeleteKey returned %lx\n", Status); 234 Status = NtClose(KeyHandle); 235 ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status); 236 Status = NtClose(ParentKeyHandle); 237 ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status); 238 } 239