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/pool.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
;
47 UNICODE_STRING LinkPath
;
48 UNICODE_STRING TargetPath
;
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
);
75 wcstombs(cPath
, StartPtr
, Length
);
79 FoundObject
= CmiScanKeyList(ParsedKey
, cPath
, Attributes
);
80 if (FoundObject
== NULL
)
82 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
89 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
91 return(STATUS_UNSUCCESSFUL
);
94 if ((SubKeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
95 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
) /*(end == NULL)*/))
97 RtlInitUnicodeString(&LinkPath
, NULL
);
98 Status
= CmiGetLinkTarget(ParsedKey
->RegistryHive
,
101 if (NT_SUCCESS(Status
))
103 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
105 /* build new FullPath for reparsing */
106 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
109 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
111 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
112 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
113 TargetPath
.MaximumLength
);
114 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
117 wcscat(TargetPath
.Buffer
, EndPtr
);
120 RtlFreeUnicodeString(FullPath
);
121 RtlFreeUnicodeString(&LinkPath
);
122 FullPath
->Length
= TargetPath
.Length
;
123 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
124 FullPath
->Buffer
= TargetPath
.Buffer
;
126 DPRINT("FullPath '%wZ'\n", FullPath
);
128 /* reinitialize Path for reparsing */
129 *Path
= FullPath
->Buffer
;
132 return(STATUS_REPARSE
);
136 /* Create new key object and put into linked list */
137 DPRINT("CmiObjectParse: %s\n", cPath
);
138 Status
= ObCreateObject(NULL
,
139 STANDARD_RIGHTS_REQUIRED
,
142 (PVOID
*)&FoundObject
);
143 if (!NT_SUCCESS(Status
))
148 FoundObject
->Flags
= 0;
150 FoundObject
->Name
.Length
= Length
* sizeof(WCHAR
);
151 FoundObject
->Name
.MaximumLength
= FoundObject
->Name
.Length
+ sizeof(WCHAR
);
152 FoundObject
->Name
.Buffer
= ExAllocatePool(NonPagedPool
, FoundObject
->Name
.MaximumLength
);
153 RtlCopyMemory(FoundObject
->Name
.Buffer
, StartPtr
, FoundObject
->Name
.Length
);
154 FoundObject
->Name
.Buffer
[FoundObject
->Name
.Length
/ sizeof(WCHAR
)] = 0;
156 FoundObject
->KeyCell
= SubKeyCell
;
157 FoundObject
->BlockOffset
= BlockOffset
;
158 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
159 CmiAddKeyToList(ParsedKey
, FoundObject
);
160 DPRINT("Created object 0x%x\n", FoundObject
);
164 if ((FoundObject
->KeyCell
->Flags
& REG_KEY_LINK_CELL
) &&
165 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)/*(end == NULL)*/))
167 DPRINT("Found link\n");
169 RtlInitUnicodeString(&LinkPath
, NULL
);
170 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
171 FoundObject
->KeyCell
,
173 if (NT_SUCCESS(Status
))
175 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
177 /* build new FullPath for reparsing */
178 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
181 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
183 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
184 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
185 TargetPath
.MaximumLength
);
186 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
189 wcscat(TargetPath
.Buffer
, EndPtr
);
192 RtlFreeUnicodeString(FullPath
);
193 RtlFreeUnicodeString(&LinkPath
);
194 FullPath
->Length
= TargetPath
.Length
;
195 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
196 FullPath
->Buffer
= TargetPath
.Buffer
;
198 DPRINT("FullPath '%wZ'\n", FullPath
);
200 /* reinitialize Path for reparsing */
201 *Path
= FullPath
->Buffer
;
204 return(STATUS_REPARSE
);
208 ObReferenceObjectByPointer(FoundObject
,
209 STANDARD_RIGHTS_REQUIRED
,
214 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
218 VERIFY_KEY_OBJECT(FoundObject
);
220 *NextObject
= FoundObject
;
222 return(STATUS_SUCCESS
);
227 CmiObjectCreate(PVOID ObjectBody
,
230 POBJECT_ATTRIBUTES ObjectAttributes
)
232 PKEY_OBJECT KeyObject
= ObjectBody
;
235 KeyObject
->ParentKey
= Parent
;
238 Start
= RemainingPath
;
241 RtlCreateUnicodeString(&KeyObject
->Name
,
246 RtlInitUnicodeString(&KeyObject
->Name
,
250 return STATUS_SUCCESS
;
255 CmiObjectDelete(PVOID DeletedObject
)
257 PKEY_OBJECT KeyObject
;
259 DPRINT("Delete object key\n");
261 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
263 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
265 DPRINT1("Key not found in parent list ???\n");
268 RtlFreeUnicodeString(&KeyObject
->Name
);
270 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
272 DPRINT("delete really key\n");
274 CmiRemoveSubKey(KeyObject
->RegistryHive
,
275 KeyObject
->ParentKey
,
278 if (!IsVolatileHive(KeyObject
->RegistryHive
))
287 CmiObjectSecurity(PVOID ObjectBody
,
288 SECURITY_OPERATION_CODE OperationCode
,
289 SECURITY_INFORMATION SecurityInformation
,
290 PSECURITY_DESCRIPTOR SecurityDescriptor
,
293 DPRINT1("CmiObjectSecurity() called\n");
295 return(STATUS_SUCCESS
);
300 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
305 DPRINT("ParentKey %.08x\n", ParentKey
);
307 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
309 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
311 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
312 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(ULONG
));
314 if (ParentKey
->NumberOfSubKeys
> 0)
316 RtlCopyMemory (tmpSubKeys
,
318 ParentKey
->NumberOfSubKeys
* sizeof(ULONG
));
321 if (ParentKey
->SubKeys
)
322 ExFreePool(ParentKey
->SubKeys
);
324 ParentKey
->SubKeys
= tmpSubKeys
;
325 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
328 /* FIXME: Please maintain the list in alphabetic order */
329 /* to allow a dichotomic search */
330 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
332 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
334 ObReferenceObjectByPointer(ParentKey
,
335 STANDARD_RIGHTS_REQUIRED
,
338 NewKey
->ParentKey
= ParentKey
;
339 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
344 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
346 PKEY_OBJECT ParentKey
;
350 ParentKey
= KeyToRemove
->ParentKey
;
351 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
352 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
353 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
355 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
357 if (Index
< ParentKey
->NumberOfSubKeys
-1)
358 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
359 &ParentKey
->SubKeys
[Index
+ 1],
360 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
361 ParentKey
->NumberOfSubKeys
--;
362 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
364 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
366 ObDereferenceObject(ParentKey
);
367 return STATUS_SUCCESS
;
370 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
372 return STATUS_UNSUCCESSFUL
;
377 CmiScanKeyList(PKEY_OBJECT Parent
,
384 UNICODE_STRING UName
;
386 DPRINT("Scanning key list for: %s (Parent: %wZ)\n",
387 KeyName
, &Parent
->Name
);
389 RtlCreateUnicodeStringFromAsciiz(&UName
,
392 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
393 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
394 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
396 CurKey
= Parent
->SubKeys
[Index
];
397 if (Attributes
& OBJ_CASE_INSENSITIVE
)
399 if ((UName
.Length
== CurKey
->Name
.Length
)
400 && (_wcsicmp(UName
.Buffer
, CurKey
->Name
.Buffer
) == 0))
402 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
403 RtlFreeUnicodeString(&UName
);
409 if ((UName
.Length
== CurKey
->Name
.Length
)
410 && (wcscmp(UName
.Buffer
, CurKey
->Name
.Buffer
) == 0))
412 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
413 RtlFreeUnicodeString(&UName
);
418 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
419 RtlFreeUnicodeString(&UName
);
426 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
428 PUNICODE_STRING TargetPath
)
430 UNICODE_STRING LinkName
= UNICODE_STRING_INITIALIZER(L
"SymbolicLinkValue");
431 PVALUE_CELL ValueCell
;
435 DPRINT("CmiGetLinkTarget() called\n");
437 /* Get Value block of interest */
438 Status
= CmiScanKeyForValue(RegistryHive
,
443 if (!NT_SUCCESS(Status
))
445 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
449 if (ValueCell
->DataType
!= REG_LINK
)
451 DPRINT1("Type != REG_LINK\n!");
452 return(STATUS_UNSUCCESSFUL
);
455 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
457 TargetPath
->Length
= 0;
458 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
459 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
460 TargetPath
->MaximumLength
);
463 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
464 (ULONG
) ValueCell
->DataSize
);
466 if (ValueCell
->DataSize
> 0)
468 DataCell
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, NULL
);
469 RtlCopyMemory(TargetPath
->Buffer
,
472 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
476 RtlCopyMemory(TargetPath
->Buffer
,
477 &ValueCell
->DataOffset
,
479 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
482 DPRINT("TargetPath '%wZ'\n", TargetPath
);
484 return(STATUS_SUCCESS
);