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 #if defined(_M_AMD64) 68 if (!winetest_interactive) 69 { 70 skip("ROSTESTS-365: Skipping ntdll_apitest:NtSetValueKey because it hangs on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); 71 return; 72 } 73 #endif 74 75 Status = RtlOpenCurrentUser(READ_CONTROL, &ParentKeyHandle); 76 ok(Status == STATUS_SUCCESS, "RtlOpenCurrentUser returned %lx\n", Status); 77 if (!NT_SUCCESS(Status)) 78 { 79 skip("No user key handle\n"); 80 return; 81 } 82 83 InitializeObjectAttributes(&ObjectAttributes, 84 &KeyName, 85 OBJ_CASE_INSENSITIVE, 86 ParentKeyHandle, 87 NULL); 88 Status = NtCreateKey(&KeyHandle, 89 KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE, 90 &ObjectAttributes, 91 0, 92 NULL, 93 REG_OPTION_VOLATILE, 94 NULL); 95 ok(Status == STATUS_SUCCESS, "NtCreateKey returned %lx\n", Status); 96 if (!NT_SUCCESS(Status)) 97 { 98 NtClose(ParentKeyHandle); 99 skip("No key handle\n"); 100 return; 101 } 102 103 LargeBufferLength = 0x20000; 104 LargeBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, LargeBufferLength); 105 106 PartialInfoLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[LargeBufferLength]); 107 PartialInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, PartialInfoLength); 108 109 if (LargeBuffer == NULL || PartialInfo == NULL) 110 { 111 RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer); 112 RtlFreeHeap(GetProcessHeap(), 0, PartialInfo); 113 NtDeleteKey(KeyHandle); 114 NtClose(KeyHandle); 115 NtClose(ParentKeyHandle); 116 skip("Could not allocate buffers\n"); 117 return; 118 } 119 120 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 121 { 122 /* 123 * Existing value 124 */ 125 /* Make sure it exists */ 126 RtlInitUnicodeString(&ValueName, L"ExistingValue"); 127 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, Default, sizeof(Default)); 128 ok(Status == STATUS_SUCCESS, "[%lu] NtSetValueKey failed with %lx", i, Status); 129 130 /* Set it */ 131 Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 132 if (Status == Tests[i].StatusExisting2) 133 ok(Status == Tests[i].StatusExisting || Status == Tests[i].StatusExisting2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n", 134 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting, Tests[i].StatusExisting2); 135 else 136 ok(Status == Tests[i].StatusExisting, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n", 137 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting); 138 139 /* Check it */ 140 RtlZeroMemory(PartialInfo, PartialInfoLength); 141 QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength); 142 ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n", 143 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus); 144 if (NT_SUCCESS(QueryStatus)) 145 { 146 if (NT_SUCCESS(Status)) 147 { 148 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n", 149 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex); 150 ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n", 151 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type); 152 ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n", 153 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength); 154 ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n", 155 Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 156 } 157 else 158 { 159 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n", 160 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex); 161 ok(PartialInfo->Type == REG_SZ, "[%lu, %p, %lu] Type = %lu\n", 162 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type); 163 ok(PartialInfo->DataLength == sizeof(Default), "[%lu, %p, %lu] DataLength = %lu\n", 164 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength); 165 ok(!memcmp(PartialInfo->Data, Default, sizeof(Default)), "[%lu, %p, %lu] Data does not match default\n", 166 Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 167 } 168 } 169 170 /* 171 * New value 172 */ 173 /* Make sure it doesn't exist */ 174 RtlInitUnicodeString(&ValueName, L"NewValue"); 175 Status = NtDeleteValueKey(KeyHandle, &ValueName); 176 ok(Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND, 177 "[%lu] NtDeleteValueKey failed with %lx", i, Status); 178 179 /* Set it */ 180 Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 181 if (Tests[i].StatusNew2) 182 ok(Status == Tests[i].StatusNew || Status == Tests[i].StatusNew2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n", 183 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew, Tests[i].StatusNew2); 184 else 185 ok(Status == Tests[i].StatusNew, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n", 186 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew); 187 188 /* Check it */ 189 RtlZeroMemory(PartialInfo, PartialInfoLength); 190 QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength); 191 if (NT_SUCCESS(Status)) 192 { 193 ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n", 194 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus); 195 if (NT_SUCCESS(QueryStatus)) 196 { 197 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n", 198 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex); 199 ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n", 200 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type); 201 ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n", 202 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength); 203 ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n", 204 Tests[i].Type, Tests[i].Data, Tests[i].DataSize); 205 } 206 } 207 else 208 { 209 ok(QueryStatus == STATUS_OBJECT_NAME_NOT_FOUND, "[%lu, %p, %lu] QueryStatus = %lx\n", 210 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus); 211 } 212 } 213 214 /* String value larger than MAXUSHORT */ 215 { 216 const ULONG DataLengths[] = { 0x10000, 0x10002, 0x20000 }; 217 218 RtlInitUnicodeString(&ValueName, L"ExistingValue"); 219 for (i = 0; i < RTL_NUMBER_OF(DataLengths); i++) 220 { 221 DataLength = DataLengths[i]; 222 RtlFillMemoryUlong(LargeBuffer, DataLength, '\0B\0A'); 223 LargeBuffer[DataLength / sizeof(WCHAR) - 2] = L'C'; 224 LargeBuffer[DataLength / sizeof(WCHAR) - 1] = UNICODE_NULL; 225 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, LargeBuffer, DataLength); 226 ok(Status == STATUS_SUCCESS, "[0x%lx] NtSetValueKey failed with %lx", DataLength, Status); 227 228 RtlZeroMemory(PartialInfo, PartialInfoLength); 229 Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength); 230 ok(Status == STATUS_SUCCESS, "[0x%lx] NtQueryValueKey failed with %lx\n", DataLength, Status); 231 ok(PartialInfo->TitleIndex == 0, "[0x%lx] TitleIndex = %lu\n", DataLength, PartialInfo->TitleIndex); 232 ok(PartialInfo->Type == REG_SZ, "[0x%lx] Type = %lu\n", DataLength, PartialInfo->Type); 233 ok(PartialInfo->DataLength == DataLength, "[0x%lx] DataLength = %lu\n", DataLength, PartialInfo->DataLength); 234 ok(!memcmp(PartialInfo->Data, LargeBuffer, DataLength), "[0x%lx] Data does not match set value\n", DataLength); 235 } 236 } 237 238 RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer); 239 RtlFreeHeap(GetProcessHeap(), 0, PartialInfo); 240 Status = NtDeleteKey(KeyHandle); 241 ok(Status == STATUS_SUCCESS, "NtDeleteKey returned %lx\n", Status); 242 Status = NtClose(KeyHandle); 243 ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status); 244 Status = NtClose(ParentKeyHandle); 245 ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status); 246 } 247