ReactOS 0.4.17-dev-684-ga6524ef
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 */
671 Kcb = (*CachedKcb)->ValueCache.RealKcb;
672
673 /* Before we drop all locks, we need to reference the real KCB */
675 {
676 DPRINT("Failed to reference the real KCB, attempt a reparse\n");
677 return STATUS_REPARSE;
678 }
679
680 /*
681 * Lock the real KCB of the symlink exclusively, we don't want anybody
682 * to mess it up.
683 */
684 CmpUnLockKcbArray(KcbsLocked);
685 KcbsLocked[0] = 1;
686 KcbsLocked[1] = GET_HASH_INDEX(Kcb->ConvKey);
688 IsLockShared = FALSE;
689
690 /* Was the real KCB deleted? */
691 if (Kcb->Delete)
692 {
693 /*
694 * The real KCB is gone, do a reparse. We used to lock the KCB in
695 * shared mode as others may have taken use of it but since we
696 * must do a reparse of the key the only thing that matter is us.
697 * Lock the KCB exclusively so nobody is going to mess with the KCB.
698 */
699 DPRINT1("The real KCB is deleted, attempt a reparse\n");
700 CmpUnLockKcbArray(KcbsLocked);
703 CmpCleanUpKcbValueCache(*CachedKcb);
704 KcbsLocked[0] = 1;
705 KcbsLocked[1] = GET_HASH_INDEX((*CachedKcb)->ConvKey);
706 return STATUS_REPARSE;
707 }
708 }
709 else
710 {
711 /* We must do a reparse */
712 DPRINT("The symlink is not found, attempt a reparse\n");
713 return STATUS_REPARSE;
714 }
715 }
716 else
717 {
718 /* This is not a symlink, just give the cached KCB already */
719 Kcb = *CachedKcb;
720
721 /* The caller wants to open a cached KCB */
723 {
724 /* Return failure code */
726 }
727 }
728 }
729 else
730 {
731 /*
732 * The caller wants to create a new KCB. Unlike the code path above, here
733 * we must check if the lock is exclusively held because in the scenario
734 * where the caller doesn't want to create a KCB is because it is already
735 * in the cache and it must have a shared lock instead.
736 */
737 ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
738
739 /* Check if this is a symlink */
740 if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
741 {
742 /* Create the KCB for the symlink */
743 Kcb = CmpCreateKeyControlBlock(Hive,
744 Cell,
745 Node,
746 *CachedKcb,
747 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
748 KeyName);
749 if (!Kcb)
750 {
751 /* Return failure */
753 }
754
755 /* Make sure it's also locked, and set the pointer */
757 *CachedKcb = Kcb;
758
759 /* Return reparse required */
760 return STATUS_REPARSE;
761 }
762
763 /* Create the KCB */
764 Kcb = CmpCreateKeyControlBlock(Hive,
765 Cell,
766 Node,
767 *CachedKcb,
768 LockKcb ? CMP_LOCK_HASHES_FOR_KCB : 0,
769 KeyName);
770 if (!Kcb)
771 {
772 /* Return failure */
774 }
775
776 /* Make sure it's also locked, and set the pointer */
778 *CachedKcb = Kcb;
779 }
780
781 /* Allocate the key object */
784 NULL,
786 NULL,
787 sizeof(CM_KEY_BODY),
788 0,
789 0,
790 Object);
791 if (NT_SUCCESS(Status))
792 {
793 /* Get the key body and fill it out */
794 KeyBody = (PCM_KEY_BODY)(*Object);
795 KeyBody->KeyControlBlock = Kcb;
796 KeyBody->Type = CM_KEY_BODY_TYPE;
797 KeyBody->ProcessID = PsGetCurrentProcessId();
798 KeyBody->NotifyBlock = NULL;
799
800 /* Link to the KCB */
802
803 /*
804 * We are already holding a lock against the KCB that is assigned
805 * to this key body. This is to prevent a potential deadlock on
806 * CmpSecurityMethod as ObCheckObjectAccess will invoke the Object
807 * Manager to call that method, of which CmpSecurityMethod would
808 * attempt to acquire a lock again.
809 */
810 KeyBody->KcbLocked = TRUE;
811
814 FALSE,
816 &Status))
817 {
818 /* Access check failed */
820 }
821
822 /*
823 * We are done, the lock we are holding will be released
824 * once the registry parsing is done.
825 */
826 KeyBody->KcbLocked = FALSE;
827 }
828 else
829 {
830 /* Failed, dereference the KCB */
832 }
833
834 /* Return status */
835 return Status;
836}
837
839NTAPI
841 IN HCELL_INDEX Cell,
847 IN PCM_KEY_CONTROL_BLOCK ParentKcb,
848 IN PULONG KcbsLocked,
850{
852 HCELL_INDEX KeyCell, LinkCell, ChildCell;
853 PCM_KEY_BODY KeyBody;
855 PCM_KEY_NODE KeyNode;
856 PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb;
857
858 /* Link nodes only allowed on the master */
859 if (Hive != &CmiVolatileHive->Hive)
860 {
861 /* Fail */
862 DPRINT1("Invalid link node attempt\n");
864 }
865
866 /* Make sure the KCB is locked and lock the flusher */
867 CMP_ASSERT_KCB_LOCK(ParentKcb);
869 CmpLockHiveFlusherShared((PCMHIVE)Context->ChildHive.KeyHive);
870
871 /* Bail out on read-only KCBs */
872 if (ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)
873 {
875 goto Exit;
876 }
877
878 /* Check if the parent is being deleted */
879 if (ParentKcb->Delete)
880 {
881 /* It is, quit */
882 ASSERT(FALSE);
884 goto Exit;
885 }
886
887 /* Allocate a link node */
888 LinkCell = HvAllocateCell(Hive,
890 CmpNameSize(Hive, &Name),
891 Stable,
892 HCELL_NIL);
893 if (LinkCell == HCELL_NIL)
894 {
895 /* Fail */
897 goto Exit;
898 }
899
900 /* Get the key cell */
901 KeyCell = Context->ChildHive.KeyCell;
902 if (KeyCell != HCELL_NIL)
903 {
904 /* Hive exists! */
905 ChildCell = KeyCell;
906
907 /* Get the node data */
908 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
909 if (!KeyNode)
910 {
911 /* Fail */
912 ASSERT(FALSE);
914 goto Exit;
915 }
916
917 /* Fill out the data */
918 KeyNode->Parent = LinkCell;
919 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
920 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
921
922 /* Now open the key cell */
923 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell);
924 if (!KeyNode)
925 {
926 /* Fail */
927 ASSERT(FALSE);
929 goto Exit;
930 }
931
932 /* Open the parent */
933 Status = CmpDoOpen(Context->ChildHive.KeyHive,
934 KeyCell,
935 KeyNode,
939 NULL,
941 &Kcb,
942 KcbsLocked,
943 &Name,
944 Object);
945 HvReleaseCell(Context->ChildHive.KeyHive, KeyCell);
946 }
947 else
948 {
949 /* Do the actual create operation */
950 Status = CmpDoCreateChild(Context->ChildHive.KeyHive,
951 Cell,
952 NULL,
954 &Name,
956 Context,
957 ParentKcb,
959 &ChildCell,
960 Object);
961 if (NT_SUCCESS(Status))
962 {
963 /* Setup root pointer */
964 Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;
965 }
966 }
967
968 /* Check if open or create suceeded */
969 if (NT_SUCCESS(Status))
970 {
971 /* Mark the cell dirty */
972 HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE);
973
974 /* Get the key node */
975 KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
976 if (!KeyNode)
977 {
978 /* Fail */
979 ASSERT(FALSE);
981 goto Exit;
982 }
983
984 /* Release it */
985 HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
986
987 /* Set the parent and flags */
988 KeyNode->Parent = LinkCell;
989 KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
990
991 /* Get the link node */
992 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, LinkCell);
993 if (!KeyNode)
994 {
995 /* Fail */
996 ASSERT(FALSE);
998 goto Exit;
999 }
1000
1001 /* Set it up */
1003 KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;
1004 KeyNode->Parent = Cell;
1005 KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name);
1006 if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME;
1008 KeyNode->LastWriteTime = TimeStamp;
1009
1010 /* Clear out the rest */
1011 KeyNode->SubKeyCounts[Stable] = 0;
1012 KeyNode->SubKeyCounts[Volatile] = 0;
1013 KeyNode->SubKeyLists[Stable] = HCELL_NIL;
1014 KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
1015 KeyNode->ValueList.Count = 0;
1016 KeyNode->ValueList.List = HCELL_NIL;
1017 KeyNode->ClassLength = 0;
1018
1019 /* Reference the root node */
1020 KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;
1021 KeyNode->ChildHiveReference.KeyCell = ChildCell;
1022 HvReleaseCell(Hive, LinkCell);
1023
1024 /* Get the parent node */
1025 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1026 if (!KeyNode)
1027 {
1028 /* Fail */
1029 ASSERT(FALSE);
1031 goto Exit;
1032 }
1033
1034 /* Now add the subkey */
1035 if (!CmpAddSubKey(Hive, Cell, LinkCell))
1036 {
1037 /* Failure! We don't handle this yet! */
1038 ASSERT(FALSE);
1039 }
1040
1041 /* Get the key body */
1042 KeyBody = (PCM_KEY_BODY)*Object;
1043
1044 /* Clean up information on this subkey */
1045 CmpCleanUpSubKeyInfo(KeyBody->KeyControlBlock->ParentKcb);
1046
1047 /* Sanity checks */
1048 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
1049 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
1050 ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
1051
1052 /* Update the timestamp */
1054 KeyNode->LastWriteTime = TimeStamp;
1055 KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
1056
1057 /* Check if we need to update name maximum */
1058 if (KeyNode->MaxNameLen < Name.Length)
1059 {
1060 /* Do it */
1061 KeyNode->MaxNameLen = Name.Length;
1062 KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length;
1063 }
1064
1065 /* Check if we need to update class length maximum */
1066 if (KeyNode->MaxClassLen < Context->Class.Length)
1067 {
1068 /* Update it */
1069 KeyNode->MaxClassLen = Context->Class.Length;
1070 }
1071
1072 /* Release the cell */
1073 HvReleaseCell(Hive, Cell);
1074 }
1075 else
1076 {
1077 /* Release the link cell */
1078 HvReleaseCell(Hive, LinkCell);
1079 }
1080
1081Exit:
1082 /* Release the flusher locks and return status */
1083 CmpUnlockHiveFlusher((PCMHIVE)Context->ChildHive.KeyHive);
1085 return Status;
1086}
1087
1088VOID
1089NTAPI
1091 IN OUT HCELL_INDEX *Cell,
1092 IN OUT PCM_KEY_NODE *KeyNode,
1093 IN OUT PHHIVE *ReleaseHive,
1094 IN OUT HCELL_INDEX *ReleaseCell)
1095{
1096 /* Check if we have anything to release */
1097 if (*ReleaseCell != HCELL_NIL)
1098 {
1099 /* Release it */
1100 ASSERT(*ReleaseHive != NULL);
1101 HvReleaseCell(*ReleaseHive, *ReleaseCell);
1102 }
1103
1104 /* Get the link references */
1105 *Hive = (*KeyNode)->ChildHiveReference.KeyHive;
1106 *Cell = (*KeyNode)->ChildHiveReference.KeyCell;
1107
1108 /* Get the new node */
1109 *KeyNode = (PCM_KEY_NODE)HvGetCell(*Hive, *Cell);
1110 if (*KeyNode)
1111 {
1112 /* Set the new release values */
1113 *ReleaseCell = *Cell;
1114 *ReleaseHive = *Hive;
1115 }
1116 else
1117 {
1118 /* Nothing to release */
1119 *ReleaseCell = HCELL_NIL;
1120 *ReleaseHive = NULL;
1121 }
1122}
1123
1149static
1150ULONG
1153 _In_ ULONG ConvKey,
1154 _Inout_ PCM_HASH_CACHE_STACK HashCacheStack,
1155 _Out_ PULONG TotalSubKeys)
1156{
1157 ULONG CopyConvKey;
1158 ULONG SubkeysInTotal;
1159 ULONG RemainingSubkeysInTotal;
1160 PWCHAR RemainingNameBuffer;
1161 USHORT RemainingNameLength;
1163
1164 /* Don't compute the hashes on a NULL remaining name */
1165 RemainingNameBuffer = RemainingName->Buffer;
1166 RemainingNameLength = RemainingName->Length;
1167 if (RemainingNameLength == 0)
1168 {
1169 *TotalSubKeys = 0;
1170 return 0;
1171 }
1172
1173 /* Skip any leading separator */
1174 while (RemainingNameLength >= sizeof(WCHAR) &&
1175 *RemainingNameBuffer == OBJ_NAME_PATH_SEPARATOR)
1176 {
1177 RemainingNameBuffer++;
1178 RemainingNameLength -= sizeof(WCHAR);
1179 }
1180
1181 /* Now set up the hash stack entries and compute the hashes */
1182 SubkeysInTotal = 0;
1183 RemainingSubkeysInTotal = 0;
1184 KeyNameLength = 0;
1185 CopyConvKey = ConvKey;
1186 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Buffer = RemainingNameBuffer;
1187 while (RemainingNameLength > 0)
1188 {
1189 /* Is this character a separator? */
1190 if (*RemainingNameBuffer != OBJ_NAME_PATH_SEPARATOR)
1191 {
1192 /* It's not, add it to the hash */
1193 CopyConvKey = COMPUTE_HASH_CHAR(CopyConvKey, *RemainingNameBuffer);
1194
1195 /* Go to the next character (add up the length of the character as well) */
1196 RemainingNameBuffer++;
1197 KeyNameLength += sizeof(WCHAR);
1198 RemainingNameLength -= sizeof(WCHAR);
1199
1200 /*
1201 * We are at the end of the key name path. Take into account
1202 * the last character and if we still have space in the hash
1203 * stack, add it up in the remaining list.
1204 */
1205 if (RemainingNameLength == 0)
1206 {
1207 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1208 {
1209 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Length = KeyNameLength;
1210 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.MaximumLength = KeyNameLength;
1211 HashCacheStack[RemainingSubkeysInTotal].ConvKey = CopyConvKey;
1212 RemainingSubkeysInTotal++;
1213 }
1214
1215 SubkeysInTotal++;
1216 }
1217 }
1218 else
1219 {
1220 /* Skip any leading separator */
1221 while (RemainingNameLength >= sizeof(WCHAR) &&
1222 *RemainingNameBuffer == OBJ_NAME_PATH_SEPARATOR)
1223 {
1224 RemainingNameBuffer++;
1225 RemainingNameLength -= sizeof(WCHAR);
1226 }
1227
1228 /*
1229 * It would be possible that a malformed key pathname may be passed
1230 * to the registry parser such as a path with only separators like
1231 * "\\\\" for example. This would trick the function into believing
1232 * the key path has subkeys albeit that is not the case.
1233 */
1234 ASSERT(RemainingNameLength != 0);
1235
1236 /* Take into account this subkey */
1237 SubkeysInTotal++;
1238
1239 /* And add it up to the hash stack */
1240 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1241 {
1242 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Length = KeyNameLength;
1243 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.MaximumLength = KeyNameLength;
1244 HashCacheStack[RemainingSubkeysInTotal].ConvKey = CopyConvKey;
1245
1246 RemainingSubkeysInTotal++;
1247 KeyNameLength = 0;
1248
1249 /*
1250 * Precaution check -- we have added up a remaining
1251 * subkey above but we must ensure we still have space
1252 * to hold up the new subkey for which we will compute
1253 * the hashes, so that we don't blow up the hash stack.
1254 */
1255 if (RemainingSubkeysInTotal < CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1256 {
1257 HashCacheStack[RemainingSubkeysInTotal].NameOfKey.Buffer = RemainingNameBuffer;
1258 }
1259 }
1260 }
1261 }
1262
1263 *TotalSubKeys = SubkeysInTotal;
1264 return RemainingSubkeysInTotal;
1265}
1266
1292static
1293BOOLEAN
1295 _In_ PCM_HASH_CACHE_STACK HashCacheStack,
1296 _In_ PCM_KEY_CONTROL_BLOCK CurrentKcb,
1297 _In_ ULONG RemainingSubkeys,
1298 _Out_ PCM_KEY_CONTROL_BLOCK *ParentKcb)
1299{
1300 LONG HashStackIndex;
1301 LONG Result;
1302 PCM_NAME_CONTROL_BLOCK NameBlock;
1303 UNICODE_STRING CurrentNameBlock;
1304
1305 ASSERT(CurrentKcb != NULL);
1306
1307 /* Loop each hash and check that they match */
1308 HashStackIndex = RemainingSubkeys;
1309 while (HashStackIndex >= 0)
1310 {
1311 /* Does the subkey hash match? */
1312 if (CurrentKcb->ConvKey != HashCacheStack[HashStackIndex].ConvKey)
1313 {
1314 *ParentKcb = CurrentKcb;
1315 return FALSE;
1316 }
1317
1318 /* Compare the subkey string, is the name compressed? */
1319 NameBlock = CurrentKcb->NameBlock;
1320 if (NameBlock->Compressed)
1321 {
1322 Result = CmpCompareCompressedName(&HashCacheStack[HashStackIndex].NameOfKey,
1323 NameBlock->Name,
1324 NameBlock->NameLength);
1325 }
1326 else
1327 {
1328 CurrentNameBlock.Buffer = NameBlock->Name;
1329 CurrentNameBlock.Length = NameBlock->NameLength;
1330 CurrentNameBlock.MaximumLength = NameBlock->NameLength;
1331
1332 Result = RtlCompareUnicodeString(&HashCacheStack[HashStackIndex].NameOfKey,
1333 &CurrentNameBlock,
1334 TRUE);
1335 }
1336
1337 /* Do the subkey names match? */
1338 if (Result)
1339 {
1340 *ParentKcb = CurrentKcb;
1341 return FALSE;
1342 }
1343
1344 /* Go to the next subkey hash */
1345 HashStackIndex--;
1346 }
1347
1348 /* All the subkeys match */
1349 *ParentKcb = CurrentKcb->ParentKcb;
1350 return TRUE;
1351}
1352
1369static
1370VOID
1372 _In_ PCM_HASH_CACHE_STACK HashCacheStack,
1373 _In_ ULONG RemainingSubkeys,
1375{
1376 ULONG HashStackIndex = 0;
1377
1378 /* Skip any leading separator on matching name */
1379 while (RemainingName->Length >= sizeof(WCHAR) &&
1381 {
1382 RemainingName->Buffer++;
1383 RemainingName->Length -= sizeof(WCHAR);
1384 }
1385
1386 /* Skip the subkeys as well */
1387 while (HashStackIndex <= RemainingSubkeys)
1388 {
1389 RemainingName->Buffer += HashCacheStack[HashStackIndex].NameOfKey.Length / sizeof(WCHAR);
1390 RemainingName->Length -= HashCacheStack[HashStackIndex].NameOfKey.Length;
1391
1392 /* Skip any leading separator */
1393 while (RemainingName->Length >= sizeof(WCHAR) &&
1395 {
1396 RemainingName->Buffer++;
1397 RemainingName->Length -= sizeof(WCHAR);
1398 }
1399
1400 /* Go to the next hash */
1401 HashStackIndex++;
1402 }
1403}
1404
1468static
1471 _In_ PCM_HASH_CACHE_STACK HashCacheStack,
1472 _In_ BOOLEAN LockKcbsExclusive,
1473 _In_ ULONG TotalRemainingSubkeys,
1475 _Inout_ PULONG OuterStackArray,
1477 _Out_ PHHIVE *Hive,
1478 _Out_ PHCELL_INDEX Cell,
1479 _Out_ PULONG MatchRemainSubkeyLevel)
1480{
1481 LONG RemainingSubkeys;
1482 ULONG TotalLevels;
1483 BOOLEAN SubkeysMatch;
1484 PCM_KEY_CONTROL_BLOCK CurrentKcb, ParentKcb;
1486 BOOLEAN KeyFoundInCache = FALSE;
1487 PULONG LockedKcbs = NULL;
1488
1489 /* Reference the KCB */
1490 if (!CmpReferenceKeyControlBlock(*Kcb))
1491 {
1492 /* This key is opened too many times, bail out */
1493 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1494 return STATUS_UNSUCCESSFUL;
1495 }
1496
1497 /* Prepare to lock the KCBs */
1498 LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1500 *Kcb,
1501 OuterStackArray,
1502 TotalRemainingSubkeys,
1503 0);
1504 NT_ASSERT(LockedKcbs);
1505
1506 /* Lookup in the cache */
1507 RemainingSubkeys = TotalRemainingSubkeys - 1;
1508 TotalLevels = TotalRemainingSubkeys + (*Kcb)->TotalLevels + 1;
1509 while (RemainingSubkeys >= 0)
1510 {
1511 /* Get the hash entry from the cache */
1512 HashEntry = GET_HASH_ENTRY(CmpCacheTable, HashCacheStack[RemainingSubkeys].ConvKey)->Entry;
1513
1514 /* Take one level down as we are processing this hash entry */
1515 TotalLevels--;
1516
1517 while (HashEntry != NULL)
1518 {
1519 /* Validate this hash and obtain the current KCB */
1522
1523 /* Does this KCB have matching levels? */
1524 if (TotalLevels == CurrentKcb->TotalLevels)
1525 {
1526 /*
1527 * We have matching subkey levels but don't directly assume we have
1528 * a matching key path in cache. Start comparing each subkey.
1529 */
1530 SubkeysMatch = CmpCompareSubkeys(HashCacheStack,
1531 CurrentKcb,
1532 RemainingSubkeys,
1533 &ParentKcb);
1534 if (SubkeysMatch)
1535 {
1536 /* All subkeys match, now check if the base KCB matches with parent */
1537 if (*Kcb == ParentKcb)
1538 {
1539 /* Is the KCB marked as deleted? */
1540 if (CurrentKcb->Delete ||
1541 CurrentKcb->ParentKcb->Delete)
1542 {
1543 /*
1544 * Either the current or its parent KCB is marked
1545 * but we had a shared lock so probably a naughty
1546 * thread was deleting it. Retry doing a cache
1547 * lookup again with exclusive lock.
1548 */
1549 if (!LockKcbsExclusive)
1550 {
1551 CmpUnLockKcbArray(LockedKcbs);
1553 DPRINT1("The current KCB or its parent is deleted, retrying looking in the cache\n");
1554 return STATUS_RETRY;
1555 }
1556
1557 /* We're under an exclusive lock, is the KCB deleted yet? */
1558 if (CurrentKcb->Delete)
1559 {
1560 /* The KCB is gone, the key should no longer belong in the cache */
1561 CmpRemoveKeyControlBlock(CurrentKcb);
1562 CmpUnLockKcbArray(LockedKcbs);
1564 DPRINT1("The current KCB is deleted (KCB 0x%p)\n", CurrentKcb);
1566 }
1567
1568 /*
1569 * The parent is deleted so it must be that somebody created
1570 * a fake key. Assert ourselves that is the case.
1571 */
1572 ASSERT(CurrentKcb->ExtFlags & CM_KCB_KEY_NON_EXIST);
1573
1574 /* Remove this KCB out of cache if someone still uses it */
1575 if (CurrentKcb->RefCount != 0)
1576 {
1577 CurrentKcb->Delete = TRUE;
1578 CmpRemoveKeyControlBlock(CurrentKcb);
1579 }
1580 else
1581 {
1582 /* Otherwise expunge it */
1583 CmpRemoveFromDelayedClose(CurrentKcb);
1584 CmpCleanUpKcbCacheWithLock(CurrentKcb, FALSE);
1585 }
1586
1587 /* Stop looking for next hashes as the KCB is kaput */
1588 break;
1589 }
1590
1591 /* We finally found the key in cache, acknowledge it */
1592 KeyFoundInCache = TRUE;
1593
1594 /* Remove the subkeys in the remaining name and stop looking in the cache */
1595 CmpRemoveSubkeysInRemainingName(HashCacheStack, RemainingSubkeys, RemainingName);
1596 break;
1597 }
1598 }
1599 }
1600
1601 /* Go to the next hash */
1602 HashEntry = HashEntry->NextHash;
1603 }
1604
1605 /* Stop looking in cache if we found the matching key */
1606 if (KeyFoundInCache)
1607 {
1608 DPRINT("Key found in cache, stop looking\n");
1609 break;
1610 }
1611
1612 /* Keep looking in the cache until we run out of remaining subkeys */
1613 RemainingSubkeys--;
1614 }
1615
1616 /* Return the matching subkey levels */
1617 *MatchRemainSubkeyLevel = RemainingSubkeys + 1;
1618
1619 /* We have to update the KCB if the key was found in cache */
1620 if (KeyFoundInCache)
1621 {
1622 /*
1623 * Reference the new KCB before dropping the locks.
1624 */
1625 if (!CmpReferenceKeyControlBlock(CurrentKcb))
1626 {
1627 /* This key is opened too many times, bail out */
1628 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", CurrentKcb);
1629
1630 /*
1631 * Make sure to unlock the KCBs and release the KCB reference we took
1632 * at the start of the function, so that the caller sees a clean state.
1633 */
1634 CmpUnLockKcbArray(LockedKcbs);
1636 return STATUS_UNSUCCESSFUL;
1637 }
1638
1639 /*
1640 * Dereference the prior KCB that we no longer need
1641 * and switch to the newly referenced one.
1642 */
1643 CmpUnLockKcbArray(LockedKcbs);
1645 *Kcb = CurrentKcb;
1646
1647 /* Update hive and cell data from current KCB */
1648 *Hive = CurrentKcb->KeyHive;
1649 *Cell = CurrentKcb->KeyCell;
1650 return STATUS_SUCCESS;
1651 }
1652
1653 /* Unlock the KCBs */
1654 CmpUnLockKcbArray(LockedKcbs);
1655 return STATUS_SUCCESS;
1656}
1657
1716NTAPI
1718 _In_ PCM_KEY_BODY ParseObject,
1720 _In_ PUNICODE_STRING Current,
1721 _Out_ PHHIVE *Hive,
1722 _Out_ PHCELL_INDEX Cell,
1723 _Out_ PULONG TotalRemainingSubkeys,
1724 _Out_ PULONG MatchRemainSubkeyLevel,
1725 _Out_ PULONG TotalSubkeys,
1726 _Inout_ PULONG OuterStackArray,
1727 _Out_ PULONG *LockedKcbs)
1728{
1730 ULONG ConvKey;
1731 ULONG SubkeysInTotal, RemainingSubkeysInTotal, MatchRemainingSubkeys;
1733
1734 /* Make sure it's not a dead KCB */
1735 ASSERT((*Kcb)->RefCount > 0);
1736
1737 /* Lock the registry */
1739
1740 /* Calculate hash values for every subkey this key path has */
1741 ConvKey = (*Kcb)->ConvKey;
1742 RemainingSubkeysInTotal = CmpComputeHashValue(Current,
1743 ConvKey,
1744 HashCacheStack,
1745 &SubkeysInTotal);
1746
1747 /* This key path has too many subkeys */
1748 if (SubkeysInTotal > CMP_SUBKEY_LEVELS_DEPTH_LIMIT)
1749 {
1750 DPRINT1("The key path has too many subkeys - %lu\n", SubkeysInTotal);
1751 *LockedKcbs = NULL;
1752 return STATUS_NAME_TOO_LONG;
1753 }
1754
1755 /* Return hive and cell data */
1756 *Hive = (*Kcb)->KeyHive;
1757 *Cell = (*Kcb)->KeyCell;
1758
1759 /* Do we have any subkeys? */
1760 if (!RemainingSubkeysInTotal && !SubkeysInTotal)
1761 {
1762 /*
1763 * We don't have any subkeys nor remaining levels, the
1764 * KCB points to the actual key. Lock it.
1765 */
1766 if (!CmpReferenceKeyControlBlock(*Kcb))
1767 {
1768 /* This key is opened too many times, bail out */
1769 DPRINT1("Could not reference the KCB, too many references (KCB 0x%p)\n", Kcb);
1770 return STATUS_UNSUCCESSFUL;
1771 }
1772
1774
1775 /* Add this KCB in the array of locked KCBs */
1776 OuterStackArray[0] = 1;
1777 OuterStackArray[1] = GET_HASH_INDEX(ConvKey);
1778 *LockedKcbs = OuterStackArray;
1779
1780 /* And return all the subkey level counters */
1781 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1782 *MatchRemainSubkeyLevel = 0;
1783 *TotalSubkeys = SubkeysInTotal;
1784 return STATUS_SUCCESS;
1785 }
1786
1787 /* Lookup in the cache */
1788 Status = CmpLookInCache(HashCacheStack,
1789 FALSE,
1790 RemainingSubkeysInTotal,
1791 Current,
1792 OuterStackArray,
1793 Kcb,
1794 Hive,
1795 Cell,
1796 &MatchRemainingSubkeys);
1797 if (!NT_SUCCESS(Status))
1798 {
1799 /* Bail out if cache lookup failed for other reasons */
1800 if (Status != STATUS_RETRY)
1801 {
1802 DPRINT1("CmpLookInCache() failed (Status 0x%lx)\n", Status);
1803 *LockedKcbs = NULL;
1804 return Status;
1805 }
1806
1807 /* Retry looking in the cache but with KCBs locked exclusively */
1808 Status = CmpLookInCache(HashCacheStack,
1809 TRUE,
1810 RemainingSubkeysInTotal,
1811 Current,
1812 OuterStackArray,
1813 Kcb,
1814 Hive,
1815 Cell,
1816 &MatchRemainingSubkeys);
1817 if (!NT_SUCCESS(Status))
1818 {
1819 DPRINT1("CmpLookInCache() failed after retry (Status 0x%lx)\n", Status);
1820 *LockedKcbs = NULL;
1821 return Status;
1822 }
1823 }
1824
1825 /*
1826 * Check if we have a full match of remaining levels.
1827 *
1828 * FIXME: It is possible we can catch a fake key from the cache
1829 * when we did the lookup, in such case we should not do any
1830 * locking as such KCB does not point to any real information.
1831 * Currently ReactOS doesn't create fake KCBs so we are good
1832 * for now.
1833 */
1834 if (RemainingSubkeysInTotal == MatchRemainingSubkeys)
1835 {
1836 /*
1837 * Just simply lock this KCB as it points to the full
1838 * subkey levels in cache.
1839 */
1841 OuterStackArray[0] = 1;
1842 OuterStackArray[1] = GET_HASH_INDEX((*Kcb)->ConvKey);
1843 *LockedKcbs = OuterStackArray;
1844 }
1845 else
1846 {
1847 /*
1848 * We only have a partial match so other subkey levels
1849 * have each KCB. Simply just lock them.
1850 */
1851 *LockedKcbs = CmpBuildAndLockKcbArray(HashCacheStack,
1853 *Kcb,
1854 OuterStackArray,
1855 RemainingSubkeysInTotal,
1856 MatchRemainingSubkeys);
1857 NT_ASSERT(*LockedKcbs);
1858 }
1859
1860 /* Return all the subkey level counters */
1861 *TotalRemainingSubkeys = RemainingSubkeysInTotal;
1862 *MatchRemainSubkeyLevel = MatchRemainingSubkeys;
1863 *TotalSubkeys = SubkeysInTotal;
1864 return Status;
1865}
1866
1868NTAPI
1874 IN OUT PUNICODE_STRING CompleteName,
1878 OUT PVOID *Object)
1879{
1881 PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb;
1882 PHHIVE Hive = NULL;
1884 HCELL_INDEX Cell = HCELL_NIL, NextCell;
1885 PHHIVE HiveToRelease = NULL;
1886 HCELL_INDEX CellToRelease = HCELL_NIL;
1887 UNICODE_STRING Current, NextName;
1888 PCM_PARSE_CONTEXT ParseContext = Context;
1889 ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0;
1890 ULONG LockedKcbArray[CMP_KCBS_IN_ARRAY_LIMIT];
1891 PULONG LockedKcbs;
1892 BOOLEAN IsKeyCached = FALSE;
1893 BOOLEAN Result, Last;
1894 PAGED_CODE();
1895
1896 /* Loop path separators at the end */
1897 while (RemainingName->Length &&
1898 (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] ==
1900 {
1901 /* Remove path separator */
1902 RemainingName->Length -= sizeof(WCHAR);
1903 }
1904
1905 /* Fail if this isn't a key object */
1907
1908 /* Copy the remaining name */
1909 Current = *RemainingName;
1910
1911 /* Check if this is a create */
1912 if (!ParseContext || !ParseContext->CreateOperation)
1913 {
1914 /* It isn't, so no context */
1915 ParseContext = NULL;
1916 }
1917
1918 /* Grab the KCB */
1919 Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
1920
1921 /* Sanity check */
1922 ASSERT(Kcb != NULL);
1923
1924 /* Fail if the key was marked as deleted */
1925 if (Kcb->Delete)
1926 return STATUS_KEY_DELETED;
1927
1928 /* Lookup in the cache */
1930 &Kcb,
1931 &Current,
1932 &Hive,
1933 &Cell,
1934 &TotalRemainingSubkeys,
1935 &MatchRemainSubkeyLevel,
1936 &TotalSubkeys,
1937 LockedKcbArray,
1938 &LockedKcbs);
1940 if (!NT_SUCCESS(Status))
1941 {
1942 DPRINT1("Failed to look in cache, stop parsing (Status 0x%lx)\n", Status);
1943 ParentKcb = NULL;
1944 goto Quickie;
1945 }
1946
1947 /* This is now the parent */
1948 ParentKcb = Kcb;
1949
1950 /* Sanity check */
1951 ASSERT(ParentKcb != NULL);
1952
1953 /* Don't do anything if we're being deleted */
1954 if (Kcb->Delete)
1955 {
1957 goto Quickie;
1958 }
1959
1960 /* Check if everything was found cached */
1961 if (!TotalRemainingSubkeys)
1962 {
1963 /*
1964 * We don't have any remaining subkey levels so we're good
1965 * that we have an already perfect candidate for a KCB, just
1966 * do the open directly.
1967 */
1968 DPRINT("No remaining subkeys, the KCB points to the actual key\n");
1969 IsKeyCached = TRUE;
1970 goto KeyCachedOpenNow;
1971 }
1972
1973 /* Check if we have a matching level */
1974 if (MatchRemainSubkeyLevel)
1975 {
1976 /*
1977 * We have a matching level, check if that matches
1978 * with the total levels of subkeys. Do the open directly
1979 * if that is the case, because the whole subkeys levels
1980 * is cached.
1981 */
1982 if (MatchRemainSubkeyLevel == TotalSubkeys)
1983 {
1984 DPRINT("We have a full matching level, open the key now\n");
1985 IsKeyCached = TRUE;
1986 goto KeyCachedOpenNow;
1987 }
1988
1989 /*
1990 * We only have a partial match, make sure we did not
1991 * get mismatched hive data.
1992 */
1993 ASSERT(Hive == Kcb->KeyHive);
1994 ASSERT(Cell == Kcb->KeyCell);
1995 }
1996
1997 /*
1998 * FIXME: Currently the registry parser doesn't check for fake
1999 * KCBs. CmpCreateKeyControlBlock does have the necessary implementation
2000 * to create such fake keys but we don't create these fake keys anywhere.
2001 * When we will do, we must improve the registry parser routine to handle
2002 * fake keys a bit differently here.
2003 */
2004
2005 /* Check if this is a symlink */
2006 if (Kcb->Flags & KEY_SYM_LINK)
2007 {
2008 /* Get the next name */
2009 Result = CmpGetNextName(&Current, &NextName, &Last);
2010 Current.Buffer = NextName.Buffer;
2011
2012 /* Validate the current name string length */
2013 if (Current.Length + NextName.Length > MAXUSHORT)
2014 {
2015 /* too long */
2017 goto Quickie;
2018 }
2019 Current.Length += NextName.Length;
2020
2021 /* Validate the current name string maximum length */
2022 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2023 {
2024 /* too long */
2026 goto Quickie;
2027 }
2028 Current.MaximumLength += NextName.MaximumLength;
2029
2030 /* CmpGetSymbolicLink doesn't want a lock */
2031 CmpUnLockKcbArray(LockedKcbs);
2032 LockedKcbs = NULL;
2033
2034 /* Parse the symlink */
2035 if (CmpGetSymbolicLink(Hive,
2036 CompleteName,
2037 Kcb,
2038 &Current))
2039 {
2040 /* Symlink parse succeeded */
2042 }
2043 else
2044 {
2045 /* Couldn't find symlink */
2047 }
2048
2049 /* We're done */
2050 goto Quickie;
2051 }
2052
2053 /* Get the key node */
2054 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2055 if (!Node)
2056 {
2058 goto Quickie;
2059 }
2060
2061 /* Start parsing */
2063 while (TRUE)
2064 {
2065 /* Get the next component */
2066 Result = CmpGetNextName(&Current, &NextName, &Last);
2067 if (Result && NextName.Length)
2068 {
2069 /* See if this is a sym link */
2070 if (!(Kcb->Flags & KEY_SYM_LINK))
2071 {
2072 /* Find the subkey */
2073 NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
2074 if (NextCell != HCELL_NIL)
2075 {
2076 /* Get the new node */
2077 Cell = NextCell;
2078 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
2079 ASSERT(Node);
2080
2081 /* Check if this was the last key */
2082 if (Last)
2083 {
2084 /* Is this an exit node */
2085 if (Node->Flags & KEY_HIVE_EXIT)
2086 {
2087 /* Handle it */
2088 CmpHandleExitNode(&Hive,
2089 &Cell,
2090 &Node,
2091 &HiveToRelease,
2092 &CellToRelease);
2093 if (!Node)
2094 {
2095 /* Fail */
2097 break;
2098 }
2099 }
2100
2101KeyCachedOpenNow:
2102 /* Do the open */
2103 Status = CmpDoOpen(Hive,
2104 Cell,
2105 Node,
2107 AccessMode,
2108 Attributes,
2109 ParseContext,
2111 &Kcb,
2112 LockedKcbs,
2113 &NextName,
2114 Object);
2115 if (Status == STATUS_REPARSE)
2116 {
2117 /* CmpGetSymbolicLink doesn't want a lock */
2118 CmpUnLockKcbArray(LockedKcbs);
2119 LockedKcbs = NULL;
2120
2121 /* Parse the symlink */
2122 if (!CmpGetSymbolicLink(Hive,
2123 CompleteName,
2124 Kcb,
2125 NULL))
2126 {
2127 /* Symlink parse failed */
2129 }
2130 }
2131
2132 /* We are done */
2133 break;
2134 }
2135
2136 /* Is this an exit node */
2137 if (Node->Flags & KEY_HIVE_EXIT)
2138 {
2139 /* Handle it */
2140 CmpHandleExitNode(&Hive,
2141 &Cell,
2142 &Node,
2143 &HiveToRelease,
2144 &CellToRelease);
2145 if (!Node)
2146 {
2147 /* Fail */
2149 break;
2150 }
2151 }
2152
2153 /* Create a KCB for this key */
2154 Kcb = CmpCreateKeyControlBlock(Hive,
2155 Cell,
2156 Node,
2157 ParentKcb,
2159 &NextName);
2160 if (!Kcb)
2161 {
2162 /* Fail */
2164 break;
2165 }
2166
2167 /* Dereference the parent and set the new one */
2169 ParentKcb = Kcb;
2170 }
2171 else
2172 {
2173 /* Check if this was the last key for a create */
2174 if (Last && ParseContext)
2175 {
2176 /* Check if we're doing a link node */
2177 if (ParseContext->CreateLink)
2178 {
2179 /* The only thing we should see */
2181 Cell,
2183 NextName,
2184 AccessMode,
2185 Attributes,
2186 ParseContext,
2187 ParentKcb,
2188 LockedKcbs,
2189 Object);
2190 }
2191 else if (Hive == &CmiVolatileHive->Hive && CmpNoVolatileCreates)
2192 {
2193 /* Creating keys in the master hive is not allowed */
2195 }
2196 else
2197 {
2198 /* Do the create */
2199 Status = CmpDoCreate(Hive,
2200 Cell,
2202 &NextName,
2203 AccessMode,
2204 ParseContext,
2205 ParentKcb,
2206 Object);
2207 }
2208
2209 /* Check for reparse (in this case, someone beat us) */
2210 if (Status == STATUS_REPARSE) break;
2211
2212 /* Update disposition */
2213 ParseContext->Disposition = REG_CREATED_NEW_KEY;
2214 break;
2215 }
2216 else
2217 {
2218 /* Key not found */
2220 break;
2221 }
2222 }
2223 }
2224 else
2225 {
2226 /* Save the next name */
2227 Current.Buffer = NextName.Buffer;
2228
2229 /* Validate the current name string length */
2230 if (Current.Length + NextName.Length > MAXUSHORT)
2231 {
2232 /* too long */
2234 break;
2235 }
2236 Current.Length += NextName.Length;
2237
2238 /* Validate the current name string maximum length */
2239 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
2240 {
2241 /* too long */
2243 break;
2244 }
2245 Current.MaximumLength += NextName.MaximumLength;
2246
2247 /* CmpGetSymbolicLink doesn't want a lock */
2248 CmpUnLockKcbArray(LockedKcbs);
2249 LockedKcbs = NULL;
2250
2251 /* Parse the symlink */
2252 if (CmpGetSymbolicLink(Hive,
2253 CompleteName,
2254 Kcb,
2255 &Current))
2256 {
2257 /* Symlink parse succeeded */
2259 }
2260 else
2261 {
2262 /* Couldn't find symlink */
2264 }
2265
2266 /* We're done */
2267 break;
2268 }
2269 }
2270 else if (Result && Last)
2271 {
2272 /* Opening the root. Is this an exit node? */
2273 if (Node->Flags & KEY_HIVE_EXIT)
2274 {
2275 /* Handle it */
2276 CmpHandleExitNode(&Hive,
2277 &Cell,
2278 &Node,
2279 &HiveToRelease,
2280 &CellToRelease);
2281 if (!Node)
2282 {
2283 /* Fail */
2285 break;
2286 }
2287 }
2288
2289 /* Do the open */
2290 Status = CmpDoOpen(Hive,
2291 Cell,
2292 Node,
2294 AccessMode,
2295 Attributes,
2296 ParseContext,
2298 &Kcb,
2299 LockedKcbs,
2300 &NextName,
2301 Object);
2302 if (Status == STATUS_REPARSE)
2303 {
2304 /* Nothing to do */
2305 }
2306
2307 /* We're done */
2308 break;
2309 }
2310 else
2311 {
2312 /* Bogus */
2314 break;
2315 }
2316 }
2317
2318Quickie:
2319 /* Unlock all the KCBs */
2320 if (LockedKcbs != NULL)
2321 {
2322 CmpUnLockKcbArray(LockedKcbs);
2323 }
2324
2325 /* Dereference the parent if it exists */
2326 if (ParentKcb)
2328
2329 /* Unlock the registry */
2331 return Status;
2332}
#define PAGED_CODE()
#define CmpKeyObjectType
Definition: ObTypes.cpp:179
unsigned char BOOLEAN
Definition: actypes.h:127
#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:41
#define GET_HASH_ENTRY(Table, ConvKey)
Definition: cm_x.h:39
FORCEINLINE VOID CmpAcquireKcbLockExclusiveByIndex(ULONG Index)
Definition: cm_x.h:118
#define GET_HASH_INDEX(ConvKey)
Definition: cm_x.h:37
#define CMP_ASSERT_REGISTRY_LOCK()
Definition: cm_x.h:65
#define CmpIsKcbLockedExclusive(k)
Definition: cm_x.h:101
#define CMP_ASSERT_KCB_LOCK(k)
Definition: cm_x.h:278
#define COMPUTE_HASH_CHAR(ConvKey, Char)
Definition: cm_x.h:31
#define CmpAcquireKcbLockSharedByIndex(i)
Definition: cm_x.h:108
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:460
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:457
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:1717
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:1470
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:1151
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:1869
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:1294
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:840
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:1371
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:1090
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:2081
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1995
VOID NTAPI CmpLockHiveFlusherShared(IN PCMHIVE Hive)
Definition: cmsysini.c:2042
BOOLEAN CmpNoVolatileCreates
Definition: cmsysini.c:34
PCMHIVE CmiVolatileHive
Definition: cmsysini.c:16
VOID NTAPI CmpUnlockHiveFlusher(IN PCMHIVE Hive)
Definition: cmsysini.c:2053
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
#define STATUS_OBJECT_TYPE_MISMATCH
Definition: d3dkmdt.h:46
LPWSTR Name
Definition: desk.c:124
#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:33
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:24
#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 ASSERT(a)
Definition: mode.c:44
ObjectType
Definition: metafile.c:88
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
#define REG_OPTION_CREATE_LINK
Definition: nt_native.h:1066
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1087
#define REG_LINK
Definition: nt_native.h:1503
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1088
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1063
#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:136
#define STATUS_KEY_DELETED
Definition: ntstatus.h:707
#define STATUS_CHILD_MUST_BE_VOLATILE
Definition: ntstatus.h:712
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:592
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:1040
VOID NTAPI ObDereferenceObjectDeferDelete(IN PVOID Object)
Definition: obref.c:357
short WCHAR
Definition: pedump.c:58
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
SECURITY_INTEGER TimeStamp
Definition: sspi.h:78
#define OBJ_OPENLINK
Definition: winternl.h:230
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
static void Exit(void)
Definition: sock.c:1330
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
_In_ PVOID Context
Definition: storport.h:2269
Definition: hash.c:61
struct _CM_KEY_CONTROL_BLOCK * RealKcb
Definition: cm.h:218
union _CELL_DATA::@4795 u
WCHAR KeyString[ANYSIZE_ARRAY]
Definition: cmdata.h:206
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:236
HANDLE ProcessID
Definition: cm.h:239
BOOLEAN KcbLocked
Definition: cm.h:243
struct _CM_NOTIFY_BLOCK * NotifyBlock
Definition: cm.h:238
struct _CM_KEY_CONTROL_BLOCK * KeyControlBlock
Definition: cm.h:237
ULONG TotalLevels
Definition: cm.h:279
ULONG RefCount
Definition: cm.h:272
PHHIVE KeyHive
Definition: cm.h:288
struct _CM_KEY_CONTROL_BLOCK * ParentKcb
Definition: cm.h:292
ULONG ExtFlags
Definition: cm.h:275
HCELL_INDEX KeyCell
Definition: cm.h:289
CACHED_CHILD_LIST ValueCache
Definition: cm.h:295
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:251
USHORT NameLength
Definition: cm.h:260
WCHAR Name[ANYSIZE_ARRAY]
Definition: cm.h:261
ULONG Disposition
Definition: cm.h:440
BOOLEAN CreateLink
Definition: cm.h:443
BOOLEAN CreateOperation
Definition: cm.h:444
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:2705
_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:3327
_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