[NTDLL][SHLWAPI][SYSDM] ReportAsWorkstation should always override the product type (#7052)

Allows "ROS as a workstation" installs to report itself as a basic server to Win32 applications when the user toggles the sysdm.cpl checkbox (to unchecked in this case).
This commit is contained in:
Whindmar Saksit 2025-03-19 00:10:46 +01:00 committed by GitHub
parent 19c1f5661f
commit 4a1877d0f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 87 additions and 21 deletions

View file

@ -9,6 +9,8 @@
*/ */
#include "precomp.h" #include "precomp.h"
#define WIN32_NO_STATUS
#include "pstypes.h" /* SharedUserData */
static TCHAR BugLink[] = _T("http://jira.reactos.org/"); static TCHAR BugLink[] = _T("http://jira.reactos.org/");
static TCHAR ReportAsWorkstationKey[] = _T("SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version"); static TCHAR ReportAsWorkstationKey[] = _T("SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version");
@ -51,9 +53,10 @@ static VOID
OnInitSysSettingsDialog(HWND hwndDlg) OnInitSysSettingsDialog(HWND hwndDlg)
{ {
HKEY hKey; HKEY hKey;
DWORD dwVal; DWORD dwVal = 0;
DWORD dwType = REG_DWORD; DWORD dwType = REG_DWORD;
DWORD cbData = sizeof(DWORD); DWORD cbData = sizeof(DWORD);
BOOL ReportAsWorkstation = SharedUserData->NtProductType == VER_NT_WORKSTATION;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
ReportAsWorkstationKey, ReportAsWorkstationKey,
@ -68,19 +71,14 @@ OnInitSysSettingsDialog(HWND hwndDlg)
(LPBYTE)&dwVal, (LPBYTE)&dwVal,
&cbData) == ERROR_SUCCESS) &cbData) == ERROR_SUCCESS)
{ {
if (dwVal != FALSE) if (cbData == sizeof(DWORD))
{ ReportAsWorkstation = dwVal != FALSE;
// set the check box
SendDlgItemMessageW(hwndDlg,
IDC_REPORTASWORKSTATION,
BM_SETCHECK,
BST_CHECKED,
0);
}
} }
RegCloseKey(hKey); RegCloseKey(hKey);
} }
SendDlgItemMessageW(hwndDlg, IDC_REPORTASWORKSTATION, BM_SETCHECK,
ReportAsWorkstation ? BST_CHECKED : BST_UNCHECKED, 0);
} }
INT_PTR CALLBACK INT_PTR CALLBACK

View file

@ -17,6 +17,8 @@
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
static signed char g_ReportProductType = 0;
/* HACK: ReactOS specific changes, see bug-reports CORE-6611 and CORE-4620 (aka. #5003) */ /* HACK: ReactOS specific changes, see bug-reports CORE-6611 and CORE-4620 (aka. #5003) */
static VOID NTAPI static VOID NTAPI
SetRosSpecificInfo(IN OUT PRTL_OSVERSIONINFOEXW VersionInformation) SetRosSpecificInfo(IN OUT PRTL_OSVERSIONINFOEXW VersionInformation)
@ -24,7 +26,6 @@ SetRosSpecificInfo(IN OUT PRTL_OSVERSIONINFOEXW VersionInformation)
CHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; CHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = (PVOID)Buffer; PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = (PVOID)Buffer;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
ULONG ReportAsWorkstation = 0;
HANDLE hKey; HANDLE hKey;
ULONG Length; ULONG Length;
NTSTATUS Status; NTSTATUS Status;
@ -38,7 +39,7 @@ SetRosSpecificInfo(IN OUT PRTL_OSVERSIONINFOEXW VersionInformation)
NULL); NULL);
/* Don't change anything if the key doesn't exist */ /* Don't change anything if the key doesn't exist */
Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes); Status = (g_ReportProductType == 0) ? NtOpenKey(&hKey, KEY_READ, &ObjectAttributes) : STATUS_CANCELLED;
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Get the value from the registry and make sure it's a 32-bit value */ /* Get the value from the registry and make sure it's a 32-bit value */
@ -52,20 +53,28 @@ SetRosSpecificInfo(IN OUT PRTL_OSVERSIONINFOEXW VersionInformation)
(kvpInfo->Type == REG_DWORD) && (kvpInfo->Type == REG_DWORD) &&
(kvpInfo->DataLength == sizeof(ULONG))) (kvpInfo->DataLength == sizeof(ULONG)))
{ {
/* Is the value set? */ ULONG IsWorkstation = SharedUserData->NtProductType == NtProductWinNt;
ReportAsWorkstation = *(PULONG)kvpInfo->Data; ULONG ReportAsWorkstation = (*(PULONG)kvpInfo->Data) != 0;
if ((VersionInformation->wProductType == VER_NT_SERVER) && if (IsWorkstation != ReportAsWorkstation)
(ReportAsWorkstation != 0))
{ {
/* It is, modify the product type to report a workstation */ g_ReportProductType = ReportAsWorkstation ? NtProductWinNt : NtProductServer;
VersionInformation->wProductType = VER_NT_WORKSTATION;
DPRINT("We modified the reported OS from NtProductServer to NtProductWinNt\n");
} }
} }
/* Close the handle */ /* Close the handle */
NtClose(hKey); NtClose(hKey);
} }
if (g_ReportProductType > 0)
{
VersionInformation->wProductType = g_ReportProductType;
DPRINT("We modified the reported OS product type from %d to %d\n",
SharedUserData->NtProductType, VersionInformation->wProductType);
}
else
{
g_ReportProductType = -1;
}
} }
/********************************************************************** /**********************************************************************
@ -96,6 +105,21 @@ BOOLEAN NTAPI
RtlGetNtProductType(_Out_ PNT_PRODUCT_TYPE ProductType) RtlGetNtProductType(_Out_ PNT_PRODUCT_TYPE ProductType)
{ {
*ProductType = SharedUserData->NtProductType; *ProductType = SharedUserData->NtProductType;
if (g_ReportProductType == 0)
{
/* Initialize cached value */
RTL_OSVERSIONINFOEXW ovi;
ovi.dwOSVersionInfoSize = sizeof(ovi);
ovi.wProductType = *ProductType;
SetRosSpecificInfo(&ovi);
}
if (g_ReportProductType > 0)
{
*ProductType = g_ReportProductType;
DPRINT("Overriding RtlGetNtProductType to return %d\n", *ProductType);
}
return TRUE; return TRUE;
} }

