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

commit f87fb4e3df68aa1acffea5ca31d2d733d882128d
Author:     George Bișoc <[email protected]>
AuthorDate: Sat Aug 8 16:32:12 2020 +0200
Commit:     Stanislav Motylkov <[email protected]>
CommitDate: Wed Aug 26 17:40:45 2020 +0300

    [NTOS:RTL] Implement the kernel-mode version of RtlGetNtProductType (#3029)
    
    RtlGetNtProductType comes into two variants: one in user-mode that is 
exported for use from NTDLL layer and the kernel-mode that is used exclusively 
by the NT kernel. The kernel-mode variant of the function is not exported.
---
 ntoskrnl/rtl/misc.c        | 143 +++++++++++++++++++++++++++++++++++++++++++++
 sdk/include/ndk/rtlfuncs.h |   1 +
 2 files changed, 144 insertions(+)

diff --git a/ntoskrnl/rtl/misc.c b/ntoskrnl/rtl/misc.c
index 5d0861d9f11..5cb930e2fb8 100644
--- a/ntoskrnl/rtl/misc.c
+++ b/ntoskrnl/rtl/misc.c
@@ -19,6 +19,7 @@ extern ULONG NtGlobalFlag;
 extern ULONG NtMajorVersion;
 extern ULONG NtMinorVersion;
 extern ULONG NtOSCSDVersion;
+#define PRODUCT_TAG 'iPtR'
 
 /* FUNCTIONS *****************************************************************/
 
@@ -62,6 +63,148 @@ RtlGetVersion(IN OUT PRTL_OSVERSIONINFOW 
lpVersionInformation)
     return STATUS_SUCCESS;
 }
 
