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>
19 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
21 PUNICODE_STRING TargetPath
);
23 /* FUNCTONS *****************************************************************/
26 CmiObjectParse(PVOID ParsedObject
,
28 PUNICODE_STRING FullPath
,
32 BLOCK_OFFSET BlockOffset
;
33 PKEY_OBJECT FoundObject
;
34 PKEY_OBJECT ParsedKey
;
40 UNICODE_STRING LinkPath
;
41 UNICODE_STRING TargetPath
;
42 UNICODE_STRING KeyName
;
44 ParsedKey
= ParsedObject
;
46 VERIFY_KEY_OBJECT(ParsedKey
);
52 DPRINT("*Path is NULL\n");
53 return STATUS_UNSUCCESSFUL
;
56 DPRINT("Path '%S'\n", *Path
);
58 /* Extract relevant path name */
60 if (*StartPtr
== L
'\\')
63 EndPtr
= wcschr(StartPtr
, L
'\\');
65 Length
= ((PCHAR
)EndPtr
- (PCHAR
)StartPtr
) / sizeof(WCHAR
);
67 Length
= wcslen(StartPtr
);
70 KeyName
.Length
= Length
* sizeof(WCHAR
);
71 KeyName
.MaximumLength
= KeyName
.Length
+ sizeof(WCHAR
);
72 KeyName
.Buffer
= ExAllocatePool(NonPagedPool
,
73 KeyName
.MaximumLength
);
74 RtlCopyMemory(KeyName
.Buffer
,
77 KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] = 0;
80 FoundObject
= CmiScanKeyList(ParsedKey
,
83 if (FoundObject
== NULL
)
85 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
92 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
94 RtlFreeUnicodeString(&KeyName
);
95 return(STATUS_UNSUCCESSFUL
);
98 if ((SubKeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
99 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
101 RtlInitUnicodeString(&LinkPath
, NULL
);
102 Status
= CmiGetLinkTarget(ParsedKey
->RegistryHive
,
105 if (NT_SUCCESS(Status
))
107 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
109 /* build new FullPath for reparsing */
110 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
113 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
115 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
116 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
117 TargetPath
.MaximumLength
);
118 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
121 wcscat(TargetPath
.Buffer
, EndPtr
);
124 RtlFreeUnicodeString(FullPath
);
125 RtlFreeUnicodeString(&LinkPath
);
126 FullPath
->Length
= TargetPath
.Length
;
127 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
128 FullPath
->Buffer
= TargetPath
.Buffer
;
130 DPRINT("FullPath '%wZ'\n", FullPath
);
132 /* reinitialize Path for reparsing */
133 *Path
= FullPath
->Buffer
;
137 RtlFreeUnicodeString(&KeyName
);
138 return(STATUS_REPARSE
);
142 /* Create new key object and put into linked list */
143 DPRINT("CmiObjectParse: %s\n", Path
);
144 Status
= ObCreateObject(KernelMode
,
152 (PVOID
*)&FoundObject
);
153 if (!NT_SUCCESS(Status
))
155 RtlFreeUnicodeString(&KeyName
);
159 FoundObject
->Flags
= 0;
160 FoundObject
->KeyCell
= SubKeyCell
;
161 FoundObject
->KeyCellOffset
= BlockOffset
;
162 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
163 RtlpCreateUnicodeString(&FoundObject
->Name
,
164 KeyName
.Buffer
, NonPagedPool
);
165 CmiAddKeyToList(ParsedKey
, FoundObject
);
166 DPRINT("Created object 0x%x\n", FoundObject
);
170 if ((FoundObject
->KeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
171 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
173 DPRINT("Found link\n");
175 RtlInitUnicodeString(&LinkPath
, NULL
);
176 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
177 FoundObject
->KeyCell
,
179 if (NT_SUCCESS(Status
))
181 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
183 /* build new FullPath for reparsing */
184 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
187 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
189 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
190 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
191 TargetPath
.MaximumLength
);
192 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
195 wcscat(TargetPath
.Buffer
, EndPtr
);
198 RtlFreeUnicodeString(FullPath
);
199 RtlFreeUnicodeString(&LinkPath
);
200 FullPath
->Length
= TargetPath
.Length
;
201 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
202 FullPath
->Buffer
= TargetPath
.Buffer
;
204 DPRINT("FullPath '%wZ'\n", FullPath
);
206 /* reinitialize Path for reparsing */
207 *Path
= FullPath
->Buffer
;
211 RtlFreeUnicodeString(&KeyName
);
212 return(STATUS_REPARSE
);
216 ObReferenceObjectByPointer(FoundObject
,
217 STANDARD_RIGHTS_REQUIRED
,
222 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
226 VERIFY_KEY_OBJECT(FoundObject
);
228 *NextObject
= FoundObject
;
230 RtlFreeUnicodeString(&KeyName
);
232 return(STATUS_SUCCESS
);
237 CmiObjectCreate(PVOID ObjectBody
,
240 POBJECT_ATTRIBUTES ObjectAttributes
)
242 PKEY_OBJECT KeyObject
= ObjectBody
;
245 KeyObject
->ParentKey
= Parent
;
248 Start
= RemainingPath
;
251 RtlpCreateUnicodeString(&KeyObject
->Name
,
252 Start
, NonPagedPool
);
256 RtlInitUnicodeString(&KeyObject
->Name
,
260 return STATUS_SUCCESS
;
265 CmiObjectDelete(PVOID DeletedObject
)
267 PKEY_OBJECT ParentKeyObject
;
268 PKEY_OBJECT KeyObject
;
270 DPRINT("Delete key object (%p)\n", DeletedObject
);
272 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
273 ParentKeyObject
= KeyObject
->ParentKey
;
275 ObReferenceObject (ParentKeyObject
);
277 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
279 DPRINT1("Key not found in parent list ???\n");
282 RtlFreeUnicodeString(&KeyObject
->Name
);
284 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
286 DPRINT("delete really key\n");
288 CmiRemoveSubKey(KeyObject
->RegistryHive
,
292 KeQuerySystemTime (&ParentKeyObject
->KeyCell
->LastWriteTime
);
293 CmiMarkBlockDirty (ParentKeyObject
->RegistryHive
,
294 ParentKeyObject
->KeyCellOffset
);
296 if (!IsNoFileHive (KeyObject
->RegistryHive
) ||
297 !IsNoFileHive (ParentKeyObject
->RegistryHive
))
303 ObDereferenceObject (ParentKeyObject
);
305 if (KeyObject
->NumberOfSubKeys
)
307 KEBUGCHECK(REGISTRY_ERROR
);
310 if (KeyObject
->SizeOfSubKeys
)
312 ExFreePool(KeyObject
->SubKeys
);
318 CmiQuerySecurityDescriptor(PKEY_OBJECT KeyObject
,
319 SECURITY_INFORMATION SecurityInformation
,
320 PSECURITY_DESCRIPTOR SecurityDescriptor
,
328 DPRINT("CmiQuerySecurityDescriptor() called\n");
332 * This is a big hack!!
333 * We need to retrieve the security descriptor from the keys security cell!
336 if (SecurityInformation
== 0)
338 return STATUS_ACCESS_DENIED
;
341 SidSize
= RtlLengthSid(SeWorldSid
);
342 SdSize
= sizeof(SECURITY_DESCRIPTOR
) + (2 * SidSize
);
344 if (*BufferLength
< SdSize
)
346 *BufferLength
= SdSize
;
347 return STATUS_BUFFER_TOO_SMALL
;
350 *BufferLength
= SdSize
;
352 Status
= RtlCreateSecurityDescriptor(SecurityDescriptor
,
353 SECURITY_DESCRIPTOR_REVISION
);
354 if (!NT_SUCCESS(Status
))
359 SecurityDescriptor
->Control
|= SE_SELF_RELATIVE
;
360 Current
= (ULONG_PTR
)SecurityDescriptor
+ sizeof(SECURITY_DESCRIPTOR
);
362 if (SecurityInformation
& OWNER_SECURITY_INFORMATION
)
364 RtlCopyMemory((PVOID
)Current
,
367 SecurityDescriptor
->Owner
= (PSID
)((ULONG_PTR
)Current
- (ULONG_PTR
)SecurityDescriptor
);
371 if (SecurityInformation
& GROUP_SECURITY_INFORMATION
)
373 RtlCopyMemory((PVOID
)Current
,
376 SecurityDescriptor
->Group
= (PSID
)((ULONG_PTR
)Current
- (ULONG_PTR
)SecurityDescriptor
);
380 if (SecurityInformation
& DACL_SECURITY_INFORMATION
)
382 SecurityDescriptor
->Control
|= SE_DACL_PRESENT
;
385 if (SecurityInformation
& SACL_SECURITY_INFORMATION
)
387 SecurityDescriptor
->Control
|= SE_SACL_PRESENT
;
390 return STATUS_SUCCESS
;
395 CmiAssignSecurityDescriptor(PKEY_OBJECT KeyObject
,
396 PSECURITY_DESCRIPTOR SecurityDescriptor
)
401 DPRINT1("CmiAssignSecurityDescriptor() callled\n");
403 DPRINT1("KeyObject %p\n", KeyObject
);
404 DPRINT1("KeyObject->RegistryHive %p\n", KeyObject
->RegistryHive
);
406 Hive
= KeyObject
->RegistryHive
;
409 DPRINT1("Create new root security cell\n");
410 return STATUS_SUCCESS
;
413 if (Hive
->RootSecurityCell
== NULL
)
415 DPRINT1("Create new root security cell\n");
420 DPRINT1("Search for security cell\n");
425 return STATUS_SUCCESS
;
430 CmiObjectSecurity(PVOID ObjectBody
,
431 SECURITY_OPERATION_CODE OperationCode
,
432 SECURITY_INFORMATION SecurityInformation
,
433 PSECURITY_DESCRIPTOR SecurityDescriptor
,
436 DPRINT("CmiObjectSecurity() called\n");
438 switch (OperationCode
)
440 case SetSecurityDescriptor
:
441 DPRINT("Set security descriptor\n");
442 return STATUS_SUCCESS
;
444 case QuerySecurityDescriptor
:
445 DPRINT("Query security descriptor\n");
446 return CmiQuerySecurityDescriptor((PKEY_OBJECT
)ObjectBody
,
451 case DeleteSecurityDescriptor
:
452 DPRINT("Delete security descriptor\n");
453 return STATUS_SUCCESS
;
455 case AssignSecurityDescriptor
:
456 DPRINT("Assign security descriptor\n");
457 return CmiAssignSecurityDescriptor((PKEY_OBJECT
)ObjectBody
,
461 return STATUS_UNSUCCESSFUL
;
466 CmiObjectQueryName (PVOID ObjectBody
,
467 POBJECT_NAME_INFORMATION ObjectNameInfo
,
471 POBJECT_NAME_INFORMATION LocalInfo
;
472 PKEY_OBJECT KeyObject
;
473 ULONG LocalReturnLength
;
476 DPRINT ("CmiObjectQueryName() called\n");
478 KeyObject
= (PKEY_OBJECT
)ObjectBody
;
480 LocalInfo
= ExAllocatePool (NonPagedPool
,
481 sizeof(OBJECT_NAME_INFORMATION
) +
482 MAX_PATH
* sizeof(WCHAR
));
483 if (LocalInfo
== NULL
)
484 return STATUS_INSUFFICIENT_RESOURCES
;
486 if (KeyObject
->ParentKey
!= KeyObject
)
488 Status
= ObQueryNameString (KeyObject
->ParentKey
,
490 MAX_PATH
* sizeof(WCHAR
),
495 /* KeyObject is the root key */
496 Status
= ObQueryNameString (BODY_TO_HEADER(KeyObject
)->Parent
,
498 MAX_PATH
* sizeof(WCHAR
),
502 if (!NT_SUCCESS (Status
))
504 ExFreePool (LocalInfo
);
507 DPRINT ("Parent path: %wZ\n", &LocalInfo
->Name
);
509 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
511 ExFreePool (LocalInfo
);
512 if (!NT_SUCCESS (Status
))
515 Status
= RtlAppendUnicodeToString (&ObjectNameInfo
->Name
,
517 if (!NT_SUCCESS (Status
))
520 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
522 if (NT_SUCCESS (Status
))
524 DPRINT ("Total path: %wZ\n", &ObjectNameInfo
->Name
);
532 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
537 DPRINT("ParentKey %.08x\n", ParentKey
);
539 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
541 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
543 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
544 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(ULONG
));
546 if (ParentKey
->NumberOfSubKeys
> 0)
548 RtlCopyMemory (tmpSubKeys
,
550 ParentKey
->NumberOfSubKeys
* sizeof(ULONG
));
553 if (ParentKey
->SubKeys
)
554 ExFreePool(ParentKey
->SubKeys
);
556 ParentKey
->SubKeys
= tmpSubKeys
;
557 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
560 /* FIXME: Please maintain the list in alphabetic order */
561 /* to allow a dichotomic search */
562 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
564 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
566 ObReferenceObjectByPointer(ParentKey
,
567 STANDARD_RIGHTS_REQUIRED
,
570 NewKey
->ParentKey
= ParentKey
;
571 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
576 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
578 PKEY_OBJECT ParentKey
;
582 ParentKey
= KeyToRemove
->ParentKey
;
583 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
584 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
585 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
587 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
589 if (Index
< ParentKey
->NumberOfSubKeys
-1)
590 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
591 &ParentKey
->SubKeys
[Index
+ 1],
592 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
593 ParentKey
->NumberOfSubKeys
--;
594 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
596 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
598 ObDereferenceObject(ParentKey
);
599 return STATUS_SUCCESS
;
602 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
604 return STATUS_UNSUCCESSFUL
;
609 CmiScanKeyList(PKEY_OBJECT Parent
,
610 PUNICODE_STRING KeyName
,
617 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
618 KeyName
, &Parent
->Name
);
620 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
621 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
622 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
624 CurKey
= Parent
->SubKeys
[Index
];
625 if (Attributes
& OBJ_CASE_INSENSITIVE
)
627 if ((KeyName
->Length
== CurKey
->Name
.Length
)
628 && (_wcsicmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
630 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
636 if ((KeyName
->Length
== CurKey
->Name
.Length
)
637 && (wcscmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
639 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
644 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
651 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
653 PUNICODE_STRING TargetPath
)
655 UNICODE_STRING LinkName
= ROS_STRING_INITIALIZER(L
"SymbolicLinkValue");
656 PVALUE_CELL ValueCell
;
660 DPRINT("CmiGetLinkTarget() called\n");
662 /* Get Value block of interest */
663 Status
= CmiScanKeyForValue(RegistryHive
,
668 if (!NT_SUCCESS(Status
))
670 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
674 if (ValueCell
->DataType
!= REG_LINK
)
676 DPRINT1("Type != REG_LINK\n!");
677 return(STATUS_UNSUCCESSFUL
);
680 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
682 TargetPath
->Length
= 0;
683 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
684 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
685 TargetPath
->MaximumLength
);
688 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
689 (ULONG
) ValueCell
->DataSize
);
691 if (ValueCell
->DataSize
> 0)
693 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
694 RtlCopyMemory(TargetPath
->Buffer
,
697 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
701 RtlCopyMemory(TargetPath
->Buffer
,
702 &ValueCell
->DataOffset
,
704 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
707 DPRINT("TargetPath '%wZ'\n", TargetPath
);
709 return(STATUS_SUCCESS
);