https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f87fb4e3df68aa1acffea…
commit f87fb4e3df68aa1acffea5ca31d2d733d882128d
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sat Aug 8 16:32:12 2020 +0200
Commit: Stanislav Motylkov <x86corez(a)gmail.com>
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