View file

@ -4106,6 +4106,23 @@ HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id)
*/ */
BOOL WINAPI IsOS(DWORD feature) BOOL WINAPI IsOS(DWORD feature)
{ {
#ifdef __REACTOS__
OSVERSIONINFOEXA osvi;
DWORD platform, majorv, minorv;
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (!GetVersionExA((OSVERSIONINFOA*)&osvi))
{
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
if (!GetVersionExA((OSVERSIONINFOA*)&osvi))
{
ERR("GetVersionEx failed\n");
return FALSE;
}
osvi.wProductType = VER_NT_WORKSTATION;
osvi.wSuiteMask = 0;
}
#else
OSVERSIONINFOA osvi; OSVERSIONINFOA osvi;
DWORD platform, majorv, minorv; DWORD platform, majorv, minorv;
@ -4114,7 +4131,7 @@ BOOL WINAPI IsOS(DWORD feature)
ERR("GetVersionEx failed\n"); ERR("GetVersionEx failed\n");
return FALSE; return FALSE;
} }
#endif
majorv = osvi.dwMajorVersion; majorv = osvi.dwMajorVersion;
minorv = osvi.dwMinorVersion; minorv = osvi.dwMinorVersion;
platform = osvi.dwPlatformId; platform = osvi.dwPlatformId;
@ -4189,7 +4206,11 @@ BOOL WINAPI IsOS(DWORD feature)
FIXME("(OS_DOMAINMEMBER) What should we return here?\n"); FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
return TRUE; return TRUE;
case OS_ANYSERVER: case OS_ANYSERVER:
#ifdef __REACTOS__
ISOS_RETURN(osvi.wProductType > VER_NT_WORKSTATION)
#else
ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
#endif
case OS_WOW6432: case OS_WOW6432:
{ {
BOOL is_wow64; BOOL is_wow64;

View file

@ -91,7 +91,7 @@ ChangeNtProductType(DWORD NtProductType)
} }
else else
{ {
ok(FALSE, "Passed invalid product type to CHangeNtProduct: %lu", NtProductType); ok(FALSE, "Passed invalid product type to ChangeNtProduct: %lu", NtProductType);
} }
Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Result = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
@ -129,6 +129,19 @@ START_TEST(RtlGetNtProductType)
DWORD ProductNtType; DWORD ProductNtType;
NT_PRODUCT_TYPE ProductType = NtProductWinNt, ProductType2; NT_PRODUCT_TYPE ProductType = NtProductWinNt, ProductType2;
/* Remove ReportAsWorkstation override during tests */
DWORD ReportAsWorkstation = 0xbaadf00d;
HKEY hKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version",
0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
DWORD cb = sizeof(DWORD);
if (RegQueryValueExW(hKey, L"ReportAsWorkstation", NULL, NULL, (PBYTE)&ReportAsWorkstation, &cb))
ReportAsWorkstation = 0xbaadf00d;
RegDeleteValueW(hKey, L"ReportAsWorkstation");
RegCloseKey(hKey);
}
/* /*
* Wrap the call in SEH. This ensures the testcase won't crash but also * Wrap the call in SEH. This ensures the testcase won't crash but also
* it proves to us that RtlGetNtProductType() throws an exception if a NULL * it proves to us that RtlGetNtProductType() throws an exception if a NULL
@ -164,4 +177,14 @@ START_TEST(RtlGetNtProductType)
ok_long(ProductType2, ProductType); ok_long(ProductType2, ProductType);
ok_char(ChangeNtProductType(ProductType), TRUE); ok_char(ChangeNtProductType(ProductType), TRUE);
/* Restore ReportAsWorkstation */
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version",
0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
if (ReportAsWorkstation != 0xbaadf00d)
RegSetValueExW(hKey, L"ReportAsWorkstation", 0, REG_DWORD, (PBYTE)&ReportAsWorkstation, sizeof(DWORD));
RegCloseKey(hKey);
}
} }