+/**
+ * @brief
+ * Retrieves the NT type product of the operating system. This is the 
kernel-mode variant
+ * of this function.
+ *
+ * @param[out]  ProductType
+ *      The NT type product enumeration value returned by the call.
+ *
+ * @return
+ *      The function returns TRUE when the call successfully returned the type 
product of the system.
+ *      It'll return FALSE on failure otherwise. In the latter case the 
function will return WinNT
+ *      as the default product type.
+ *
+ * @remarks
+ *      The call expects to be called at PASSIVE_LEVEL. The function firstly 
checks if the product type is
+ *      actually valid by checking the "ProductTypeIsValid" member of 
_KUSER_SHARED_DATA structure.
+ *      Currently we do not implement code that is responsible for the 
management of this member, yet.
+ * 
+ */
+BOOLEAN
+NTAPI
+RtlGetNtProductType(OUT PNT_PRODUCT_TYPE ProductType)
+{
+    HANDLE Key;
+    BOOLEAN Success;
+    ULONG ReturnedLength;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    NTSTATUS Status;
+    PKEY_VALUE_PARTIAL_INFORMATION BufferKey;
+    ULONG BufferKeyLength = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + (256 * 
sizeof(WCHAR));
+    UNICODE_STRING NtProductType;
+    static UNICODE_STRING WorkstationProduct = RTL_CONSTANT_STRING(L"WinNT");
+    static UNICODE_STRING LanManProduct = RTL_CONSTANT_STRING(L"LanmanNT");
+    static UNICODE_STRING ServerProduct = RTL_CONSTANT_STRING(L"ServerNT");
+    static UNICODE_STRING KeyProduct = 
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions");
+    static UNICODE_STRING ValueNtProduct = RTL_CONSTANT_STRING(L"ProductType");
+
+    PAGED_CODE();
+
+    /* Before doing anything else we must allocate some buffer space in the 
pool */
+    BufferKey = ExAllocatePoolWithTag(PagedPool, BufferKeyLength, PRODUCT_TAG);
+    if (!BufferKey)
+    {
+        /* We failed to allocate pool memory, bail out */
+        DPRINT1("RtlGetNtProductType(): Memory pool allocation has failed!\n");
+        Success = FALSE;
+        goto Exit;
+    }
+
+    /* Initialize the object attributes to open our key */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyProduct,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               NULL,
+                               NULL);
+
+    /* Open the key */
+    Status = ZwOpenKey(&Key, KEY_QUERY_VALUE, &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlGetNtProductType(): The ZwOpenKey() function has failed! 
(Status: 0x%lx)\n", Status);
+        Success = FALSE;
+        goto Exit;
+    }
+
+    /* Now it's time to query the value from the key to check what kind of 
product the OS is */
+    Status = ZwQueryValueKey(Key,
+                             &ValueNtProduct,
+                             KeyValuePartialInformation,
+                             BufferKey,
+                             BufferKeyLength,
+                             &ReturnedLength);
+
+    /* Free the key from the memory */
+    ZwClose(Key);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlGetNtProductType(): The ZwQueryValueKey() function has 
failed! (Status: 0x%lx)\n", Status);
+        Success = FALSE;
+        goto Exit;
+    }
+
+    /*
+     * Do a sanity check before we get the product type of the operating system
+     * so that we're sure the type of the value we've got is actually correct.
+     */
+    if (BufferKey->Type != REG_SZ)
+    {
+        /* We've got something else, so bail out */
+        DPRINT1("RtlGetNtProductType(): An invalid value type has been 
found!\n");
+        Success = FALSE;
+        goto Exit;
+    }
+
+    /* Initialise the Unicode string with the data from the registry value */
+    NtProductType.Length = NtProductType.MaximumLength = BufferKey->DataLength;
+    NtProductType.Buffer = (PWCHAR)BufferKey->Data;
+
+    if (NtProductType.Length > sizeof(WCHAR) && 
NtProductType.Buffer[NtProductType.Length /
+        sizeof(WCHAR) - 1] == UNICODE_NULL)
+    {
+        NtProductType.Length -= sizeof(WCHAR);
+    }
+
+    /* Now it's time to get the product based on the value data */
+    if (RtlCompareUnicodeString(&NtProductType, &WorkstationProduct, TRUE) == 
0)
+    {
+        /* The following product is an OS Workstation */
+        *ProductType = NtProductWinNt;
+        Success = TRUE;
+    }
+    else if (RtlCompareUnicodeString(&NtProductType, &LanManProduct, TRUE) == 
0)
+    {
+        /* The following product is an OS Advanced Server */
+        *ProductType = NtProductLanManNt;
+        Success = TRUE;
+    }
+    else if (RtlCompareUnicodeString(&NtProductType, &ServerProduct, TRUE) == 
0)
+    {
+        /* The following product is an OS Server */
+        *ProductType = NtProductServer;
+        Success = TRUE;
+    }
+    else
+    {
+        /* None of the product types match so bail out */
+        DPRINT1("RtlGetNtProductType(): Couldn't find a valid product type! 
Defaulting to WinNT...\n");
+        Success = FALSE;
+        goto Exit;
+    }
+
+Exit:
+    if (!Success)
+    {
+        *ProductType = NtProductWinNt;
+    }
+
+    ExFreePoolWithTag(BufferKey, PRODUCT_TAG);
+    return Success;
+}
+
 #if !defined(_M_IX86)
 //
 // Stub for architectures which don't have this implemented
diff --git a/sdk/include/ndk/rtlfuncs.h b/sdk/include/ndk/rtlfuncs.h
index 85110d3c213..c2a823f17f6 100644
--- a/sdk/include/ndk/rtlfuncs.h
+++ b/sdk/include/ndk/rtlfuncs.h
@@ -4615,6 +4615,7 @@ RtlGetVersion(
         PRTL_OSVERSIONINFOW lpVersionInformation
 );
 
+_IRQL_requires_max_(PASSIVE_LEVEL)
 NTSYSAPI
 BOOLEAN
 NTAPI

Reply via email to