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.
11 #include <internal/ob.h>
14 #include <internal/registry.h>
15 #include <ntos/minmax.h>
18 #include <internal/debug.h>
24 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
26 PUNICODE_STRING TargetPath
);
28 /* FUNCTONS *****************************************************************/
31 CmiObjectParse(PVOID ParsedObject
,
33 PUNICODE_STRING FullPath
,
37 BLOCK_OFFSET BlockOffset
;
38 PKEY_OBJECT FoundObject
;
39 PKEY_OBJECT ParsedKey
;
45 UNICODE_STRING LinkPath
;
46 UNICODE_STRING TargetPath
;
47 UNICODE_STRING KeyName
;
49 ParsedKey
= ParsedObject
;
51 VERIFY_KEY_OBJECT(ParsedKey
);
57 DPRINT("*Path is NULL\n");
58 return STATUS_UNSUCCESSFUL
;
61 DPRINT("Path '%S'\n", *Path
);
63 /* Extract relevant path name */
65 if (*StartPtr
== L
'\\')
68 EndPtr
= wcschr(StartPtr
, L
'\\');
70 Length
= ((PCHAR
)EndPtr
- (PCHAR
)StartPtr
) / sizeof(WCHAR
);
72 Length
= wcslen(StartPtr
);
75 KeyName
.Length
= Length
* sizeof(WCHAR
);
76 KeyName
.MaximumLength
= KeyName
.Length
+ sizeof(WCHAR
);
77 KeyName
.Buffer
= ExAllocatePool(NonPagedPool
,
78 KeyName
.MaximumLength
);
79 RtlCopyMemory(KeyName
.Buffer
,
82 KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] = 0;
85 FoundObject
= CmiScanKeyList(ParsedKey
,
88 if (FoundObject
== NULL
)
90 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
97 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
99 RtlFreeUnicodeString(&KeyName
);
100 return(STATUS_UNSUCCESSFUL
);
103 if ((SubKeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
104 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
106 RtlInitUnicodeString(&LinkPath
, NULL
);
107 Status
= CmiGetLinkTarget(ParsedKey
->RegistryHive
,
110 if (NT_SUCCESS(Status
))
112 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
114 /* build new FullPath for reparsing */
115 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
118 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
120 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
121 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
122 TargetPath
.MaximumLength
);
123 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
126 wcscat(TargetPath
.Buffer
, EndPtr
);
129 RtlFreeUnicodeString(FullPath
);
130 RtlFreeUnicodeString(&LinkPath
);
131 FullPath
->Length
= TargetPath
.Length
;
132 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
133 FullPath
->Buffer
= TargetPath
.Buffer
;
135 DPRINT("FullPath '%wZ'\n", FullPath
);
137 /* reinitialize Path for reparsing */
138 *Path
= FullPath
->Buffer
;
142 RtlFreeUnicodeString(&KeyName
);
143 return(STATUS_REPARSE
);
147 /* Create new key object and put into linked list */
148 DPRINT("CmiObjectParse: %s\n", cPath
);
149 Status
= ObCreateObject(NULL
,
150 STANDARD_RIGHTS_REQUIRED
,
153 (PVOID
*)&FoundObject
);
154 if (!NT_SUCCESS(Status
))
156 RtlFreeUnicodeString(&KeyName
);
160 FoundObject
->Flags
= 0;
161 FoundObject
->KeyCell
= SubKeyCell
;
162 FoundObject
->BlockOffset
= BlockOffset
;
163 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
164 RtlCreateUnicodeString(&FoundObject
->Name
,
166 CmiAddKeyToList(ParsedKey
, FoundObject
);
167 DPRINT("Created object 0x%x\n", FoundObject
);
171 if ((FoundObject
->KeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
172 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)))
174 DPRINT("Found link\n");
176 RtlInitUnicodeString(&LinkPath
, NULL
);
177 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
178 FoundObject
->KeyCell
,
180 if (NT_SUCCESS(Status
))
182 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
184 /* build new FullPath for reparsing */
185 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
188 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
190 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
191 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
192 TargetPath
.MaximumLength
);
193 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
196 wcscat(TargetPath
.Buffer
, EndPtr
);
199 RtlFreeUnicodeString(FullPath
);
200 RtlFreeUnicodeString(&LinkPath
);
201 FullPath
->Length
= TargetPath
.Length
;
202 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
203 FullPath
->Buffer
= TargetPath
.Buffer
;
205 DPRINT("FullPath '%wZ'\n", FullPath
);
207 /* reinitialize Path for reparsing */
208 *Path
= FullPath
->Buffer
;
212 RtlFreeUnicodeString(&KeyName
);
213 return(STATUS_REPARSE
);
217 ObReferenceObjectByPointer(FoundObject
,
218 STANDARD_RIGHTS_REQUIRED
,
223 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
227 VERIFY_KEY_OBJECT(FoundObject
);
229 *NextObject
= FoundObject
;
231 RtlFreeUnicodeString(&KeyName
);
233 return(STATUS_SUCCESS
);
238 CmiObjectCreate(PVOID ObjectBody
,
241 POBJECT_ATTRIBUTES ObjectAttributes
)
243 PKEY_OBJECT KeyObject
= ObjectBody
;
246 KeyObject
->ParentKey
= Parent
;
249 Start
= RemainingPath
;
252 RtlCreateUnicodeString(&KeyObject
->Name
,
257 RtlInitUnicodeString(&KeyObject
->Name
,
261 return STATUS_SUCCESS
;
266 CmiObjectDelete(PVOID DeletedObject
)
268 PKEY_OBJECT KeyObject
;
270 DPRINT("Delete object key\n");
272 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
274 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
276 DPRINT1("Key not found in parent list ???\n");
279 RtlFreeUnicodeString(&KeyObject
->Name
);
281 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
283 DPRINT("delete really key\n");
285 CmiRemoveSubKey(KeyObject
->RegistryHive
,
286 KeyObject
->ParentKey
,
289 if (!IsVolatileHive(KeyObject
->RegistryHive
))
298 CmiObjectSecurity(PVOID ObjectBody
,
299 SECURITY_OPERATION_CODE OperationCode
,
300 SECURITY_INFORMATION SecurityInformation
,
301 PSECURITY_DESCRIPTOR SecurityDescriptor
,
304 DPRINT1("CmiObjectSecurity() called\n");
306 return(STATUS_SUCCESS
);
311 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
316 DPRINT("ParentKey %.08x\n", ParentKey
);
318 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
320 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
322 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
323 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(ULONG
));
325 if (ParentKey
->NumberOfSubKeys
> 0)
327 RtlCopyMemory (tmpSubKeys
,
329 ParentKey
->NumberOfSubKeys
* sizeof(ULONG
));
332 if (ParentKey
->SubKeys
)
333 ExFreePool(ParentKey
->SubKeys
);
335 ParentKey
->SubKeys
= tmpSubKeys
;
336 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
339 /* FIXME: Please maintain the list in alphabetic order */
340 /* to allow a dichotomic search */
341 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
343 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
345 ObReferenceObjectByPointer(ParentKey
,
346 STANDARD_RIGHTS_REQUIRED
,
349 NewKey
->ParentKey
= ParentKey
;
350 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
355 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
357 PKEY_OBJECT ParentKey
;
361 ParentKey
= KeyToRemove
->ParentKey
;
362 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
363 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
364 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
366 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
368 if (Index
< ParentKey
->NumberOfSubKeys
-1)
369 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
370 &ParentKey
->SubKeys
[Index
+ 1],
371 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
372 ParentKey
->NumberOfSubKeys
--;
373 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
375 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
377 ObDereferenceObject(ParentKey
);
378 return STATUS_SUCCESS
;
381 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
383 return STATUS_UNSUCCESSFUL
;
388 CmiScanKeyList(PKEY_OBJECT Parent
,
389 PUNICODE_STRING KeyName
,
396 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
397 KeyName
, &Parent
->Name
);
399 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
400 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
401 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
403 CurKey
= Parent
->SubKeys
[Index
];
404 if (Attributes
& OBJ_CASE_INSENSITIVE
)
406 if ((KeyName
->Length
== CurKey
->Name
.Length
)
407 && (_wcsicmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
409 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
415 if ((KeyName
->Length
== CurKey
->Name
.Length
)
416 && (wcscmp(KeyName
->Buffer
, CurKey
->Name
.Buffer
) == 0))
418 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
423 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
430 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
432 PUNICODE_STRING TargetPath
)
434 UNICODE_STRING LinkName
= UNICODE_STRING_INITIALIZER(L
"SymbolicLinkValue");
435 PVALUE_CELL ValueCell
;
439 DPRINT("CmiGetLinkTarget() called\n");
441 /* Get Value block of interest */
442 Status
= CmiScanKeyForValue(RegistryHive
,
447 if (!NT_SUCCESS(Status
))
449 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
453 if (ValueCell
->DataType
!= REG_LINK
)
455 DPRINT1("Type != REG_LINK\n!");
456 return(STATUS_UNSUCCESSFUL
);
459 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
461 TargetPath
->Length
= 0;
462 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
463 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
464 TargetPath
->MaximumLength
);
467 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
468 (ULONG
) ValueCell
->DataSize
);
470 if (ValueCell
->DataSize
> 0)
472 DataCell
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, NULL
);
473 RtlCopyMemory(TargetPath
->Buffer
,
476 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
480 RtlCopyMemory(TargetPath
->Buffer
,
481 &ValueCell
->DataOffset
,
483 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
486 DPRINT("TargetPath '%wZ'\n", TargetPath
);
488 return(STATUS_SUCCESS
);