https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a8669e023ad50b4afb714bf12002f2d5d22080ad

commit a8669e023ad50b4afb714bf12002f2d5d22080ad
Author:     Oleg Dubinskiy <oleg.dubinskij2...@yandex.ua>
AuthorDate: Fri Jan 21 21:05:03 2022 +0200
Commit:     Oleg Dubinskiy <oleg.dubinski...@gmail.com>
CommitDate: Sun Feb 2 23:30:38 2025 +0100

    [NTOS:IO] Rewrite OpenRegistryHandlesFromSymbolicLink
    Also add a new IopOpenOrCreateSymbolicLinkSubKeys routine, which does some 
work for it.
    CORE-17361
---
 ntoskrnl/io/iomgr/deviface.c | 347 +++++++++++++++++++++++++++----------------
 1 file changed, 221 insertions(+), 126 deletions(-)

diff --git a/ntoskrnl/io/iomgr/deviface.c b/ntoskrnl/io/iomgr/deviface.c
index a5f20efb50a..5c3391f929b 100644
--- a/ntoskrnl/io/iomgr/deviface.c
+++ b/ntoskrnl/io/iomgr/deviface.c
@@ -287,187 +287,282 @@ IopSeparateSymbolicLink(
     return Status;
 }
 
+/**
+ * @brief
+ * Retrieves a handles to the device and instance registry keys
+ * for the previously opened registry key handle of the specified symbolic 
link.
+ **/
 static
 NTSTATUS
-OpenRegistryHandlesFromSymbolicLink(IN PUNICODE_STRING SymbolicLinkName,
-                                    IN ACCESS_MASK DesiredAccess,
-                                    IN OPTIONAL PHANDLE GuidKey,
-                                    IN OPTIONAL PHANDLE DeviceKey,
-                                    IN OPTIONAL PHANDLE InstanceKey)
+IopOpenOrCreateSymbolicLinkSubKeys(
+    _Out_opt_ PHANDLE DeviceHandle,
+    _Out_opt_ PULONG DeviceDisposition,
+    _Out_opt_ PHANDLE InstanceHandle,
+    _Out_opt_ PULONG InstanceDisposition,
+    _In_ HANDLE ClassHandle,
+    _In_ PCUNICODE_STRING SymbolicLinkName,
+    _In_ ACCESS_MASK DesiredAccess,
+    _In_ BOOLEAN Create)
 {
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING BaseKeyU;
-    UNICODE_STRING GuidString, SubKeyName, ReferenceString;
-    PWCHAR StartPosition, EndPosition;
-    HANDLE ClassesKey;
-    PHANDLE GuidKeyRealP, DeviceKeyRealP, InstanceKeyRealP;
-    HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal;
+    UNICODE_STRING ReferenceString = {0};
+    UNICODE_STRING SymbolicLink = {0};
+    HANDLE DeviceKeyHandle, InstanceKeyHandle;
+    ULONG DeviceKeyDisposition, InstanceKeyDisposition;
+    BOOLEAN ReferenceStringPresent = FALSE; /* Assuming no ref string by 
default */
     NTSTATUS Status;
+    USHORT i;
 
-    SubKeyName.Buffer = NULL;
+    DeviceKeyHandle = InstanceKeyHandle = NULL;
 
-    if (GuidKey != NULL)
-        GuidKeyRealP = GuidKey;
-    else
-        GuidKeyRealP = &GuidKeyReal;
+    /* Duplicate the symbolic link (we'll modify it later) */
+    Status = RtlDuplicateUnicodeString(0, SymbolicLinkName, &SymbolicLink);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlDuplicateUnicodeString() failed, Status 0x%08lx\n", 
Status);
+        goto Quit;
+    }
 
-    if (DeviceKey != NULL)
-        DeviceKeyRealP = DeviceKey;
-    else
-        DeviceKeyRealP = &DeviceKeyReal;
+    /* Separate it into its constituents */
+    Status = IopSeparateSymbolicLink(&SymbolicLink,
+                                     NULL,
+                                     NULL,
+                                     NULL,
+                                     &ReferenceString,
+                                     &ReferenceStringPresent,
+                                     NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to separate symbolic link %wZ, Status 0x%08lx\n", 
&SymbolicLink, Status);
+        goto Quit;
+    }
 
