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.
12 #include <ddk/ntddk.h>
14 #include <internal/ob.h>
17 #include <internal/pool.h>
18 #include <internal/registry.h>
19 #include <ntos/minmax.h>
22 #include <internal/debug.h>
29 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
31 PUNICODE_STRING TargetPath
);
33 /* FUNCTONS *****************************************************************/
36 CmiObjectParse(PVOID ParsedObject
,
38 PUNICODE_STRING FullPath
,
42 BLOCK_OFFSET BlockOffset
;
43 PKEY_OBJECT FoundObject
;
44 PKEY_OBJECT ParsedKey
;
51 UNICODE_STRING LinkPath
;
52 UNICODE_STRING TargetPath
;
54 ParsedKey
= ParsedObject
;
56 VERIFY_KEY_OBJECT(ParsedKey
);
62 DPRINT("*Path is NULL\n");
63 return STATUS_UNSUCCESSFUL
;
66 DPRINT("Path '%S'\n", *Path
);
68 /* Extract relevant path name */
70 if (*StartPtr
== L
'\\')
73 EndPtr
= wcschr(StartPtr
, L
'\\');
75 Length
= ((PCHAR
)EndPtr
- (PCHAR
)StartPtr
) / sizeof(WCHAR
);
77 Length
= wcslen(StartPtr
);
79 wcstombs(cPath
, StartPtr
, Length
);
83 FoundObject
= CmiScanKeyList(ParsedKey
, cPath
, Attributes
);
84 if (FoundObject
== NULL
)
86 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
93 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
95 return(STATUS_UNSUCCESSFUL
);
98 if ((SubKeyCell
->Type
== REG_LINK_KEY_CELL_TYPE
) &&
99 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
) /*(end == 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
;
136 return(STATUS_REPARSE
);
140 /* Create new key object and put into linked list */
141 DPRINT("CmiObjectParse: %s\n", cPath
);
142 Status
= ObCreateObject(NULL
,
143 STANDARD_RIGHTS_REQUIRED
,
146 (PVOID
*)&FoundObject
);
147 if (!NT_SUCCESS(Status
))
152 FoundObject
->Flags
= 0;
153 FoundObject
->Name
= SubKeyCell
->Name
;
154 FoundObject
->NameSize
= SubKeyCell
->NameSize
;
155 FoundObject
->KeyCell
= SubKeyCell
;
156 FoundObject
->BlockOffset
= BlockOffset
;
157 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
158 CmiAddKeyToList(ParsedKey
, FoundObject
);
159 DPRINT("Created object 0x%x\n", FoundObject
);
163 if ((FoundObject
->KeyCell
->Type
== REG_LINK_KEY_CELL_TYPE
) &&
164 !((Attributes
& OBJ_OPENLINK
) && (EndPtr
== NULL
)/*(end == NULL)*/))
166 DPRINT("Found link\n");
168 RtlInitUnicodeString(&LinkPath
, NULL
);
169 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
170 FoundObject
->KeyCell
,
172 if (NT_SUCCESS(Status
))
174 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
176 /* build new FullPath for reparsing */
177 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
180 TargetPath
.MaximumLength
+= (wcslen(EndPtr
) * sizeof(WCHAR
));
182 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
183 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
184 TargetPath
.MaximumLength
);
185 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
188 wcscat(TargetPath
.Buffer
, EndPtr
);
191 RtlFreeUnicodeString(FullPath
);
192 RtlFreeUnicodeString(&LinkPath
);
193 FullPath
->Length
= TargetPath
.Length
;
194 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
195 FullPath
->Buffer
= TargetPath
.Buffer
;
197 DPRINT("FullPath '%wZ'\n", FullPath
);
199 /* reinitialize Path for reparsing */
200 *Path
= FullPath
->Buffer
;
203 return(STATUS_REPARSE
);
207 ObReferenceObjectByPointer(FoundObject
,
208 STANDARD_RIGHTS_REQUIRED
,
213 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
216 char buffer
[_BUFFER_LEN
];
217 memset(buffer
, 0, _BUFFER_LEN
);
218 strncpy(buffer
, FoundObject
->Name
, min(FoundObject
->NameSize
, _BUFFER_LEN
- 1));
219 DPRINT("CmiObjectParse: %s\n", buffer
);
225 VERIFY_KEY_OBJECT(FoundObject
);
227 *NextObject
= FoundObject
;
229 return(STATUS_SUCCESS
);
234 CmiObjectCreate(PVOID ObjectBody
,
237 POBJECT_ATTRIBUTES ObjectAttributes
)
239 PKEY_OBJECT pKey
= ObjectBody
;
241 pKey
->ParentKey
= Parent
;
244 if(RemainingPath
[0]== L
'\\')
246 pKey
->Name
= (PCHAR
)(&RemainingPath
[1]);
247 pKey
->NameSize
= wcslen(RemainingPath
) - 1;
251 pKey
->Name
= (PCHAR
)RemainingPath
;
252 pKey
->NameSize
= wcslen(RemainingPath
);
260 return STATUS_SUCCESS
;
265 CmiObjectDelete(PVOID DeletedObject
)
267 PKEY_OBJECT KeyObject
;
269 DPRINT("Delete object key\n");
271 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
273 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
275 DPRINT1("Key not found in parent list ???\n");
278 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
280 DPRINT("delete really key\n");
282 CmiRemoveSubKey(KeyObject
->RegistryHive
,
283 KeyObject
->ParentKey
,
286 if (IsPermanentHive(KeyObject
->RegistryHive
))
291 CmiReleaseBlock(KeyObject
->RegistryHive
, KeyObject
->KeyCell
);
297 CmiObjectSecurity(PVOID ObjectBody
,
298 SECURITY_OPERATION_CODE OperationCode
,
299 SECURITY_INFORMATION SecurityInformation
,
300 PSECURITY_DESCRIPTOR SecurityDescriptor
,
303 DPRINT1("CmiObjectSecurity() called\n");
305 return(STATUS_SUCCESS
);
310 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
315 DPRINT("ParentKey %.08x\n", ParentKey
);
317 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
319 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
321 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
322 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(DWORD
));
324 if (ParentKey
->NumberOfSubKeys
> 0)
328 ParentKey
->NumberOfSubKeys
* sizeof(DWORD
));
331 if (ParentKey
->SubKeys
)
332 ExFreePool(ParentKey
->SubKeys
);
334 ParentKey
->SubKeys
= tmpSubKeys
;
335 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
338 /* FIXME: Please maintain the list in alphabetic order */
339 /* to allow a dichotomic search */
340 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
342 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
344 ObReferenceObjectByPointer(ParentKey
,
345 STANDARD_RIGHTS_REQUIRED
,
348 NewKey
->ParentKey
= ParentKey
;
349 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
354 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
356 PKEY_OBJECT ParentKey
;
360 ParentKey
= KeyToRemove
->ParentKey
;
361 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
362 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
363 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
365 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
367 if (Index
< ParentKey
->NumberOfSubKeys
-1)
368 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
369 &ParentKey
->SubKeys
[Index
+ 1],
370 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
371 ParentKey
->NumberOfSubKeys
--;
372 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
374 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
376 ObDereferenceObject(ParentKey
);
377 return STATUS_SUCCESS
;
380 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
382 return STATUS_UNSUCCESSFUL
;
387 CmiScanKeyList(PKEY_OBJECT Parent
,
397 DPRINT("Scanning key list for: %s (Parent: %s)\n",
398 KeyName
, Parent
->Name
);
401 char buffer
[_BUFFER_LEN
];
402 memset(buffer
, 0, _BUFFER_LEN
);
403 strncpy(buffer
, Parent
->Name
, min(Parent
->NameSize
, _BUFFER_LEN
- 1));
404 DPRINT("Scanning key list for: %s (Parent: %s)\n", KeyName
, buffer
);
408 NameSize
= strlen(KeyName
);
409 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
410 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
411 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
413 CurKey
= Parent
->SubKeys
[Index
];
414 if (Attributes
& OBJ_CASE_INSENSITIVE
)
416 if ((NameSize
== CurKey
->NameSize
)
417 && (_strnicmp(KeyName
, CurKey
->Name
, NameSize
) == 0))
419 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
425 if ((NameSize
== CurKey
->NameSize
)
426 && (strncmp(KeyName
,CurKey
->Name
,NameSize
) == 0))
428 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
433 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
440 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
442 PUNICODE_STRING TargetPath
)
444 UNICODE_STRING LinkName
= UNICODE_STRING_INITIALIZER(L
"SymbolicLinkValue");
445 PVALUE_CELL ValueCell
;
449 DPRINT("CmiGetLinkTarget() called\n");
451 /* Get Value block of interest */
452 Status
= CmiScanKeyForValue(RegistryHive
,
457 if (!NT_SUCCESS(Status
))
459 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
463 if (ValueCell
->DataType
!= REG_LINK
)
465 DPRINT1("Type != REG_LINK\n!");
466 return(STATUS_UNSUCCESSFUL
);
469 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
471 TargetPath
->Length
= 0;
472 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
473 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
474 TargetPath
->MaximumLength
);
477 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
478 (ULONG
) ValueCell
->DataSize
);
480 if (ValueCell
->DataSize
> 0)
482 DataCell
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, NULL
);
483 RtlCopyMemory(TargetPath
->Buffer
,
486 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
487 CmiReleaseBlock(RegistryHive
, DataCell
);
491 RtlCopyMemory(TargetPath
->Buffer
,
492 &ValueCell
->DataOffset
,
494 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
497 DPRINT("TargetPath '%wZ'\n", TargetPath
);
499 return(STATUS_SUCCESS
);