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