xref: /reactos/dll/win32/samsrv/registry.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         Security Account Manager (SAM) Server
4  * FILE:            reactos/dll/win32/samsrv/registry.c
5  * PURPOSE:         Registry helper functions
6  *
7  * PROGRAMMERS:     Eric Kohl
8  */
9 
10 #include "samsrv.h"
11 
12 #include <ndk/cmfuncs.h>
13 #include <ndk/obfuncs.h>
14 
15 /* FUNCTIONS ***************************************************************/
16 
17 static
18 BOOLEAN
IsStringType(ULONG Type)19 IsStringType(ULONG Type)
20 {
21     return (Type == REG_SZ) || (Type == REG_EXPAND_SZ) || (Type == REG_MULTI_SZ);
22 }
23 
24 
25 NTSTATUS
SampRegCloseKey(IN OUT PHANDLE KeyHandle)26 SampRegCloseKey(IN OUT PHANDLE KeyHandle)
27 {
28     NTSTATUS Status;
29 
30     if (KeyHandle == NULL || *KeyHandle == NULL)
31         return STATUS_SUCCESS;
32 
33     Status = NtClose(*KeyHandle);
34     if (NT_SUCCESS(Status))
35         *KeyHandle = NULL;
36 
37     return Status;
38 }
39 
40 
41 NTSTATUS
SampRegCreateKey(IN HANDLE ParentKeyHandle,IN LPCWSTR KeyName,IN ACCESS_MASK DesiredAccess,OUT PHANDLE KeyHandle)42 SampRegCreateKey(IN HANDLE ParentKeyHandle,
43                  IN LPCWSTR KeyName,
44                  IN ACCESS_MASK DesiredAccess,
45                  OUT PHANDLE KeyHandle)
46 {
47     OBJECT_ATTRIBUTES ObjectAttributes;
48     UNICODE_STRING Name;
49     ULONG Disposition;
50 
51     RtlInitUnicodeString(&Name, KeyName);
52 
53     InitializeObjectAttributes(&ObjectAttributes,
54                                &Name,
55                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
56                                ParentKeyHandle,
57                                NULL);
58 
59     /* Create the key */
60     return ZwCreateKey(KeyHandle,
61                        DesiredAccess,
62                        &ObjectAttributes,
63                        0,
64                        NULL,
65                        0,
66                        &Disposition);
67 }
68 
69 
70 NTSTATUS
SampRegDeleteKey(IN HANDLE ParentKeyHandle,IN LPCWSTR KeyName)71 SampRegDeleteKey(IN HANDLE ParentKeyHandle,
72                  IN LPCWSTR KeyName)
73 {
74     OBJECT_ATTRIBUTES ObjectAttributes;
75     UNICODE_STRING SubKeyName;
76     HANDLE TargetKey;
77     NTSTATUS Status;
78 
79     RtlInitUnicodeString(&SubKeyName,
80                          (LPWSTR)KeyName);
81     InitializeObjectAttributes(&ObjectAttributes,
82                                &SubKeyName,
83                                OBJ_CASE_INSENSITIVE,
84                                ParentKeyHandle,
85                                NULL);
86     Status = NtOpenKey(&TargetKey,
87                        DELETE,
88                        &ObjectAttributes);
89     if (!NT_SUCCESS(Status))
90         return Status;
91 
92     Status = NtDeleteKey(TargetKey);
93 
94     NtClose(TargetKey);
95 
96     return Status;
97 }
98 
99 
100 NTSTATUS
SampRegEnumerateSubKey(IN HANDLE KeyHandle,IN ULONG Index,IN ULONG Length,OUT LPWSTR Buffer)101 SampRegEnumerateSubKey(IN HANDLE KeyHandle,
102                        IN ULONG Index,
103                        IN ULONG Length,
104                        OUT LPWSTR Buffer)
105 {
106     PKEY_BASIC_INFORMATION KeyInfo = NULL;
107     ULONG BufferLength = 0;
108     ULONG ReturnedLength;
109     NTSTATUS Status;
110 
111     /* Check if we have a name */
112     if (Length)
113     {
114         /* Allocate a buffer for it */
115         BufferLength = sizeof(KEY_BASIC_INFORMATION) + Length * sizeof(WCHAR);
116 
117         KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
118         if (KeyInfo == NULL)
119             return STATUS_NO_MEMORY;
120     }
121 
122     /* Enumerate the key */
123     Status = ZwEnumerateKey(KeyHandle,
124                             Index,
125                             KeyBasicInformation,
126                             KeyInfo,
127                             BufferLength,
128                             &ReturnedLength);
129     if (NT_SUCCESS(Status))
130     {
131         /* Check if the name fits */
132         if (KeyInfo->NameLength < (Length * sizeof(WCHAR)))
133         {
134             /* Copy it */
135             RtlMoveMemory(Buffer,
136                           KeyInfo->Name,
137                           KeyInfo->NameLength);
138 
139             /* Terminate the string */
140             Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
141         }
142         else
143         {
144             /* Otherwise, we ran out of buffer space */
145             Status = STATUS_BUFFER_OVERFLOW;
146         }
147     }
148 
149     /* Free the buffer and return status */
150     if (KeyInfo)
151         RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
152 
153     return Status;
154 }
155 
156 
157 NTSTATUS
SampRegOpenKey(IN HANDLE ParentKeyHandle,IN LPCWSTR KeyName,IN ACCESS_MASK DesiredAccess,OUT PHANDLE KeyHandle)158 SampRegOpenKey(IN HANDLE ParentKeyHandle,
159                IN LPCWSTR KeyName,
160                IN ACCESS_MASK DesiredAccess,
161                OUT PHANDLE KeyHandle)
162 {
163     OBJECT_ATTRIBUTES ObjectAttributes;
164     UNICODE_STRING Name;
165 
166     RtlInitUnicodeString(&Name, KeyName);
167 
168     InitializeObjectAttributes(&ObjectAttributes,
169                                &Name,
170                                OBJ_CASE_INSENSITIVE,
171                                ParentKeyHandle,
172                                NULL);
173 
174     return NtOpenKey(KeyHandle,
175                      DesiredAccess,
176                      &ObjectAttributes);
177 }
178 
179 
180 NTSTATUS
SampRegQueryKeyInfo(IN HANDLE KeyHandle,OUT PULONG SubKeyCount,OUT PULONG ValueCount)181 SampRegQueryKeyInfo(IN HANDLE KeyHandle,
182                     OUT PULONG SubKeyCount,
183                     OUT PULONG ValueCount)
184 {
185     KEY_FULL_INFORMATION FullInfoBuffer;
186     ULONG Length;
187     NTSTATUS Status;
188 
189     FullInfoBuffer.ClassLength = 0;
190     FullInfoBuffer.ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
191 
192     Status = NtQueryKey(KeyHandle,
193                         KeyFullInformation,
194                         &FullInfoBuffer,
195                         sizeof(KEY_FULL_INFORMATION),
196                         &Length);
197     TRACE("NtQueryKey() returned status 0x%08lX\n", Status);
198     if (!NT_SUCCESS(Status))
199         return Status;
200 
201     if (SubKeyCount != NULL)
202         *SubKeyCount = FullInfoBuffer.SubKeys;
203 
204     if (ValueCount != NULL)
205         *ValueCount = FullInfoBuffer.Values;
206 
207     return Status;
208 }
209 
210 
211 NTSTATUS
SampRegDeleteValue(IN HANDLE KeyHandle,IN LPCWSTR ValueName)212 SampRegDeleteValue(IN HANDLE KeyHandle,
213                    IN LPCWSTR ValueName)
214 {
215     UNICODE_STRING Name;
216 
217     RtlInitUnicodeString(&Name,
218                          ValueName);
219 
220     return NtDeleteValueKey(KeyHandle,
221                             &Name);
222 }
223 
224 
225 NTSTATUS
SampRegEnumerateValue(IN HANDLE KeyHandle,IN ULONG Index,OUT LPWSTR Name,IN OUT PULONG NameLength,OUT PULONG Type OPTIONAL,OUT PVOID Data OPTIONAL,IN OUT PULONG DataLength OPTIONAL)226 SampRegEnumerateValue(IN HANDLE KeyHandle,
227                       IN ULONG Index,
228                       OUT LPWSTR Name,
229                       IN OUT PULONG NameLength,
230                       OUT PULONG Type OPTIONAL,
231                       OUT PVOID Data OPTIONAL,
232                       IN OUT PULONG DataLength OPTIONAL)
233 {
234     PKEY_VALUE_FULL_INFORMATION ValueInfo = NULL;
235     ULONG BufferLength = 0;
236     ULONG ReturnedLength;
237     NTSTATUS Status;
238 
239     TRACE("Index: %lu\n", Index);
240 
241     /* Calculate the required buffer length */
242     BufferLength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
243     BufferLength += (MAX_PATH + 1) * sizeof(WCHAR);
244     if (Data != NULL)
245         BufferLength += *DataLength;
246 
247     /* Allocate the value buffer */
248     ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
249     if (ValueInfo == NULL)
250         return STATUS_NO_MEMORY;
251 
252     /* Enumerate the value*/
253     Status = ZwEnumerateValueKey(KeyHandle,
254                                  Index,
255                                  KeyValueFullInformation,
256                                  ValueInfo,
257                                  BufferLength,
258                                  &ReturnedLength);
259     if (NT_SUCCESS(Status))
260     {
261         if (Name != NULL)
262         {
263             /* Check if the name fits */
264             if (ValueInfo->NameLength < (*NameLength * sizeof(WCHAR)))
265             {
266                 /* Copy it */
267                 RtlMoveMemory(Name,
268                               ValueInfo->Name,
269                               ValueInfo->NameLength);
270 
271                 /* Terminate the string */
272                 Name[ValueInfo->NameLength / sizeof(WCHAR)] = 0;
273             }
274             else
275             {
276                 /* Otherwise, we ran out of buffer space */
277                 Status = STATUS_BUFFER_OVERFLOW;
278                 goto done;
279             }
280         }
281 
282         if (Data != NULL)
283         {
284             /* Check if the data fits */
285             if (ValueInfo->DataLength <= *DataLength)
286             {
287                 /* Copy it */
288                 RtlMoveMemory(Data,
289                               (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset),
290                               ValueInfo->DataLength);
291 
292                 /* if the type is REG_SZ and data is not 0-terminated
293                  * and there is enough space in the buffer NT appends a \0 */
294                 if (IsStringType(ValueInfo->Type) &&
295                     ValueInfo->DataLength <= *DataLength - sizeof(WCHAR))
296                 {
297                     WCHAR *ptr = (WCHAR *)((ULONG_PTR)Data + ValueInfo->DataLength);
298                     if ((ptr > (WCHAR *)Data) && ptr[-1])
299                         *ptr = 0;
300                 }
301             }
302             else
303             {
304                 Status = STATUS_BUFFER_OVERFLOW;
305                 goto done;
306             }
307         }
308     }
309 
310 done:
311     if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
312     {
313         if (Type != NULL)
314             *Type = ValueInfo->Type;
315 
316         if (NameLength != NULL)
317             *NameLength = ValueInfo->NameLength;
318 
319         if (DataLength != NULL)
320             *DataLength = ValueInfo->DataLength;
321     }
322 
323     /* Free the buffer and return status */
324     if (ValueInfo)
325         RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
326 
327     return Status;
328 }
329 
330 
331 NTSTATUS
SampRegQueryValue(IN HANDLE KeyHandle,IN LPCWSTR ValueName,OUT PULONG Type OPTIONAL,OUT PVOID Data OPTIONAL,IN OUT PULONG DataLength OPTIONAL)332 SampRegQueryValue(IN HANDLE KeyHandle,
333                   IN LPCWSTR ValueName,
334                   OUT PULONG Type OPTIONAL,
335                   OUT PVOID Data OPTIONAL,
336                   IN OUT PULONG DataLength OPTIONAL)
337 {
338     PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
339     UNICODE_STRING Name;
340     ULONG BufferLength = 0;
341     NTSTATUS Status;
342 
343     RtlInitUnicodeString(&Name,
344                          ValueName);
345 
346     if (DataLength != NULL)
347         BufferLength = *DataLength;
348 
349     BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
350 
351     /* Allocate memory for the value */
352     ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
353     if (ValueInfo == NULL)
354         return STATUS_NO_MEMORY;
355 
356     /* Query the value */
357     Status = ZwQueryValueKey(KeyHandle,
358                              &Name,
359                              KeyValuePartialInformation,
360                              ValueInfo,
361                              BufferLength,
362                              &BufferLength);
363     if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
364     {
365         if (Type != NULL)
366             *Type = ValueInfo->Type;
367 
368         if (DataLength != NULL)
369             *DataLength = ValueInfo->DataLength;
370     }
371 
372     /* Check if the caller wanted data back, and we got it */
373     if ((NT_SUCCESS(Status)) && (Data != NULL))
374     {
375         /* Copy it */
376         RtlMoveMemory(Data,
377                       ValueInfo->Data,
378                       ValueInfo->DataLength);
379 
380         /* if the type is REG_SZ and data is not 0-terminated
381          * and there is enough space in the buffer NT appends a \0 */
382         if (IsStringType(ValueInfo->Type) &&
383             ValueInfo->DataLength <= *DataLength - sizeof(WCHAR))
384         {
385             WCHAR *ptr = (WCHAR *)((ULONG_PTR)Data + ValueInfo->DataLength);
386             if ((ptr > (WCHAR *)Data) && ptr[-1])
387                 *ptr = 0;
388         }
389     }
390 
391     /* Free the memory and return status */
392     RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
393 
394     if ((Data == NULL) && (Status == STATUS_BUFFER_OVERFLOW))
395         Status = STATUS_SUCCESS;
396 
397     return Status;
398 }
399 
400 
401 NTSTATUS
SampRegSetValue(HANDLE KeyHandle,LPCWSTR ValueName,ULONG Type,LPVOID Data,ULONG DataLength)402 SampRegSetValue(HANDLE KeyHandle,
403                 LPCWSTR ValueName,
404                 ULONG Type,
405                 LPVOID Data,
406                 ULONG DataLength)
407 {
408     UNICODE_STRING Name;
409 
410     RtlInitUnicodeString(&Name,
411                          ValueName);
412 
413     return ZwSetValueKey(KeyHandle,
414                          &Name,
415                          0,
416                          Type,
417                          Data,
418                          DataLength);
419 }
420