[NTOSKRNL]
authorCameron Gutman <aicommander@gmail.com>
Mon, 26 Apr 2010 04:54:25 +0000 (04:54 +0000)
committerCameron Gutman <aicommander@gmail.com>
Mon, 26 Apr 2010 04:54:25 +0000 (04:54 +0000)
- Create a helper function named OpenRegistryHandlesFromSymbolicLink which opens handles to various paths associated with a symbolic link
- Store the Linked value in IoSetDeviceInterfaceState
- Implement checking if an interface is enabled by reading the Linked value
- Interfaces reported from IoGetDeviceInterfaces are only active ones now (unless the caller explicitly says that they want disabled ones too)

svn path=/trunk/; revision=47029

reactos/ntoskrnl/io/iomgr/deviface.c

index 59eddeb..8a8db7a 100644 (file)
 
 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
 
 
 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
 
+static
+NTSTATUS
+OpenRegistryHandlesFromSymbolicLink(IN PUNICODE_STRING SymbolicLinkName,
+                                    IN ACCESS_MASK DesiredAccess,
+                                    IN OPTIONAL PHANDLE GuidKey,
+                                    IN OPTIONAL PHANDLE DeviceKey,
+                                    IN OPTIONAL PHANDLE InstanceKey)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    WCHAR PathBuffer[MAX_PATH];
+    UNICODE_STRING BaseKeyU;
+    UNICODE_STRING GuidString, SubKeyName, ReferenceString;
+    PWCHAR StartPosition, EndPosition;
+    HANDLE ClassesKey;
+    PHANDLE GuidKeyRealP, DeviceKeyRealP, InstanceKeyRealP;
+    HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal;
+    NTSTATUS Status;
+
+    SubKeyName.Buffer = NULL;
+
+    if (GuidKey != NULL)
+        GuidKeyRealP = GuidKey;
+    else
+        GuidKeyRealP = &GuidKeyReal;
+
+    if (DeviceKey != NULL)
+        DeviceKeyRealP = DeviceKey;
+    else
+        DeviceKeyRealP = &DeviceKeyReal;
+
+    if (InstanceKey != NULL)
+        InstanceKeyRealP = InstanceKey;
+    else
+        InstanceKeyRealP = &InstanceKeyReal;
+
+    *GuidKeyRealP = INVALID_HANDLE_VALUE;
+    *DeviceKeyRealP = INVALID_HANDLE_VALUE;
+    *InstanceKeyRealP = INVALID_HANDLE_VALUE;
+
+    BaseKeyU.Buffer = PathBuffer;
+    BaseKeyU.Length = 0;
+    BaseKeyU.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+    RtlAppendUnicodeToString(&BaseKeyU, BaseKeyString);
+
+    /* 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;
+    }
+
+    StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
+    EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
+    if (!StartPosition || !EndPosition || StartPosition > EndPosition)
+    {
+        DPRINT1("Bad symbolic link: %wZ\n", SymbolicLinkName);
+        return STATUS_INVALID_PARAMETER_1;
+    }
+    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 = ZwOpenKey(GuidKeyRealP,
+                       DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
+                       &ObjectAttributes);
+    ZwClose(ClassesKey);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to open %wZ%wZ (%x)\n", &BaseKeyU, &GuidString, Status);
+        goto cleanup;
+    }
+
+    SubKeyName.Buffer = ExAllocatePool(PagedPool, SymbolicLinkName->Length);
+    if (!SubKeyName.Buffer)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto cleanup;
+    }
+    SubKeyName.MaximumLength = SymbolicLinkName->Length;
+    SubKeyName.Length = 0;
+
+    RtlAppendUnicodeStringToString(&SubKeyName,
+                                   SymbolicLinkName);
+
+    SubKeyName.Buffer[0] = L'#';
+    SubKeyName.Buffer[1] = L'#';
+    SubKeyName.Buffer[2] = L'?';
+    SubKeyName.Buffer[3] = L'#';
+
+    ReferenceString.Buffer = wcsrchr(SubKeyName.Buffer, '\\');
+    if (ReferenceString.Buffer != NULL)
+    {
+        ReferenceString.Buffer[0] = L'#';
+
+        SubKeyName.Length = ReferenceString.Buffer - SubKeyName.Buffer;
+        ReferenceString.Length = SymbolicLinkName->Length - SubKeyName.Length;
+    }
+    else
+    {
+        RtlInitUnicodeString(&ReferenceString, L"#");
+    }
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &SubKeyName,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               *GuidKeyRealP,
+                               NULL);
+    Status = ZwOpenKey(DeviceKeyRealP,
+                       DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
+                       &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to open %wZ%wZ\\%wZ\n", &BaseKeyU, &GuidString, &SubKeyName);
+        goto cleanup;
+    }
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &ReferenceString,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               *DeviceKeyRealP,
+                               NULL);
+    Status = ZwOpenKey(InstanceKeyRealP,
+                       DesiredAccess,
+                       &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU, &GuidString, &SubKeyName, &ReferenceString, Status);
+        goto cleanup;
+    }
+
+    Status = STATUS_SUCCESS;
+
+cleanup:
+    if (SubKeyName.Buffer != NULL)
+       ExFreePool(SubKeyName.Buffer);
+
+    if (NT_SUCCESS(Status))
+    {
+       if (!GuidKey)
+          ZwClose(*GuidKeyRealP);
+
+       if (!DeviceKey)
+          ZwClose(*DeviceKeyRealP);
+
+       if (!InstanceKey)
+          ZwClose(*InstanceKeyRealP);
+    }
+    else
+    {
+       if (*GuidKeyRealP != INVALID_HANDLE_VALUE)
+          ZwClose(*GuidKeyRealP);
+
+       if (*DeviceKeyRealP != INVALID_HANDLE_VALUE)
+          ZwClose(*DeviceKeyRealP);
+
+       if (*InstanceKeyRealP != INVALID_HANDLE_VALUE)
+          ZwClose(*InstanceKeyRealP);
+    }
+
+    return Status;
+}
 /*++
  * @name IoOpenDeviceInterfaceRegistryKey
  * @unimplemented
 /*++
  * @name IoOpenDeviceInterfaceRegistryKey
  * @unimplemented
@@ -395,10 +569,11 @@ IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid,
     PKEY_BASIC_INFORMATION DeviceBi = NULL;
     PKEY_BASIC_INFORMATION ReferenceBi = NULL;
     PKEY_VALUE_PARTIAL_INFORMATION bip = NULL;
     PKEY_BASIC_INFORMATION DeviceBi = NULL;
     PKEY_BASIC_INFORMATION ReferenceBi = NULL;
     PKEY_VALUE_PARTIAL_INFORMATION bip = NULL;
+    PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
     UNICODE_STRING KeyName;
     OBJECT_ATTRIBUTES ObjectAttributes;
     BOOLEAN FoundRightPDO = FALSE;
     UNICODE_STRING KeyName;
     OBJECT_ATTRIBUTES ObjectAttributes;
     BOOLEAN FoundRightPDO = FALSE;
-    ULONG i = 0, j, Size;
+    ULONG i = 0, j, Size, NeededLength, ActualLength, LinkedValue;
     UNICODE_STRING ReturnBuffer = { 0, 0, NULL };
     NTSTATUS Status;
 
     UNICODE_STRING ReturnBuffer = { 0, 0, NULL };
     NTSTATUS Status;
 
@@ -552,7 +727,6 @@ IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid,
                 /* We have to check if the interface is enabled, by
                 * reading the Linked value in the Control subkey
                 */
                 /* We have to check if the interface is enabled, by
                 * reading the Linked value in the Control subkey
                 */
