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