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