-#if 0
                 InitializeObjectAttributes(
                     &ObjectAttributes,
                     &Control,
                 InitializeObjectAttributes(
                     &ObjectAttributes,
                     &Control,
@@ -572,17 +746,63 @@ IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid,
                 }
                 else if (!NT_SUCCESS(Status))
                 {
                 }
                 else if (!NT_SUCCESS(Status))
                 {
-                    DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
+                    DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
+                    goto cleanup;
+                }
+
+                RtlInitUnicodeString(&KeyName, L"Linked");
+                Status = ZwQueryValueKey(ControlKey,
+                                         &KeyName,
+                                         KeyValuePartialInformation,
+                                         NULL,
+                                         0,
+                                         &NeededLength);
+                if (Status == STATUS_BUFFER_TOO_SMALL)
+                {
+                    ActualLength = NeededLength;
+                    PartialInfo = ExAllocatePool(NonPagedPool, ActualLength);
+                    if (!PartialInfo)
+                    {
+                        Status = STATUS_INSUFFICIENT_RESOURCES;
+                        goto cleanup;
+                    }
+
+                    Status = ZwQueryValueKey(ControlKey,
+                                             &KeyName,
+                                             KeyValuePartialInformation,
+                                             PartialInfo,
+                                             ActualLength,
+                                             &NeededLength);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status);
+                        ExFreePool(PartialInfo);
+                        goto cleanup;
+                    }
+
+                    if (PartialInfo->Type != REG_DWORD || PartialInfo->DataLength != sizeof(ULONG))
+                    {
+                        DPRINT1("Bad registry read\n");
+                        ExFreePool(PartialInfo);
+                        goto cleanup;
+                    }
+
+                    RtlCopyMemory(&LinkedValue,
+                                  PartialInfo->Data,
+                                  PartialInfo->DataLength);
+
+                    ExFreePool(PartialInfo);
+                    if (LinkedValue == 0)
+                    {
+                        /* This interface isn't active */
+                        goto NextReferenceString;
+                    }
+                }
+                else
+                {
+                    DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status);
                     goto cleanup;
                 }
                     goto cleanup;
                 }
