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
12 #include <internal/ob.h>
15 #include <internal/registry.h>
16 #include <ntos/minmax.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
= ObRosCreateObject(NULL
,
151 STANDARD_RIGHTS_REQUIRED
,
154 (PVOID
*)&FoundObject
);
155 if (!NT_SUCCESS(Status
))
157 RtlFreeUnicodeString(&KeyName
);
161 FoundObject
->Flags
= 0;
162 FoundObject
->KeyCell
= SubKeyCell
;
163 FoundObject
->BlockOffset
= BlockOffset
;
164 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
165 RtlCreateUnicodeString(&FoundObject
->Name
,
167 CmiAddKeyToList(ParsedKey
, FoundObject
);
168 DPRINT("Created object 0x%x\n", FoundObject
);
172 if ((FoundObject
->KeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
173 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
175 DPRINT("Found link\n");
177 RtlInitUnicodeString(&LinkPath
, NULL
);
178 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
179 FoundObject
->KeyCell
,
181 if (NT_SUCCESS(Status
))
183 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
185 /* build new FullPath for reparsing */
186 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
189 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
191 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
192 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
193 TargetPath
.MaximumLength
);
194 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
197 wcscat(TargetPath
.Buffer
, EndPtr
);
200 RtlFreeUnicodeString(FullPath
);
201 RtlFreeUnicodeString(&LinkPath
);
202 FullPath
->Length
= TargetPath
.Length
;
203 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
204 FullPath
->Buffer
= TargetPath
.Buffer
;
206 DPRINT("FullPath '%wZ'\n", FullPath
);
208 /* reinitialize Path for reparsing */
209 *Path
= FullPath
->Buffer
;
213 RtlFreeUnicodeString(&KeyName
);
214 return(STATUS_REPARSE
);
218 ObReferenceObjectByPointer(FoundObject
,
219 STANDARD_RIGHTS_REQUIRED
,
224 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
228 VERIFY_KEY_OBJECT(FoundObject
);
230 *NextObject
= FoundObject
;
232 RtlFreeUnicodeString(&KeyName
);
234 return(STATUS_SUCCESS
);
239 CmiObjectCreate(PVOID ObjectBody
,
242 POBJECT_ATTRIBUTES ObjectAttributes
)
244 PKEY_OBJECT KeyObject
= ObjectBody
;
247 KeyObject
->ParentKey
= Parent
;
250 Start
= RemainingPath
;
253 RtlCreateUnicodeString(&KeyObject
->Name
,
258 RtlInitUnicodeString(&KeyObject
->Name
,
262 return STATUS_SUCCESS
;
267 CmiObjectDelete(PVOID DeletedObject
)
269 PKEY_OBJECT KeyObject
;
271 DPRINT("Delete key object (%p)\n", DeletedObject
);
273 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
275 ObReferenceObject(KeyObject
->ParentKey
);
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
,
289 KeyObject
->ParentKey
,
292 if (!IsNoFileHive(KeyObject
->RegistryHive
))
297 ObDereferenceObject(KeyObject
->ParentKey
);
298 if (KeyObject
->NumberOfSubKeys
)
302 if (KeyObject
->SizeOfSubKeys
)
304 ExFreePool(KeyObject
->SubKeys
);
311 CmiObjectSecurity(PVOID ObjectBody
,
312 SECURITY_OPERATION_CODE OperationCode
,
313 SECURITY_INFORMATION SecurityInformation
,
314 PSECURITY_DESCRIPTOR SecurityDescriptor
,
317 DPRINT1 ("CmiObjectSecurity() called\n");
319 return STATUS_SUCCESS
;
324 CmiObjectQueryName (PVOID ObjectBody
,
325 POBJECT_NAME_INFORMATION ObjectNameInfo
,
329 POBJECT_NAME_INFORMATION LocalInfo
;
330 PKEY_OBJECT KeyObject
;
331 ULONG LocalReturnLength
;
334 DPRINT ("CmiObjectQueryName() called\n");
336 KeyObject
= (PKEY_OBJECT
)ObjectBody
;
338 LocalInfo
= ExAllocatePool (NonPagedPool
,
339 sizeof(OBJECT_NAME_INFORMATION
) +
340 MAX_PATH
* sizeof(WCHAR
));
341 if (LocalInfo
== NULL
)
342 return STATUS_INSUFFICIENT_RESOURCES
;
344 if (KeyObject
->ParentKey
!= KeyObject
)
346 Status
= ObQueryNameString (KeyObject
->ParentKey
,
348 MAX_PATH
* sizeof(WCHAR
),
353 /* KeyObject is the root key */
354 Status
= ObQueryNameString (BODY_TO_HEADER(KeyObject
)->Parent
,
356 MAX_PATH
* sizeof(WCHAR
),
360 if (!NT_SUCCESS (Status
))
362 ExFreePool (LocalInfo
);
365 DPRINT ("Parent path: %wZ\n", &LocalInfo
->Name
);
367 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
369 ExFreePool (LocalInfo
);
370 if (!NT_SUCCESS (Status
))
373 Status
= RtlAppendUnicodeToString (&ObjectNameInfo
->Name
,
375 if (!NT_SUCCESS (Status
))
378 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
380 if (NT_SUCCESS (Status
))
382 DPRINT ("Total path: %wZ\n", &ObjectNameInfo
->Name
);
390 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
395 DPRINT("ParentKey %.08x\n", ParentKey
);
397 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
399 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
401 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
402 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(ULONG
));
404 if (ParentKey
->NumberOfSubKeys
> 0)
406 RtlCopyMemory (tmpSubKeys
,
408 ParentKey
->NumberOfSubKeys
* sizeof(ULONG
));
411 if (ParentKey
->SubKeys
)
412 ExFreePool(ParentKey
->SubKeys
);
414 ParentKey
->SubKeys
= tmpSubKeys
;
415 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
418 /* FIXME: Please maintain the list in alphabetic order */
419 /* to allow a dichotomic search */
420 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
422 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
424 ObReferenceObjectByPointer(ParentKey
,
425 STANDARD_RIGHTS_REQUIRED
,
428 NewKey
->ParentKey
= ParentKey
;
429 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
434 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
436 PKEY_OBJECT ParentKey
;
440 ParentKey
= KeyToRemove
->ParentKey
;
441 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
442 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
443 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
445 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
447 if (Index
< ParentKey
->NumberOfSubKeys
-1)
448 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
449 &ParentKey
->SubKeys
[Index
+ 1],
450 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
451 ParentKey
->NumberOfSubKeys
--;
452 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
454 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
456 ObDereferenceObject(ParentKey
);
457 return STATUS_SUCCESS
;
460 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
462 return STATUS_UNSUCCESSFUL
;
467 CmiScanKeyList(PKEY_OBJECT Parent
,
468 PUNICODE_STRING KeyName
,
475 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
476 KeyName
, &Parent
->Name
);
478 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
479 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
480 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
482 CurKey
= Parent
->SubKeys
[Index
];
483 if (Attributes
& OBJ_CASE_INSENSITIVE
)
485 if ((KeyName
->Length
== CurKey
->Name
.Length
)
486 && (_wcsicmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
488 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
494 if ((KeyName
->Length
== CurKey
->Name
.Length
)
495 && (wcscmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
497 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
502 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
509 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
511 PUNICODE_STRING TargetPath
)
513 UNICODE_STRING LinkName
= UNICODE_STRING_INITIALIZER(L
"SymbolicLinkValue");
514 PVALUE_CELL ValueCell
;
518 DPRINT("CmiGetLinkTarget() called\n");
520 /* Get Value block of interest */
521 Status
= CmiScanKeyForValue(RegistryHive
,
526 if (!NT_SUCCESS(Status
))
528 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
532 if (ValueCell
->DataType
!= REG_LINK
)
534 DPRINT1("Type != REG_LINK\n!");
535 return(STATUS_UNSUCCESSFUL
);
538 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
540 TargetPath
->Length
= 0;
541 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
542 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
543 TargetPath
->MaximumLength
);
546 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
547 (ULONG
) ValueCell
->DataSize
);
549 if (ValueCell
->DataSize
> 0)
551 DataCell
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, NULL
);
552 RtlCopyMemory(TargetPath
->Buffer
,
555 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
559 RtlCopyMemory(TargetPath
->Buffer
,
560 &ValueCell
->DataOffset
,
562 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
565 DPRINT("TargetPath '%wZ'\n", TargetPath
);
567 return(STATUS_SUCCESS
);