ReactOS 0.4.15-dev-7788-g1ad9096
cmparse.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmparse.c
5 * PURPOSE: Configuration Manager - Object Manager Parse Interface
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include "ntoskrnl.h"
12#define NDEBUG
13#include "debug.h"
14
15/* GLOBALS *******************************************************************/
16
17/* FUNCTIONS *****************************************************************/
18
22 OUT PUNICODE_STRING NextName,
23 OUT PBOOLEAN LastName)
24{
25 BOOLEAN NameValid = TRUE;
26
27 ASSERT(RemainingName->Length % sizeof(WCHAR) == 0);
28
29 /* Check if there's nothing left in the name */
30 if (!(RemainingName->Buffer) ||
31 (!RemainingName->Length) ||
32 !(*RemainingName->Buffer))
33 {
34 /* Clear the next name and set this as last */
35 *LastName = TRUE;
36 NextName->Buffer = NULL;
37 NextName->Length = 0;
38 return TRUE;
39 }
40
41 /* Check if we have a path separator */
42 while (RemainingName->Length &&
44 {
45 /* Skip it */
46 RemainingName->Buffer++;
47 RemainingName->Length -= sizeof(WCHAR);
48 RemainingName->MaximumLength -= sizeof(WCHAR);
49 }
50
51 /* Start loop at where the current buffer is */
52 NextName->Buffer = RemainingName->Buffer;
53 while (RemainingName->Length &&
55 {
56 /* Move to the next character */
57 RemainingName->Buffer++;
58 RemainingName->Length -= sizeof(WCHAR);
59 RemainingName->MaximumLength -= sizeof(WCHAR);
60 }
61
62 /* See how many chars we parsed and validate the length */
63 NextName->Length = (USHORT)((ULONG_PTR)RemainingName->Buffer -
64 (ULONG_PTR)NextName->Buffer);
65 if (NextName->Length > 512) NameValid = FALSE;
66 NextName->MaximumLength = NextName->Length;
67
68 /* If there's nothing left, we're last */
69 *LastName = !RemainingName->Length;
70 return NameValid;
71}
72
77 IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb,
79{
80 HCELL_INDEX LinkCell = HCELL_NIL;
81 PCM_KEY_VALUE LinkValue = NULL;
82 PWSTR LinkName = NULL;
83 BOOLEAN LinkNameAllocated = FALSE;
84 PWSTR NewBuffer;
85 ULONG Length = 0;
88 HCELL_INDEX CellToRelease = HCELL_NIL;
90 UNICODE_STRING NewObjectName;
91
92 /* Make sure we're not being deleted */
93 if (SymbolicKcb->Delete) return FALSE;
94
95 /* Get the key node */
96 Node = (PCM_KEY_NODE)HvGetCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell);
97 if (!Node) goto Exit;
98
99 /* Find the symbolic link key */
101 HvReleaseCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell);
102 if (LinkCell == HCELL_NIL) goto Exit;
103
104 /* Get the value cell */
105 LinkValue = (PCM_KEY_VALUE)HvGetCell(Hive, LinkCell);
106 if (!LinkValue) goto Exit;
107
108 /* Make sure it's a registry link */
109 if (LinkValue->Type != REG_LINK) goto Exit;
110
111 /* Now read the value data */
112 if (!CmpGetValueData(Hive,
113 LinkValue,
115 (PVOID*)&LinkName,
116 &LinkNameAllocated,
117 &CellToRelease))
118 {
119 /* Fail */
120 goto Exit;
121 }
122
123 /* Get the length */
124 Length = ValueLength + sizeof(WCHAR);
125
126 /* Make sure we start with a slash */
127 if (*LinkName != OBJ_NAME_PATH_SEPARATOR) goto Exit;
128
129 /* Add the remaining name if needed */
130 if (RemainingName) Length += RemainingName->Length + sizeof(WCHAR);
131
132 /* Check for overflow */
133 if (Length > 0xFFFF) goto Exit;
134
135 /* Check if we need a new buffer */
136 if (Length > ObjectName->MaximumLength)
137 {
138 /* We do -- allocate one */
140 if (!NewBuffer) goto Exit;
141
142 /* Setup the new string and copy the symbolic target */
143 NewObjectName.Buffer = NewBuffer;
144 NewObjectName.MaximumLength = (USHORT)Length;
145 NewObjectName.Length = (USHORT)ValueLength;
146 RtlCopyMemory(NewBuffer, LinkName, ValueLength);
147
148 /* Check if we need to add anything else */
149 if (RemainingName)
150 {
151 /* Add the remaining name */
152 NewBuffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
153 NewObjectName.Length += sizeof(WCHAR);
155 }
156
157 /* Free the old buffer */
158 ExFreePool(ObjectName->Buffer);
159 *ObjectName = NewObjectName;
160 }
161 else
162 {
163 /* The old name is large enough -- update the length */
164 ObjectName->Length = (USHORT)ValueLength;
165 if (RemainingName)
166 {
167 /* Copy the remaining name inside */
168 RtlMoveMemory(&ObjectName->Buffer[(ValueLength / sizeof(WCHAR)) + 1],
169 RemainingName->Buffer,
170 RemainingName->Length);
171
172 /* Add the slash and update the length */
174 ObjectName->Length += RemainingName->Length + sizeof(WCHAR);
175 }
176
177 /* Copy the symbolic link target name */
178 RtlCopyMemory(ObjectName->Buffer, LinkName, ValueLength);
179 }
180
181 /* Null-terminate the whole thing */
182 ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] = UNICODE_NULL;
183 Result = TRUE;
184
185Exit:
186 /* Free the link name */
187 if (LinkNameAllocated) ExFreePool(LinkName);
188
189 /* Check if we had a value cell */
190 if (LinkValue)
191 {
192 /* Release it */
193 ASSERT(LinkCell != HCELL_NIL);
194 HvReleaseCell(Hive, LinkCell);
195 }
196
197 /* Check if we had an active cell and release it, then return the result */
198 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
199 return Result;
200}
201
203NTAPI
205 IN HCELL_INDEX ParentCell,
206 IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
210 IN PCM_PARSE_CONTEXT ParseContext,
211 IN PCM_KEY_CONTROL_BLOCK ParentKcb,
212 IN ULONG Flags,
213 OUT PHCELL_INDEX KeyCell,
215{
217 PCM_KEY_BODY KeyBody;
218 HCELL_INDEX ClassCell = HCELL_NIL;
219 PCM_KEY_NODE KeyNode;
220 PCELL_DATA CellData;
221 ULONG StorageType;
224
225 /* Get the storage type */
226 StorageType = Stable;
227 if (ParseContext->CreateOptions & REG_OPTION_VOLATILE) StorageType = Volatile;
228
229 /* Allocate the child */
230 *KeyCell = HvAllocateCell(Hive,
232 CmpNameSize(Hive, Name),
233 StorageType,
234 HCELL_NIL);
235 if (*KeyCell == HCELL_NIL)
236 {
237 /* Fail */
239 goto Quickie;
240 }
241
242 /* Get the key node */
243 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, *KeyCell);
244 if (!KeyNode)
245 {
246 /* Fail, this should never happen */
247 ASSERT(FALSE);
249 goto Quickie;
250 }
251
252 /* Release the cell */
253 HvReleaseCell(Hive, *KeyCell);
254
255 /* Check if we have a class name */
256 if (ParseContext->Class.Length > 0)
257 {
258 /* Allocate a class cell */
259 ClassCell = HvAllocateCell(Hive,
260 ParseContext->Class.Length,
261 StorageType,
262 HCELL_NIL);
263 if (ClassCell == HCELL_NIL)
264 {
265 /* Fail */
267 goto Quickie;
268 }
269 }
270
271 /* Allocate the Cm Object */
274 NULL,
276 NULL,
277 sizeof(CM_KEY_BODY),
278 0,
279 0,
280 Object);
281 if (!NT_SUCCESS(Status)) goto Quickie;
282
283 /* Setup the key body */
284 KeyBody = (PCM_KEY_BODY)(*Object);
285 KeyBody->Type = CM_KEY_BODY_TYPE;
286 KeyBody->KeyControlBlock = NULL;
287 KeyBody->KcbLocked = FALSE;
288
289 /* Check if we had a class */
290 if (ParseContext->Class.Length > 0)
291 {
292 /* Get the class cell */
293 CellData = HvGetCell(Hive, ClassCell);
294 if (!CellData)
295 {
296 /* Fail, this should never happen */
297 ASSERT(FALSE);
300 goto Quickie;
301 }
302
303 /* Release the cell */
304 HvReleaseCell(Hive, ClassCell);
305
306 /* Copy the class data */
307 RtlCopyMemory(&CellData->u.KeyString[0],
308 ParseContext->Class.Buffer,
309 ParseContext->Class.Length);
310 }
311
312 /* Fill out the key node */
314 KeyNode->Flags = Flags;
316 KeyNode->Spare = 0;
317 KeyNode->Parent = ParentCell;
318 KeyNode->SubKeyCounts[Stable] = 0;
319 KeyNode->SubKeyCounts[Volatile] = 0;
320 KeyNode->SubKeyLists[Stable] = HCELL_NIL;
321 KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
322 KeyNode->ValueList.Count = 0;
323 KeyNode->ValueList.List = HCELL_NIL;
324 KeyNode->Security = HCELL_NIL;
325 KeyNode->Class = ClassCell;
326 KeyNode->ClassLength = ParseContext->Class.Length;
327 KeyNode->MaxValueDataLen = 0;
328 KeyNode->MaxNameLen = 0;
329 KeyNode->MaxValueNameLen = 0;
330 KeyNode->MaxClassLen = 0;
331 KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, Name);
332 if (KeyNode->NameLength < Name->Length) KeyNode->Flags |= KEY_COMP_NAME;
333
334 /* Create the KCB */
335 Kcb = CmpCreateKeyControlBlock(Hive,
336 *KeyCell,
337 KeyNode,
338 ParentKcb,
340 Name);
341 if (!Kcb)
342 {
343 /* Fail */
346 goto Quickie;
347 }
348
349 /* Sanity check */
350 ASSERT(Kcb->RefCount == 1);
351
352 /* Now fill out the Cm object */
353 KeyBody->NotifyBlock = NULL;
354 KeyBody->ProcessID = PsGetCurrentProcessId();
355 KeyBody->KeyControlBlock = Kcb;
356
357 /* Link it with the KCB */
359
360 /* Assign security */
361 Status = SeAssignSecurity(ParentDescriptor,
362 AccessState->SecurityDescriptor,
364 TRUE,
365 &AccessState->SubjectSecurityContext,
366 &CmpKeyObjectType->TypeInfo.GenericMapping,
367 CmpKeyObjectType->TypeInfo.PoolType);
368 if (NT_SUCCESS(Status))
369 {
370 /*
371 * FIXME: We must acquire a security lock when assigning
372 * a security descriptor to this hive but since the
373 * CmpAssignSecurityDescriptor function does nothing
374 * (we lack the necessary security management implementations
375 * anyway), do not do anything for now.
376 */
378 }
379
380 /* Now that the security descriptor is copied in the hive, we can free the original */
381 SeDeassignSecurity(&NewDescriptor);
382
383 if (NT_SUCCESS(Status))
384 {
385 /* Send notification to registered callbacks */
387 }
388
389Quickie:
390 /* Check if we got here because of failure */
391 if (!NT_SUCCESS(Status))
392 {
393 /* Free any cells we might've allocated */
394 if (ParseContext->Class.Length > 0) HvFreeCell(Hive, ClassCell);
395 HvFreeCell(Hive, *KeyCell);
396 }
397
398 /* Return status */
399 return Status;
400}
401
403NTAPI
405 IN HCELL_INDEX Cell,
409 IN PCM_PARSE_CONTEXT ParseContext,
410 IN PCM_KEY_CONTROL_BLOCK ParentKcb,
412{
414 PCELL_DATA CellData;
415 HCELL_INDEX KeyCell;
416 ULONG ParentType;
417 PCM_KEY_BODY KeyBody;
420 PCM_KEY_NODE KeyNode;
421
422 /* Make sure the KCB is locked and lock the flusher */
423 CMP_ASSERT_KCB_LOCK(ParentKcb);
425
426 /* Bail out on read-only KCBs */
427 if (ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)
428 {
430 goto Exit;
431 }
432
433 /* Check if the parent is being deleted */
434 if (ParentKcb->Delete)
435 {
436 /* It has, quit */
437 ASSERT(FALSE);
439 goto Exit;
440 }
441
442 /* Get the parent node */
443 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
444 if (!KeyNode)
445 {
446 /* Fail */
447 ASSERT(FALSE);
449 goto Exit;
450 }
451
452 /* Make sure nobody added us yet */
453 if (CmpFindSubKeyByName(Hive, KeyNode, Name) != HCELL_NIL)
454 {
455 /* Fail */
456 ASSERT(FALSE);
458 goto Exit;
459 }
460
461 /* Sanity check */
462 ASSERT(Cell == ParentKcb->KeyCell);
463
464 /* Get the parent type */
465 ParentType = HvGetCellType(Cell);
466 if ((ParentType == Volatile) &&
467 !(ParseContext->CreateOptions & REG_OPTION_VOLATILE))
468 {
469 /* Children of volatile parents must also be volatile */
470 //ASSERT(FALSE);
472 goto Exit;
473 }
474
475 /* Don't allow children under symlinks */
476 if (ParentKcb->Flags & KEY_SYM_LINK)
477 {
478 /* Fail */
479 ASSERT(FALSE);
481 goto Exit;
482 }
483
484 /* Make the cell dirty for now */
485 HvMarkCellDirty(Hive, Cell, FALSE);
486
487 /* Do the actual create operation */
489 Cell,
492 Name,
494 ParseContext,
495 ParentKcb,
496 0,
497 &KeyCell,
498 Object);
499 if (NT_SUCCESS(Status))
500 {
501 /* Get the key body */
502 KeyBody = (PCM_KEY_BODY)(*Object);
503
504 /* Now add the subkey */
505 if (!CmpAddSubKey(Hive, Cell, KeyCell))
506 {
507 /* Free the created child */
508 CmpFreeKeyByCell(Hive, KeyCell, FALSE);
509
510 /* Purge out this KCB */
511 KeyBody->KeyControlBlock->Delete = TRUE;
513
514 /* And cleanup the key body object */
517 goto Exit;
518 }
519
520 /* Get the key node */
521 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
522 if (!KeyNode)
523 {
524 /* Fail, this shouldn't happen */
525 CmpFreeKeyByCell(Hive, KeyCell, TRUE); // Subkey linked above
526
527 /* Purge out this KCB */
528 KeyBody->KeyControlBlock->Delete = TRUE;
530
531 /* And cleanup the key body object */
534 goto Exit;
535 }
536
537 /* Clean up information on this subkey */
538 CmpCleanUpSubKeyInfo(KeyBody->KeyControlBlock->ParentKcb);
539
540 /* Sanity checks */
541 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
542 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
543 ASSERT(KeyBody->KeyControlBlock->ParentKcb == ParentKcb);
544 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
545
546 /* Update the timestamp */
548 KeyNode->LastWriteTime = TimeStamp;
549 KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
550
551 /* Check if we need to update name maximum */
552 if (KeyNode->MaxNameLen < Name->Length)
553 {
554 /* Do it */
555 KeyNode->MaxNameLen = Name->Length;
556 KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name->Length;
557 }
558
559 /* Check if we need to update class length maximum */
560 if (KeyNode->MaxClassLen < ParseContext->Class.Length)
561 {
562 /* Update it */
563 KeyNode->MaxClassLen = ParseContext->Class.Length;
564 }
565
566 /* Check if we're creating a symbolic link */
567 if (ParseContext->CreateOptions & REG_OPTION_CREATE_LINK)
568 {
569 /* Get the cell data */
570 CellData = HvGetCell(Hive, KeyCell);
571 if (!CellData)
572 {
573 /* This shouldn't happen */
574 CmpFreeKeyByCell(Hive, KeyCell, TRUE); // Subkey linked above
575
576 /* Purge out this KCB */
577 KeyBody->KeyControlBlock->Delete = TRUE;
579
580 /* And cleanup the key body object */
583 goto Exit;
584 }
585
586 /* Update the flags */
587 CellData->u.KeyNode.Flags |= KEY_SYM_LINK;
588 KeyBody->KeyControlBlock->Flags = CellData->u.KeyNode.Flags;
589 HvReleaseCell(Hive, KeyCell);
590 }
591 }
592
593Exit:
594 /* Release the flusher lock and return status */
596 return Status;
597}
598
600NTAPI
602 IN HCELL_INDEX Cell,
608 IN ULONG ControlFlags,
609 IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb,
610 IN PULONG KcbsLocked,
613{
615 BOOLEAN LockKcb = FALSE;
616 BOOLEAN IsLockShared = FALSE;
617 PCM_KEY_BODY KeyBody = NULL;
619
620 /* Make sure the hive isn't locked */
621 if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&
622 (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))
623 {
624 /* It is, don't touch it */
626 }
627
628 /* Check if we have a context */
629 if (Context)
630 {
631 /* Check if this is a link create (which shouldn't be an open) */
632 if (Context->CreateLink)
633 {
635 }
636
637 /* Check if this is symlink create attempt */
638 if (Context->CreateOptions & REG_OPTION_CREATE_LINK)
639 {
640 /* Key already exists */
642 }
643
644 /* Set the disposition */
645 Context->Disposition = REG_OPENED_EXISTING_KEY;
646 }
647
648 /* Lock the KCB on creation if asked */
649 if (ControlFlags & CMP_CREATE_KCB_KCB_LOCKED)
650 {
651 LockKcb = TRUE;
652 }
653
654 /* Check if caller doesn't want to create a KCB */
655 if (ControlFlags & CMP_OPEN_KCB_NO_CREATE)
656 {
657 /*
658 * The caller doesn't want to create a KCB. This means the KCB
659 * is already in cache and other threads may take use of it
660 * so it has to be locked in share mode.
661 */
662 IsLockShared = TRUE;
663
664 /* Check if this is a symlink */
665 if (((*CachedKcb)->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
666 {
667 /* Is this symlink found? */
668 if ((*CachedKcb)->ExtFlags & CM_KCB_SYM_LINK_FOUND)
669 {
670 /* Get the real KCB, is this deleted? */
671 Kcb = (*CachedKcb)->ValueCache.RealKcb;
672 if (Kcb->Delete)
673 {
674 /*
675 * The real KCB is gone, do a reparse. We used to lock the KCB in
676 * shared mode as others may have taken use of it but since we
677 * must do a reparse of the key the only thing that matter is us.
678 * Lock the KCB exclusively so nobody is going to mess with the KCB.
679 */
680 DPRINT1("The real KCB is deleted, attempt a reparse\n");
681 CmpUnLockKcbArray(KcbsLocked);
683 CmpCleanUpKcbValueCache(*CachedKcb);
684 KcbsLocked[0] = 1;
685 KcbsLocked[1] = GET_HASH_INDEX((*CachedKcb)->ConvKey);
686 return STATUS_REPARSE;
687 }
688
689 /*
690 * The symlink has been found. As in the similar case above,
691 * the KCB of the symlink exclusively, we don't want anybody
692 * to mess it up.
693 */
694 CmpUnLockKcbArray(KcbsLocked);
696 KcbsLocked[0] = 1;
697 KcbsLocked[1] = GET_HASH_INDEX((*CachedKcb)->ConvKey);
698 }
699 else
700 {
701 /* We must do a reparse */
702 DPRINT("The symlink is not found, attempt a reparse\n");
703 return STATUS_REPARSE;
704 }
705 }
706 else
707 {
708 /* This is not a symlink, just give the cached KCB already */
709 Kcb = *CachedKcb;
710 }
711
712 /* The caller wants to open a cached KCB */
714 {
715 /* Return failure code */
717 }
718 }
719 else
720 {
721 /*
722 * The caller wants to create a new KCB. Unlike the code path above, here
723 * we must check if the lock is exclusively held because in the scenario
724 * where the caller doesn't want to create a KCB is because it is already
725 * in the cache and it must have a shared lock instead.
726 */
727 ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
728
729 /* Check if this is a symlink */
730 if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
731 {
732 /* Create the KCB for the symlink */
733 Kcb = CmpCreateKeyControlBlock(Hive,
734 Cell,
735 Node,
736 *CachedKcb,
737 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
738 KeyName);
739 if (!Kcb)
740 {
741 /* Return failure */
743 }
744
745 /* Make sure it's also locked, and set the pointer */
747 *CachedKcb = Kcb;
748
749 /* Return reparse required */
750 return STATUS_REPARSE;
751 }
752
753 /* Create the KCB */
754 Kcb = CmpCreateKeyControlBlock(Hive,
755 Cell,
756 Node,
757 *CachedKcb,
758 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
759 KeyName);
760 if (!Kcb)
761 {
762 /* Return failure */
764 }
765
766 /* Make sure it's also locked, and set the pointer */
768 *CachedKcb = Kcb;
769 }
770
771 /* Allocate the key object */
774 NULL,
776 NULL,
777 sizeof(CM_KEY_BODY),
778 0,
779 0,
780 Object);
781 if (NT_SUCCESS(Status))
782 {
783 /* Get the key body and fill it out */
784 KeyBody = (PCM_KEY_BODY)(*Object);
785 KeyBody->KeyControlBlock = Kcb;
786 KeyBody->Type = CM_KEY_BODY_TYPE;
787 KeyBody->ProcessID = PsGetCurrentProcessId();
788 KeyBody->NotifyBlock = NULL;
789
790 /* Link to the KCB */
792
793 /*
794 * We are already holding a lock against the KCB that is assigned
795 * to this key body. This is to prevent a potential deadlock on
796 * CmpSecurityMethod as ObCheckObjectAccess will invoke the Object
797 * Manager to call that method, of which CmpSecurityMethod would
798 * attempt to acquire a lock again.
799 */
800 KeyBody->KcbLocked = TRUE;
801
804 FALSE,
806 &Status))
807 {
808 /* Access check failed */
810 }
811
812 /*
813 * We are done, the lock we are holding will be released
814 * once the registry parsing is done.
815 */
816 KeyBody->KcbLocked = FALSE;
817 }
818 else
819 {
820 /* Failed, dereference the KCB */
822 }
823
824 /* Return status */
825 return Status;
826}
827
829NTAPI
831 IN HCELL_INDEX Cell,
837 IN PCM_KEY_CONTROL_BLOCK ParentKcb,
838 IN PULONG KcbsLocked,
840{
842 HCELL_INDEX KeyCell, LinkCell, ChildCell;
843 PCM_KEY_BODY KeyBody;
845 PCM_KEY_NODE KeyNode;
846 PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb;
847
848 /* Link nodes only allowed on the master */
849 if (Hive != &CmiVolatileHive->Hive)
850 {
851 /* Fail */
852 DPRINT1("Invalid link node attempt\n");
854 }
855
856 /* Make sure the KCB is locked and lock the flusher */
857 CMP_ASSERT_KCB_LOCK(ParentKcb);
859 CmpLockHiveFlusherShared((PCMHIVE)Context->ChildHive.KeyHive);
860
861 /* Bail out on read-only KCBs */
862 if (ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)
863 {
865 goto Exit;
866 }
867
868 /* Check if the parent is being deleted */
869 if (ParentKcb->Delete)
870 {
871 /* It is, quit */
872 ASSERT(FALSE);
874 goto Exit;
875 }
876
877 /* Allocate a link node */
878 LinkCell = HvAllocateCell(Hive,
880 CmpNameSize(Hive, &Name),
881 Stable,
882 HCELL_NIL);
883 if (LinkCell == HCELL_NIL)
884 {
885 /* Fail */
887 goto Exit;
888 }
889
890 /* Get the key cell */
891 KeyCell = Context->ChildHive.KeyCell;
892 if (KeyCell != HCELL_NIL)
893 {
894 /* Hive exists! */
895 ChildCell = KeyCell;
896
897 /* Get the node data */
898 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
899 if (!KeyNode)
900 {
901 /* Fail */
902 ASSERT(FALSE);
904 goto Exit;
905 }
906
907 /* Fill out the data */
908 KeyNode->Parent = LinkCell;
909 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
910 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
911
912 /* Now open the key cell */
913 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell);
914 if (!KeyNode)
915 {
916 /* Fail */
917 ASSERT(FALSE);
919 goto Exit;
920 }
921
922 /* Open the parent */
923 Status = CmpDoOpen(Context->ChildHive.KeyHive,
924 KeyCell,
925 KeyNode,
929 NULL,
931 &Kcb,
932 KcbsLocked,
933 &Name,
934 Object);
935 HvReleaseCell(Context->ChildHive.KeyHive, KeyCell);
936 }
937 else
938 {
939 /* Do the actual create operation */
940 Status = CmpDoCreateChild(Context->ChildHive.KeyHive,
941 Cell,
942 NULL,
944 &Name,
946 Context,
947 ParentKcb,
949 &ChildCell,
950 Object);
951 if (NT_SUCCESS(Status))
952 {
953 /* Setup root pointer */
954 Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;
955 }
956 }
957
958 /* Check if open or create suceeded */
959 if (NT_SUCCESS(Status))
960 {
961 /* Mark the cell dirty */
962 HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE);
963
964 /* Get the key node */
965 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
966 if (!KeyNode)
967 {
968 /* Fail */
969 ASSERT(FALSE);
971 goto Exit;
972 }
973
974 /* Release it */
975 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
976
977 /* Set the parent and flags */
978 KeyNode->Parent = LinkCell;
979 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
980
981 /* Get the link node */
982 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, LinkCell);
983 if (!KeyNode)
984 {
985 /* Fail */
986 ASSERT(FALSE);
988 goto Exit;
989 }
990
991 /* Set it up */
993 KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;
994 KeyNode->Parent = Cell;
995 KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name);
996 if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME;
998 KeyNode->LastWriteTime = TimeStamp;
999
1000 /* Clear out the rest */
1001 KeyNode->SubKeyCounts[Stable] = 0;
1002 KeyNode->SubKeyCounts[Volatile] = 0;
1003 KeyNode->SubKeyLists[Stable] = HCELL_NIL;
1004 KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
1005 KeyNode->ValueList.Count = 0;
1006 KeyNode->ValueList.List = HCELL_NIL;
1007 KeyNode->ClassLength = 0;
1008
1009 /* Reference the root node */
1010 KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;
1011 KeyNode->ChildHiveReference.KeyCell = ChildCell;
1012 HvReleaseCell(Hive, LinkCell);
1013
1014 /* Get the parent node */
1015 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1016 if (!KeyNode)
1017 {
1018 /* Fail */
1019 ASSERT(FALSE);
1021 goto Exit;
1022 }
1023
1024 /* Now add the subkey */
1025 if (!CmpAddSubKey(Hive, Cell, LinkCell))
1026 {
1027 /* Failure! We don't handle this yet! */
1028 ASSERT(FALSE);
1029 }
1030
1031 /* Get the key body */
1032 KeyBody = (PCM_KEY_BODY)*Object;
1033
1034 /* Clean up information on this subkey */
1035 CmpCleanUpSubKeyInfo(KeyBody->KeyControlBlock->ParentKcb);
1036
1037 /* Sanity checks */
1038 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
1039 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
1040 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
1041
1042 /* Update the timestamp */
1044 KeyNode->LastWriteTime = TimeStamp;
1045 KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
1046
1047 /* Check if we need to update name maximum */
1048 if (KeyNode->MaxNameLen < Name.Length)
1049 {
1050 /* Do it */
1051 KeyNode->MaxNameLen = Name.Length;
1052 KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length;
1053 }
1054
1055 /* Check if we need to update class length maximum */
1056 if (KeyNode->MaxClassLen < Context->Class.Length)
1057 {
1058 /* Update it */
1059 KeyNode->MaxClassLen = Context->Class.Length;
1060 }
1061
1062 /* Release the cell */
1063 HvReleaseCell(Hive, Cell);
1064 }
1065 else
1066 {
1067 /* Release the link cell */
1068 HvReleaseCell(Hive, LinkCell);
1069 }
1070
1071Exit:
1072 /* Release the flusher locks and return status */
1073 CmpUnlockHiveFlusher((PCMHIVE)Context->ChildHive.KeyHive);
1075 return Status;
1076}
1077
1078VOID
1079NTAPI
1081 IN OUT HCELL_INDEX *Cell,
1082 IN OUT PCM_KEY_NODE *KeyNode,
1083 IN OUT PHHIVE *ReleaseHive,
1084 IN OUT HCELL_INDEX *ReleaseCell)
1085{
1086 /* Check if we have anything to release */
1087 if (*ReleaseCell != HCELL_NIL)
1088 {
1089 /* Release it */
1090 ASSERT(*ReleaseHive != NULL);
1091 HvReleaseCell(*ReleaseHive, *ReleaseCell);
1092 }
1093
1094 /* Get the link references */
1095 *Hive = (*KeyNode)->ChildHiveReference.KeyHive;
1096 *Cell = (*KeyNode)->ChildHiveReference.KeyCell;
1097
1098 /* Get the new node */
1099 *KeyNode = (PCM_KEY_NODE)HvGetCell(*Hive, *Cell);
1100 if (*KeyNode)
1101 {
1102 /* Set the new release values */
1103 *ReleaseCell = *Cell;
1104 *ReleaseHive = *Hive;
1105 }
1106 else
1107 {
1108 /* Nothing to release */
1109 *ReleaseCell = HCELL_NIL;
1110 *ReleaseHive = NULL;
1111 }
1112}
1113
1139static
1140ULONG
1143 _In_ ULONG ConvKey,
1144 _Inout_ PCM_HASH_CACHE_STACK HashCacheStack,
1145 _Out_ PULONG TotalSubKeys)
1146{
1147 ULONG CopyConvKey;
1148 ULONG SubkeysInTotal;
1149 ULONG RemainingSubkeysInTotal;
1150 PWCHAR RemainingNameBuffer;
1151 USHORT RemainingNameLength;
1153
1154 /* Don't compute the hashes on a NULL remaining name */
1155 RemainingNameBuffer = RemainingName->Buffer;
1156 RemainingNameLength = RemainingName->Length;
1157 if (RemainingNameLength == 0)
1158 {
1159 *TotalSubKeys = 0;
1160 return 0;
1161 }
1162
1163 /* Skip any leading separator */
1164 while (RemainingNameLength >= sizeof(WCHAR) &&
1165 *RemainingNameBuffer == OBJ_NAME_PATH_SEPARATOR)
1166 {
1167 RemainingNameBuffer++;
1168 RemainingNameLength -= sizeof(WCHAR);
1169 }
1170
1171 /* Now set up the hash stack entries and compute the hashes */
1172 SubkeysInTotal = 0;
1173 RemainingSubkeysInTotal = 0;
1174 KeyNameLength = 0;
1175 CopyConvKey = ConvKey;
1176 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Buffer = RemainingNameBuffer;
1177 while (RemainingNameLength > 0)
1178 {
1179 /* Is this character a separator? */
1180 if (*RemainingNameBuffer != OBJ_NAME_PATH_SEPARATOR)
1181 {
1182 /* It's not, add it to the hash */
1183 CopyConvKey = COMPUTE_HASH_CHAR(CopyConvKey, *RemainingNameBuffer);
1184
1185 /* Go to the next character (add up the length of the character as well) */
1186 RemainingNameBuffer++;
1187 KeyNameLength += sizeof(WCHAR);
1188 RemainingNameLength -= sizeof(WCHAR);
1189
1190 /*
1191 * We are at the end of the key name path. Take into account
1192 * the last character and if we still have space in the hash
1193 * stack, add it up in the remaining list.
1194 */
1195 if (RemainingNameLength == 0)
1196 {
1197 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1198 {
1199 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Length = KeyNameLength;
1200 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.MaximumLength = KeyNameLength;
1201 HashCacheStack[RemainingSubkeysInTotal].ConvKey = CopyConvKey;
1202 RemainingSubkeysInTotal++;
1203 }
1204
1205 SubkeysInTotal++;
1206 }
1207 }
1208 else
1209 {
1210 /* Skip any leading separator */
1211 while (RemainingNameLength >= sizeof(WCHAR) &&
1212 *RemainingNameBuffer == OBJ_NAME_PATH_SEPARATOR)
1213 {
1214 RemainingNameBuffer++;
1215 RemainingNameLength -= sizeof(WCHAR);
1216 }
1217
1218 /*
1219 * It would be possible that a malformed key pathname may be passed
1220 * to the registry parser such as a path with only separators like
1221 * "\\\\" for example. This would trick the function into believing
1222 * the key path has subkeys albeit that is not the case.
1223 */
1224 ASSERT(RemainingNameLength != 0);
1225
1226 /* Take into account this subkey */
1227 SubkeysInTotal++;
1228
1229 /* And add it up to the hash stack */
1230 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1231 {
1232 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Length = KeyNameLength;
1233 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.MaximumLength = KeyNameLength;
1234 HashCacheStack[RemainingSubkeysInTotal].ConvKey = CopyConvKey;
1235
1236 RemainingSubkeysInTotal++;
1237 KeyNameLength = 0;
1238
1239 /*
1240 * Precaution check -- we have added up a remaining
1241 * subkey above but we must ensure we still have space
1242 * to hold up the new subkey for which we will compute
1243 * the hashes, so that we don't blow up the hash stack.
1244 */
1245 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1246 {
1247 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Buffer = RemainingNameBuffer;
1248 }
1249 }
1250 }
1251 }
1252
1253 *TotalSubKeys = SubkeysInTotal;
1254 return RemainingSubkeysInTotal;
1255}
1256
1282static
1283BOOLEAN
1285 _In_ PCM_HASH_CACHE_STACK HashCacheStack,
1286 _In_ PCM_KEY_CONTROL_BLOCK CurrentKcb,
1287 _In_ ULONG RemainingSubkeys,
1288 _Out_ PCM_KEY_CONTROL_BLOCK *ParentKcb)
1289{
1290 LONG HashStackIndex;
1291 LONG Result;
1292 PCM_NAME_CONTROL_BLOCK NameBlock;
1293 UNICODE_STRING CurrentNameBlock;
1294
1295 ASSERT(CurrentKcb != NULL);
1296
1297 /* Loop each hash and check that they match */
1298 HashStackIndex = RemainingSubkeys;
1299 while (HashStackIndex >= 0)
1300 {
1301 /* Does the subkey hash match? */
1302 if (CurrentKcb->ConvKey != HashCacheStack[HashStackIndex].ConvKey)
1303 {
1304 *ParentKcb = CurrentKcb;
1305 return FALSE;
1306 }
1307
1308 /* Compare the subkey string, is the name compressed? */
1309 NameBlock = CurrentKcb->NameBlock;
1310 if (NameBlock->Compressed)
1311 {
1312 Result = CmpCompareCompressedName(&HashCacheStack[HashStackIndex].NameOfKey,
1313 NameBlock->Name,
1314 NameBlock->NameLength);
1315 }
1316 else
1317 {
1318 CurrentNameBlock.Buffer = NameBlock->Name;
1319 CurrentNameBlock.Length = NameBlock->NameLength;
1320 CurrentNameBlock.MaximumLength = NameBlock->NameLength;
1321
1322 Result = RtlCompareUnicodeString(&HashCacheStack[HashStackIndex].NameOfKey,
1323 &CurrentNameBlock,
1324 TRUE);
1325 }
1326
1327 /* Do the subkey names match? */
1328 if (Result)
1329 {
1330 *ParentKcb = CurrentKcb;
1331 return FALSE;
1332 }
1333
1334 /* Go to the next subkey hash */
1335 HashStackIndex--;
1336 }
1337
1338 /* All the subkeys match */
1339 *ParentKcb = CurrentKcb->ParentKcb;
1340 return TRUE;
1341}
1342
1359static
1360VOID
1362 _In_ PCM_HASH_CACHE_STACK HashCacheStack,
1363 _In_ ULONG RemainingSubkeys,
1365{
1366 ULONG HashStackIndex = 0;
1367
1368 /* Skip any leading separator on matching name */
1369 while (RemainingName->Length >= sizeof(WCHAR) &&
1371 {
1372 RemainingName->Buffer++;
1373 RemainingName->Length -= sizeof(WCHAR);
1374 }
1375
1376 /* Skip the subkeys as well */
1377 while (HashStackIndex <= RemainingSubkeys)
1378 {
1379 RemainingName->Buffer += HashCacheStack[HashStackIndex].NameOfKey.Length / sizeof(WCHAR);
1380 RemainingName->Length -= HashCacheStack[HashStackIndex].NameOfKey.Length;
1381
1382 /* Skip any leading separator */
1383 while (RemainingName->Length >= sizeof(WCHAR) &&
1385 {
1386 RemainingName->Buffer++;
1387 RemainingName->Length -= sizeof(WCHAR);
1388 }
1389
1390 /* Go to the next hash */
1391 HashStackIndex++;
1392 }
1393}
1394
1458static
1461 _In_ PCM_HASH_CACHE_STACK HashCacheStack,
1462 _In_ BOOLEAN LockKcbsExclusive,
1463 _In_ ULONG TotalRemainingSubkeys,
1465 _Inout_ PULONG OuterStackArray,
1467 _Out_ PHHIVE *Hive,
1468 _Out_ PHCELL_INDEX Cell,
1469 _Out_ PULONG MatchRemainSubkeyLevel)
1470{
1471 LONG RemainingSubkeys;
1472 ULONG TotalLevels;
1473 BOOLEAN SubkeysMatch;
1474 PCM_KEY_CONTROL_BLOCK CurrentKcb, ParentKcb;
1476 BOOLEAN KeyFoundInCache = FALSE;
1477 PULONG LockedKcbs = NULL;
1478
1479 /* Reference the KCB */
1480 if (!CmpReferenceKeyControlBlock(*Kcb))
1481 {
1482 /* This key is opened too many times, bail out */
1483 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1484 return STATUS_UNSUCCESSFUL;
1485 }
1486
1487 /* Prepare to lock the KCBs */
1488 LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1490 *Kcb,
1491 OuterStackArray,
1492 TotalRemainingSubkeys,
1493 0);
1494 NT_ASSERT(LockedKcbs);
1495
1496 /* Lookup in the cache */
1497 RemainingSubkeys = TotalRemainingSubkeys - 1;
1498 TotalLevels = TotalRemainingSubkeys + (*Kcb)->TotalLevels + 1;
1499 while (RemainingSubkeys >= 0)
1500 {
1501 /* Get the hash entry from the cache */
1502 HashEntry = GET_HASH_ENTRY(CmpCacheTable, HashCacheStack[RemainingSubkeys].ConvKey)->Entry;
1503
1504 /* Take one level down as we are processing this hash entry */
1505 TotalLevels--;
1506
1507 while (HashEntry != NULL)
1508 {
1509 /* Validate this hash and obtain the current KCB */
1512
1513 /* Does this KCB have matching levels? */
1514 if (TotalLevels == CurrentKcb->TotalLevels)
1515 {
1516 /*
1517 * We have matching subkey levels but don't directly assume we have
1518 * a matching key path in cache. Start comparing each subkey.
1519 */
1520 SubkeysMatch = CmpCompareSubkeys(HashCacheStack,
1521 CurrentKcb,
1522 RemainingSubkeys,
1523 &ParentKcb);
1524 if (SubkeysMatch)
1525 {
1526 /* All subkeys match, now check if the base KCB matches with parent */
1527 if (*Kcb == ParentKcb)
1528 {
1529 /* Is the KCB marked as deleted? */
1530 if (CurrentKcb->Delete ||
1531 CurrentKcb->ParentKcb->Delete)
1532 {
1533 /*
1534 * Either the current or its parent KCB is marked
1535 * but we had a shared lock so probably a naughty
1536 * thread was deleting it. Retry doing a cache
1537 * lookup again with exclusive lock.
1538 */
1539 if (!LockKcbsExclusive)
1540 {
1541 CmpUnLockKcbArray(LockedKcbs);
1543 DPRINT1("The current KCB or its parent is deleted, retrying looking in the cache\n");
1544 return STATUS_RETRY;
1545 }
1546
1547 /* We're under an exclusive lock, is the KCB deleted yet? */
1548 if (CurrentKcb->Delete)
1549 {
1550 /* The KCB is gone, the key should no longer belong in the cache */
1551 CmpRemoveKeyControlBlock(CurrentKcb);
1552 CmpUnLockKcbArray(LockedKcbs);
1554 DPRINT1("The current KCB is deleted (KCB 0x%p)\n", CurrentKcb);
1556 }
1557
1558 /*
1559 * The parent is deleted so it must be that somebody created
1560 * a fake key. Assert ourselves that is the case.
1561 */
1562 ASSERT(CurrentKcb->ExtFlags & CM_KCB_KEY_NON_EXIST);
1563
1564 /* Remove this KCB out of cache if someone still uses it */
1565 if (CurrentKcb->RefCount != 0)
1566 {
1567 CurrentKcb->Delete = TRUE;
1568 CmpRemoveKeyControlBlock(CurrentKcb);
1569 }
1570 else
1571 {
1572 /* Otherwise expunge it */
1573 CmpRemoveFromDelayedClose(CurrentKcb);
1574 CmpCleanUpKcbCacheWithLock(CurrentKcb, FALSE);
1575 }
1576
1577 /* Stop looking for next hashes as the KCB is kaput */
1578 break;
1579 }
1580
1581 /* We finally found the key in cache, acknowledge it */
1582 KeyFoundInCache = TRUE;
1583
1584 /* Remove the subkeys in the remaining name and stop looking in the cache */
1585 CmpRemoveSubkeysInRemainingName(HashCacheStack, RemainingSubkeys, RemainingName);
1586 break;
1587 }
1588 }
1589 }
1590
1591 /* Go to the next hash */
1592 HashEntry = HashEntry->NextHash;
1593 }
1594
1595 /* Stop looking in cache if we found the matching key */
1596 if (KeyFoundInCache)
1597 {
1598 DPRINT("Key found in cache, stop looking\n");
1599 break;
1600 }
1601
1602 /* Keep looking in the cache until we run out of remaining subkeys */
1603 RemainingSubkeys--;
1604 }
1605
1606 /* Return the matching subkey levels */
1607 *MatchRemainSubkeyLevel = RemainingSubkeys + 1;
1608
1609 /* We have to update the KCB if the key was found in cache */
1610 if (KeyFoundInCache)
1611 {
1612 /*
1613 * Before we change the KCB we must dereference the prior
1614 * KCB that we no longer need it.
1615 */
1617 *Kcb = CurrentKcb;
1618
1619 /* Reference the new KCB now */
1620 if (!CmpReferenceKeyControlBlock(*Kcb))
1621 {
1622 /* This key is opened too many times, bail out */
1623 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1624 return STATUS_UNSUCCESSFUL;
1625 }
1626
1627 /* Update hive and cell data from current KCB */
1628 *Hive = CurrentKcb->KeyHive;
1629 *Cell = CurrentKcb->KeyCell;
1630 }
1631
1632 /* Unlock the KCBs */
1633 CmpUnLockKcbArray(LockedKcbs);
1634 return STATUS_SUCCESS;
1635}
1636
1695NTAPI
1697 _In_ PCM_KEY_BODY ParseObject,
1699 _In_ PUNICODE_STRING Current,
1700 _Out_ PHHIVE *Hive,
1701 _Out_ PHCELL_INDEX Cell,
1702 _Out_ PULONG TotalRemainingSubkeys,
1703 _Out_ PULONG MatchRemainSubkeyLevel,
1704 _Out_ PULONG TotalSubkeys,
1705 _Inout_ PULONG OuterStackArray,
1706 _Out_ PULONG *LockedKcbs)
1707{
1709 ULONG ConvKey;
1710 ULONG SubkeysInTotal, RemainingSubkeysInTotal, MatchRemainingSubkeys;
1712
1713 /* Make sure it's not a dead KCB */
1714 ASSERT((*Kcb)->RefCount > 0);
1715
1716 /* Lock the registry */
1718
1719 /* Calculate hash values for every subkey this key path has */
1720 ConvKey = (*Kcb)->ConvKey;
1721 RemainingSubkeysInTotal = CmpComputeHashValue(Current,
1722 ConvKey,
1723 HashCacheStack,
1724 &SubkeysInTotal);
1725
1726 /* This key path has too many subkeys */
1727 if (SubkeysInTotal > CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1728 {
1729 DPRINT1("The key path has too many subkeys - %lu\n", SubkeysInTotal);
1730 *LockedKcbs = NULL;
1731 return STATUS_NAME_TOO_LONG;
1732 }
1733
1734 /* Return hive and cell data */
1735 *Hive = (*Kcb)->KeyHive;
1736 *Cell = (*Kcb)->KeyCell;
1737
1738 /* Do we have any subkeys? */
1739 if (!RemainingSubkeysInTotal && !SubkeysInTotal)
1740 {
1741 /*
1742 * We don't have any subkeys nor remaining levels, the
1743 * KCB points to the actual key. Lock it.
1744 */
1745 if (!CmpReferenceKeyControlBlock(*Kcb))
1746 {
1747 /* This key is opened too many times, bail out */
1748 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1749 return STATUS_UNSUCCESSFUL;
1750 }
1751
1753
1754 /* Add this KCB in the array of locked KCBs */
1755 OuterStackArray[0] = 1;
1756 OuterStackArray[1] = GET_HASH_INDEX(ConvKey);
1757 *LockedKcbs = OuterStackArray;
1758
1759 /* And return all the subkey level counters */
1760 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1761 *MatchRemainSubkeyLevel = 0;
1762 *TotalSubkeys = SubkeysInTotal;
1763 return STATUS_SUCCESS;
1764 }
1765
1766 /* Lookup in the cache */
1767 Status = CmpLookInCache(HashCacheStack,
1768 FALSE,
1769 RemainingSubkeysInTotal,
1770 Current,
1771 OuterStackArray,
1772 Kcb,
1773 Hive,
1774 Cell,
1775 &MatchRemainingSubkeys);
1776 if (!NT_SUCCESS(Status))
1777 {
1778 /* Bail out if cache lookup failed for other reasons */
1779 if (Status != STATUS_RETRY)
1780 {
1781 DPRINT1("CmpLookInCache() failed (Status 0x%lx)\n", Status);
1782 *LockedKcbs = NULL;
1783 return Status;
1784 }
1785
1786 /* Retry looking in the cache but with KCBs locked exclusively */
1787 Status = CmpLookInCache(HashCacheStack,
1788 TRUE,
1789 RemainingSubkeysInTotal,
1790 Current,
1791 OuterStackArray,
1792 Kcb,
1793 Hive,
1794 Cell,
1795 &MatchRemainingSubkeys);
1796 if (!NT_SUCCESS(Status))
1797 {
1798 DPRINT1("CmpLookInCache() failed after retry (Status 0x%lx)\n", Status);
1799 *LockedKcbs = NULL;
1800 return Status;
1801 }
1802 }
1803
1804 /*
1805 * Check if we have a full match of remaining levels.
1806 *
1807 * FIXME: It is possible we can catch a fake key from the cache
1808 * when we did the lookup, in such case we should not do any
1809 * locking as such KCB does not point to any real information.
1810 * Currently ReactOS doesn't create fake KCBs so we are good
1811 * for now.
1812 */
1813 if (RemainingSubkeysInTotal == MatchRemainingSubkeys)
1814 {
1815 /*
1816 * Just simply lock this KCB as it points to the full
1817 * subkey levels in cache.
1818 */
1820 OuterStackArray[0] = 1;
1821 OuterStackArray[1] = GET_HASH_INDEX((*Kcb)->ConvKey);
1822 *LockedKcbs = OuterStackArray;
1823 }
1824 else
1825 {
1826 /*
1827 * We only have a partial match so other subkey levels
1828 * have each KCB. Simply just lock them.
1829 */
1830 *LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1832 *Kcb,
1833 OuterStackArray,
1834 RemainingSubkeysInTotal,
1835 MatchRemainingSubkeys);
1836 NT_ASSERT(*LockedKcbs);
1837 }
1838
1839 /* Return all the subkey level counters */
1840 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1841 *MatchRemainSubkeyLevel = MatchRemainingSubkeys;
1842 *TotalSubkeys = SubkeysInTotal;
1843 return Status;
1844}
1845
1847NTAPI
1853 IN OUT PUNICODE_STRING CompleteName,
1857 OUT PVOID *Object)
1858{
1860 PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb;
1861 PHHIVE Hive = NULL;
1863 HCELL_INDEX Cell = HCELL_NIL, NextCell;
1864 PHHIVE HiveToRelease = NULL;
1865 HCELL_INDEX CellToRelease = HCELL_NIL;
1866 UNICODE_STRING Current, NextName;
1867 PCM_PARSE_CONTEXT ParseContext = Context;
1868 ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0;
1869 ULONG LockedKcbArray[CMP_KCBS_IN_ARRAY_LIMIT];
1870 PULONG LockedKcbs;
1871 BOOLEAN IsKeyCached = FALSE;
1872 BOOLEAN Result, Last;
1873 PAGED_CODE();
1874
1875 /* Loop path separators at the end */
1876 while (RemainingName->Length &&
1877 (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] ==
1879 {
1880 /* Remove path separator */
1881 RemainingName->Length -= sizeof(WCHAR);
1882 }
1883
1884 /* Fail if this isn't a key object */
1886
1887 /* Copy the remaining name */
1888 Current = *RemainingName;
1889
1890 /* Check if this is a create */
1891 if (!ParseContext || !ParseContext->CreateOperation)
1892 {
1893 /* It isn't, so no context */
1894 ParseContext = NULL;
1895 }
1896
1897 /* Grab the KCB */
1898 Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
1899
1900 /* Sanity check */
1901 ASSERT(Kcb != NULL);
1902
1903 /* Fail if the key was marked as deleted */
1904 if (Kcb->Delete)
1905 return STATUS_KEY_DELETED;
1906
1907 /* Lookup in the cache */
1909 &Kcb,
1910 &Current,
1911 &Hive,
1912 &Cell,
1913 &TotalRemainingSubkeys,
1914 &MatchRemainSubkeyLevel,
1915 &TotalSubkeys,
1916 LockedKcbArray,
1917 &LockedKcbs);
1919 if (!NT_SUCCESS(Status))
1920 {
1921 DPRINT1("Failed to look in cache, stop parsing (Status 0x%lx)\n", Status);
1922 ParentKcb = NULL;
1923 goto Quickie;
1924 }
1925
1926 /* This is now the parent */
1927 ParentKcb = Kcb;
1928
1929 /* Sanity check */
1930 ASSERT(ParentKcb != NULL);
1931
1932 /* Don't do anything if we're being deleted */
1933 if (Kcb->Delete)
1934 {
1936 goto Quickie;
1937 }
1938
1939 /* Check if everything was found cached */
1940 if (!TotalRemainingSubkeys)
1941 {
1942 /*
1943 * We don't have any remaining subkey levels so we're good
1944 * that we have an already perfect candidate for a KCB, just
1945 * do the open directly.
1946 */
1947 DPRINT("No remaining subkeys, the KCB points to the actual key\n");
1948 IsKeyCached = TRUE;
1949 goto KeyCachedOpenNow;
1950 }
1951
1952 /* Check if we have a matching level */
1953 if (MatchRemainSubkeyLevel)
1954 {
1955 /*
1956 * We have a matching level, check if that matches
1957 * with the total levels of subkeys. Do the open directly
1958 * if that is the case, because the whole subkeys levels
1959 * is cached.
1960 */
1961 if (MatchRemainSubkeyLevel == TotalSubkeys)
1962 {
1963 DPRINT("We have a full matching level, open the key now\n");
1964 IsKeyCached = TRUE;
1965 goto KeyCachedOpenNow;
1966 }
1967
1968 /*
1969 * We only have a partial match, make sure we did not
1970 * get mismatched hive data.
1971 */
1972 ASSERT(Hive == Kcb->KeyHive);
1973 ASSERT(Cell == Kcb->KeyCell);
1974 }
1975
1976 /*
1977 * FIXME: Currently the registry parser doesn't check for fake
1978 * KCBs. CmpCreateKeyControlBlock does have the necessary implementation
1979 * to create such fake keys but we don't create these fake keys anywhere.
1980 * When we will do, we must improve the registry parser routine to handle
1981 * fake keys a bit differently here.
1982 */
1983
1984 /* Check if this is a symlink */
1985 if (Kcb->Flags & KEY_SYM_LINK)
1986 {
1987 /* Get the next name */
1988 Result = CmpGetNextName(&Current, &NextName, &Last);
1989 Current.Buffer = NextName.Buffer;
1990
1991 /* Validate the current name string length */
1992 if (Current.Length + NextName.Length > MAXUSHORT)
1993 {
1994 /* too long */
1996 goto Quickie;
1997 }
1998 Current.Length += NextName.Length;
1999
2000 /* Validate the current name string maximum length */
2001 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2002 {
2003 /* too long */
2005 goto Quickie;
2006 }
2007 Current.MaximumLength += NextName.MaximumLength;
2008
2009 /* CmpGetSymbolicLink doesn't want a lock */
2010 CmpUnLockKcbArray(LockedKcbs);
2011 LockedKcbs = NULL;
2012
2013 /* Parse the symlink */
2014 if (CmpGetSymbolicLink(Hive,
2015 CompleteName,
2016 Kcb,
2017 &Current))
2018 {
2019 /* Symlink parse succeeded */
2021 }
2022 else
2023 {
2024 /* Couldn't find symlink */
2026 }
2027
2028 /* We're done */
2029 goto Quickie;
2030 }
2031
2032 /* Get the key node */
2033 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2034 if (!Node)
2035 {
2037 goto Quickie;
2038 }
2039
2040 /* Start parsing */
2042 while (TRUE)
2043 {
2044 /* Get the next component */
2045 Result = CmpGetNextName(&Current, &NextName, &Last);
2046 if (Result && NextName.Length)
2047 {
2048 /* See if this is a sym link */
2049 if (!(Kcb->Flags & KEY_SYM_LINK))
2050 {
2051 /* Find the subkey */
2052 NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
2053 if (NextCell != HCELL_NIL)
2054 {
2055 /* Get the new node */
2056 Cell = NextCell;
2057 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2058 ASSERT(Node);
2059
2060 /* Check if this was the last key */
2061 if (Last)
2062 {
2063 /* Is this an exit node */
2064 if (Node->Flags & KEY_HIVE_EXIT)
2065 {
2066 /* Handle it */
2067 CmpHandleExitNode(&Hive,
2068 &Cell,
2069 &Node,
2070 &HiveToRelease,
2071 &CellToRelease);
2072 if (!Node)
2073 {
2074 /* Fail */
2076 break;
2077 }
2078 }
2079
2080KeyCachedOpenNow:
2081 /* Do the open */
2082 Status = CmpDoOpen(Hive,
2083 Cell,
2084 Node,
2086 AccessMode,
2087 Attributes,
2088 ParseContext,
2090 &Kcb,
2091 LockedKcbs,
2092 &NextName,
2093 Object);
2094 if (Status == STATUS_REPARSE)
2095 {
2096 /* CmpGetSymbolicLink doesn't want a lock */
2097 CmpUnLockKcbArray(LockedKcbs);
2098 LockedKcbs = NULL;
2099
2100 /* Parse the symlink */
2101 if (!CmpGetSymbolicLink(Hive,
2102 CompleteName,
2103 Kcb,
2104 NULL))
2105 {
2106 /* Symlink parse failed */
2108 }
2109 }
2110
2111 /* We are done */
2112 break;
2113 }
2114
2115 /* Is this an exit node */
2116 if (Node->Flags & KEY_HIVE_EXIT)
2117 {
2118 /* Handle it */
2119 CmpHandleExitNode(&Hive,
2120 &Cell,
2121 &Node,
2122 &HiveToRelease,
2123 &CellToRelease);
2124 if (!Node)
2125 {
2126 /* Fail */
2128 break;
2129 }
2130 }
2131
2132 /* Create a KCB for this key */
2133 Kcb = CmpCreateKeyControlBlock(Hive,
2134 Cell,
2135 Node,
2136 ParentKcb,
2138 &NextName);
2139 if (!Kcb)
2140 {
2141 /* Fail */
2143 break;
2144 }
2145
2146 /* Dereference the parent and set the new one */
2148 ParentKcb = Kcb;
2149 }
2150 else
2151 {
2152 /* Check if this was the last key for a create */
2153 if (Last && ParseContext)
2154 {
2155 /* Check if we're doing a link node */
2156 if (ParseContext->CreateLink)
2157 {
2158 /* The only thing we should see */
2160 Cell,
2162 NextName,
2163 AccessMode,
2164 Attributes,
2165 ParseContext,
2166 ParentKcb,
2167 LockedKcbs,
2168 Object);
2169 }
2170 else if (Hive == &CmiVolatileHive->Hive && CmpNoVolatileCreates)
2171 {
2172 /* Creating keys in the master hive is not allowed */
2174 }
2175 else
2176 {
2177 /* Do the create */
2178 Status = CmpDoCreate(Hive,
2179 Cell,
2181 &NextName,
2182 AccessMode,
2183 ParseContext,
2184 ParentKcb,
2185 Object);
2186 }
2187
2188 /* Check for reparse (in this case, someone beat us) */
2189 if (Status == STATUS_REPARSE) break;
2190
2191 /* Update disposition */
2192 ParseContext->Disposition = REG_CREATED_NEW_KEY;
2193 break;
2194 }
2195 else
2196 {
2197 /* Key not found */
2199 break;
2200 }
2201 }
2202 }
2203 else
2204 {
2205 /* Save the next name */
2206 Current.Buffer = NextName.Buffer;
2207
2208 /* Validate the current name string length */
2209 if (Current.Length + NextName.Length > MAXUSHORT)
2210 {
2211 /* too long */
2213 break;
2214 }
2215 Current.Length += NextName.Length;
2216
2217 /* Validate the current name string maximum length */
2218 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2219 {
2220 /* too long */
2222 break;
2223 }
2224 Current.MaximumLength += NextName.MaximumLength;
2225
2226 /* CmpGetSymbolicLink doesn't want a lock */
2227 CmpUnLockKcbArray(LockedKcbs);
2228 LockedKcbs = NULL;
2229
2230 /* Parse the symlink */
2231 if (CmpGetSymbolicLink(Hive,
2232 CompleteName,
2233 Kcb,
2234 &Current))
2235 {
2236 /* Symlink parse succeeded */
2238 }
2239 else
2240 {
2241 /* Couldn't find symlink */
2243 }
2244
2245 /* We're done */
2246 break;
2247 }
2248 }
2249 else if (Result && Last)
2250 {
2251 /* Opening the root. Is this an exit node? */
2252 if (Node->Flags & KEY_HIVE_EXIT)
2253 {
2254 /* Handle it */
2255 CmpHandleExitNode(&Hive,
2256 &Cell,
2257 &Node,
2258 &HiveToRelease,
2259 &CellToRelease);
2260 if (!Node)
2261 {
2262 /* Fail */
2264 break;
2265 }
2266 }
2267
2268 /* Do the open */
2269 Status = CmpDoOpen(Hive,
2270 Cell,
2271 Node,
2273 AccessMode,
2274 Attributes,
2275 ParseContext,
2277 &Kcb,
2278 LockedKcbs,
2279 &NextName,
2280 Object);
2281 if (Status == STATUS_REPARSE)
2282 {
2283 /* Nothing to do */
2284 }
2285
2286 /* We're done */
2287 break;
2288 }
2289 else
2290 {
2291 /* Bogus */
2293 break;
2294 }
2295 }
2296
2297Quickie:
2298 /* Unlock all the KCBs */
2299 if (LockedKcbs != NULL)
2300 {
2301 CmpUnLockKcbArray(LockedKcbs);
2302 }
2303
2304 /* Dereference the parent if it exists */
2305 if (ParentKcb)
2307
2308 /* Unlock the registry */
2310 return Status;
2311}
#define PAGED_CODE()
#define CmpKeyObjectType
Definition: ObTypes.c:127
unsigned char BOOLEAN
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
_Inout_ PFCB _Inout_ PUNICODE_STRING RemainingName
Definition: cdprocs.h:802
#define CMP_LOCK_KCB_ARRAY_SHARED
Definition: cm.h:102
#define CM_KCB_KEY_NON_EXIST
Definition: cm.h:56
#define CMP_KCBS_IN_ARRAY_LIMIT
Definition: cm.h:132
#define CMP_ENLIST_KCB_LOCKED_SHARED
Definition: cm.h:95
#define CMP_OPEN_KCB_NO_CREATE
Definition: cm.h:90
struct _CM_KEY_BODY * PCM_KEY_BODY
#define CM_KCB_SYM_LINK_FOUND
Definition: cm.h:55
#define CMP_LOCK_HASHES_FOR_KCB
Definition: cm.h:84
#define CM_KEY_BODY_TYPE
Definition: cm.h:64
#define CMP_CREATE_KCB_KCB_LOCKED
Definition: cm.h:89
#define CMP_ENLIST_KCB_LOCKED_EXCLUSIVE
Definition: cm.h:96
#define CMP_SUBKEY_LEVELS_DEPTH_LIMIT
Definition: cm.h:131
#define CMP_LOCK_KCB_ARRAY_EXCLUSIVE
Definition: cm.h:101
#define CM_KCB_READ_ONLY_KEY
Definition: cm.h:59
#define ASSERT_VALID_HASH(h)
Definition: cm_x.h:28
#define GET_HASH_ENTRY(Table, ConvKey)
Definition: cm_x.h:26
FORCEINLINE VOID CmpAcquireKcbLockExclusiveByIndex(ULONG Index)
Definition: cm_x.h:105
#define GET_HASH_INDEX(ConvKey)
Definition: cm_x.h:24
#define CMP_ASSERT_REGISTRY_LOCK()
Definition: cm_x.h:52
#define CmpIsKcbLockedExclusive(k)
Definition: cm_x.h:88
#define CMP_ASSERT_KCB_LOCK(k)
Definition: cm_x.h:261
#define COMPUTE_HASH_CHAR(ConvKey, Char)
Definition: cm_x.h:18
#define CmpAcquireKcbLockSharedByIndex(i)
Definition: cm_x.h:95
UNICODE_STRING CmSymbolicLinkValueName
Definition: cmdata.c:52
struct _CM_KEY_NODE * PCM_KEY_NODE
#define KEY_COMP_NAME
Definition: cmdata.h:35
struct _CM_KEY_VALUE * PCM_KEY_VALUE
#define KEY_NO_DELETE
Definition: cmdata.h:33
#define KEY_HIVE_EXIT
Definition: cmdata.h:31
#define CM_KEY_NODE_SIGNATURE
Definition: cmdata.h:21
#define CM_LINK_NODE_SIGNATURE
Definition: cmdata.h:22
#define KEY_SYM_LINK
Definition: cmdata.h:34
#define KEY_HIVE_ENTRY
Definition: cmdata.h:32
VOID NTAPI CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmdelay.c:425
BOOLEAN NTAPI CmpAddSubKey(IN PHHIVE Hive, IN HCELL_INDEX Parent, IN HCELL_INDEX Child)
Definition: cmindex.c:1465
HCELL_INDEX NTAPI CmpFindSubKeyByName(IN PHHIVE Hive, IN PCM_KEY_NODE Parent, IN PCUNICODE_STRING SearchName)
Definition: cmindex.c:683
VOID NTAPI CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, IN BOOLEAN LockHeldExclusively)
Definition: cmkcbncb.c:476
VOID CmpUnLockKcbArray(_In_ PULONG KcbArray)
Unlocks a number of KCBs provided by a KCB array.
Definition: cmkcbncb.c:1145
PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable
Definition: cmkcbncb.c:18
BOOLEAN NTAPI CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:357
PCM_KEY_CONTROL_BLOCK NTAPI CmpCreateKeyControlBlock(IN PHHIVE Hive, IN HCELL_INDEX Index, IN PCM_KEY_NODE Node, IN PCM_KEY_CONTROL_BLOCK Parent, IN ULONG Flags, IN PUNICODE_STRING KeyName)
Definition: cmkcbncb.c:655
VOID NTAPI CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:431
VOID NTAPI CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, IN BOOLEAN LockHeldExclusively)
Definition: cmkcbncb.c:606
VOID NTAPI CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:571
VOID NTAPI CmpCleanUpSubKeyInfo(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:517
VOID NTAPI CmpRemoveKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
Definition: cmkcbncb.c:306
PULONG NTAPI CmpBuildAndLockKcbArray(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ ULONG KcbLockFlags, _In_ PCM_KEY_CONTROL_BLOCK Kcb, _Inout_ PULONG OuterStackArray, _In_ ULONG TotalRemainingSubkeys, _In_ ULONG MatchRemainSubkeyLevel)
Builds an array of KCBs and locks them. Whether these KCBs are locked exclusively or in shared mode b...
Definition: cmkcbncb.c:1302
VOID NTAPI EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody, IN ULONG Flags)
Definition: cmkcbncb.c:1042
NTSTATUS NTAPI CmpFreeKeyByCell(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN BOOLEAN Unlink)
Definition: cmkeydel.c:159
#define HvReleaseCell(Hive, Cell)
Definition: cmlib.h:455
USHORT NTAPI CmpCopyName(IN PHHIVE Hive, OUT PWCHAR Destination, IN PCUNICODE_STRING Source)
Definition: cmname.c:21
USHORT NTAPI CmpNameSize(IN PHHIVE Hive, IN PCUNICODE_STRING Name)
Definition: cmname.c:74
BOOLEAN NTAPI CmpGetValueData(IN PHHIVE Hive, IN PCM_KEY_VALUE Value, OUT PULONG Length, OUT PVOID *Buffer, OUT PBOOLEAN BufferAllocated, OUT PHCELL_INDEX CellToRelease)
Definition: cmvalue.c:125
HCELL_INDEX NTAPI CmpFindValueByName(IN PHHIVE Hive, IN PCM_KEY_NODE KeyNode, IN PCUNICODE_STRING Name)
Definition: cmvalue.c:99
VOID CMAPI HvFreeCell(PHHIVE RegistryHive, HCELL_INDEX CellOffset)
Definition: hivecell.c:468
LONG NTAPI CmpCompareCompressedName(IN PCUNICODE_STRING SearchName, IN PWCHAR CompressedName, IN ULONG NameLength)
Definition: cmname.c:109
BOOLEAN CMAPI HvMarkCellDirty(PHHIVE RegistryHive, HCELL_INDEX CellOffset, BOOLEAN HoldingLock)
Definition: hivecell.c:109
#define HvGetCell(Hive, Cell)
Definition: cmlib.h:452
HCELL_INDEX CMAPI HvAllocateCell(PHHIVE RegistryHive, ULONG Size, HSTORAGE_TYPE Storage, IN HCELL_INDEX Vicinity)
#define TAG_CM
Definition: cmlib.h:212
VOID NTAPI CmpReportNotify(IN PCM_KEY_CONTROL_BLOCK Kcb, IN PHHIVE Hive, IN HCELL_INDEX Cell, IN ULONG Filter)
Definition: cmnotify.c:19
NTSTATUS NTAPI CmpBuildHashStackAndLookupCache(_In_ PCM_KEY_BODY ParseObject, _Inout_ PCM_KEY_CONTROL_BLOCK *Kcb, _In_ PUNICODE_STRING Current, _Out_ PHHIVE *Hive, _Out_ PHCELL_INDEX Cell, _Out_ PULONG TotalRemainingSubkeys, _Out_ PULONG MatchRemainSubkeyLevel, _Out_ PULONG TotalSubkeys, _Inout_ PULONG OuterStackArray, _Out_ PULONG *LockedKcbs)
Builds a hash stack cache and looks up in the pool cache for a matching key pathname.
Definition: cmparse.c:1696
BOOLEAN NTAPI CmpGetSymbolicLink(IN PHHIVE Hive, IN OUT PUNICODE_STRING ObjectName, IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, IN PUNICODE_STRING RemainingName OPTIONAL)
Definition: cmparse.c:75
static NTSTATUS CmpLookInCache(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ BOOLEAN LockKcbsExclusive, _In_ ULONG TotalRemainingSubkeys, _Inout_ PUNICODE_STRING RemainingName, _Inout_ PULONG OuterStackArray, _Inout_ PCM_KEY_CONTROL_BLOCK *Kcb, _Out_ PHHIVE *Hive, _Out_ PHCELL_INDEX Cell, _Out_ PULONG MatchRemainSubkeyLevel)
Looks up in the pool cache for key pathname that matches with one in the said cache and returns a KCB...
Definition: cmparse.c:1460
static ULONG CmpComputeHashValue(_In_ PUNICODE_STRING RemainingName, _In_ ULONG ConvKey, _Inout_ PCM_HASH_CACHE_STACK HashCacheStack, _Out_ PULONG TotalSubKeys)
Computes the hashes of each subkey in key path name and stores them in a hash stack for cache lookup.
Definition: cmparse.c:1141
NTSTATUS NTAPI CmpParseKey(IN PVOID ParseObject, IN PVOID ObjectType, IN OUT PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN OUT PUNICODE_STRING CompleteName, IN OUT PUNICODE_STRING RemainingName, IN OUT PVOID Context OPTIONAL, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, OUT PVOID *Object)
Definition: cmparse.c:1848
static BOOLEAN CmpCompareSubkeys(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ PCM_KEY_CONTROL_BLOCK CurrentKcb, _In_ ULONG RemainingSubkeys, _Out_ PCM_KEY_CONTROL_BLOCK *ParentKcb)
Compares each subkey's hash and name with those captured in the hash cache stack.
Definition: cmparse.c:1284
NTSTATUS NTAPI CmpCreateLinkNode(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PACCESS_STATE AccessState, IN UNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN ULONG CreateOptions, IN PCM_PARSE_CONTEXT Context, IN PCM_KEY_CONTROL_BLOCK ParentKcb, IN PULONG KcbsLocked, OUT PVOID *Object)
Definition: cmparse.c:830
static VOID CmpRemoveSubkeysInRemainingName(_In_ PCM_HASH_CACHE_STACK HashCacheStack, _In_ ULONG RemainingSubkeys, _Inout_ PUNICODE_STRING RemainingName)
Removes the subkeys on a remaining key pathname.
Definition: cmparse.c:1361
NTSTATUS NTAPI CmpDoOpen(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PCM_KEY_NODE Node, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN PCM_PARSE_CONTEXT Context OPTIONAL, IN ULONG ControlFlags, IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, IN PULONG KcbsLocked, IN PUNICODE_STRING KeyName, OUT PVOID *Object)
Definition: cmparse.c:601
NTSTATUS NTAPI CmpDoCreateChild(IN PHHIVE Hive, IN HCELL_INDEX ParentCell, IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL, IN PACCESS_STATE AccessState, IN PUNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN PCM_PARSE_CONTEXT ParseContext, IN PCM_KEY_CONTROL_BLOCK ParentKcb, IN ULONG Flags, OUT PHCELL_INDEX KeyCell, OUT PVOID *Object)
Definition: cmparse.c:204
VOID NTAPI CmpHandleExitNode(IN OUT PHHIVE *Hive, IN OUT HCELL_INDEX *Cell, IN OUT PCM_KEY_NODE *KeyNode, IN OUT PHHIVE *ReleaseHive, IN OUT HCELL_INDEX *ReleaseCell)
Definition: cmparse.c:1080
NTSTATUS NTAPI CmpDoCreate(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PACCESS_STATE AccessState, IN PUNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN PCM_PARSE_CONTEXT ParseContext, IN PCM_KEY_CONTROL_BLOCK ParentKcb, OUT PVOID *Object)
Definition: cmparse.c:404
BOOLEAN NTAPI CmpGetNextName(IN OUT PUNICODE_STRING RemainingName, OUT PUNICODE_STRING NextName, OUT PBOOLEAN LastName)
Definition: cmparse.c:21
VOID NTAPI CmpUnlockRegistry(VOID)
Definition: cmsysini.c:2053
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1967
VOID NTAPI CmpLockHiveFlusherShared(IN PCMHIVE Hive)
Definition: cmsysini.c:2014
BOOLEAN CmpNoVolatileCreates
Definition: cmsysini.c:34
PCMHIVE CmiVolatileHive
Definition: cmsysini.c:16
VOID NTAPI CmpUnlockHiveFlusher(IN PCMHIVE Hive)
Definition: cmsysini.c:2025
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
union node Node
Definition: types.h:1255
#define ULONG_PTR
Definition: config.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define PagedPool
Definition: env_spec_w32.h:308
Status
Definition: gdiplustypes.h:25
#define KeGetCurrentThread
Definition: hal.h:55
ULONG * PHCELL_INDEX
Definition: hivedata.h:105
@ Volatile
Definition: hivedata.h:128
@ Stable
Definition: hivedata.h:127
#define HIVE_IS_UNLOADING
Definition: hivedata.h:28
#define HCELL_NIL
Definition: hivedata.h:110
ULONG HCELL_INDEX
Definition: hivedata.h:105
#define HvGetCellType(Cell)
Definition: hivedata.h:120
#define OBJ_OPENLINK
Definition: winternl.h:230
#define ASSERT(a)
Definition: mode.c:44
ObjectType
Definition: metafile.c:81
#define _Inout_
Definition: ms_sal.h:378
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
#define REG_OPTION_CREATE_LINK
Definition: nt_native.h:1063
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1084
#define REG_LINK
Definition: nt_native.h:1500
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1085
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define UNICODE_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTATUS CmpAssignSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb, IN PSECURITY_DESCRIPTOR SecurityDescriptor)
Definition: cmse.c:251
HANDLE NTAPI PsGetCurrentProcessId(VOID)
Definition: process.c:1123
#define STATUS_REPARSE
Definition: ntstatus.h:83
#define STATUS_KEY_DELETED
Definition: ntstatus.h:613
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define STATUS_CHILD_MUST_BE_VOLATILE
Definition: ntstatus.h:618
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:498
#define STATUS_OBJECT_TYPE_MISMATCH
Definition: ntstatus.h:273
BOOLEAN NTAPI ObCheckObjectAccess(IN PVOID Object, IN OUT PACCESS_STATE AccessState, IN BOOLEAN LockHeld, IN KPROCESSOR_MODE AccessMode, OUT PNTSTATUS ReturnedStatus)
Definition: obsecure.c:441
NTSTATUS NTAPI ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, IN POBJECT_TYPE Type, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, IN ULONG ObjectSize, IN ULONG PagedPoolCharge OPTIONAL, IN ULONG NonPagedPoolCharge OPTIONAL, OUT PVOID *Object)
Definition: oblife.c:1039
VOID NTAPI ObDereferenceObjectDeferDelete(IN PVOID Object)
Definition: obref.c:358
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
SECURITY_INTEGER TimeStamp
Definition: sspi.h:78
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
static void Exit(void)
Definition: sock.c:1330
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: hash.c:61
struct _CM_KEY_CONTROL_BLOCK * RealKcb
Definition: cm.h:215
WCHAR KeyString[ANYSIZE_ARRAY]
Definition: cmdata.h:206
union _CELL_DATA::@4298 u
CM_KEY_NODE KeyNode
Definition: cmdata.h:200
HCELL_INDEX List
Definition: cmdata.h:75
ULONG Count
Definition: cmdata.h:74
Definition: cmlib.h:316
HHIVE Hive
Definition: cmlib.h:317
ULONG Type
Definition: cm.h:233
HANDLE ProcessID
Definition: cm.h:236
BOOLEAN KcbLocked
Definition: cm.h:240
struct _CM_NOTIFY_BLOCK * NotifyBlock
Definition: cm.h:235
struct _CM_KEY_CONTROL_BLOCK * KeyControlBlock
Definition: cm.h:234
ULONG TotalLevels
Definition: cm.h:276
ULONG RefCount
Definition: cm.h:269
PHHIVE KeyHive
Definition: cm.h:285
struct _CM_KEY_CONTROL_BLOCK * ParentKcb
Definition: cm.h:289
ULONG ExtFlags
Definition: cm.h:272
HCELL_INDEX KeyCell
Definition: cm.h:286
CACHED_CHILD_LIST ValueCache
Definition: cm.h:292
USHORT Signature
Definition: cmdata.h:92
ULONG Spare
Definition: cmdata.h:95
CM_KEY_REFERENCE ChildHiveReference
Definition: cmdata.h:105
HCELL_INDEX Parent
Definition: cmdata.h:96
WCHAR Name[ANYSIZE_ARRAY]
Definition: cmdata.h:116
HCELL_INDEX SubKeyLists[HTYPE_COUNT]
Definition: cmdata.h:102
ULONG MaxValueNameLen
Definition: cmdata.h:111
ULONG MaxNameLen
Definition: cmdata.h:109
ULONG SubKeyCounts[HTYPE_COUNT]
Definition: cmdata.h:97
HCELL_INDEX Security
Definition: cmdata.h:107
USHORT NameLength
Definition: cmdata.h:114
USHORT ClassLength
Definition: cmdata.h:115
ULONG MaxClassLen
Definition: cmdata.h:110
HCELL_INDEX Class
Definition: cmdata.h:108
ULONG MaxValueDataLen
Definition: cmdata.h:112
CHILD_LIST ValueList
Definition: cmdata.h:103
USHORT Flags
Definition: cmdata.h:93
LARGE_INTEGER LastWriteTime
Definition: cmdata.h:94
PHHIVE KeyHive
Definition: cmdata.h:84
HCELL_INDEX KeyCell
Definition: cmdata.h:83
ULONG Type
Definition: cmdata.h:128
BOOLEAN Compressed
Definition: cm.h:248
USHORT NameLength
Definition: cm.h:257
WCHAR Name[ANYSIZE_ARRAY]
Definition: cm.h:258
ULONG Disposition
Definition: cm.h:437
BOOLEAN CreateLink
Definition: cm.h:440
BOOLEAN CreateOperation
Definition: cm.h:441
USHORT MaximumLength
Definition: env_spec_w32.h:370
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define MAXUSHORT
Definition: typedefs.h:83
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_RETRY
Definition: udferr_usr.h:182
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
Definition: dlist.c:348
_In_ ULONG _In_ ULONG KeyNameLength
Definition: usbdlib.h:208
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2699
_Must_inspect_result_ _In_opt_ WDFKEY _In_ PCUNICODE_STRING _In_ ACCESS_MASK _In_ ULONG CreateOptions
Definition: wdfregistry.h:118
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
#define REG_NOTIFY_CHANGE_NAME
Definition: winreg.h:38
_In_ USHORT _In_ ULONG _In_ PSOCKADDR _In_ PSOCKADDR _Reserved_ ULONG _In_opt_ PVOID _In_opt_ const WSK_CLIENT_CONNECTION_DISPATCH _In_opt_ PEPROCESS _In_opt_ PETHREAD _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor
Definition: wsk.h:191
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_In_ PVOID _Out_opt_ PULONG_PTR _Outptr_opt_ PCUNICODE_STRING * ObjectName
Definition: cmfuncs.h:64
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_ PEPROCESS _In_ KPROCESSOR_MODE AccessMode
Definition: mmfuncs.h:396
#define ObDereferenceObject
Definition: obfuncs.h:203
#define NT_ASSERT
Definition: rtlfuncs.h:3310
_In_opt_ PVOID _In_opt_ PUNICODE_STRING _In_ PSECURITY_DESCRIPTOR _In_ PACCESS_STATE AccessState
Definition: sefuncs.h:417
_In_opt_ PSECURITY_DESCRIPTOR _Out_ PSECURITY_DESCRIPTOR * NewDescriptor
Definition: sefuncs.h:30
__wchar_t WCHAR
Definition: xmlstorage.h:180