3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/regobj.c
6 * PURPOSE: Registry object manipulation routines.
8 * PROGRAMMERS: No programmer listed.
13 #include <internal/debug.h>
17 extern LIST_ENTRY CmiKeyObjectListHead
;
18 extern ULONG CmiTimer
;
21 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
23 PUNICODE_STRING TargetPath
);
25 /* FUNCTONS *****************************************************************/
28 CmiObjectParse(PVOID ParsedObject
,
30 PUNICODE_STRING FullPath
,
34 BLOCK_OFFSET BlockOffset
;
35 PKEY_OBJECT FoundObject
;
36 PKEY_OBJECT ParsedKey
;
42 UNICODE_STRING LinkPath
;
43 UNICODE_STRING TargetPath
;
44 UNICODE_STRING KeyName
;
46 ParsedKey
= ParsedObject
;
48 VERIFY_KEY_OBJECT(ParsedKey
);
54 DPRINT("*Path is NULL\n");
55 return STATUS_UNSUCCESSFUL
;
58 DPRINT("Path '%S'\n", *Path
);
60 /* Extract relevant path name */
62 if (*StartPtr
== L
'\\')
65 EndPtr
= wcschr(StartPtr
, L
'\\');
67 Length
= ((PCHAR
)EndPtr
- (PCHAR
)StartPtr
) / sizeof(WCHAR
);
69 Length
= wcslen(StartPtr
);
72 KeyName
.Length
= Length
* sizeof(WCHAR
);
73 KeyName
.MaximumLength
= KeyName
.Length
+ sizeof(WCHAR
);
74 KeyName
.Buffer
= ExAllocatePool(NonPagedPool
,
75 KeyName
.MaximumLength
);
76 RtlCopyMemory(KeyName
.Buffer
,
79 KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] = 0;
81 /* Acquire hive lock */
82 KeEnterCriticalRegion();
83 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
86 Status
= CmiScanKeyList(ParsedKey
,
90 if (!NT_SUCCESS(Status
))
92 ExReleaseResourceLite(&CmiRegistryLock
);
93 KeLeaveCriticalRegion();
94 ExFreePool(KeyName
.Buffer
);
97 if (FoundObject
== NULL
)
99 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
106 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
108 ExReleaseResourceLite(&CmiRegistryLock
);
109 KeLeaveCriticalRegion();
110 ExFreePool(KeyName
.Buffer
);
111 return(STATUS_UNSUCCESSFUL
);
114 if ((SubKeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
115 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
117 RtlInitUnicodeString(&LinkPath
, NULL
);
118 Status
= CmiGetLinkTarget(ParsedKey
->RegistryHive
,
121 if (NT_SUCCESS(Status
))
123 ExReleaseResourceLite(&CmiRegistryLock
);
124 KeLeaveCriticalRegion();
126 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
128 /* build new FullPath for reparsing */
129 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
132 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
134 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
135 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
136 TargetPath
.MaximumLength
);
137 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
140 wcscat(TargetPath
.Buffer
, EndPtr
);
143 ExFreePool(FullPath
->Buffer
);
144 RtlFreeUnicodeString(&LinkPath
);
145 FullPath
->Length
= TargetPath
.Length
;
146 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
147 FullPath
->Buffer
= TargetPath
.Buffer
;
149 DPRINT("FullPath '%wZ'\n", FullPath
);
151 /* reinitialize Path for reparsing */
152 *Path
= FullPath
->Buffer
;
156 ExFreePool(KeyName
.Buffer
);
157 return(STATUS_REPARSE
);
161 /* Create new key object and put into linked list */
162 DPRINT("CmiObjectParse: %S\n", *Path
);
163 Status
= ObCreateObject(KernelMode
,
171 (PVOID
*)&FoundObject
);
172 if (!NT_SUCCESS(Status
))
174 ExReleaseResourceLite(&CmiRegistryLock
);
175 KeLeaveCriticalRegion();
176 ExFreePool(KeyName
.Buffer
);
179 /* Add the keep-alive reference */
180 ObReferenceObject(FoundObject
);
182 FoundObject
->Flags
= 0;
183 FoundObject
->KeyCell
= SubKeyCell
;
184 FoundObject
->KeyCellOffset
= BlockOffset
;
185 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
186 InsertTailList(&CmiKeyObjectListHead
, &FoundObject
->ListEntry
);
187 RtlpCreateUnicodeString(&FoundObject
->Name
,
188 KeyName
.Buffer
, NonPagedPool
);
189 CmiAddKeyToList(ParsedKey
, FoundObject
);
190 DPRINT("Created object 0x%x\n", FoundObject
);
194 if ((FoundObject
->KeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
195 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
197 DPRINT("Found link\n");
199 RtlInitUnicodeString(&LinkPath
, NULL
);
200 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
201 FoundObject
->KeyCell
,
203 if (NT_SUCCESS(Status
))
205 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
207 ExReleaseResourceLite(&CmiRegistryLock
);
208 KeLeaveCriticalRegion();
210 ObDereferenceObject(FoundObject
);
212 /* build new FullPath for reparsing */
213 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
216 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
218 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
219 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
220 TargetPath
.MaximumLength
);
221 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
224 wcscat(TargetPath
.Buffer
, EndPtr
);
227 ExFreePool(FullPath
->Buffer
);
228 ExFreePool(LinkPath
.Buffer
);
229 FullPath
->Length
= TargetPath
.Length
;
230 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
231 FullPath
->Buffer
= TargetPath
.Buffer
;
233 DPRINT("FullPath '%wZ'\n", FullPath
);
235 /* reinitialize Path for reparsing */
236 *Path
= FullPath
->Buffer
;
240 ExFreePool(KeyName
.Buffer
);
241 return(STATUS_REPARSE
);
246 RemoveEntryList(&FoundObject
->ListEntry
);
247 InsertHeadList(&CmiKeyObjectListHead
, &FoundObject
->ListEntry
);
248 FoundObject
->TimeStamp
= CmiTimer
;
250 ExReleaseResourceLite(&CmiRegistryLock
);
251 KeLeaveCriticalRegion();
253 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
257 VERIFY_KEY_OBJECT(FoundObject
);
259 *NextObject
= FoundObject
;
261 ExFreePool(KeyName
.Buffer
);
263 return(STATUS_SUCCESS
);
268 CmiObjectCreate(PVOID ObjectBody
,
271 POBJECT_ATTRIBUTES ObjectAttributes
)
273 PKEY_OBJECT KeyObject
= ObjectBody
;
276 KeyObject
->ParentKey
= Parent
;
279 Start
= RemainingPath
;
282 RtlpCreateUnicodeString(&KeyObject
->Name
,
283 Start
, NonPagedPool
);
287 RtlInitUnicodeString(&KeyObject
->Name
,
291 return STATUS_SUCCESS
;
296 CmiObjectDelete(PVOID DeletedObject
)
298 PKEY_OBJECT ParentKeyObject
;
299 PKEY_OBJECT KeyObject
;
301 DPRINT("Delete key object (%p)\n", DeletedObject
);
303 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
304 ParentKeyObject
= KeyObject
->ParentKey
;
306 ObReferenceObject (ParentKeyObject
);
308 /* Acquire hive lock */
309 KeEnterCriticalRegion();
310 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
312 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
314 DPRINT1("Key not found in parent list ???\n");
317 RemoveEntryList(&KeyObject
->ListEntry
);
318 RtlFreeUnicodeString(&KeyObject
->Name
);
320 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
322 DPRINT("delete really key\n");
324 CmiRemoveSubKey(KeyObject
->RegistryHive
,
328 KeQuerySystemTime (&ParentKeyObject
->KeyCell
->LastWriteTime
);
329 CmiMarkBlockDirty (ParentKeyObject
->RegistryHive
,
330 ParentKeyObject
->KeyCellOffset
);
332 if (!IsNoFileHive (KeyObject
->RegistryHive
) ||
333 !IsNoFileHive (ParentKeyObject
->RegistryHive
))
339 ObDereferenceObject (ParentKeyObject
);
341 ExReleaseResourceLite(&CmiRegistryLock
);
342 KeLeaveCriticalRegion();
344 if (KeyObject
->NumberOfSubKeys
)
346 KEBUGCHECK(REGISTRY_ERROR
);
349 if (KeyObject
->SizeOfSubKeys
)
351 ExFreePool(KeyObject
->SubKeys
);
357 CmiQuerySecurityDescriptor(PKEY_OBJECT KeyObject
,
358 SECURITY_INFORMATION SecurityInformation
,
359 PSECURITY_DESCRIPTOR SecurityDescriptor
,
367 DPRINT("CmiQuerySecurityDescriptor() called\n");
371 * This is a big hack!!
372 * We need to retrieve the security descriptor from the keys security cell!
375 if (SecurityInformation
== 0)
377 return STATUS_ACCESS_DENIED
;
380 SidSize
= RtlLengthSid(SeWorldSid
);
381 SdSize
= sizeof(SECURITY_DESCRIPTOR
) + (2 * SidSize
);
383 if (*BufferLength
< SdSize
)
385 *BufferLength
= SdSize
;
386 return STATUS_BUFFER_TOO_SMALL
;
389 *BufferLength
= SdSize
;
391 Status
= RtlCreateSecurityDescriptor(SecurityDescriptor
,
392 SECURITY_DESCRIPTOR_REVISION
);
393 if (!NT_SUCCESS(Status
))
398 SecurityDescriptor
->Control
|= SE_SELF_RELATIVE
;
399 Current
= (ULONG_PTR
)SecurityDescriptor
+ sizeof(SECURITY_DESCRIPTOR
);
401 if (SecurityInformation
& OWNER_SECURITY_INFORMATION
)
403 RtlCopyMemory((PVOID
)Current
,
406 SecurityDescriptor
->Owner
= (PSID
)((ULONG_PTR
)Current
- (ULONG_PTR
)SecurityDescriptor
);
410 if (SecurityInformation
& GROUP_SECURITY_INFORMATION
)
412 RtlCopyMemory((PVOID
)Current
,
415 SecurityDescriptor
->Group
= (PSID
)((ULONG_PTR
)Current
- (ULONG_PTR
)SecurityDescriptor
);
419 if (SecurityInformation
& DACL_SECURITY_INFORMATION
)
421 SecurityDescriptor
->Control
|= SE_DACL_PRESENT
;
424 if (SecurityInformation
& SACL_SECURITY_INFORMATION
)
426 SecurityDescriptor
->Control
|= SE_SACL_PRESENT
;
429 return STATUS_SUCCESS
;
434 CmiAssignSecurityDescriptor(PKEY_OBJECT KeyObject
,
435 PSECURITY_DESCRIPTOR SecurityDescriptor
)
440 DPRINT1("CmiAssignSecurityDescriptor() callled\n");
442 DPRINT1("KeyObject %p\n", KeyObject
);
443 DPRINT1("KeyObject->RegistryHive %p\n", KeyObject
->RegistryHive
);
445 Hive
= KeyObject
->RegistryHive
;
448 DPRINT1("Create new root security cell\n");
449 return STATUS_SUCCESS
;
452 if (Hive
->RootSecurityCell
== NULL
)
454 DPRINT1("Create new root security cell\n");
459 DPRINT1("Search for security cell\n");
464 return STATUS_SUCCESS
;
469 CmiObjectSecurity(PVOID ObjectBody
,
470 SECURITY_OPERATION_CODE OperationCode
,
471 SECURITY_INFORMATION SecurityInformation
,
472 PSECURITY_DESCRIPTOR SecurityDescriptor
,
475 DPRINT("CmiObjectSecurity() called\n");
477 switch (OperationCode
)
479 case SetSecurityDescriptor
:
480 DPRINT("Set security descriptor\n");
481 return STATUS_SUCCESS
;
483 case QuerySecurityDescriptor
:
484 DPRINT("Query security descriptor\n");
485 return CmiQuerySecurityDescriptor((PKEY_OBJECT
)ObjectBody
,
490 case DeleteSecurityDescriptor
:
491 DPRINT("Delete security descriptor\n");
492 return STATUS_SUCCESS
;
494 case AssignSecurityDescriptor
:
495 DPRINT("Assign security descriptor\n");
496 return CmiAssignSecurityDescriptor((PKEY_OBJECT
)ObjectBody
,
500 return STATUS_UNSUCCESSFUL
;
505 CmiObjectQueryName (PVOID ObjectBody
,
506 POBJECT_NAME_INFORMATION ObjectNameInfo
,
510 POBJECT_NAME_INFORMATION LocalInfo
;
511 PKEY_OBJECT KeyObject
;
512 ULONG LocalReturnLength
;
515 DPRINT ("CmiObjectQueryName() called\n");
517 KeyObject
= (PKEY_OBJECT
)ObjectBody
;
519 LocalInfo
= ExAllocatePool (NonPagedPool
,
520 sizeof(OBJECT_NAME_INFORMATION
) +
521 MAX_PATH
* sizeof(WCHAR
));
522 if (LocalInfo
== NULL
)
523 return STATUS_INSUFFICIENT_RESOURCES
;
525 if (KeyObject
->ParentKey
!= KeyObject
)
527 Status
= ObQueryNameString (KeyObject
->ParentKey
,
529 MAX_PATH
* sizeof(WCHAR
),
534 /* KeyObject is the root key */
535 Status
= ObQueryNameString (BODY_TO_HEADER(KeyObject
)->Parent
,
537 MAX_PATH
* sizeof(WCHAR
),
541 if (!NT_SUCCESS (Status
))
543 ExFreePool (LocalInfo
);
546 DPRINT ("Parent path: %wZ\n", &LocalInfo
->Name
);
548 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
550 ExFreePool (LocalInfo
);
551 if (!NT_SUCCESS (Status
))
554 Status
= RtlAppendUnicodeToString (&ObjectNameInfo
->Name
,
556 if (!NT_SUCCESS (Status
))
559 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
561 if (NT_SUCCESS (Status
))
563 DPRINT ("Total path: %wZ\n", &ObjectNameInfo
->Name
);
571 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
575 DPRINT("ParentKey %.08x\n", ParentKey
);
578 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
580 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
581 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(ULONG
));
583 if (ParentKey
->NumberOfSubKeys
> 0)
585 RtlCopyMemory (tmpSubKeys
,
587 ParentKey
->NumberOfSubKeys
* sizeof(ULONG
));
590 if (ParentKey
->SubKeys
)
591 ExFreePool(ParentKey
->SubKeys
);
593 ParentKey
->SubKeys
= tmpSubKeys
;
594 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
597 /* FIXME: Please maintain the list in alphabetic order */
598 /* to allow a dichotomic search */
599 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
601 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
603 ObReferenceObjectByPointer(ParentKey
,
604 STANDARD_RIGHTS_REQUIRED
,
607 NewKey
->ParentKey
= ParentKey
;
612 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
614 PKEY_OBJECT ParentKey
;
617 ParentKey
= KeyToRemove
->ParentKey
;
618 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
619 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
621 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
623 if (Index
< ParentKey
->NumberOfSubKeys
-1)
624 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
625 &ParentKey
->SubKeys
[Index
+ 1],
626 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
627 ParentKey
->NumberOfSubKeys
--;
629 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
631 ObDereferenceObject(ParentKey
);
632 return STATUS_SUCCESS
;
636 return STATUS_UNSUCCESSFUL
;
641 CmiScanKeyList(PKEY_OBJECT Parent
,
642 PUNICODE_STRING KeyName
,
644 PKEY_OBJECT
* ReturnedObject
)
649 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
650 KeyName
, &Parent
->Name
);
652 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
653 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
655 CurKey
= Parent
->SubKeys
[Index
];
656 if (Attributes
& OBJ_CASE_INSENSITIVE
)
658 if ((KeyName
->Length
== CurKey
->Name
.Length
)
659 && (_wcsicmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
666 if ((KeyName
->Length
== CurKey
->Name
.Length
)
667 && (wcscmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
674 if (Index
< Parent
->NumberOfSubKeys
)
676 if (CurKey
->Flags
& KO_MARKED_FOR_DELETE
)
678 *ReturnedObject
= NULL
;
679 return STATUS_UNSUCCESSFUL
;
681 ObReferenceObject(CurKey
);
682 *ReturnedObject
= CurKey
;
686 *ReturnedObject
= NULL
;
688 return STATUS_SUCCESS
;
693 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
695 PUNICODE_STRING TargetPath
)
697 UNICODE_STRING LinkName
= ROS_STRING_INITIALIZER(L
"SymbolicLinkValue");
698 PVALUE_CELL ValueCell
;
702 DPRINT("CmiGetLinkTarget() called\n");
704 /* Get Value block of interest */
705 Status
= CmiScanKeyForValue(RegistryHive
,
710 if (!NT_SUCCESS(Status
))
712 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
716 if (ValueCell
->DataType
!= REG_LINK
)
718 DPRINT1("Type != REG_LINK\n!");
719 return(STATUS_UNSUCCESSFUL
);
722 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
724 TargetPath
->Length
= 0;
725 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
726 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
727 TargetPath
->MaximumLength
);
730 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
731 (ULONG
) ValueCell
->DataSize
);
733 if (ValueCell
->DataSize
> 0)
735 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
736 RtlCopyMemory(TargetPath
->Buffer
,
739 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
743 RtlCopyMemory(TargetPath
->Buffer
,
744 &ValueCell
->DataOffset
,
746 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
749 DPRINT("TargetPath '%wZ'\n", TargetPath
);
751 return(STATUS_SUCCESS
);