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