-#endif
-                /* FIXME: Read the Linked value
-                * If it doesn't exist => ERROR
-                * If it is not a REG_DWORD or Size != sizeof(ULONG) => ERROR
-                * If its value is 0, go to NextReferenceString
-                * At the moment, do as if it is active...
-                */
-                DPRINT1("Checking if device is enabled is not implemented yet!\n");
             }
 
             /* Read the SymbolicLink string and add it into SymbolicLinkList */
             }
 
             /* Read the SymbolicLink string and add it into SymbolicLinkList */
@@ -1118,7 +1338,10 @@ IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
     PWCHAR EndPosition;
     NTSTATUS Status;
     LPCGUID EventGuid;
     PWCHAR EndPosition;
     NTSTATUS Status;
     LPCGUID EventGuid;
-
+    HANDLE InstanceHandle, ControlHandle;
+    UNICODE_STRING KeyName;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    ULONG LinkedValue;
 
     if (SymbolicLinkName == NULL)
         return STATUS_INVALID_PARAMETER_1;
 
     if (SymbolicLinkName == NULL)
         return STATUS_INVALID_PARAMETER_1;
@@ -1140,6 +1363,51 @@ IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
     SymLink.Buffer = SymbolicLinkName->Buffer;
     SymLink.MaximumLength = SymLink.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)SymLink.Buffer);
     DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
     SymLink.Buffer = SymbolicLinkName->Buffer;
     SymLink.MaximumLength = SymLink.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)SymLink.Buffer);
     DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
+
+    Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName,
+                                                 KEY_CREATE_SUB_KEY,
+                                                 NULL,
+                                                 NULL,
+                                                 &InstanceHandle);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    RtlInitUnicodeString(&KeyName, L"Control");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyName,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               InstanceHandle,
+                               NULL);
+    Status = ZwCreateKey(&ControlHandle,
+                         KEY_SET_VALUE,
+                         &ObjectAttributes,
+                         0,
+                         NULL,
+                         REG_OPTION_VOLATILE,
+                         NULL);
+    ZwClose(InstanceHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create the Control subkey\n");
+        return Status;
+    }
+
+    LinkedValue = (Enable ? 1 : 0);
+
+    RtlInitUnicodeString(&KeyName, L"Linked");
+    Status = ZwSetValueKey(ControlHandle,
+                           &KeyName,
+                           0,
+                           REG_DWORD,
+                           &LinkedValue,
+                           sizeof(ULONG));
+    ZwClose(ControlHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to write the Linked value\n");
+        return Status;
+    }
+
     /* Get pointer to the PDO */
     Status = IoGetDeviceObjectPointer(
         &SymLink,
     /* Get pointer to the PDO */
     Status = IoGetDeviceObjectPointer(
         &SymLink,