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