Synchronize up to trunk's revision r57784.
[reactos.git] / dll / win32 / lsasrv / registry.c
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 /* INCLUDES ****************************************************************/
11
12 #include "lsasrv.h"
13
14 WINE_DEFAULT_DEBUG_CHANNEL(lsasrv);
15
16 /* FUNCTIONS ***************************************************************/
17
18 static
19 BOOLEAN
20 IsStringType(ULONG Type)
21 {
22 return (Type == REG_SZ) || (Type == REG_EXPAND_SZ) || (Type == REG_MULTI_SZ);
23 }
24
25
26 NTSTATUS
27 LsapRegCloseKey(IN HANDLE KeyHandle)
28 {
29 return NtClose(KeyHandle);
30 }
31
32
33 NTSTATUS
34 LsapRegCreateKey(IN HANDLE ParentKeyHandle,
35 IN LPCWSTR KeyName,
36 IN ACCESS_MASK DesiredAccess,
37 OUT HANDLE KeyHandle)
38 {
39 OBJECT_ATTRIBUTES ObjectAttributes;
40 UNICODE_STRING Name;
41 ULONG Disposition;
42
43 RtlInitUnicodeString(&Name, KeyName);
44
45 InitializeObjectAttributes(&ObjectAttributes,
46 &Name,
47 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
48 ParentKeyHandle,
49 NULL);
50
51 /* Create the key */
52 return ZwCreateKey(KeyHandle,
53 DesiredAccess,
54 &ObjectAttributes,
55 0,
56 NULL,
57 0,
58 &Disposition);
59 }
60
61
62 NTSTATUS
63 LsapRegDeleteSubKey(IN HANDLE ParentKeyHandle,
64 IN LPCWSTR KeyName)
65 {
66 OBJECT_ATTRIBUTES ObjectAttributes;
67 UNICODE_STRING SubKeyName;
68 HANDLE TargetKey;
69 NTSTATUS Status;
70
71 RtlInitUnicodeString(&SubKeyName,
72 (LPWSTR)KeyName);
73 InitializeObjectAttributes(&ObjectAttributes,
74 &SubKeyName,
75 OBJ_CASE_INSENSITIVE,
76 ParentKeyHandle,
77 NULL);
78 Status = NtOpenKey(&TargetKey,
79 DELETE,
80 &ObjectAttributes);
81 if (!NT_SUCCESS(Status))
82 return Status;
83
84 Status = NtDeleteKey(TargetKey);
85
86 NtClose(TargetKey);
87
88 return Status;
89 }
90
91
92 NTSTATUS
93 LsapRegDeleteKey(IN HANDLE KeyHandle)
94 {
95 return NtDeleteKey(KeyHandle);
96 }
97
98
99 NTSTATUS
100 LsapRegEnumerateSubKey(IN HANDLE KeyHandle,
101 IN ULONG Index,
102 IN ULONG Length,
103 OUT LPWSTR Buffer)
104 {
105 PKEY_BASIC_INFORMATION KeyInfo = NULL;
106 ULONG BufferLength = 0;
107 ULONG ReturnedLength;
108 NTSTATUS Status;
109
110 /* Check if we have a name */
111 if (Length)
112 {
113 /* Allocate a buffer for it */
114 BufferLength = sizeof(KEY_BASIC_INFORMATION) + Length * sizeof(WCHAR);
115
116 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
117 if (KeyInfo == NULL)
118 return STATUS_NO_MEMORY;
119 }
120
121 /* Enumerate the key */
122 Status = ZwEnumerateKey(KeyHandle,
123 Index,
124 KeyBasicInformation,
125 KeyInfo,
126 BufferLength,
127 &ReturnedLength);
128 if (NT_SUCCESS(Status))
129 {
130 /* Check if the name fits */
131 if (KeyInfo->NameLength < (Length * sizeof(WCHAR)))
132 {
133 /* Copy it */
134 RtlMoveMemory(Buffer,
135 KeyInfo->Name,
136 KeyInfo->NameLength);
137
138 /* Terminate the string */
139 Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
140 }
141 else
142 {
143 /* Otherwise, we ran out of buffer space */
144 Status = STATUS_BUFFER_OVERFLOW;
145 }
146 }
147
148 /* Free the buffer and return status */
149 if (KeyInfo)
150 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
151
152 return Status;
153 }
154
155
156 NTSTATUS
157 LsapRegOpenKey(IN HANDLE ParentKeyHandle,
158 IN LPCWSTR KeyName,
159 IN ACCESS_MASK DesiredAccess,
160 OUT HANDLE KeyHandle)
161 {
162 OBJECT_ATTRIBUTES ObjectAttributes;
163 UNICODE_STRING Name;
164
165 RtlInitUnicodeString(&Name, KeyName);
166
167 InitializeObjectAttributes(&ObjectAttributes,
168 &Name,
169 OBJ_CASE_INSENSITIVE,
170 ParentKeyHandle,
171 NULL);
172
173 return NtOpenKey(KeyHandle,
174 DesiredAccess,
175 &ObjectAttributes);
176 }
177
178
179 NTSTATUS
180 LsapRegQueryKeyInfo(IN HANDLE KeyHandle,
181 OUT PULONG SubKeyCount,
182 OUT PULONG ValueCount)
183 {
184 KEY_FULL_INFORMATION FullInfoBuffer;
185 ULONG Length;
186 NTSTATUS Status;
187
188 FullInfoBuffer.ClassLength = 0;
189 FullInfoBuffer.ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
190
191 Status = NtQueryKey(KeyHandle,
192 KeyFullInformation,
193 &FullInfoBuffer,
194 sizeof(KEY_FULL_INFORMATION),
195 &Length);
196 TRACE("NtQueryKey() returned status 0x%08lX\n", Status);
197 if (!NT_SUCCESS(Status))
198 return Status;
199
200 if (SubKeyCount != NULL)
201 *SubKeyCount = FullInfoBuffer.SubKeys;
202
203 if (ValueCount != NULL)
204 *ValueCount = FullInfoBuffer.Values;
205
206 return Status;
207 }
208
209
210 NTSTATUS
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
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)] = 0;
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 = 0;
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
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 = 0;
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
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 }