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