-    if (InstanceKey != NULL)
-        InstanceKeyRealP = InstanceKey;
+    /* Did we got a ref string? */
+    if (ReferenceStringPresent)
+    {
+        /* Remove it from our symbolic link */
+        SymbolicLink.MaximumLength = SymbolicLink.Length -= 
ReferenceString.Length;
+
+        /* Replace the 1st backslash `\` character by '#' pound */
+        ReferenceString.Buffer[0] = L'#';
+    }
     else
-        InstanceKeyRealP = &InstanceKeyReal;
+    {
+        /* No ref string, initialize it with a single pound character '#' */
+        RtlInitUnicodeString(&ReferenceString, L"#");
+    }
 
-    *GuidKeyRealP = NULL;
-    *DeviceKeyRealP = NULL;
-    *InstanceKeyRealP = NULL;
+    /* Replace all '\' by '#' in symbolic link */
+    for (i = 0; i < SymbolicLink.Length / sizeof(WCHAR); i++)
+    {
+        if (SymbolicLink.Buffer[i] == L'\\')
+            SymbolicLink.Buffer[i] = L'#';
+    }
 
-    RtlInitUnicodeString(&BaseKeyU, BaseKeyString);
+    /* Fix prefix: '#??#' -> '##?#' */
+    SymbolicLink.Buffer[1] = L'#';
+
+    DPRINT("Munged symbolic link is %wZ\n", &SymbolicLink);
+
+    /* Try to open or create device interface keys */
+    if (Create)
+    {
+        Status = IopCreateRegistryKeyEx(&DeviceKeyHandle,
+                                        ClassHandle,
+                                        &SymbolicLink,
+                                        DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
+                                        REG_OPTION_NON_VOLATILE,
+                                        &DeviceKeyDisposition);
+    }
+    else
+    {
+        Status = IopOpenRegistryKeyEx(&DeviceKeyHandle,
+                                      ClassHandle,
+                                      &SymbolicLink,
+                                      DesiredAccess | KEY_ENUMERATE_SUB_KEYS);
+    }
 
-    /* Open the DeviceClasses key */
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &BaseKeyU,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               NULL,
-                               NULL);
-    Status = ZwOpenKey(&ClassesKey,
-                       DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
-                       &ObjectAttributes);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to open %wZ\n", &BaseKeyU);
-        goto cleanup;
+        DPRINT1("Failed to create or open %wZ, Status 0x%08lx\n", 
&SymbolicLink, Status);
+        goto Quit;
     }
 
-    StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
-    EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
-    if (!StartPosition || !EndPosition || StartPosition > EndPosition)
+    DPRINT("Munged reference string is %wZ\n", &ReferenceString);
+
+    /* Try to open or create instance subkeys */
+    if (Create)
     {
-        DPRINT1("Bad symbolic link: %wZ\n", SymbolicLinkName);
-        return STATUS_INVALID_PARAMETER_1;
+        Status = IopCreateRegistryKeyEx(&InstanceKeyHandle,
+                                        DeviceKeyHandle,
+                                        &ReferenceString,
+                                        DesiredAccess,
+                                        REG_OPTION_NON_VOLATILE,
+                                        &InstanceKeyDisposition);
+    }
+    else
+    {
+        Status = IopOpenRegistryKeyEx(&InstanceKeyHandle,
+                                      DeviceKeyHandle,
+                                      &ReferenceString,
+                                      DesiredAccess);
     }
