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