1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Tests for the NtQueryKey API
5  * PROGRAMMER:      Jérôme Gardou <jerome.gardou@reactos.org>
6  *                  Thomas Faber <thomas.faber@reactos.org>
7  */
8 
9 #include "precomp.h"
10 
11 static
12 void
13 Test_KeyFullInformation(void)
14 {
15     UNICODE_STRING HKLM_Name = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
16     UNICODE_STRING Software_Name = RTL_CONSTANT_STRING(L"Software");
17     UNICODE_STRING Test_Name = RTL_CONSTANT_STRING(L"NtQueryKey_apitest");
18     UNICODE_STRING MyClass = RTL_CONSTANT_STRING(L"MyClass");
19     HANDLE HKLM_Key, HKLM_Software_Key, Test_Key;
20     ULONG FullInformationLength;
21     PKEY_FULL_INFORMATION FullInformation;
22     ULONG InfoLength;
23     OBJECT_ATTRIBUTES ObjectAttributes;
24     NTSTATUS Status;
25 
26     FullInformationLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class[100]);
27     FullInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullInformationLength);
28     if (!FullInformation)
29     {
30         skip("Out of memory\n");
31         return;
32     }
33 
34     InitializeObjectAttributes(&ObjectAttributes,
35         &HKLM_Name,
36         OBJ_CASE_INSENSITIVE,
37         NULL,
38         NULL);
39     Status = NtOpenKey(&HKLM_Key, KEY_READ, &ObjectAttributes);
40     ok_ntstatus(Status, STATUS_SUCCESS);
41 
42     InfoLength = 0x55555555;
43     Status = NtQueryKey(HKLM_Key, KeyFullInformation, NULL, 0, &InfoLength);
44     ok(Status == STATUS_BUFFER_TOO_SMALL, "Status = 0x%lx\n", Status);
45     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength);
46 
47     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
48     InfoLength = 0x55555555;
49     Status = NtQueryKey(HKLM_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class), &InfoLength);
50     ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status);
51     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength);
52     ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n");
53     ok(FullInformation->TitleIndex == 0, "TitleIndex = %lu\n", FullInformation->TitleIndex);
54     ok(FullInformation->ClassOffset == 0xffffffff, "ClassOffset = %lu\n", FullInformation->ClassOffset);
55     ok(FullInformation->ClassLength == 0, "ClassLength = %lu\n", FullInformation->ClassLength);
56     ok(FullInformation->SubKeys >= 5 && FullInformation->SubKeys < 20, "SubKeys = %lu\n", FullInformation->SubKeys);
57     ok(FullInformation->MaxNameLen >= 8 * sizeof(WCHAR) && FullInformation->MaxNameLen < 100 * sizeof(WCHAR), "MaxNameLen = %lu\n", FullInformation->MaxNameLen);
58     ok(FullInformation->MaxClassLen != 0x55555555 && FullInformation->MaxClassLen % sizeof(WCHAR) == 0, "MaxClassLen = %lu\n", FullInformation->MaxClassLen);
59     ok(FullInformation->Values != 0x55555555, "Values = %lu\n", FullInformation->Values);
60     ok(FullInformation->MaxValueNameLen != 0x55555555 && FullInformation->MaxValueNameLen % sizeof(WCHAR) == 0, "MaxValueNameLen = %lu\n", FullInformation->MaxValueNameLen);
61     ok(FullInformation->MaxValueDataLen != 0x55555555, "MaxValueDataLen = %lu\n", FullInformation->MaxValueDataLen);
62     ok(FullInformation->Class[0] == 0x5555, "Class[0] = %u\n", FullInformation->Class[0]);
63 
64     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
65     InfoLength = 0x55555555;
66     Status = NtQueryKey(HKLM_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) - 1, &InfoLength);
67     ok(Status == STATUS_BUFFER_TOO_SMALL, "Status = 0x%lx\n", Status);
68     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength);
69     ok(FullInformation->LastWriteTime.QuadPart == 0x5555555555555555, "LastWriteTime changed: %I64d\n", FullInformation->LastWriteTime.QuadPart);
70 
71     InitializeObjectAttributes(&ObjectAttributes,
72         &Software_Name,
73         OBJ_CASE_INSENSITIVE,
74         HKLM_Key,
75         NULL);
76     Status = NtOpenKey(&HKLM_Software_Key, KEY_READ, &ObjectAttributes);
77     ok_ntstatus(Status, STATUS_SUCCESS);
78 
79     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
80     InfoLength = 0x55555555;
81     Status = NtQueryKey(HKLM_Software_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class), &InfoLength);
82     ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status);
83     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength);
84     ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n");
85     ok(FullInformation->TitleIndex == 0, "TitleIndex = %lu\n", FullInformation->TitleIndex);
86     ok(FullInformation->ClassOffset == 0xffffffff, "ClassOffset = %lu\n", FullInformation->ClassOffset);
87     ok(FullInformation->ClassLength == 0, "ClassLength = %lu\n", FullInformation->ClassLength);
88     ok(FullInformation->SubKeys >= 5 && FullInformation->SubKeys < 1000, "SubKeys = %lu\n", FullInformation->SubKeys);
89     ok(FullInformation->MaxNameLen >= 8 * sizeof(WCHAR), "MaxNameLen = %lu\n", FullInformation->MaxNameLen);
90     ok(FullInformation->MaxClassLen != 0x55555555 && FullInformation->MaxClassLen % sizeof(WCHAR) == 0, "MaxClassLen = %lu\n", FullInformation->MaxClassLen);
91     ok(FullInformation->Values != 0x55555555, "Values = %lu\n", FullInformation->Values);
92     ok(FullInformation->MaxValueNameLen != 0x55555555 && FullInformation->MaxValueNameLen % sizeof(WCHAR) == 0, "MaxValueNameLen = %lu\n", FullInformation->MaxValueNameLen);
93     ok(FullInformation->MaxValueDataLen != 0x55555555, "MaxValueDataLen = %lu\n", FullInformation->MaxValueDataLen);
94     ok(FullInformation->Class[0] == 0x5555, "Class[0] = %u\n", FullInformation->Class[0]);
95 
96     InitializeObjectAttributes(&ObjectAttributes,
97         &Test_Name,
98         OBJ_CASE_INSENSITIVE,
99         HKLM_Software_Key,
100         NULL);
101     Status = NtCreateKey(&Test_Key, KEY_ALL_ACCESS, &ObjectAttributes, 0, &MyClass, REG_OPTION_VOLATILE, NULL);
102     ok_ntstatus(Status, STATUS_SUCCESS);
103 
104     InfoLength = 0x55555555;
105     Status = NtQueryKey(Test_Key, KeyFullInformation, NULL, 0, &InfoLength);
106     ok(Status == STATUS_BUFFER_TOO_SMALL, "Status = 0x%lx\n", Status);
107     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength);
108 
109     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
110     InfoLength = 0x55555555;
111     Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class), &InfoLength);
112     ok(Status == STATUS_BUFFER_OVERFLOW, "Status = 0x%lx\n", Status);
113     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength);
114     ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n");
115     ok(FullInformation->TitleIndex == 0, "TitleIndex = %lu\n", FullInformation->TitleIndex);
116     ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset);
117     ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength);
118     ok(FullInformation->SubKeys == 0, "SubKeys = %lu\n", FullInformation->SubKeys);
119     ok(FullInformation->MaxNameLen == 0, "MaxNameLen = %lu\n", FullInformation->MaxNameLen);
120     ok(FullInformation->MaxClassLen == 0, "MaxClassLen = %lu\n", FullInformation->MaxClassLen);
121     ok(FullInformation->Values == 0, "Values = %lu\n", FullInformation->Values);
122     ok(FullInformation->MaxValueNameLen == 0, "MaxValueNameLen = %lu\n", FullInformation->MaxValueNameLen);
123     ok(FullInformation->MaxValueDataLen == 0, "MaxValueDataLen = %lu\n", FullInformation->MaxValueDataLen);
124     ok(FullInformation->Class[0] == 0x5555, "Class[0] = %u\n", FullInformation->Class[0]);
125 
126     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
127     InfoLength = 0x55555555;
128     Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class[1]), &InfoLength);
129     ok(Status == STATUS_BUFFER_OVERFLOW, "Status = 0x%lx\n", Status);
130     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength);
131     ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n");
132     ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset);
133     ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength);
134     ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]);
135     ok(FullInformation->Class[1] == 0x5555, "Class[1] = %u\n", FullInformation->Class[1]);
136 
137     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
138     InfoLength = 0x55555555;
139     Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length - 1, &InfoLength);
140     ok(Status == STATUS_BUFFER_OVERFLOW, "Status = 0x%lx\n", Status);
141     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength);
142     ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n");
143     ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset);
144     ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength);
145     ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]);
146     ok(FullInformation->Class[1] == L'y', "Class[1] = %u\n", FullInformation->Class[1]);
147     ok(FullInformation->Class[6] == (L's' | 0x5500), "Class[6] = %u\n", FullInformation->Class[6]);
148     ok(FullInformation->Class[7] == 0x5555, "Class[7] = %u\n", FullInformation->Class[7]);
149 
150     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
151     InfoLength = 0x55555555;
152     Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, &InfoLength);
153     ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status);
154     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength);
155     ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n");
156     ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset);
157     ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength);
158     ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]);
159     ok(FullInformation->Class[1] == L'y', "Class[1] = %u\n", FullInformation->Class[1]);
160     ok(FullInformation->Class[6] == L's', "Class[6] = %u\n", FullInformation->Class[6]);
161     ok(FullInformation->Class[7] == 0x5555, "Class[7] = %u\n", FullInformation->Class[7]);
162 
163     RtlFillMemory(FullInformation, FullInformationLength, 0x55);
164     InfoLength = 0x55555555;
165     Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length + sizeof(UNICODE_NULL), &InfoLength);
166     ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status);
167     ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength);
168     ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n");
169     ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset);
170     ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength);
171     ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]);
172     ok(FullInformation->Class[1] == L'y', "Class[1] = %u\n", FullInformation->Class[1]);
173     ok(FullInformation->Class[6] == L's', "Class[6] = %u\n", FullInformation->Class[6]);
174     ok(FullInformation->Class[7] == 0x5555, "Class[7] = %u\n", FullInformation->Class[7]);
175 
176     RtlFreeHeap(RtlGetProcessHeap(), 0, FullInformation);
177 
178     Status = NtDeleteKey(Test_Key);
179     ok_ntstatus(Status, STATUS_SUCCESS);
180 
181     NtClose(Test_Key);
182     NtClose(HKLM_Software_Key);
183     NtClose(HKLM_Key);
184 }
185 
186 static
187 void
188 Test_KeyNameInformation(void)
189 {
190     UNICODE_STRING HKLM_Name = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
191     UNICODE_STRING HKLM_Software_Name = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software");
192     UNICODE_STRING Software_Name = RTL_CONSTANT_STRING(L"Software");
193     UNICODE_STRING InfoName;
194     HANDLE HKLM_Key, HKLM_Software_Key;
195     PKEY_NAME_INFORMATION NameInformation;
196     ULONG InfoLength;
197     OBJECT_ATTRIBUTES ObjectAttributes;
198     NTSTATUS Status;
199 
200     /* Open the HKCU key */
201     InitializeObjectAttributes(&ObjectAttributes,
202         &HKLM_Name,
203         OBJ_CASE_INSENSITIVE,
204         NULL,
205         NULL);
206     Status = NtOpenKey(&HKLM_Key, KEY_READ, &ObjectAttributes);
207     ok_ntstatus(Status, STATUS_SUCCESS);
208 
209     /* Get the name info length */
210     InfoLength = 0;
211     Status = NtQueryKey(HKLM_Key, KeyNameInformation, NULL, 0, &InfoLength);
212     ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL);
213     ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Name.Length/sizeof(WCHAR)]));
214 
215     /* Get it for real */
216     NameInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength);
217     if (!NameInformation)
218     {
219         skip("Out of memory\n");
220         return;
221     }
222 
223     Status = NtQueryKey(HKLM_Key, KeyNameInformation, NameInformation, InfoLength, &InfoLength);
224     ok_ntstatus(Status, STATUS_SUCCESS);
225     ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Name.Length/sizeof(WCHAR)]));
226     ok_size_t(NameInformation->NameLength, HKLM_Name.Length);
227 
228     InfoName.Buffer = NameInformation->Name;
229     InfoName.Length = NameInformation->NameLength;
230     InfoName.MaximumLength = NameInformation->NameLength;
231     ok(RtlCompareUnicodeString(&InfoName, &HKLM_Name, TRUE) == 0, "%.*S\n",
232         InfoName.Length, InfoName.Buffer);
233 
234     RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation);
235 
236     /* Open one subkey */
237     InitializeObjectAttributes(&ObjectAttributes,
238         &Software_Name,
239         OBJ_CASE_INSENSITIVE,
240         HKLM_Key,
241         NULL);
242     Status = NtOpenKey(&HKLM_Software_Key, KEY_READ, &ObjectAttributes);
243     ok_ntstatus(Status, STATUS_SUCCESS);
244 
245     /* Get the name info length */
246     InfoLength = 0;
247     Status = NtQueryKey(HKLM_Software_Key, KeyNameInformation, NULL, 0, &InfoLength);
248     ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL);
249     ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Software_Name.Length/sizeof(WCHAR)]));
250 
251     /* Get it for real */
252     NameInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength);
253     ok(NameInformation != NULL, "\n");
254 
255     Status = NtQueryKey(HKLM_Software_Key, KeyNameInformation, NameInformation, InfoLength, &InfoLength);
256     ok_ntstatus(Status, STATUS_SUCCESS);
257     ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Software_Name.Length/sizeof(WCHAR)]));
258     ok_size_t(NameInformation->NameLength, HKLM_Software_Name.Length);
259 
260     InfoName.Buffer = NameInformation->Name;
261     InfoName.Length = NameInformation->NameLength;
262     InfoName.MaximumLength = NameInformation->NameLength;
263     ok(RtlCompareUnicodeString(&InfoName, &HKLM_Software_Name, TRUE) == 0, "%.*S\n",
264         InfoName.Length, InfoName.Buffer);
265 
266     RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation);
267 
268     NtClose(HKLM_Software_Key);
269     NtClose(HKLM_Key);
270 }
271 
272 START_TEST(NtQueryKey)
273 {
274     Test_KeyFullInformation();
275     Test_KeyNameInformation();
276 }
277