-    GuidString.Buffer = StartPosition;
-    GuidString.MaximumLength = GuidString.Length = 
(USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition);
 
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &GuidString,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               ClassesKey,
-                               NULL);
-    Status = ZwCreateKey(GuidKeyRealP,
-                         DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
-                         &ObjectAttributes,
-                         0,
-                         NULL,
-                         REG_OPTION_NON_VOLATILE,
-                         NULL);
-    ZwClose(ClassesKey);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to open %wZ%wZ (%x)\n", &BaseKeyU, &GuidString, 
Status);
-        goto cleanup;
+        DPRINT1("Failed to create or open %wZ, Status 0x%08lx\n", 
&ReferenceString, Status);
+        goto Quit;
     }
 
-    SubKeyName.MaximumLength = SymbolicLinkName->Length + sizeof(WCHAR);
-    SubKeyName.Length = 0;
-    SubKeyName.Buffer = ExAllocatePool(PagedPool, SubKeyName.MaximumLength);
-    if (!SubKeyName.Buffer)
+    Status = STATUS_SUCCESS;
+
+Quit:
+    if (NT_SUCCESS(Status))
     {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto cleanup;
+        if (DeviceHandle)
+            *DeviceHandle = DeviceKeyHandle;
+        else
+            ZwClose(DeviceKeyHandle);
+
+        if (DeviceDisposition)
+            *DeviceDisposition = DeviceKeyDisposition;
+
+        if (InstanceHandle)
+            *InstanceHandle = InstanceKeyHandle;
+        else
+            ZwClose(InstanceKeyHandle);
+
+        if (InstanceDisposition)
+            *InstanceDisposition = InstanceKeyDisposition;
     }
+    else
+    {
+        if (InstanceKeyHandle)
+            ZwClose(InstanceKeyHandle);
 
-    RtlAppendUnicodeStringToString(&SubKeyName,
-                                   SymbolicLinkName);
+        if (Create)
+            ZwDeleteKey(DeviceKeyHandle);
 
-    SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+        if (DeviceKeyHandle)
+            ZwClose(DeviceKeyHandle);
+    }
 
-    SubKeyName.Buffer[0] = L'#';
-    SubKeyName.Buffer[1] = L'#';
-    SubKeyName.Buffer[2] = L'?';
-    SubKeyName.Buffer[3] = L'#';
+    if (SymbolicLink.Buffer)
+        RtlFreeUnicodeString(&SymbolicLink);
 
-    ReferenceString.Buffer = wcsrchr(SubKeyName.Buffer, '\\');
-    if (ReferenceString.Buffer != NULL)
-    {
-        ReferenceString.Buffer[0] = L'#';
+    return Status;
+}
 
-        SubKeyName.Length = (USHORT)((ULONG_PTR)(ReferenceString.Buffer) - 
(ULONG_PTR)SubKeyName.Buffer);
-        ReferenceString.Length = SymbolicLinkName->Length - SubKeyName.Length;
+/**
+ * @brief
+ * Retrieves a handles to the GUID, device and instance registry keys
+ * for the specified symbolic link.
+ **/
+static
+NTSTATUS
+OpenRegistryHandlesFromSymbolicLink(
+    _In_ PCUNICODE_STRING SymbolicLinkName,
+    _In_ ACCESS_MASK DesiredAccess,
+    _Out_opt_ PHANDLE GuidKey,
+    _Out_opt_ PHANDLE DeviceKey,
+    _Out_opt_ PHANDLE InstanceKey)
+{
+    UNICODE_STRING BaseKeyU;
+    UNICODE_STRING GuidString;
+    HANDLE ClassesKey;
+    HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal;
+    NTSTATUS Status;
+
+    ClassesKey = GuidKeyReal = DeviceKeyReal = InstanceKeyReal = NULL;
+
+    RtlInitUnicodeString(&BaseKeyU, BaseKeyString);
+
+    /* Separate symbolic link onto the parts */
+    Status = IopSeparateSymbolicLink(SymbolicLinkName,
+                                     NULL,
+                                     NULL,
+                                     &GuidString,
+                                     NULL,
+                                     NULL,
+                                     NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to parse symbolic link %wZ, Status 0x%08lx\n",
+                SymbolicLinkName, Status);
+        goto Quit;
     }
