xref: /reactos/ntoskrnl/config/cmparse.c (revision 7eead935)
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 
19 BOOLEAN
20 NTAPI
21 CmpGetNextName(IN OUT PUNICODE_STRING RemainingName,
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) &&
43            (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR))
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) &&
54            (*RemainingName->Buffer != OBJ_NAME_PATH_SEPARATOR))
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 
73 BOOLEAN
74 NTAPI
75 CmpGetSymbolicLink(IN PHHIVE Hive,
76                    IN OUT PUNICODE_STRING ObjectName,
77                    IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb,
78                    IN PUNICODE_STRING RemainingName OPTIONAL)
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;
86     ULONG ValueLength = 0;
87     BOOLEAN Result = FALSE;
88     HCELL_INDEX CellToRelease = HCELL_NIL;
89     PCM_KEY_NODE Node;
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 */
100     LinkCell = CmpFindValueByName(Hive, Node, &CmSymbolicLinkValueName);
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,
114                          &ValueLength,
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 */
139         NewBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
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);
154             RtlAppendUnicodeStringToString(&NewObjectName, RemainingName);
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 */
173             ObjectName->Buffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
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 
185 Exit:
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 
202 NTSTATUS
203 NTAPI
204 CmpDoCreateChild(IN PHHIVE Hive,
205                  IN HCELL_INDEX ParentCell,
206                  IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
207                  IN PACCESS_STATE AccessState,
208                  IN PUNICODE_STRING Name,
209                  IN KPROCESSOR_MODE AccessMode,
210                  IN PCM_PARSE_CONTEXT ParseContext,
211                  IN PCM_KEY_CONTROL_BLOCK ParentKcb,
212                  IN ULONG Flags,
213                  OUT PHCELL_INDEX KeyCell,
214                  OUT PVOID *Object)
215 {
216     NTSTATUS Status = STATUS_SUCCESS;
217     PCM_KEY_BODY KeyBody;
218     HCELL_INDEX ClassCell = HCELL_NIL;
219     PCM_KEY_NODE KeyNode;
220     PCELL_DATA CellData;
221     ULONG StorageType;
222     PCM_KEY_CONTROL_BLOCK Kcb;
223     PSECURITY_DESCRIPTOR NewDescriptor;
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,
231                               FIELD_OFFSET(CM_KEY_NODE, Name) +
232                               CmpNameSize(Hive, Name),
233                               StorageType,
234                               HCELL_NIL);
235     if (*KeyCell == HCELL_NIL)
236     {
237         /* Fail */
238         Status = STATUS_INSUFFICIENT_RESOURCES;
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);
248         Status = STATUS_INSUFFICIENT_RESOURCES;
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 */
266             Status = STATUS_INSUFFICIENT_RESOURCES;
267             goto Quickie;
268         }
269     }
270 
271     /* Allocate the Cm Object */
272     Status = ObCreateObject(AccessMode,
273                             CmpKeyObjectType,
274                             NULL,
275                             AccessMode,
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 
288     /* Check if we had a class */
289     if (ParseContext->Class.Length > 0)
290     {
291         /* Get the class cell */
292         CellData = HvGetCell(Hive, ClassCell);
293         if (!CellData)
294         {
295             /* Fail, this should never happen */
296             ASSERT(FALSE);
297             Status = STATUS_INSUFFICIENT_RESOURCES;
298             ObDereferenceObject(*Object);
299             goto Quickie;
300         }
301 
302         /* Release the cell */
303         HvReleaseCell(Hive, ClassCell);
304 
305         /* Copy the class data */
306         RtlCopyMemory(&CellData->u.KeyString[0],
307                       ParseContext->Class.Buffer,
308                       ParseContext->Class.Length);
309     }
310 
311     /* Fill out the key node */
312     KeyNode->Signature = CM_KEY_NODE_SIGNATURE;
313     KeyNode->Flags = Flags;
314     KeQuerySystemTime(&KeyNode->LastWriteTime);
315     KeyNode->Spare = 0;
316     KeyNode->Parent = ParentCell;
317     KeyNode->SubKeyCounts[Stable] = 0;
318     KeyNode->SubKeyCounts[Volatile] = 0;
319     KeyNode->SubKeyLists[Stable] = HCELL_NIL;
320     KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
321     KeyNode->ValueList.Count = 0;
322     KeyNode->ValueList.List = HCELL_NIL;
323     KeyNode->Security = HCELL_NIL;
324     KeyNode->Class = ClassCell;
325     KeyNode->ClassLength = ParseContext->Class.Length;
326     KeyNode->MaxValueDataLen = 0;
327     KeyNode->MaxNameLen = 0;
328     KeyNode->MaxValueNameLen = 0;
329     KeyNode->MaxClassLen = 0;
330     KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, Name);
331     if (KeyNode->NameLength < Name->Length) KeyNode->Flags |= KEY_COMP_NAME;
332 
333     /* Create the KCB */
334     Kcb = CmpCreateKeyControlBlock(Hive,
335                                    *KeyCell,
336                                    KeyNode,
337                                    ParentKcb,
338                                    0, // CMP_LOCK_HASHES_FOR_KCB,
339                                    Name);
340     if (!Kcb)
341     {
342         /* Fail */
343         ObDereferenceObjectDeferDelete(*Object);
344         Status = STATUS_INSUFFICIENT_RESOURCES;
345         goto Quickie;
346     }
347 
348     /* Sanity check */
349     ASSERT(Kcb->RefCount == 1);
350 
351     /* Now fill out the Cm object */
352     KeyBody->NotifyBlock = NULL;
353     KeyBody->ProcessID = PsGetCurrentProcessId();
354     KeyBody->KeyControlBlock = Kcb;
355 
356     /* Link it with the KCB */
357     EnlistKeyBodyWithKCB(KeyBody, 0);
358 
359     /* Assign security */
360     Status = SeAssignSecurity(ParentDescriptor,
361                               AccessState->SecurityDescriptor,
362                               &NewDescriptor,
363                               TRUE,
364                               &AccessState->SubjectSecurityContext,
365                               &CmpKeyObjectType->TypeInfo.GenericMapping,
366                               CmpKeyObjectType->TypeInfo.PoolType);
367     if (NT_SUCCESS(Status))
368     {
369         Status = CmpSecurityMethod(*Object,
370                                    AssignSecurityDescriptor,
371                                    NULL,
372                                    NewDescriptor,
373                                    NULL,
374                                    NULL,
375                                    CmpKeyObjectType->TypeInfo.PoolType,
376                                    &CmpKeyObjectType->TypeInfo.GenericMapping);
377     }
378 
379     /* Now that the security descriptor is copied in the hive, we can free the original */
380     SeDeassignSecurity(&NewDescriptor);
381 
382 Quickie:
383     /* Check if we got here because of failure */
384     if (!NT_SUCCESS(Status))
385     {
386         /* Free any cells we might've allocated */
387         if (ParseContext->Class.Length > 0) HvFreeCell(Hive, ClassCell);
388         HvFreeCell(Hive, *KeyCell);
389     }
390 
391     /* Return status */
392     return Status;
393 }
394 
395 NTSTATUS
396 NTAPI
397 CmpDoCreate(IN PHHIVE Hive,
398             IN HCELL_INDEX Cell,
399             IN PACCESS_STATE AccessState,
400             IN PUNICODE_STRING Name,
401             IN KPROCESSOR_MODE AccessMode,
402             IN PCM_PARSE_CONTEXT ParseContext,
403             IN PCM_KEY_CONTROL_BLOCK ParentKcb,
404             OUT PVOID *Object)
405 {
406     NTSTATUS Status;
407     PCELL_DATA CellData;
408     HCELL_INDEX KeyCell;
409     ULONG ParentType;
410     PCM_KEY_BODY KeyBody;
411     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
412     LARGE_INTEGER TimeStamp;
413     PCM_KEY_NODE KeyNode;
414 
415     /* Check if the parent is being deleted */
416     if (ParentKcb->Delete)
417     {
418         /* It has, quit */
419         ASSERT(FALSE);
420         Status = STATUS_OBJECT_NAME_NOT_FOUND;
421         goto Exit;
422     }
423 
424     /* Get the parent node */
425     KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
426     if (!KeyNode)
427     {
428         /* Fail */
429         ASSERT(FALSE);
430         Status = STATUS_INSUFFICIENT_RESOURCES;
431         goto Exit;
432     }
433 
434     /* Make sure nobody added us yet */
435     if (CmpFindSubKeyByName(Hive, KeyNode, Name) != HCELL_NIL)
436     {
437         /* Fail */
438         ASSERT(FALSE);
439         Status = STATUS_REPARSE;
440         goto Exit;
441     }
442 
443     /* Sanity check */
444     ASSERT(Cell == ParentKcb->KeyCell);
445 
446     /* Get the parent type */
447     ParentType = HvGetCellType(Cell);
448     if ((ParentType == Volatile) &&
449         !(ParseContext->CreateOptions & REG_OPTION_VOLATILE))
450     {
451         /* Children of volatile parents must also be volatile */
452         //ASSERT(FALSE);
453         Status = STATUS_CHILD_MUST_BE_VOLATILE;
454         goto Exit;
455     }
456 
457     /* Don't allow children under symlinks */
458     if (ParentKcb->Flags & KEY_SYM_LINK)
459     {
460         /* Fail */
461         ASSERT(FALSE);
462         Status = STATUS_ACCESS_DENIED;
463         goto Exit;
464     }
465 
466     /* Make the cell dirty for now */
467     HvMarkCellDirty(Hive, Cell, FALSE);
468 
469     /* Do the actual create operation */
470     Status = CmpDoCreateChild(Hive,
471                               Cell,
472                               SecurityDescriptor,
473                               AccessState,
474                               Name,
475                               AccessMode,
476                               ParseContext,
477                               ParentKcb,
478                               0,
479                               &KeyCell,
480                               Object);
481     if (NT_SUCCESS(Status))
482     {
483         /* Get the key body */
484         KeyBody = (PCM_KEY_BODY)(*Object);
485 
486         /* Now add the subkey */
487         if (!CmpAddSubKey(Hive, Cell, KeyCell))
488         {
489             /* Failure! We don't handle this yet! */
490             ASSERT(FALSE);
491         }
492 
493         /* Get the key node */
494         KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
495         if (!KeyNode)
496         {
497             /* Fail, this shouldn't happen */
498             ASSERT(FALSE);
499         }
500 
501         /* Sanity checks */
502         ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
503         ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
504         ASSERT(KeyBody->KeyControlBlock->ParentKcb == ParentKcb);
505         ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
506 
507         /* Update the timestamp */
508         KeQuerySystemTime(&TimeStamp);
509         KeyNode->LastWriteTime = TimeStamp;
510         KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
511 
512         /* Check if we need to update name maximum */
513         if (KeyNode->MaxNameLen < Name->Length)
514         {
515             /* Do it */
516             KeyNode->MaxNameLen = Name->Length;
517             KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name->Length;
518         }
519 
520         /* Check if we need to update class length maximum */
521         if (KeyNode->MaxClassLen < ParseContext->Class.Length)
522         {
523             /* Update it */
524             KeyNode->MaxClassLen = ParseContext->Class.Length;
525         }
526 
527         /* Check if we're creating a symbolic link */
528         if (ParseContext->CreateOptions & REG_OPTION_CREATE_LINK)
529         {
530             /* Get the cell data */
531             CellData = HvGetCell(Hive, KeyCell);
532             if (!CellData)
533             {
534                 /* This shouldn't happen */
535                 ASSERT(FALSE);
536             }
537 
538             /* Update the flags */
539             CellData->u.KeyNode.Flags |= KEY_SYM_LINK;
540             KeyBody->KeyControlBlock->Flags = CellData->u.KeyNode.Flags;
541             HvReleaseCell(Hive, KeyCell);
542         }
543     }
544 
545 Exit:
546     /* Release the flusher lock and return status */
547     return Status;
548 }
549 
550 NTSTATUS
551 NTAPI
552 CmpDoOpen(IN PHHIVE Hive,
553           IN HCELL_INDEX Cell,
554           IN PCM_KEY_NODE Node,
555           IN PACCESS_STATE AccessState,
556           IN KPROCESSOR_MODE AccessMode,
557           IN ULONG Attributes,
558           IN PCM_PARSE_CONTEXT Context OPTIONAL,
559           IN ULONG ControlFlags,
560           IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb,
561           IN PUNICODE_STRING KeyName,
562           OUT PVOID *Object)
563 {
564     NTSTATUS Status;
565     PCM_KEY_BODY KeyBody = NULL;
566     PCM_KEY_CONTROL_BLOCK Kcb = NULL;
567 
568     /* Make sure the hive isn't locked */
569     if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&
570         (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))
571     {
572         /* It is, don't touch it */
573         return STATUS_OBJECT_NAME_NOT_FOUND;
574     }
575 
576     /* Check if we have a context */
577     if (Context)
578     {
579         /* Check if this is a link create (which shouldn't be an open) */
580         if (Context->CreateLink)
581         {
582             return STATUS_ACCESS_DENIED;
583         }
584 
585         /* Check if this is symlink create attempt */
586         if (Context->CreateOptions & REG_OPTION_CREATE_LINK)
587         {
588             /* Key already exists */
589             return STATUS_OBJECT_NAME_COLLISION;
590         }
591 
592         /* Set the disposition */
593         Context->Disposition = REG_OPENED_EXISTING_KEY;
594     }
595 
596     /* Do this in the registry lock */
597     CmpLockRegistry();
598 
599     /* If we have a KCB, make sure it's locked */
600     //ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
601 
602     /* Check if caller doesn't want to create a KCB */
603     if (ControlFlags & CMP_OPEN_KCB_NO_CREATE)
604     {
605         /* Check if this is a symlink */
606         if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
607         {
608             /* This case for a cached KCB is not implemented yet */
609             ASSERT(FALSE);
610         }
611 
612         /* The caller wants to open a cached KCB */
613         if (!CmpReferenceKeyControlBlock(*CachedKcb))
614         {
615             /* Release the registry lock */
616             CmpUnlockRegistry();
617 
618             /* Return failure code */
619             return STATUS_INSUFFICIENT_RESOURCES;
620         }
621 
622         /* Our kcb is that one */
623         Kcb = *CachedKcb;
624     }
625     else
626     {
627         /* Check if this is a symlink */
628         if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK))
629         {
630             /* Create the KCB for the symlink */
631             Kcb = CmpCreateKeyControlBlock(Hive,
632                                            Cell,
633                                            Node,
634                                            *CachedKcb,
635                                            0,
636                                            KeyName);
637             if (!Kcb)
638             {
639                 /* Release registry lock and return failure */
640                 CmpUnlockRegistry();
641                 return STATUS_INSUFFICIENT_RESOURCES;
642             }
643 
644             /* Make sure it's also locked, and set the pointer */
645             //ASSERT(CmpIsKcbLockedExclusive(Kcb));
646             *CachedKcb = Kcb;
647 
648             /* Release the registry lock */
649             CmpUnlockRegistry();
650 
651             /* Return reparse required */
652             return STATUS_REPARSE;
653         }
654 
655         /* Create the KCB. FIXME: Use lock flag */
656         Kcb = CmpCreateKeyControlBlock(Hive,
657                                        Cell,
658                                        Node,
659                                        *CachedKcb,
660                                        0,
661                                        KeyName);
662         if (!Kcb)
663         {
664             /* Release registry lock and return failure */
665             CmpUnlockRegistry();
666             return STATUS_INSUFFICIENT_RESOURCES;
667         }
668     }
669 
670     /* Make sure it's also locked, and set the pointer */
671     //ASSERT(CmpIsKcbLockedExclusive(Kcb));
672     *CachedKcb = Kcb;
673 
674     /* Release the registry lock */
675     CmpUnlockRegistry();
676 
677     /* Allocate the key object */
678     Status = ObCreateObject(AccessMode,
679                             CmpKeyObjectType,
680                             NULL,
681                             AccessMode,
682                             NULL,
683                             sizeof(CM_KEY_BODY),
684                             0,
685                             0,
686                             Object);
687     if (NT_SUCCESS(Status))
688     {
689         /* Get the key body and fill it out */
690         KeyBody = (PCM_KEY_BODY)(*Object);
691         KeyBody->KeyControlBlock = Kcb;
692         KeyBody->Type = CM_KEY_BODY_TYPE;
693         KeyBody->ProcessID = PsGetCurrentProcessId();
694         KeyBody->NotifyBlock = NULL;
695 
696         /* Link to the KCB */
697         EnlistKeyBodyWithKCB(KeyBody, 0);
698 
699         if (!ObCheckObjectAccess(*Object,
700                                  AccessState,
701                                  FALSE,
702                                  AccessMode,
703                                  &Status))
704         {
705             /* Access check failed */
706             ObDereferenceObject(*Object);
707         }
708     }
709     else
710     {
711         /* Failed, dereference the KCB */
712         CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE);
713     }
714 
715     /* Return status */
716     return Status;
717 }
718 
719 NTSTATUS
720 NTAPI
721 CmpCreateLinkNode(IN PHHIVE Hive,
722                   IN HCELL_INDEX Cell,
723                   IN PACCESS_STATE AccessState,
724                   IN UNICODE_STRING Name,
725                   IN KPROCESSOR_MODE AccessMode,
726                   IN ULONG CreateOptions,
727                   IN PCM_PARSE_CONTEXT Context,
728                   IN PCM_KEY_CONTROL_BLOCK ParentKcb,
729                   OUT PVOID *Object)
730 {
731     NTSTATUS Status;
732     HCELL_INDEX KeyCell, LinkCell, ChildCell;
733     PCM_KEY_BODY KeyBody;
734     LARGE_INTEGER TimeStamp;
735     PCM_KEY_NODE KeyNode;
736     PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb;
737 
738     /* Link nodes only allowed on the master */
739     if (Hive != &CmiVolatileHive->Hive)
740     {
741         /* Fail */
742         DPRINT1("Invalid link node attempt\n");
743         return STATUS_ACCESS_DENIED;
744     }
745 
746     /* Check if the parent is being deleted */
747     if (ParentKcb->Delete)
748     {
749         /* It is, quit */
750         ASSERT(FALSE);
751         Status = STATUS_OBJECT_NAME_NOT_FOUND;
752         goto Exit;
753     }
754 
755     /* Allocate a link node */
756     LinkCell = HvAllocateCell(Hive,
757                               FIELD_OFFSET(CM_KEY_NODE, Name) +
758                               CmpNameSize(Hive, &Name),
759                               Stable,
760                               HCELL_NIL);
761     if (LinkCell == HCELL_NIL)
762     {
763         /* Fail */
764         Status = STATUS_INSUFFICIENT_RESOURCES;
765         goto Exit;
766     }
767 
768     /* Get the key cell */
769     KeyCell = Context->ChildHive.KeyCell;
770     if (KeyCell != HCELL_NIL)
771     {
772         /* Hive exists! */
773         ChildCell = KeyCell;
774 
775         /* Get the node data */
776         KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);
777         if (!KeyNode)
778         {
779             /* Fail */
780             ASSERT(FALSE);
781             Status = STATUS_INSUFFICIENT_RESOURCES;
782             goto Exit;
783         }
784 
785         /* Fill out the data */
786         KeyNode->Parent = LinkCell;
787         KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
788         HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
789 
790         /* Now open the key cell */
791         KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell);
792         if (!KeyNode)
793         {
794             /* Fail */
795             ASSERT(FALSE);
796             Status = STATUS_INSUFFICIENT_RESOURCES;
797             goto Exit;
798         }
799 
800         /* Open the parent */
801         Status = CmpDoOpen(Context->ChildHive.KeyHive,
802                            KeyCell,
803                            KeyNode,
804                            AccessState,
805                            AccessMode,
806                            CreateOptions,
807                            NULL,
808                            0,
809                            &Kcb,
810                            &Name,
811                            Object);
812         HvReleaseCell(Context->ChildHive.KeyHive, KeyCell);
813     }
814     else
815     {
816         /* Do the actual create operation */
817         Status = CmpDoCreateChild(Context->ChildHive.KeyHive,
818                                   Cell,
819                                   NULL,
820                                   AccessState,
821                                   &Name,
822                                   AccessMode,
823                                   Context,
824                                   ParentKcb,
825                                   KEY_HIVE_ENTRY | KEY_NO_DELETE,
826                                   &ChildCell,
827                                   Object);
828         if (NT_SUCCESS(Status))
829         {
830             /* Setup root pointer */
831             Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;
832         }
833     }
834 
835     /* Check if open or create suceeded */
836     if (NT_SUCCESS(Status))
837     {
838         /* Mark the cell dirty */
839         HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE);
840 
841         /* Get the key node */
842         KeyNode = HvGetCell(Context->ChildHive.KeyHive, ChildCell);
843         if (!KeyNode)
844         {
845             /* Fail */
846             ASSERT(FALSE);
847             Status = STATUS_INSUFFICIENT_RESOURCES;
848             goto Exit;
849         }
850 
851         /* Release it */
852         HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
853 
854         /* Set the parent and flags */
855         KeyNode->Parent = LinkCell;
856         KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
857 
858         /* Get the link node */
859         KeyNode = HvGetCell(Hive, LinkCell);
860         if (!KeyNode)
861         {
862             /* Fail */
863             ASSERT(FALSE);
864             Status = STATUS_INSUFFICIENT_RESOURCES;
865             goto Exit;
866         }
867 
868         /* Set it up */
869         KeyNode->Signature = CM_LINK_NODE_SIGNATURE;
870         KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;
871         KeyNode->Parent = Cell;
872         KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name);
873         if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME;
874         KeQuerySystemTime(&TimeStamp);
875         KeyNode->LastWriteTime = TimeStamp;
876 
877         /* Clear out the rest */
878         KeyNode->SubKeyCounts[Stable] = 0;
879         KeyNode->SubKeyCounts[Volatile] = 0;
880         KeyNode->SubKeyLists[Stable] = HCELL_NIL;
881         KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
882         KeyNode->ValueList.Count = 0;
883         KeyNode->ValueList.List = HCELL_NIL;
884         KeyNode->ClassLength = 0;
885 
886         /* Reference the root node */
887         KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;
888         KeyNode->ChildHiveReference.KeyCell = ChildCell;
889         HvReleaseCell(Hive, LinkCell);
890 
891         /* Get the parent node */
892         KeyNode = HvGetCell(Hive, Cell);
893         if (!KeyNode)
894         {
895             /* Fail */
896             ASSERT(FALSE);
897             Status = STATUS_INSUFFICIENT_RESOURCES;
898             goto Exit;
899         }
900 
901         /* Now add the subkey */
902         if (!CmpAddSubKey(Hive, Cell, LinkCell))
903         {
904             /* Failure! We don't handle this yet! */
905             ASSERT(FALSE);
906         }
907 
908         /* Get the key body */
909         KeyBody = (PCM_KEY_BODY)*Object;
910 
911         /* Sanity checks */
912         ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);
913         ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);
914         ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);
915 
916         /* Update the timestamp */
917         KeQuerySystemTime(&TimeStamp);
918         KeyNode->LastWriteTime = TimeStamp;
919         KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
920 
921         /* Check if we need to update name maximum */
922         if (KeyNode->MaxNameLen < Name.Length)
923         {
924             /* Do it */
925             KeyNode->MaxNameLen = Name.Length;
926             KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length;
927         }
928 
929         /* Check if we need to update class length maximum */
930         if (KeyNode->MaxClassLen < Context->Class.Length)
931         {
932             /* Update it */
933             KeyNode->MaxClassLen = Context->Class.Length;
934         }
935 
936         /* Release the cell */
937         HvReleaseCell(Hive, Cell);
938     }
939     else
940     {
941         /* Release the link cell */
942         HvReleaseCell(Hive, LinkCell);
943     }
944 
945 Exit:
946     /* Release the flusher locks and return status */
947     return Status;
948 }
949 
950 VOID
951 NTAPI
952 CmpHandleExitNode(IN OUT PHHIVE *Hive,
953                   IN OUT HCELL_INDEX *Cell,
954                   IN OUT PCM_KEY_NODE *KeyNode,
955                   IN OUT PHHIVE *ReleaseHive,
956                   IN OUT HCELL_INDEX *ReleaseCell)
957 {
958     /* Check if we have anything to release */
959     if (*ReleaseCell != HCELL_NIL)
960     {
961         /* Release it */
962         ASSERT(*ReleaseHive != NULL);
963         HvReleaseCell(*ReleaseHive, *ReleaseCell);
964     }
965 
966     /* Get the link references */
967     *Hive = (*KeyNode)->ChildHiveReference.KeyHive;
968     *Cell = (*KeyNode)->ChildHiveReference.KeyCell;
969 
970     /* Get the new node */
971     *KeyNode = (PCM_KEY_NODE)HvGetCell(*Hive, *Cell);
972     if (*KeyNode)
973     {
974         /* Set the new release values */
975         *ReleaseCell = *Cell;
976         *ReleaseHive = *Hive;
977     }
978     else
979     {
980         /* Nothing to release */
981         *ReleaseCell = HCELL_NIL;
982         *ReleaseHive = NULL;
983     }
984 }
985 
986 NTSTATUS
987 NTAPI
988 CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject,
989                                 IN OUT PCM_KEY_CONTROL_BLOCK *Kcb,
990                                 IN PUNICODE_STRING Current,
991                                 OUT PHHIVE *Hive,
992                                 OUT HCELL_INDEX *Cell,
993                                 OUT PULONG TotalRemainingSubkeys,
994                                 OUT PULONG MatchRemainSubkeyLevel,
995                                 OUT PULONG TotalSubkeys,
996                                 OUT PULONG OuterStackArray,
997                                 OUT PULONG *LockedKcbs)
998 {
999     /* We don't lock anything for now */
1000     *LockedKcbs = NULL;
1001 
1002     /* Calculate hash values */
1003     *TotalRemainingSubkeys = 0xBAADF00D;
1004 
1005     /* Lock the registry */
1006     CmpLockRegistry();
1007 
1008     /* Return hive and cell data */
1009     *Hive = (*Kcb)->KeyHive;
1010     *Cell = (*Kcb)->KeyCell;
1011 
1012     /* Make sure it's not a dead KCB */
1013     ASSERT((*Kcb)->RefCount > 0);
1014 
1015     /* Reference it */
1016     (VOID)CmpReferenceKeyControlBlock(*Kcb);
1017 
1018     /* Return success for now */
1019     return STATUS_SUCCESS;
1020 }
1021 
1022 NTSTATUS
1023 NTAPI
1024 CmpParseKey(IN PVOID ParseObject,
1025             IN PVOID ObjectType,
1026             IN OUT PACCESS_STATE AccessState,
1027             IN KPROCESSOR_MODE AccessMode,
1028             IN ULONG Attributes,
1029             IN OUT PUNICODE_STRING CompleteName,
1030             IN OUT PUNICODE_STRING RemainingName,
1031             IN OUT PVOID Context OPTIONAL,
1032             IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
1033             OUT PVOID *Object)
1034 {
1035     NTSTATUS Status;
1036     PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb;
1037     PHHIVE Hive = NULL;
1038     PCM_KEY_NODE Node = NULL;
1039     HCELL_INDEX Cell = HCELL_NIL, NextCell;
1040     PHHIVE HiveToRelease = NULL;
1041     HCELL_INDEX CellToRelease = HCELL_NIL;
1042     UNICODE_STRING Current, NextName;
1043     PCM_PARSE_CONTEXT ParseContext = Context;
1044     ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0;
1045     PULONG LockedKcbs = NULL;
1046     BOOLEAN Result, Last;
1047     PAGED_CODE();
1048 
1049     /* Loop path separators at the end */
1050     while ((RemainingName->Length) &&
1051            (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] ==
1052             OBJ_NAME_PATH_SEPARATOR))
1053     {
1054         /* Remove path separator */
1055         RemainingName->Length -= sizeof(WCHAR);
1056     }
1057 
1058     /* Fail if this isn't a key object */
1059     if (ObjectType != CmpKeyObjectType) return STATUS_OBJECT_TYPE_MISMATCH;
1060 
1061     /* Copy the remaining name */
1062     Current = *RemainingName;
1063 
1064     /* Check if this is a create */
1065     if (!(ParseContext) || !(ParseContext->CreateOperation))
1066     {
1067         /* It isn't, so no context */
1068         ParseContext = NULL;
1069     }
1070 
1071     /* Grab the KCB */
1072     Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
1073 
1074     /* Sanity check */
1075     ASSERT(Kcb != NULL);
1076 
1077     /* Fail if the key was marked as deleted */
1078     if (Kcb->Delete)
1079         return STATUS_KEY_DELETED;
1080 
1081     /* Lookup in the cache */
1082     Status = CmpBuildHashStackAndLookupCache(ParseObject,
1083                                              &Kcb,
1084                                              &Current,
1085                                              &Hive,
1086                                              &Cell,
1087                                              &TotalRemainingSubkeys,
1088                                              &MatchRemainSubkeyLevel,
1089                                              &TotalSubkeys,
1090                                              NULL,
1091                                              &LockedKcbs);
1092 
1093     /* This is now the parent */
1094     ParentKcb = Kcb;
1095 
1096     /* Sanity check */
1097     ASSERT(ParentKcb != NULL);
1098 
1099     /* Check if everything was found cached */
1100     if (!TotalRemainingSubkeys)
1101         ASSERTMSG("Caching not implemented\n", FALSE);
1102 
1103     /* Don't do anything if we're being deleted */
1104     if (Kcb->Delete)
1105     {
1106         Status = STATUS_OBJECT_NAME_NOT_FOUND;
1107         goto Quickie;
1108     }
1109 
1110     /* Check if this is a symlink */
1111     if (Kcb->Flags & KEY_SYM_LINK)
1112     {
1113         /* Get the next name */
1114         Result = CmpGetNextName(&Current, &NextName, &Last);
1115         Current.Buffer = NextName.Buffer;
1116 
1117         /* Validate the current name string length */
1118         if (Current.Length + NextName.Length > MAXUSHORT)
1119         {
1120             /* too long */
1121             Status = STATUS_NAME_TOO_LONG;
1122             goto Quickie;
1123         }
1124         Current.Length += NextName.Length;
1125 
1126         /* Validate the current name string maximum length */
1127         if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
1128         {
1129             /* too long */
1130             Status = STATUS_NAME_TOO_LONG;
1131             goto Quickie;
1132         }
1133         Current.MaximumLength += NextName.MaximumLength;
1134 
1135         /* Parse the symlink */
1136         if (CmpGetSymbolicLink(Hive,
1137                                CompleteName,
1138                                Kcb,
1139                                &Current))
1140         {
1141             /* Symlink parse succeeded */
1142             Status = STATUS_REPARSE;
1143         }
1144         else
1145         {
1146             /* Couldn't find symlink */
1147             Status = STATUS_OBJECT_NAME_NOT_FOUND;
1148         }
1149 
1150         /* We're done */
1151         goto Quickie;
1152     }
1153 
1154     /* Get the key node */
1155     Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1156     if (!Node)
1157     {
1158         Status = STATUS_INSUFFICIENT_RESOURCES;
1159         goto Quickie;
1160     }
1161 
1162     /* Start parsing */
1163     Status = STATUS_NOT_IMPLEMENTED;
1164     while (TRUE)
1165     {
1166         /* Get the next component */
1167         Result = CmpGetNextName(&Current, &NextName, &Last);
1168         if ((Result) && (NextName.Length))
1169         {
1170             /* See if this is a sym link */
1171             if (!(Kcb->Flags & KEY_SYM_LINK))
1172             {
1173                 /* Find the subkey */
1174                 NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
1175                 if (NextCell != HCELL_NIL)
1176                 {
1177                     /* Get the new node */
1178                     Cell = NextCell;
1179                     Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1180                     if (!Node) ASSERT(FALSE);
1181 
1182                     /* Check if this was the last key */
1183                     if (Last)
1184                     {
1185                         /* Is this an exit node */
1186                         if (Node->Flags & KEY_HIVE_EXIT)
1187                         {
1188                             /* Handle it */
1189                             CmpHandleExitNode(&Hive,
1190                                               &Cell,
1191                                               &Node,
1192                                               &HiveToRelease,
1193                                               &CellToRelease);
1194                             if (!Node)
1195                             {
1196                                 /* Fail */
1197                                 Status = STATUS_INSUFFICIENT_RESOURCES;
1198                                 break;
1199                             }
1200                         }
1201 
1202                         /* Do the open */
1203                         Status = CmpDoOpen(Hive,
1204                                            Cell,
1205                                            Node,
1206                                            AccessState,
1207                                            AccessMode,
1208                                            Attributes,
1209                                            ParseContext,
1210                                            0,
1211                                            &Kcb,
1212                                            &NextName,
1213                                            Object);
1214                         if (Status == STATUS_REPARSE)
1215                         {
1216                             /* Parse the symlink */
1217                             if (!CmpGetSymbolicLink(Hive,
1218                                                     CompleteName,
1219                                                     Kcb,
1220                                                     NULL))
1221                             {
1222                                 /* Symlink parse failed */
1223                                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1224                             }
1225                         }
1226 
1227                         /* We are done */
1228                         break;
1229                     }
1230 
1231                     /* Is this an exit node */
1232                     if (Node->Flags & KEY_HIVE_EXIT)
1233                     {
1234                         /* Handle it */
1235                         CmpHandleExitNode(&Hive,
1236                                           &Cell,
1237                                           &Node,
1238                                           &HiveToRelease,
1239                                           &CellToRelease);
1240                         if (!Node)
1241                         {
1242                             /* Fail */
1243                             Status = STATUS_INSUFFICIENT_RESOURCES;
1244                             break;
1245                         }
1246                     }
1247 
1248                     /* Create a KCB for this key */
1249                     Kcb = CmpCreateKeyControlBlock(Hive,
1250                                                    Cell,
1251                                                    Node,
1252                                                    ParentKcb,
1253                                                    0,
1254                                                    &NextName);
1255                     if (!Kcb)
1256                     {
1257                         /* Fail */
1258                         Status = STATUS_INSUFFICIENT_RESOURCES;
1259                         break;
1260                     }
1261 
1262                     /* Dereference the parent and set the new one */
1263                     CmpDereferenceKeyControlBlock(ParentKcb);
1264                     ParentKcb = Kcb;
1265                 }
1266                 else
1267                 {
1268                     /* Check if this was the last key for a create */
1269                     if ((Last) && (ParseContext))
1270                     {
1271                         /* Check if we're doing a link node */
1272                         if (ParseContext->CreateLink)
1273                         {
1274                             /* The only thing we should see */
1275                             Status = CmpCreateLinkNode(Hive,
1276                                                        Cell,
1277                                                        AccessState,
1278                                                        NextName,
1279                                                        AccessMode,
1280                                                        Attributes,
1281                                                        ParseContext,
1282                                                        ParentKcb,
1283                                                        Object);
1284                         }
1285                         else if (Hive == &CmiVolatileHive->Hive && CmpNoVolatileCreates)
1286                         {
1287                             /* Creating keys in the master hive is not allowed */
1288                             Status = STATUS_INVALID_PARAMETER;
1289                         }
1290                         else
1291                         {
1292                             /* Do the create */
1293                             Status = CmpDoCreate(Hive,
1294                                                  Cell,
1295                                                  AccessState,
1296                                                  &NextName,
1297                                                  AccessMode,
1298                                                  ParseContext,
1299                                                  ParentKcb,
1300                                                  Object);
1301                         }
1302 
1303                         /* Check for reparse (in this case, someone beat us) */
1304                         if (Status == STATUS_REPARSE) break;
1305 
1306                         /* Update disposition */
1307                         ParseContext->Disposition = REG_CREATED_NEW_KEY;
1308                         break;
1309                     }
1310                     else
1311                     {
1312                         /* Key not found */
1313                         Status = STATUS_OBJECT_NAME_NOT_FOUND;
1314                         break;
1315                     }
1316                 }
1317             }
1318             else
1319             {
1320                 /* Save the next name */
1321                 Current.Buffer = NextName.Buffer;
1322 
1323                 /* Validate the current name string length */
1324                 if (Current.Length + NextName.Length > MAXUSHORT)
1325                 {
1326                     /* too long */
1327                     Status = STATUS_NAME_TOO_LONG;
1328                     break;
1329                 }
1330                 Current.Length += NextName.Length;
1331 
1332                 /* Validate the current name string maximum length */
1333                 if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT)
1334                 {
1335                     /* too long */
1336                     Status = STATUS_NAME_TOO_LONG;
1337                     break;
1338                 }
1339                 Current.MaximumLength += NextName.MaximumLength;
1340 
1341                 /* Parse the symlink */
1342                 if (CmpGetSymbolicLink(Hive,
1343                                        CompleteName,
1344                                        Kcb,
1345                                        &Current))
1346                 {
1347                     /* Symlink parse succeeded */
1348                     Status = STATUS_REPARSE;
1349                 }
1350                 else
1351                 {
1352                     /* Couldn't find symlink */
1353                     Status = STATUS_OBJECT_NAME_NOT_FOUND;
1354                 }
1355 
1356                 /* We're done */
1357                 break;
1358             }
1359         }
1360         else if ((Result) && (Last))
1361         {
1362             /* Opening the root. Is this an exit node? */
1363             if (Node->Flags & KEY_HIVE_EXIT)
1364             {
1365                 /* Handle it */
1366                 CmpHandleExitNode(&Hive,
1367                                   &Cell,
1368                                   &Node,
1369                                   &HiveToRelease,
1370                                   &CellToRelease);
1371                 if (!Node)
1372                 {
1373                     /* Fail */
1374                     Status = STATUS_INSUFFICIENT_RESOURCES;
1375                     break;
1376                 }
1377             }
1378 
1379             /* Do the open */
1380             Status = CmpDoOpen(Hive,
1381                                Cell,
1382                                Node,
1383                                AccessState,
1384                                AccessMode,
1385                                Attributes,
1386                                ParseContext,
1387                                CMP_OPEN_KCB_NO_CREATE /* | CMP_CREATE_KCB_KCB_LOCKED */,
1388                                &Kcb,
1389                                &NextName,
1390                                Object);
1391             if (Status == STATUS_REPARSE)
1392             {
1393                 /* Nothing to do */
1394             }
1395 
1396             /* We're done */
1397             break;
1398         }
1399         else
1400         {
1401             /* Bogus */
1402             Status = STATUS_INVALID_PARAMETER;
1403             break;
1404         }
1405     }
1406 
1407     /* Dereference the parent if it exists */
1408 Quickie:
1409     if (ParentKcb)
1410         CmpDereferenceKeyControlBlock(ParentKcb);
1411 
1412     /* Unlock the registry */
1413     CmpUnlockRegistry();
1414     return Status;
1415 }
1416