Partially fixed up tree after merge from HEAD. More to do.
[reactos.git] / reactos / lib / rtl / registry.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Rtl registry functions
5 * FILE: lib/rtl/registry.c
6 * PROGRAMER: Eric Kohl
7 */
8
9 /*
10 * TODO:
11 * - finish RtlQueryRegistryValues()
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <rtl.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #define TAG_RTLREGISTRY TAG('R', 't', 'l', 'R')
22
23 /* DATA **********************************************************************/
24
25 PCWSTR RtlpRegPaths[RTL_REGISTRY_MAXIMUM] =
26 {
27 NULL,
28 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services",
29 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
30 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion",
31 L"\\Registry\\Machine\\Hardware\\DeviceMap",
32 L"\\Registry\\User\\.Default",
33 };
34
35 /* PRIVATE FUNCTIONS *********************************************************/
36
37 NTSTATUS
38 NTAPI
39 RtlpGetRegistryHandle(IN ULONG RelativeTo,
40 IN PCWSTR Path,
41 IN BOOLEAN Create,
42 IN PHANDLE KeyHandle)
43 {
44 UNICODE_STRING KeyPath, KeyName;
45 WCHAR KeyBuffer[MAX_PATH];
46 OBJECT_ATTRIBUTES ObjectAttributes;
47 NTSTATUS Status;
48
49 /* Check if we just want the handle */
50 if (RelativeTo & RTL_REGISTRY_HANDLE)
51 {
52 *KeyHandle = (HANDLE)Path;
53 return STATUS_SUCCESS;
54 }
55
56 /* Check for optional flag */
57 if (RelativeTo & RTL_REGISTRY_OPTIONAL)
58 {
59 /* Mask it out */
60 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
61 }
62
63 /* Fail on invalid parameter */
64 if (RelativeTo >= RTL_REGISTRY_MAXIMUM) return STATUS_INVALID_PARAMETER;
65
66 /* Initialize the key name */
67 RtlInitEmptyUnicodeString(&KeyName, KeyBuffer, sizeof(KeyBuffer));
68
69 /* Check if we have to lookup a path to prefix */
70 if (RelativeTo != RTL_REGISTRY_ABSOLUTE)
71 {
72 /* Check if we need the current user key */
73 if (RelativeTo == RTL_REGISTRY_USER)
74 {
75 /* Get the path */
76 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
77 if (!NT_SUCCESS(Status)) return(Status);
78
79 /* Append it */
80 Status = RtlAppendUnicodeStringToString(&KeyName, &KeyPath);
81 RtlFreeUnicodeString (&KeyPath);
82 }
83 else
84 {
85 /* Get one of the prefixes */
86 Status = RtlAppendUnicodeToString(&KeyName,
87 RtlpRegPaths[RelativeTo]);
88 }
89
90 /* Check for failure, otherwise, append the path separator */
91 if (!NT_SUCCESS(Status)) return Status;
92 Status = RtlAppendUnicodeToString(&KeyName, L"\\");
93 if (!NT_SUCCESS(Status)) return Status;
94 }
95
96 /* And now append the path */
97 if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE) Path++; // HACK!
98 Status = RtlAppendUnicodeToString(&KeyName, Path);
99 if (!NT_SUCCESS(Status)) return Status;
100
101 /* Initialize the object attributes */
102 InitializeObjectAttributes(&ObjectAttributes,
103 &KeyName,
104 OBJ_CASE_INSENSITIVE,
105 NULL,
106 NULL);
107
108 /* Check if we want to create it */
109 if (Create)
110 {
111 /* Create the key with write privileges */
112 Status = ZwCreateKey(KeyHandle,
113 GENERIC_WRITE,
114 &ObjectAttributes,
115 0,
116 NULL,
117 0,
118 NULL);
119 }
120 else
121 {
122 /* Otherwise, just open it with read access */
123 Status = ZwOpenKey(KeyHandle,
124 MAXIMUM_ALLOWED | GENERIC_READ,
125 &ObjectAttributes);
126 }
127
128 /* Return status */
129 return Status;
130 }
131
132 /* PUBLIC FUNCTIONS **********************************************************/
133
134 /*
135 * @implemented
136 */
137 NTSTATUS
138 NTAPI
139 RtlCheckRegistryKey(IN ULONG RelativeTo,
140 IN PWSTR Path)
141 {
142 HANDLE KeyHandle;
143 NTSTATUS Status;
144 PAGED_CODE_RTL();
145
146 /* Call the helper */
147 Status = RtlpGetRegistryHandle(RelativeTo,
148 Path,
149 FALSE,
150 &KeyHandle);
151 if (!NT_SUCCESS(Status)) return Status;
152
153 /* All went well, close the handle and return success */
154 ZwClose(KeyHandle);
155 return STATUS_SUCCESS;
156 }
157
158 /*
159 * @implemented
160 */
161 NTSTATUS
162 NTAPI
163 RtlCreateRegistryKey(IN ULONG RelativeTo,
164 IN PWSTR Path)
165 {
166 HANDLE KeyHandle;
167 NTSTATUS Status;
168 PAGED_CODE_RTL();
169
170 /* Call the helper */
171 Status = RtlpGetRegistryHandle(RelativeTo,
172 Path,
173 TRUE,
174 &KeyHandle);
175 if (!NT_SUCCESS(Status)) return Status;
176
177 /* All went well, close the handle and return success */
178 ZwClose(KeyHandle);
179 return STATUS_SUCCESS;
180 }
181
182 /*
183 * @implemented
184 */
185 NTSTATUS
186 NTAPI
187 RtlDeleteRegistryValue(IN ULONG RelativeTo,
188 IN PCWSTR Path,
189 IN PCWSTR ValueName)
190 {
191 HANDLE KeyHandle;
192 NTSTATUS Status;
193 UNICODE_STRING Name;
194 PAGED_CODE_RTL();
195
196 /* Call the helper */
197 Status = RtlpGetRegistryHandle(RelativeTo,
198 Path,
199 TRUE,
200 &KeyHandle);
201 if (!NT_SUCCESS(Status)) return Status;
202
203 /* Initialize the key name and delete it */
204 RtlInitUnicodeString(&Name, ValueName);
205 Status = ZwDeleteValueKey(KeyHandle, &Name);
206
207 /* All went well, close the handle and return status */
208 ZwClose(KeyHandle);
209 return Status;
210 }
211
212 /*
213 * @implemented
214 */
215 NTSTATUS
216 NTAPI
217 RtlWriteRegistryValue(IN ULONG RelativeTo,
218 IN PCWSTR Path,
219 IN PCWSTR ValueName,
220 IN ULONG ValueType,
221 IN PVOID ValueData,
222 IN ULONG ValueLength)
223 {
224 HANDLE KeyHandle;
225 NTSTATUS Status;
226 UNICODE_STRING Name;
227 PAGED_CODE_RTL();
228
229 /* Call the helper */
230 Status = RtlpGetRegistryHandle(RelativeTo,
231 Path,
232 TRUE,
233 &KeyHandle);
234 if (!NT_SUCCESS(Status)) return Status;
235
236 /* Initialize the key name and set it */
237 RtlInitUnicodeString(&Name, ValueName);
238 Status = ZwSetValueKey(KeyHandle,
239 &Name,
240 0,
241 ValueType,
242 ValueData,
243 ValueLength);
244
245 /* All went well, close the handle and return status */
246 ZwClose(KeyHandle);
247 return Status;
248 }
249
250 /*
251 * @implemented
252 */
253 NTSTATUS
254 NTAPI
255 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
256 OUT PHANDLE KeyHandle)
257 {
258 OBJECT_ATTRIBUTES ObjectAttributes;
259 UNICODE_STRING KeyPath;
260 NTSTATUS Status;
261 PAGED_CODE_RTL();
262
263 /* Get the user key */
264 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
265 if (NT_SUCCESS(Status))
266 {
267 /* Initialize the attributes and open it */
268 InitializeObjectAttributes(&ObjectAttributes,
269 &KeyPath,
270 OBJ_CASE_INSENSITIVE,
271 NULL,
272 NULL);
273 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
274
275 /* Free the path and return success if it worked */
276 RtlFreeUnicodeString(&KeyPath);
277 if (NT_SUCCESS(Status)) return STATUS_SUCCESS;
278 }
279
280 /* It didn't work, so use the default key */
281 RtlInitUnicodeString(&KeyPath, RtlpRegPaths[RTL_REGISTRY_USER]);
282 InitializeObjectAttributes(&ObjectAttributes,
283 &KeyPath,
284 OBJ_CASE_INSENSITIVE,
285 NULL,
286 NULL);
287 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
288
289 /* Return status */
290 return Status;
291 }
292
293 /*
294 * @implemented
295 */
296 NTSTATUS
297 NTAPI
298 RtlFormatCurrentUserKeyPath(OUT PUNICODE_STRING KeyPath)
299 {
300 HANDLE TokenHandle;
301 UCHAR Buffer[256];
302 PSID_AND_ATTRIBUTES SidBuffer;
303 ULONG Length;
304 UNICODE_STRING SidString;
305 NTSTATUS Status;
306 PAGED_CODE_RTL();
307
308 /* Open the thread token */
309 Status = ZwOpenThreadToken(NtCurrentThread(),
310 TOKEN_QUERY,
311 TRUE,
312 &TokenHandle);
313 if (!NT_SUCCESS(Status))
314 {
315 /* We failed, is it because we don't have a thread token? */
316 if (Status != STATUS_NO_TOKEN) return Status;
317
318 /* It is, so use the process token */
319 Status = ZwOpenProcessToken(NtCurrentProcess(),
320 TOKEN_QUERY,
321 &TokenHandle);
322 if (!NT_SUCCESS(Status)) return Status;
323 }
324
325 /* Now query the token information */
326 SidBuffer = (PSID_AND_ATTRIBUTES)Buffer;
327 Status = ZwQueryInformationToken(TokenHandle,
328 TokenUser,
329 (PVOID)SidBuffer,
330 sizeof(Buffer),
331 &Length);
332
333 /* Close the handle and handle failure */
334 ZwClose(TokenHandle);
335 if (!NT_SUCCESS(Status)) return Status;
336
337 /* Convert the SID */
338 Status = RtlConvertSidToUnicodeString(&SidString, SidBuffer[0].Sid, TRUE);
339 if (!NT_SUCCESS(Status)) return Status;
340
341 /* Add the length of the prefix */
342 Length = SidString.Length + sizeof(L"\\REGISTRY\\USER\\");
343
344 /* Initialize a string */
345 RtlInitEmptyUnicodeString(KeyPath,
346 RtlpAllocateStringMemory(Length, TAG_USTR),
347 Length);
348 if (!KeyPath->Buffer)
349 {
350 /* Free the string and fail */
351 RtlFreeUnicodeString(&SidString);
352 return STATUS_NO_MEMORY;
353 }
354
355 /* Append the prefix and SID */
356 RtlAppendUnicodeToString(KeyPath, L"\\REGISTRY\\USER\\");
357 RtlAppendUnicodeStringToString(KeyPath, &SidString);
358
359 /* Free the temporary string and return success */
360 RtlFreeUnicodeString(&SidString);
361 return STATUS_SUCCESS;
362 }
363
364 /*
365 * @implemented
366 */
367 NTSTATUS
368 NTAPI
369 RtlpNtCreateKey(OUT HANDLE KeyHandle,
370 IN ACCESS_MASK DesiredAccess,
371 IN POBJECT_ATTRIBUTES ObjectAttributes,
372 IN ULONG TitleIndex,
373 IN PUNICODE_STRING Class,
374 OUT PULONG Disposition)
375 {
376 /* Check if we have object attributes */
377 if (ObjectAttributes)
378 {
379 /* Mask out the unsupported flags */
380 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
381 }
382
383 /* Create the key */
384 return ZwCreateKey(KeyHandle,
385 DesiredAccess,
386 ObjectAttributes,
387 0,
388 NULL,
389 0,
390 Disposition);
391 }
392
393 /*
394 * @implemented
395 */
396 NTSTATUS
397 NTAPI
398 RtlpNtEnumerateSubKey(IN HANDLE KeyHandle,
399 OUT PUNICODE_STRING SubKeyName,
400 IN ULONG Index,
401 IN ULONG Unused)
402 {
403 PKEY_BASIC_INFORMATION KeyInfo = NULL;
404 ULONG BufferLength = 0;
405 ULONG ReturnedLength;
406 NTSTATUS Status;
407
408 /* Check if we have a name */
409 if (SubKeyName->MaximumLength)
410 {
411 /* Allocate a buffer for it */
412 BufferLength = SubKeyName->MaximumLength +
413 sizeof(KEY_BASIC_INFORMATION);
414 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
415 if (!KeyInfo) return STATUS_NO_MEMORY;
416 }
417
418 /* Enumerate the key */
419 Status = ZwEnumerateKey(KeyHandle,
420 Index,
421 KeyBasicInformation,
422 KeyInfo,
423 BufferLength,
424 &ReturnedLength);
425 if (NT_SUCCESS(Status))
426 {
427 /* Check if the name fits */
428 if (KeyInfo->NameLength <= SubKeyName->MaximumLength)
429 {
430 /* Set the length */
431 SubKeyName->Length = KeyInfo->NameLength;
432
433 /* Copy it */
434 RtlMoveMemory(SubKeyName->Buffer,
435 KeyInfo->Name,
436 SubKeyName->Length);
437 }
438 else
439 {
440 /* Otherwise, we ran out of buffer space */
441 Status = STATUS_BUFFER_OVERFLOW;
442 }
443 }
444
445 /* Free the buffer and return status */
446 if (KeyInfo) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
447 return Status;
448 }
449
450 /*
451 * @implemented
452 */
453 NTSTATUS
454 NTAPI
455 RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle)
456 {
457 /* This just deletes the key */
458 return ZwDeleteKey(KeyHandle);
459 }
460
461 /*
462 * @implemented
463 */
464 NTSTATUS
465 NTAPI
466 RtlpNtOpenKey(OUT HANDLE KeyHandle,
467 IN ACCESS_MASK DesiredAccess,
468 IN POBJECT_ATTRIBUTES ObjectAttributes,
469 IN ULONG Unused)
470 {
471 /* Check if we have object attributes */
472 if (ObjectAttributes)
473 {
474 /* Mask out the unsupported flags */
475 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
476 }
477
478 /* Open the key */
479 return ZwOpenKey(KeyHandle, DesiredAccess, ObjectAttributes);
480 }
481
482 /*
483 * @implemented
484 */
485 NTSTATUS
486 NTAPI
487 RtlpNtQueryValueKey(IN HANDLE KeyHandle,
488 OUT PULONG Type OPTIONAL,
489 OUT PVOID Data OPTIONAL,
490 IN OUT PULONG DataLength OPTIONAL,
491 IN ULONG Unused)
492 {
493 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
494 UNICODE_STRING ValueName;
495 ULONG BufferLength = 0;
496 NTSTATUS Status;
497
498 /* Clear the value name */
499 RtlInitEmptyUnicodeString(&ValueName, NULL, 0);
500
501 /* Check if we were already given a length */
502 if (DataLength) BufferLength = *DataLength;
503
504 /* Add the size of the structure */
505 BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
506
507 /* Allocate memory for the value */
508 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
509 if (!ValueInfo) return STATUS_NO_MEMORY;
510
511 /* Query the value */
512 Status = ZwQueryValueKey(KeyHandle,
513 &ValueName,
514 KeyValuePartialInformation,
515 ValueInfo,
516 BufferLength,
517 &BufferLength);
518 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
519 {
520 /* Return the length and type */
521 if (DataLength) *DataLength = ValueInfo->DataLength;
522 if (Type) *Type = ValueInfo->Type;
523 }
524
525 /* Check if the caller wanted data back, and we got it */
526 if ((NT_SUCCESS(Status)) && (Data))
527 {
528 /* Copy it */
529 RtlMoveMemory(Data, ValueInfo->Data, ValueInfo->DataLength);
530 }
531
532 /* Free the memory and return status */
533 RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
534 return Status;
535 }
536
537 /*
538 * @implemented
539 */
540 NTSTATUS
541 NTAPI
542 RtlpNtSetValueKey(IN HANDLE KeyHandle,
543 IN ULONG Type,
544 IN PVOID Data,
545 IN ULONG DataLength)
546 {
547 UNICODE_STRING ValueName;
548
549 /* Set the value */
550 RtlInitEmptyUnicodeString(&ValueName, NULL, 0);
551 return ZwSetValueKey(KeyHandle,
552 &ValueName,
553 0,
554 Type,
555 Data,
556 DataLength);
557 }
558
559 /*
560 * @unimplemented
561 */
562 NTSTATUS NTAPI
563 RtlQueryRegistryValues(IN ULONG RelativeTo,
564 IN PCWSTR Path,
565 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
566 IN PVOID Context,
567 IN PVOID Environment OPTIONAL)
568 {
569 NTSTATUS Status;
570 HANDLE BaseKeyHandle;
571 HANDLE CurrentKeyHandle;
572 PRTL_QUERY_REGISTRY_TABLE QueryEntry;
573 OBJECT_ATTRIBUTES ObjectAttributes;
574 UNICODE_STRING KeyName;
575 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
576 PKEY_VALUE_FULL_INFORMATION FullValueInfo;
577 ULONG BufferSize;
578 ULONG ResultSize;
579 ULONG Index;
580 ULONG StringLen;
581 ULONG ValueNameSize;
582 PWSTR StringPtr;
583 PWSTR ExpandBuffer;
584 PWSTR ValueName;
585 UNICODE_STRING EnvValue;
586 UNICODE_STRING EnvExpandedValue;
587 #ifdef DEBUG
588 ULONG DataSize = 0;
589 #endif
590
591 PAGED_CODE_RTL();
592
593 DPRINT("RtlQueryRegistryValues() called\n");
594
595 Status = RtlpGetRegistryHandle(RelativeTo,
596 (PWSTR)Path,
597 FALSE,
598 &BaseKeyHandle);
599 if (!NT_SUCCESS(Status))
600 {
601 DPRINT("RtlpGetRegistryHandle() failed (Status %lx)\n", Status);
602 return(Status);
603 }
604
605 CurrentKeyHandle = BaseKeyHandle;
606 QueryEntry = QueryTable;
607 while ((QueryEntry->QueryRoutine != NULL) ||
608 (QueryEntry->Name != NULL))
609 {
610 if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
611 (BaseKeyHandle != CurrentKeyHandle))
612 {
613 ZwClose(CurrentKeyHandle);
614 CurrentKeyHandle = BaseKeyHandle;
615 }
616
617 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
618 {
619 DPRINT("Open new subkey: %S\n", QueryEntry->Name);
620
621 RtlInitUnicodeString(&KeyName,
622 QueryEntry->Name);
623 InitializeObjectAttributes(&ObjectAttributes,
624 &KeyName,
625 OBJ_CASE_INSENSITIVE,
626 BaseKeyHandle,
627 NULL);
628 Status = ZwOpenKey(&CurrentKeyHandle,
629 KEY_ALL_ACCESS,
630 &ObjectAttributes);
631 if (!NT_SUCCESS(Status))
632 break;
633 }
634 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
635 {
636 DPRINT("Query value directly: %S\n", QueryEntry->Name);
637
638 RtlInitUnicodeString(&KeyName,
639 QueryEntry->Name);
640
641 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
642 ValueInfo = RtlpAllocateMemory(BufferSize, TAG_RTLREGISTRY);
643 if (ValueInfo == NULL)
644 {
645 Status = STATUS_NO_MEMORY;
646 break;
647 }
648
649 Status = ZwQueryValueKey(CurrentKeyHandle,
650 &KeyName,
651 KeyValuePartialInformation,
652 ValueInfo,
653 BufferSize,
654 &ResultSize);
655 if (!NT_SUCCESS(Status))
656 {
657 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED)
658 {
659 RtlpFreeMemory(ValueInfo, TAG_RTLREGISTRY);
660 Status = STATUS_OBJECT_NAME_NOT_FOUND;
661 break;
662 }
663
664 if (QueryEntry->DefaultType == REG_SZ)
665 {
666 PUNICODE_STRING ValueString;
667 PUNICODE_STRING SourceString;
668
669 SourceString = (PUNICODE_STRING)QueryEntry->DefaultData;
670 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
671 if (ValueString->Buffer == NULL)
672 {
673 ValueString->Length = SourceString->Length;
674 ValueString->MaximumLength = SourceString->MaximumLength;
675 ValueString->Buffer = RtlpAllocateMemory(BufferSize, TAG_RTLREGISTRY);
676 if (!ValueString->Buffer)
677 break;
678 ValueString->Buffer[0] = 0;
679 memcpy(ValueString->Buffer,
680 SourceString->Buffer,
681 SourceString->MaximumLength);
682 }
683 else
684 {
685 ValueString->Length = min(SourceString->Length,
686 ValueString->MaximumLength - sizeof(WCHAR));
687 memcpy(ValueString->Buffer,
688 SourceString->Buffer,
689 ValueString->Length);
690 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
691 }
692 }
693 else
694 {
695 memcpy(QueryEntry->EntryContext,
696 QueryEntry->DefaultData,
697 QueryEntry->DefaultLength);
698 }
699 Status = STATUS_SUCCESS;
700 }
701 else
702 {
703 if ((ValueInfo->Type == REG_SZ) ||
704 (ValueInfo->Type == REG_MULTI_SZ) ||
705 (ValueInfo->Type == REG_EXPAND_SZ && (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND)))
706 {
707 PUNICODE_STRING ValueString;
708
709 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
710 if (ValueString->Buffer == NULL)
711 {
712 ValueString->MaximumLength = ValueInfo->DataLength;
713 ValueString->Buffer = RtlpAllocateMemory(ValueString->MaximumLength, TAG_RTLREGISTRY);
714 if (ValueString->Buffer == NULL)
715 {
716 Status = STATUS_INSUFFICIENT_RESOURCES;
717 break;
718 }
719 ValueString->Buffer[0] = 0;
720 }
721 ValueString->Length = min(ValueInfo->DataLength,
722 ValueString->MaximumLength) - sizeof(WCHAR);
723 memcpy(ValueString->Buffer,
724 ValueInfo->Data,
725 ValueString->Length);
726 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
727 }
728 else if (ValueInfo->Type == REG_EXPAND_SZ)
729 {
730 PUNICODE_STRING ValueString;
731
732 DPRINT("Expand REG_EXPAND_SZ type\n");
733
734 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
735
736 ExpandBuffer = RtlpAllocateMemory(ValueInfo->DataLength * 2, TAG_RTLREGISTRY);
737 if (ExpandBuffer == NULL)
738 {
739 Status = STATUS_NO_MEMORY;
740 break;
741 }
742
743 RtlInitUnicodeString(&EnvValue,
744 (PWSTR)ValueInfo->Data);
745 EnvExpandedValue.Length = 0;
746 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2;
747 EnvExpandedValue.Buffer = ExpandBuffer;
748 *ExpandBuffer = 0;
749
750 RtlExpandEnvironmentStrings_U(Environment,
751 &EnvValue,
752 &EnvExpandedValue,
753 &StringLen);
754
755 if (ValueString->Buffer == NULL)
756 {
757 ValueString->MaximumLength = EnvExpandedValue.Length + sizeof(WCHAR);
758 ValueString->Length = EnvExpandedValue.Length;
759 ValueString->Buffer = RtlpAllocateMemory(ValueString->MaximumLength, TAG_RTLREGISTRY);
760 if (ValueString->Buffer == NULL)
761 {
762 Status = STATUS_INSUFFICIENT_RESOURCES;
763 break;
764 }
765 }
766 else
767 {
768 ValueString->Length = min(EnvExpandedValue.Length,
769 ValueString->MaximumLength - sizeof(WCHAR));
770 }
771
772 memcpy(ValueString->Buffer,
773 EnvExpandedValue.Buffer,
774 ValueString->Length);
775 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
776
777 RtlpFreeMemory(ExpandBuffer, TAG_RTLREGISTRY);
778 }
779 else
780 {
781 memcpy(QueryEntry->EntryContext,
782 ValueInfo->Data,
783 ValueInfo->DataLength);
784 }
785 }
786
787 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
788 {
789 Status = ZwDeleteValueKey(CurrentKeyHandle, &KeyName);
790
791 }
792
793 RtlpFreeMemory(ValueInfo, TAG_RTLREGISTRY);
794 }
795 else
796 {
797 DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
798 if (QueryEntry->Name != NULL)
799 {
800 RtlInitUnicodeString(&KeyName,
801 QueryEntry->Name);
802
803 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
804 ValueInfo = RtlpAllocateMemory(BufferSize, TAG_RTLREGISTRY);
805 if (ValueInfo == NULL)
806 {
807 Status = STATUS_NO_MEMORY;
808 break;
809 }
810
811 Status = ZwQueryValueKey(CurrentKeyHandle,
812 &KeyName,
813 KeyValuePartialInformation,
814 ValueInfo,
815 BufferSize,
816 &ResultSize);
817 if (!NT_SUCCESS(Status))
818 {
819 if (!(QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
820 {
821 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
822 QueryEntry->DefaultType,
823 QueryEntry->DefaultData,
824 QueryEntry->DefaultLength,
825 Context,
826 QueryEntry->EntryContext);
827 }
828 }
829 else if ((ValueInfo->Type == REG_MULTI_SZ) &&
830 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
831 {
832 DPRINT("Expand REG_MULTI_SZ type\n");
833 ULONG DataSize = 0;
834 StringPtr = (PWSTR)ValueInfo->Data;
835 while (DataSize < (ValueInfo->DataLength-2))
836 {
837 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
838 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
839 REG_SZ,
840 (PVOID)StringPtr,
841 StringLen,
842 Context,
843 QueryEntry->EntryContext);
844 if(!NT_SUCCESS(Status))
845 break;
846 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
847 DataSize += StringLen;
848 }
849 }
850 else if ((ValueInfo->Type == REG_EXPAND_SZ) &&
851 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
852 {
853 DPRINT("Expand REG_EXPAND_SZ type\n");
854
855 ExpandBuffer = RtlpAllocateMemory(ValueInfo->DataLength * 2, TAG_RTLREGISTRY);
856 if (ExpandBuffer == NULL)
857 {
858 Status = STATUS_NO_MEMORY;
859 break;
860 }
861
862 RtlInitUnicodeString(&EnvValue,
863 (PWSTR)ValueInfo->Data);
864 EnvExpandedValue.Length = 0;
865 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2 * sizeof(WCHAR);
866 EnvExpandedValue.Buffer = ExpandBuffer;
867 *ExpandBuffer = 0;
868
869 RtlExpandEnvironmentStrings_U(Environment,
870 &EnvValue,
871 &EnvExpandedValue,
872 &StringLen);
873
874 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
875 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
876 REG_SZ,
877 (PVOID)ExpandBuffer,
878 StringLen,
879 Context,
880 QueryEntry->EntryContext);
881
882 RtlpFreeMemory(ExpandBuffer, TAG_RTLREGISTRY);
883 }
884 else
885 {
886 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
887 ValueInfo->Type,
888 ValueInfo->Data,
889 ValueInfo->DataLength,
890 Context,
891 QueryEntry->EntryContext);
892 }
893
894 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
895 {
896 Status = ZwDeleteValueKey(CurrentKeyHandle, &KeyName);
897 }
898
899 RtlpFreeMemory(ValueInfo, TAG_RTLREGISTRY);
900 if (!NT_SUCCESS(Status))
901 break;
902 }
903 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOVALUE)
904 {
905 DPRINT("Simple callback\n");
906 Status = QueryEntry->QueryRoutine(NULL,
907 REG_NONE,
908 NULL,
909 0,
910 Context,
911 QueryEntry->EntryContext);
912 if (!NT_SUCCESS(Status))
913 break;
914 }
915 else
916 {
917 DPRINT("Enumerate values\n");
918
919 BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + 4096;
920 FullValueInfo = RtlpAllocateMemory(BufferSize, TAG_RTLREGISTRY);
921 if (FullValueInfo == NULL)
922 {
923 Status = STATUS_NO_MEMORY;
924 break;
925 }
926 ValueNameSize = 256 * sizeof(WCHAR);
927 ValueName = RtlpAllocateMemory(ValueNameSize, TAG_RTLREGISTRY);
928 if (ValueName == NULL)
929 {
930 Status = STATUS_NO_MEMORY;
931 break;
932 }
933 Index = 0;
934 while (TRUE)
935 {
936 Status = ZwEnumerateValueKey(CurrentKeyHandle,
937 Index,
938 KeyValueFullInformation,
939 FullValueInfo,
940 BufferSize,
941 &ResultSize);
942 if (!NT_SUCCESS(Status))
943 {
944 if ((Status == STATUS_NO_MORE_ENTRIES) &&
945 (Index == 0) &&
946 (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
947 {
948 Status = STATUS_OBJECT_NAME_NOT_FOUND;
949 }
950 else if (Status == STATUS_NO_MORE_ENTRIES)
951 {
952 Status = STATUS_SUCCESS;
953 }
954 break;
955 }
956
957 if (FullValueInfo->NameLength > ValueNameSize - sizeof(WCHAR))
958 {
959 /* Should not happen, because the name length is limited to 255 characters */
960 RtlpFreeMemory(ValueName, TAG_RTLREGISTRY);
961 ValueNameSize = FullValueInfo->NameLength + sizeof(WCHAR);
962 ValueName = RtlpAllocateMemory(ValueNameSize, TAG_RTLREGISTRY);
963 if (ValueName == NULL)
964 {
965 Status = STATUS_NO_MEMORY;
966 break;
967 }
968 }
969
970 memcpy(ValueName,
971 FullValueInfo->Name,
972 FullValueInfo->NameLength);
973 ValueName[FullValueInfo->NameLength / sizeof(WCHAR)] = 0;
974
975 DPRINT("FullValueInfo->Type: %lu\n", FullValueInfo->Type);
976 if ((FullValueInfo->Type == REG_MULTI_SZ) &&
977 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
978 {
979 DPRINT("Expand REG_MULTI_SZ type\n");
980 StringPtr = (PWSTR)((ULONG_PTR)FullValueInfo + FullValueInfo->DataOffset);
981 while (*StringPtr != 0)
982 {
983 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
984 Status = QueryEntry->QueryRoutine(ValueName,
985 REG_SZ,
986 (PVOID)StringPtr,
987 StringLen,
988 Context,
989 QueryEntry->EntryContext);
990 if(!NT_SUCCESS(Status))
991 break;
992 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
993 }
994 }
995 else if ((FullValueInfo->Type == REG_EXPAND_SZ) &&
996 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
997 {
998 DPRINT("Expand REG_EXPAND_SZ type\n");
999
1000 StringPtr = (PWSTR)((ULONG_PTR)FullValueInfo + FullValueInfo->DataOffset);
1001 ExpandBuffer = RtlpAllocateMemory(FullValueInfo->DataLength * 2, TAG_RTLREGISTRY);
1002 if (ExpandBuffer == NULL)
1003 {
1004 Status = STATUS_NO_MEMORY;
1005 break;
1006 }
1007
1008 RtlInitUnicodeString(&EnvValue,
1009 StringPtr);
1010 EnvExpandedValue.Length = 0;
1011 EnvExpandedValue.MaximumLength = FullValueInfo->DataLength * 2;
1012 EnvExpandedValue.Buffer = ExpandBuffer;
1013 *ExpandBuffer = 0;
1014
1015 RtlExpandEnvironmentStrings_U(Environment,
1016 &EnvValue,
1017 &EnvExpandedValue,
1018 &StringLen);
1019
1020 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
1021 Status = QueryEntry->QueryRoutine(ValueName,
1022 REG_SZ,
1023 (PVOID)ExpandBuffer,
1024 StringLen,
1025 Context,
1026 QueryEntry->EntryContext);
1027
1028 RtlpFreeMemory(ExpandBuffer, TAG_RTLREGISTRY);
1029 }
1030 else
1031 {
1032 Status = QueryEntry->QueryRoutine(ValueName,
1033 FullValueInfo->Type,
1034 (PVOID)((ULONG_PTR)FullValueInfo + FullValueInfo->DataOffset),
1035 FullValueInfo->DataLength,
1036 Context,
1037 QueryEntry->EntryContext);
1038 }
1039
1040 if (!NT_SUCCESS(Status))
1041 break;
1042
1043 /* FIXME: How will these be deleted? */
1044
1045 Index++;
1046 }
1047
1048 RtlpFreeMemory(FullValueInfo, TAG_RTLREGISTRY);
1049 RtlpFreeMemory(ValueName, TAG_RTLREGISTRY);
1050 if (!NT_SUCCESS(Status))
1051 break;
1052 }
1053 }
1054
1055 QueryEntry++;
1056 }
1057
1058 if (CurrentKeyHandle != BaseKeyHandle)
1059 ZwClose(CurrentKeyHandle);
1060
1061 ZwClose(BaseKeyHandle);
1062
1063 return(Status);
1064 }
1065
1066 /* EOF */