2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regobj.c
5 * PURPOSE: Registry object manipulation routines.
9 #define NTOS_MODE_KERNEL
13 #include <internal/ob.h>
14 #include <ntos/minmax.h>
15 #include <reactos/bugcodes.h>
16 #include <rosrtl/string.h>
19 #include <internal/debug.h>
25 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
27 PUNICODE_STRING TargetPath
);
29 /* FUNCTONS *****************************************************************/
32 CmiObjectParse(PVOID ParsedObject
,
34 PUNICODE_STRING FullPath
,
38 BLOCK_OFFSET BlockOffset
;
39 PKEY_OBJECT FoundObject
;
40 PKEY_OBJECT ParsedKey
;
46 UNICODE_STRING LinkPath
;
47 UNICODE_STRING TargetPath
;
48 UNICODE_STRING KeyName
;
50 ParsedKey
= ParsedObject
;
52 VERIFY_KEY_OBJECT(ParsedKey
);
58 DPRINT("*Path is NULL\n");
59 return STATUS_UNSUCCESSFUL
;
62 DPRINT("Path '%S'\n", *Path
);
64 /* Extract relevant path name */
66 if (*StartPtr
== L
'\\')
69 EndPtr
= wcschr(StartPtr
, L
'\\');
71 Length
= ((PCHAR
)EndPtr
- (PCHAR
)StartPtr
) / sizeof(WCHAR
);
73 Length
= wcslen(StartPtr
);
76 KeyName
.Length
= Length
* sizeof(WCHAR
);
77 KeyName
.MaximumLength
= KeyName
.Length
+ sizeof(WCHAR
);
78 KeyName
.Buffer
= ExAllocatePool(NonPagedPool
,
79 KeyName
.MaximumLength
);
80 RtlCopyMemory(KeyName
.Buffer
,
83 KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] = 0;
86 FoundObject
= CmiScanKeyList(ParsedKey
,
89 if (FoundObject
== NULL
)
91 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
98 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
100 RtlFreeUnicodeString(&KeyName
);
101 return(STATUS_UNSUCCESSFUL
);
104 if ((SubKeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
105 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
107 RtlInitUnicodeString(&LinkPath
, NULL
);
108 Status
= CmiGetLinkTarget(ParsedKey
->RegistryHive
,
111 if (NT_SUCCESS(Status
))
113 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
115 /* build new FullPath for reparsing */
116 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
119 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
121 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
122 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
123 TargetPath
.MaximumLength
);
124 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
127 wcscat(TargetPath
.Buffer
, EndPtr
);
130 RtlFreeUnicodeString(FullPath
);
131 RtlFreeUnicodeString(&LinkPath
);
132 FullPath
->Length
= TargetPath
.Length
;
133 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
134 FullPath
->Buffer
= TargetPath
.Buffer
;
136 DPRINT("FullPath '%wZ'\n", FullPath
);
138 /* reinitialize Path for reparsing */
139 *Path
= FullPath
->Buffer
;
143 RtlFreeUnicodeString(&KeyName
);
144 return(STATUS_REPARSE
);
148 /* Create new key object and put into linked list */
149 DPRINT("CmiObjectParse: %s\n", Path
);
150 Status
= ObCreateObject(KernelMode
,
158 (PVOID
*)&FoundObject
);
159 if (!NT_SUCCESS(Status
))
161 RtlFreeUnicodeString(&KeyName
);
165 FoundObject
->Flags
= 0;
166 FoundObject
->KeyCell
= SubKeyCell
;
167 FoundObject
->KeyCellOffset
= BlockOffset
;
168 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
169 RtlCreateUnicodeString(&FoundObject
->Name
,
171 CmiAddKeyToList(ParsedKey
, FoundObject
);
172 DPRINT("Created object 0x%x\n", FoundObject
);
176 if ((FoundObject
->KeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
177 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
179 DPRINT("Found link\n");
181 RtlInitUnicodeString(&LinkPath
, NULL
);
182 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
183 FoundObject
->KeyCell
,
185 if (NT_SUCCESS(Status
))
187 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
189 /* build new FullPath for reparsing */
190 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
193 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
195 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
196 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
197 TargetPath
.MaximumLength
);
198 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
201 wcscat(TargetPath
.Buffer
, EndPtr
);
204 RtlFreeUnicodeString(FullPath
);
205 RtlFreeUnicodeString(&LinkPath
);
206 FullPath
->Length
= TargetPath
.Length
;
207 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
208 FullPath
->Buffer
= TargetPath
.Buffer
;
210 DPRINT("FullPath '%wZ'\n", FullPath
);
212 /* reinitialize Path for reparsing */
213 *Path
= FullPath
->Buffer
;
217 RtlFreeUnicodeString(&KeyName
);
218 return(STATUS_REPARSE
);
222 ObReferenceObjectByPointer(FoundObject
,
223 STANDARD_RIGHTS_REQUIRED
,
228 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
232 VERIFY_KEY_OBJECT(FoundObject
);
234 *NextObject
= FoundObject
;
236 RtlFreeUnicodeString(&KeyName
);
238 return(STATUS_SUCCESS
);
243 CmiObjectCreate(PVOID ObjectBody
,
246 POBJECT_ATTRIBUTES ObjectAttributes
)
248 PKEY_OBJECT KeyObject
= ObjectBody
;
251 KeyObject
->ParentKey
= Parent
;
254 Start
= RemainingPath
;
257 RtlCreateUnicodeString(&KeyObject
->Name
,
262 RtlInitUnicodeString(&KeyObject
->Name
,
266 return STATUS_SUCCESS
;
271 CmiObjectDelete(PVOID DeletedObject
)
273 PKEY_OBJECT ParentKeyObject
;
274 PKEY_OBJECT KeyObject
;
276 DPRINT("Delete key object (%p)\n", DeletedObject
);
278 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
279 ParentKeyObject
= KeyObject
->ParentKey
;
281 ObReferenceObject (ParentKeyObject
);
283 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
285 DPRINT1("Key not found in parent list ???\n");
288 RtlFreeUnicodeString(&KeyObject
->Name
);
290 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
292 DPRINT("delete really key\n");
294 CmiRemoveSubKey(KeyObject
->RegistryHive
,
298 NtQuerySystemTime (&ParentKeyObject
->KeyCell
->LastWriteTime
);
299 CmiMarkBlockDirty (ParentKeyObject
->RegistryHive
,
300 ParentKeyObject
->KeyCellOffset
);
302 if (!IsNoFileHive (KeyObject
->RegistryHive
) ||
303 !IsNoFileHive (ParentKeyObject
->RegistryHive
))
309 ObDereferenceObject (ParentKeyObject
);
311 if (KeyObject
->NumberOfSubKeys
)
313 KEBUGCHECK(REGISTRY_ERROR
);
316 if (KeyObject
->SizeOfSubKeys
)
318 ExFreePool(KeyObject
->SubKeys
);
324 CmiObjectSecurity(PVOID ObjectBody
,
325 SECURITY_OPERATION_CODE OperationCode
,
326 SECURITY_INFORMATION SecurityInformation
,
327 PSECURITY_DESCRIPTOR SecurityDescriptor
,
330 DPRINT1 ("CmiObjectSecurity() called\n");
332 return STATUS_SUCCESS
;
337 CmiObjectQueryName (PVOID ObjectBody
,
338 POBJECT_NAME_INFORMATION ObjectNameInfo
,
342 POBJECT_NAME_INFORMATION LocalInfo
;
343 PKEY_OBJECT KeyObject
;
344 ULONG LocalReturnLength
;
347 DPRINT ("CmiObjectQueryName() called\n");
349 KeyObject
= (PKEY_OBJECT
)ObjectBody
;
351 LocalInfo
= ExAllocatePool (NonPagedPool
,
352 sizeof(OBJECT_NAME_INFORMATION
) +
353 MAX_PATH
* sizeof(WCHAR
));
354 if (LocalInfo
== NULL
)
355 return STATUS_INSUFFICIENT_RESOURCES
;
357 if (KeyObject
->ParentKey
!= KeyObject
)
359 Status
= ObQueryNameString (KeyObject
->ParentKey
,
361 MAX_PATH
* sizeof(WCHAR
),
366 /* KeyObject is the root key */
367 Status
= ObQueryNameString (BODY_TO_HEADER(KeyObject
)->Parent
,
369 MAX_PATH
* sizeof(WCHAR
),
373 if (!NT_SUCCESS (Status
))
375 ExFreePool (LocalInfo
);
378 DPRINT ("Parent path: %wZ\n", &LocalInfo
->Name
);
380 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
382 ExFreePool (LocalInfo
);
383 if (!NT_SUCCESS (Status
))
386 Status
= RtlAppendUnicodeToString (&ObjectNameInfo
->Name
,
388 if (!NT_SUCCESS (Status
))
391 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
393 if (NT_SUCCESS (Status
))
395 DPRINT ("Total path: %wZ\n", &ObjectNameInfo
->Name
);
403 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
408 DPRINT("ParentKey %.08x\n", ParentKey
);
410 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
412 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
414 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
415 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(ULONG
));
417 if (ParentKey
->NumberOfSubKeys
> 0)
419 RtlCopyMemory (tmpSubKeys
,
421 ParentKey
->NumberOfSubKeys
* sizeof(ULONG
));
424 if (ParentKey
->SubKeys
)
425 ExFreePool(ParentKey
->SubKeys
);
427 ParentKey
->SubKeys
= tmpSubKeys
;
428 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
431 /* FIXME: Please maintain the list in alphabetic order */
432 /* to allow a dichotomic search */
433 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
435 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
437 ObReferenceObjectByPointer(ParentKey
,
438 STANDARD_RIGHTS_REQUIRED
,
441 NewKey
->ParentKey
= ParentKey
;
442 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
447 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
449 PKEY_OBJECT ParentKey
;
453 ParentKey
= KeyToRemove
->ParentKey
;
454 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
455 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
456 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
458 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
460 if (Index
< ParentKey
->NumberOfSubKeys
-1)
461 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
462 &ParentKey
->SubKeys
[Index
+ 1],
463 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
464 ParentKey
->NumberOfSubKeys
--;
465 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
467 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
469 ObDereferenceObject(ParentKey
);
470 return STATUS_SUCCESS
;
473 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
475 return STATUS_UNSUCCESSFUL
;
480 CmiScanKeyList(PKEY_OBJECT Parent
,
481 PUNICODE_STRING KeyName
,
488 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
489 KeyName
, &Parent
->Name
);
491 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
492 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
493 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
495 CurKey
= Parent
->SubKeys
[Index
];
496 if (Attributes
& OBJ_CASE_INSENSITIVE
)
498 if ((KeyName
->Length
== CurKey
->Name
.Length
)
499 && (_wcsicmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
501 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
507 if ((KeyName
->Length
== CurKey
->Name
.Length
)
508 && (wcscmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
510 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
515 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
522 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
524 PUNICODE_STRING TargetPath
)
526 UNICODE_STRING LinkName
= ROS_STRING_INITIALIZER(L
"SymbolicLinkValue");
527 PVALUE_CELL ValueCell
;
531 DPRINT("CmiGetLinkTarget() called\n");
533 /* Get Value block of interest */
534 Status
= CmiScanKeyForValue(RegistryHive
,
539 if (!NT_SUCCESS(Status
))
541 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
545 if (ValueCell
->DataType
!= REG_LINK
)
547 DPRINT1("Type != REG_LINK\n!");
548 return(STATUS_UNSUCCESSFUL
);
551 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
553 TargetPath
->Length
= 0;
554 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
555 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
556 TargetPath
->MaximumLength
);
559 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
560 (ULONG
) ValueCell
->DataSize
);
562 if (ValueCell
->DataSize
> 0)
564 DataCell
= CmiGetCell (RegistryHive
, ValueCell
->DataOffset
, NULL
);
565 RtlCopyMemory(TargetPath
->Buffer
,
568 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
572 RtlCopyMemory(TargetPath
->Buffer
,
573 &ValueCell
->DataOffset
,
575 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
578 DPRINT("TargetPath '%wZ'\n", TargetPath
);
580 return(STATUS_SUCCESS
);