* UPDATE HISTORY:
*/
+#ifdef WIN32_REGDBG
+#include "cm_win32.h"
+#else
#include <ddk/ntddk.h>
#include <roscfg.h>
#include <internal/ob.h>
#include <string.h>
#include <internal/pool.h>
#include <internal/registry.h>
+#include <ntos/minmax.h>
#define NDEBUG
#include <internal/debug.h>
#include "cm.h"
+#endif
-extern POBJECT_TYPE CmiKeyType;
-extern KSPIN_LOCK CmiKeyListLock;
+
+static NTSTATUS
+CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
+ PKEY_CELL KeyCell,
+ PUNICODE_STRING TargetPath);
+
+/* FUNCTONS *****************************************************************/
NTSTATUS STDCALL
CmiObjectParse(PVOID ParsedObject,
- PVOID *NextObject,
- PUNICODE_STRING FullPath,
- PWSTR *Path,
- POBJECT_TYPE ObjectType,
- ULONG Attributes)
+ PVOID *NextObject,
+ PUNICODE_STRING FullPath,
+ PWSTR *Path,
+ ULONG Attributes)
{
- BLOCK_OFFSET BlockOffset;
- PKEY_OBJECT FoundObject;
- PKEY_OBJECT ParsedKey;
- PKEY_CELL SubKeyCell;
- CHAR cPath[MAX_PATH];
- NTSTATUS Status;
- PWSTR end;
-
- ParsedKey = ParsedObject;
+ BLOCK_OFFSET BlockOffset;
+ PKEY_OBJECT FoundObject;
+ PKEY_OBJECT ParsedKey;
+ PKEY_CELL SubKeyCell;
+ CHAR cPath[MAX_PATH];
+ NTSTATUS Status;
+ PWSTR end;
+ UNICODE_STRING LinkPath;
+ UNICODE_STRING TargetPath;
+
+ ParsedKey = ParsedObject;
VERIFY_KEY_OBJECT(ParsedKey);
- *NextObject = NULL;
+ *NextObject = NULL;
- if ((*Path) == NULL)
- {
+ if ((*Path) == NULL)
+ {
DPRINT("*Path is NULL\n");
- return STATUS_UNSUCCESSFUL;
- }
-
- if ((*Path[0]) == '\\')
- {
- end = wcschr((*Path) + 1, '\\');
- if (end != NULL)
- *end = 0;
- wcstombs(cPath, (*Path) + 1, wcslen((*Path) + 1));
- cPath[wcslen((*Path) + 1)] = 0;
- }
- else
- {
- end = wcschr((*Path), '\\');
- if (end != NULL)
- *end = 0;
- wcstombs(cPath, (*Path), wcslen((*Path)));
- cPath[wcslen((*Path))] = 0;
- }
+ return STATUS_UNSUCCESSFUL;
+ }
- FoundObject = CmiScanKeyList(ParsedKey, cPath, Attributes);
- if (FoundObject == NULL)
- {
- Status = CmiScanForSubKey(ParsedKey->RegistryHive,
- ParsedKey->KeyCell,
- &SubKeyCell,
- &BlockOffset,
- cPath,
- 0,
- Attributes);
-
- if (!NT_SUCCESS(Status) || (SubKeyCell == NULL))
- {
- if (end != NULL)
- {
- *end = '\\';
- }
- return STATUS_UNSUCCESSFUL;
- }
-
- /* Create new key object and put into linked list */
- DPRINT("CmiObjectParse %s\n", cPath);
- Status = ObCreateObject(NULL,
- STANDARD_RIGHTS_REQUIRED,
- NULL,
- CmiKeyType,
- (PVOID*) &FoundObject);
-
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- FoundObject->Flags = 0;
- FoundObject->Name = SubKeyCell->Name;
- FoundObject->NameSize = SubKeyCell->NameSize;
- FoundObject->KeyCell = SubKeyCell;
- FoundObject->BlockOffset = BlockOffset;
- FoundObject->RegistryHive = ParsedKey->RegistryHive;
- CmiAddKeyToList(ParsedKey, FoundObject);
- DPRINT("Created object 0x%x\n", FoundObject);
- }
- else
+ DPRINT("Path '%S'\n", *Path);
+
+ if ((*Path[0]) == '\\')
{
- ObReferenceObjectByPointer(FoundObject,
- STANDARD_RIGHTS_REQUIRED,
- NULL,
- UserMode);
+ end = wcschr((*Path) + 1, '\\');
+ if (end != NULL)
+ *end = 0;
+ wcstombs(cPath, (*Path) + 1, wcslen((*Path) + 1));
+ cPath[wcslen((*Path) + 1)] = 0;
+ }
+ else
+ {
+ end = wcschr((*Path), '\\');
+ if (end != NULL)
+ *end = 0;
+ wcstombs(cPath, (*Path), wcslen((*Path)));
+ cPath[wcslen((*Path))] = 0;
}
- DPRINT("CmiObjectParse %s\n", FoundObject->Name);
+ FoundObject = CmiScanKeyList(ParsedKey, cPath, Attributes);
+ if (FoundObject == NULL)
+ {
+ Status = CmiScanForSubKey(ParsedKey->RegistryHive,
+ ParsedKey->KeyCell,
+ &SubKeyCell,
+ &BlockOffset,
+ cPath,
+ 0,
+ Attributes);
+ if (!NT_SUCCESS(Status) || (SubKeyCell == NULL))
+ {
+ if (end != NULL)
+ {
+ *end = '\\';
+ }
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ if ((SubKeyCell->Type == REG_LINK_KEY_CELL_TYPE) &&
+ !((Attributes & OBJ_OPENLINK) && (end == NULL)))
+ {
+ RtlInitUnicodeString(&LinkPath, NULL);
+ Status = CmiGetLinkTarget(ParsedKey->RegistryHive,
+ SubKeyCell,
+ &LinkPath);
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("LinkPath '%wZ'\n", &LinkPath);
- if (end != NULL)
+ /* build new FullPath for reparsing */
+ TargetPath.MaximumLength = LinkPath.MaximumLength;
+ if (end != NULL)
{
- *end = '\\';
- *Path = end;
+ *end = '\\';
+ TargetPath.MaximumLength += (wcslen(end) * sizeof(WCHAR));
+ }
+ TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
+ TargetPath.Buffer = ExAllocatePool(NonPagedPool,
+ TargetPath.MaximumLength);
+ wcscpy(TargetPath.Buffer, LinkPath.Buffer);
+ if (end != NULL)
+ {
+ wcscat(TargetPath.Buffer, end);
}
+
+ RtlFreeUnicodeString(FullPath);
+ RtlFreeUnicodeString(&LinkPath);
+ FullPath->Length = TargetPath.Length;
+ FullPath->MaximumLength = TargetPath.MaximumLength;
+ FullPath->Buffer = TargetPath.Buffer;
+
+ DPRINT("FullPath '%wZ'\n", FullPath);
+
+ /* reinitialize Path for reparsing */
+ *Path = FullPath->Buffer;
+
+ *NextObject = NULL;
+ return(STATUS_REPARSE);
+ }
+ }
+
+ /* Create new key object and put into linked list */
+ DPRINT("CmiObjectParse: %s\n", cPath);
+ Status = ObCreateObject(NULL,
+ STANDARD_RIGHTS_REQUIRED,
+ NULL,
+ CmiKeyType,
+ (PVOID*)&FoundObject);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
+ FoundObject->Flags = 0;
+ FoundObject->Name = SubKeyCell->Name;
+ FoundObject->NameSize = SubKeyCell->NameSize;
+ FoundObject->KeyCell = SubKeyCell;
+ FoundObject->BlockOffset = BlockOffset;
+ FoundObject->RegistryHive = ParsedKey->RegistryHive;
+ CmiAddKeyToList(ParsedKey, FoundObject);
+ DPRINT("Created object 0x%x\n", FoundObject);
+ }
else
+ {
+ if ((FoundObject->KeyCell->Type == REG_LINK_KEY_CELL_TYPE) &&
+ !((Attributes & OBJ_OPENLINK) && (end == NULL)))
+ {
+ RtlInitUnicodeString(&LinkPath, NULL);
+ Status = CmiGetLinkTarget(FoundObject->RegistryHive,
+ FoundObject->KeyCell,
+ &LinkPath);
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("LinkPath '%wZ'\n", &LinkPath);
+
+ /* build new FullPath for reparsing */
+ TargetPath.MaximumLength = LinkPath.MaximumLength;
+ if (end != NULL)
{
- *Path = NULL;
+ *end = '\\';
+ TargetPath.MaximumLength += (wcslen(end) * sizeof(WCHAR));
+ }
+ TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
+ TargetPath.Buffer = ExAllocatePool(NonPagedPool,
+ TargetPath.MaximumLength);
+ wcscpy(TargetPath.Buffer, LinkPath.Buffer);
+ if (end != NULL)
+ {
+ wcscat(TargetPath.Buffer, end);
}
-VERIFY_KEY_OBJECT(FoundObject);
-
- *NextObject = FoundObject;
-
- return STATUS_SUCCESS;
+ RtlFreeUnicodeString(FullPath);
+ RtlFreeUnicodeString(&LinkPath);
+ FullPath->Length = TargetPath.Length;
+ FullPath->MaximumLength = TargetPath.MaximumLength;
+ FullPath->Buffer = TargetPath.Buffer;
+
+ DPRINT("FullPath '%wZ'\n", FullPath);
+
+ /* reinitialize Path for reparsing */
+ *Path = FullPath->Buffer;
+
+ *NextObject = NULL;
+ return(STATUS_REPARSE);
+ }
+ }
+
+ ObReferenceObjectByPointer(FoundObject,
+ STANDARD_RIGHTS_REQUIRED,
+ NULL,
+ UserMode);
+ }
+#ifndef WIN32_REGDBG
+ DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
+#else
+ {
+ char buffer[_BUFFER_LEN];
+ memset(buffer, 0, _BUFFER_LEN);
+ strncpy(buffer, FoundObject->Name, min(FoundObject->NameSize, _BUFFER_LEN - 1));
+ DPRINT("CmiObjectParse: %s\n", buffer);
+ }
+#endif
+
+ if (end != NULL)
+ {
+ *end = '\\';
+ *Path = end;
+ }
+ else
+ {
+ *Path = NULL;
+ }
+
+ VERIFY_KEY_OBJECT(FoundObject);
+
+ *NextObject = FoundObject;
+
+ return(STATUS_SUCCESS);
}
NTSTATUS STDCALL
CmiObjectCreate(PVOID ObjectBody,
- PVOID Parent,
- PWSTR RemainingPath,
- struct _OBJECT_ATTRIBUTES* ObjectAttributes)
+ PVOID Parent,
+ PWSTR RemainingPath,
+ struct _OBJECT_ATTRIBUTES* ObjectAttributes)
{
PKEY_OBJECT pKey = ObjectBody;
- pKey->ParentKey = Parent;
- if (RemainingPath)
- {
- if(RemainingPath[0]== L'\\')
- {
- pKey->Name = (PCHAR) (&RemainingPath[1]);
- pKey->NameSize = wcslen(RemainingPath) - 1;
- }
- else
- {
- pKey->Name = (PCHAR) RemainingPath;
- pKey->NameSize = wcslen(RemainingPath);
- }
- }
+
+ pKey->ParentKey = Parent;
+ if (RemainingPath)
+ {
+ if(RemainingPath[0]== L'\\')
+ {
+ pKey->Name = (PCHAR)(&RemainingPath[1]);
+ pKey->NameSize = wcslen(RemainingPath) - 1;
+ }
+ else
+ {
+ pKey->Name = (PCHAR)RemainingPath;
+ pKey->NameSize = wcslen(RemainingPath);
+ }
+ }
else
{
pKey->NameSize = 0;
KeyObject = (PKEY_OBJECT) DeletedObject;
if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
- {
- DPRINT1("Key not found in parent list ???\n");
- }
+ {
+ DPRINT1("Key not found in parent list ???\n");
+ }
if (KeyObject->Flags & KO_MARKED_FOR_DELETE)
{
DPRINT("delete really key\n");
CmiDestroyBlock(KeyObject->RegistryHive,
- KeyObject->KeyCell,
- KeyObject->BlockOffset);
+ KeyObject->KeyCell,
+ KeyObject->BlockOffset);
}
else
{
}
}
+
VOID
CmiAddKeyToList(PKEY_OBJECT ParentKey,
- PKEY_OBJECT NewKey)
+ PKEY_OBJECT NewKey)
{
KIRQL OldIrql;
DPRINT("ParentKey %.08x\n", ParentKey);
-
+
KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
if (ParentKey->SizeOfSubKeys <= ParentKey->NumberOfSubKeys)
- {
- PKEY_OBJECT *tmpSubKeys = ExAllocatePool(NonPagedPool,
- (ParentKey->NumberOfSubKeys + 1) * sizeof(DWORD));
+ {
+ PKEY_OBJECT *tmpSubKeys = ExAllocatePool(NonPagedPool,
+ (ParentKey->NumberOfSubKeys + 1) * sizeof(DWORD));
- if (ParentKey->NumberOfSubKeys > 0)
- {
- memcpy(tmpSubKeys,
- ParentKey->SubKeys,
- ParentKey->NumberOfSubKeys * sizeof(DWORD));
- }
+ if (ParentKey->NumberOfSubKeys > 0)
+ {
+ memcpy(tmpSubKeys,
+ ParentKey->SubKeys,
+ ParentKey->NumberOfSubKeys * sizeof(DWORD));
+ }
- if (ParentKey->SubKeys)
- ExFreePool(ParentKey->SubKeys);
+ if (ParentKey->SubKeys)
+ ExFreePool(ParentKey->SubKeys);
- ParentKey->SubKeys = tmpSubKeys;
- ParentKey->SizeOfSubKeys = ParentKey->NumberOfSubKeys + 1;
- }
+ ParentKey->SubKeys = tmpSubKeys;
+ ParentKey->SizeOfSubKeys = ParentKey->NumberOfSubKeys + 1;
+ }
/* FIXME: Please maintain the list in alphabetic order */
/* to allow a dichotomic search */
ParentKey->SubKeys[ParentKey->NumberOfSubKeys++] = NewKey;
-DPRINT("Reference parent key: 0x%x\n", ParentKey);
+ DPRINT("Reference parent key: 0x%x\n", ParentKey);
ObReferenceObjectByPointer(ParentKey,
STANDARD_RIGHTS_REQUIRED,
KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
/* FIXME: If list maintained in alphabetic order, use dichotomic search */
for (Index = 0; Index < ParentKey->NumberOfSubKeys; Index++)
- {
- if (ParentKey->SubKeys[Index] == KeyToRemove)
- {
- if (Index < ParentKey->NumberOfSubKeys-1)
- RtlMoveMemory(&ParentKey->SubKeys[Index],
- &ParentKey->SubKeys[Index + 1],
- (ParentKey->NumberOfSubKeys - Index - 1) * sizeof(PKEY_OBJECT));
- ParentKey->NumberOfSubKeys--;
- KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
-
-DPRINT("Dereference parent key: 0x%x\n", ParentKey);
+ {
+ if (ParentKey->SubKeys[Index] == KeyToRemove)
+ {
+ if (Index < ParentKey->NumberOfSubKeys-1)
+ RtlMoveMemory(&ParentKey->SubKeys[Index],
+ &ParentKey->SubKeys[Index + 1],
+ (ParentKey->NumberOfSubKeys - Index - 1) * sizeof(PKEY_OBJECT));
+ ParentKey->NumberOfSubKeys--;
+ KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
+
+ DPRINT("Dereference parent key: 0x%x\n", ParentKey);
- ObDereferenceObject(ParentKey);
- return STATUS_SUCCESS;
- }
- }
+ ObDereferenceObject(ParentKey);
+ return STATUS_SUCCESS;
+ }
+ }
KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
+
return STATUS_UNSUCCESSFUL;
}
PKEY_OBJECT
CmiScanKeyList(PKEY_OBJECT Parent,
- PCHAR KeyName,
- ULONG Attributes)
+ PCHAR KeyName,
+ ULONG Attributes)
{
- PKEY_OBJECT CurKey;
- KIRQL OldIrql;
- WORD NameSize;
- DWORD Index;
+ PKEY_OBJECT CurKey;
+ KIRQL OldIrql;
+ WORD NameSize;
+ DWORD Index;
- DPRINT("Scanning key list for %s (Parent %s)\n",
+#ifndef WIN32_REGDBG
+ DPRINT("Scanning key list for: %s (Parent: %s)\n",
KeyName, Parent->Name);
+#else
+ {
+ char buffer[_BUFFER_LEN];
+ memset(buffer, 0, _BUFFER_LEN);
+ strncpy(buffer, Parent->Name, min(Parent->NameSize, _BUFFER_LEN - 1));
+ DPRINT("Scanning key list for: %s (Parent: %s)\n", KeyName, buffer);
+ }
+#endif
NameSize = strlen(KeyName);
KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
/* FIXME: if list maintained in alphabetic order, use dichotomic search */
for (Index=0; Index < Parent->NumberOfSubKeys; Index++)
- {
- CurKey = Parent->SubKeys[Index];
- if (Attributes & OBJ_CASE_INSENSITIVE)
- {
- if ((NameSize == CurKey->NameSize)
- && (_strnicmp(KeyName, CurKey->Name, NameSize) == 0))
- {
- KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
- return CurKey;
- }
- }
- else
- {
- if ((NameSize == CurKey->NameSize)
- && (strncmp(KeyName,CurKey->Name,NameSize) == 0))
- {
- KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
- return CurKey;
- }
- }
- }
+ {
+ CurKey = Parent->SubKeys[Index];
+ if (Attributes & OBJ_CASE_INSENSITIVE)
+ {
+ if ((NameSize == CurKey->NameSize)
+ && (_strnicmp(KeyName, CurKey->Name, NameSize) == 0))
+ {
+ KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
+ return CurKey;
+ }
+ }
+ else
+ {
+ if ((NameSize == CurKey->NameSize)
+ && (strncmp(KeyName,CurKey->Name,NameSize) == 0))
+ {
+ KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
+ return CurKey;
+ }
+ }
+ }
KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
return NULL;
}
+
+
+static NTSTATUS
+CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
+ PKEY_CELL KeyCell,
+ PUNICODE_STRING TargetPath)
+{
+ PVALUE_CELL ValueCell;
+ PDATA_CELL DataCell;
+ NTSTATUS Status;
+
+ /* Get Value block of interest */
+ Status = CmiScanKeyForValue(RegistryHive,
+ KeyCell,
+ "SymbolicLinkValue",
+ &ValueCell,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
+ if (ValueCell->DataType != REG_LINK)
+ {
+ DPRINT1("Type != REG_LINK\n!");
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ if (TargetPath->Buffer == NULL && TargetPath->MaximumLength == 0)
+ {
+ TargetPath->Length = 0;
+ TargetPath->MaximumLength = ValueCell->DataSize + sizeof(WCHAR);
+ TargetPath->Buffer = ExAllocatePool(NonPagedPool,
+ TargetPath->MaximumLength);
+ }
+
+ TargetPath->Length = min(TargetPath->MaximumLength - sizeof(WCHAR),
+ ValueCell->DataSize);
+
+ if (ValueCell->DataSize > 0)
+ {
+ DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
+ RtlCopyMemory(TargetPath->Buffer,
+ DataCell->Data,
+ TargetPath->Length);
+ TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
+ CmiReleaseBlock(RegistryHive, DataCell);
+ }
+ else
+ {
+ RtlCopyMemory(TargetPath->Buffer,
+ &ValueCell->DataOffset,
+ TargetPath->Length);
+ TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+/* EOF */