-    else
+
+    /* Open the DeviceClasses key */
+    Status = IopOpenRegistryKeyEx(&ClassesKey,
+                                  NULL,
+                                  &BaseKeyU,
+                                  DesiredAccess | KEY_ENUMERATE_SUB_KEYS);
+    if (!NT_SUCCESS(Status))
     {
-        RtlInitUnicodeString(&ReferenceString, L"#");
+        DPRINT1("Failed to open %wZ, Status 0x%08lx\n", &BaseKeyU, Status);
+        goto Quit;
     }
 
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &SubKeyName,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               *GuidKeyRealP,
-                               NULL);
-    Status = ZwCreateKey(DeviceKeyRealP,
-                         DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
-                         &ObjectAttributes,
-                         0,
-                         NULL,
-                         REG_OPTION_NON_VOLATILE,
-                         NULL);
+    /* Open the GUID subkey */
+    Status = IopOpenRegistryKeyEx(&GuidKeyReal,
+                                  ClassesKey,
+                                  &GuidString,
+                                  DesiredAccess | KEY_ENUMERATE_SUB_KEYS);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to open %wZ%wZ\\%wZ Status %x\n", &BaseKeyU, 
&GuidString, &SubKeyName, Status);
-        goto cleanup;
+        DPRINT1("Failed to open %wZ%wZ, Status 0x%08lx\n", &BaseKeyU, 
&GuidString, Status);
+        goto Quit;
     }
 
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &ReferenceString,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               *DeviceKeyRealP,
-                               NULL);
-    Status = ZwCreateKey(InstanceKeyRealP,
-                         DesiredAccess,
-                         &ObjectAttributes,
-                         0,
-                         NULL,
-                         REG_OPTION_NON_VOLATILE,
-                         NULL);
+    /* Open the device and instance subkeys */
+    Status = IopOpenOrCreateSymbolicLinkSubKeys(&DeviceKeyReal,
+                                                NULL,
+                                                &InstanceKeyReal,
+                                                NULL,
+                                                GuidKeyReal,
+                                                SymbolicLinkName,
+                                                DesiredAccess,
+                                                FALSE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU, 
&GuidString, &SubKeyName, &ReferenceString, Status);
-        goto cleanup;
+        DPRINT1("Failed to open %wZ%wZ, Status 0x%08lx\n", &BaseKeyU, 
&GuidString, Status);
+        goto Quit;
     }
 
     Status = STATUS_SUCCESS;
 
-cleanup:
-    if (SubKeyName.Buffer != NULL)
-        ExFreePool(SubKeyName.Buffer);
-
+Quit:
     if (NT_SUCCESS(Status))
     {
-        if (!GuidKey)
-            ZwClose(*GuidKeyRealP);
+        if (GuidKey)
+            *GuidKey = GuidKeyReal;
+        else
+            ZwClose(GuidKeyReal);
 
-        if (!DeviceKey)
-            ZwClose(*DeviceKeyRealP);
+        if (DeviceKey)
+            *DeviceKey = DeviceKeyReal;
+        else
+            ZwClose(DeviceKeyReal);
 
-        if (!InstanceKey)
-            ZwClose(*InstanceKeyRealP);
+        if (InstanceKey)
+            *InstanceKey = InstanceKeyReal;
+        else
+            ZwClose(InstanceKeyReal);
     }
     else
     {
-        if (*GuidKeyRealP != NULL)
-            ZwClose(*GuidKeyRealP);
+        if (GuidKeyReal)
+            ZwClose(GuidKeyReal);
 
-        if (*DeviceKeyRealP != NULL)
-            ZwClose(*DeviceKeyRealP);
+        if (DeviceKeyReal)
+            ZwClose(DeviceKeyReal);
 
-        if (*InstanceKeyRealP != NULL)
-            ZwClose(*InstanceKeyRealP);
+        if (InstanceKeyReal)
+            ZwClose(InstanceKeyReal);
     }
 
+    if (ClassesKey)
+        ZwClose(ClassesKey);
+
     return Status;
 }
 

Reply via email to