Windows-Server-2003/shell/inc/isos.c

551 lines
18 KiB
C
Raw Normal View History

2024-08-04 01:28:15 +02:00
#include <shlwapi.h>
#include <regstr.h>
#if (_WIN32_WINNT >= 0x0500)
#include <lm.h> // for NetGetJoinInformation
#endif
// stolen from winuser
#ifndef SM_REMOTESESSION
#define SM_REMOTESESSION 0x1000
#endif
BOOL IsWinlogonRegValueSet(HKEY hKey, LPSTR pszKeyName, LPSTR pszPolicyKeyName, LPSTR pszValueName)
{
BOOL bRet = FALSE;
DWORD dwType;
DWORD dwSize;
HKEY hkey;
// first check the per-machine location.
if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
{
dwSize = sizeof(bRet);
if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
{
if (dwType != REG_DWORD)
{
bRet = FALSE;
}
}
RegCloseKey(hkey);
}
// then let the policy value override
if (RegOpenKeyExA(hKey, pszPolicyKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
{
dwSize = sizeof(bRet);
if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
{
if (dwType != REG_DWORD)
{
bRet = FALSE;
}
}
RegCloseKey(hkey);
}
return bRet;
}
BOOL IsWinlogonRegValuePresent(HKEY hKey, LPSTR pszKeyName, LPSTR pszValueName)
{
BOOL bRet = FALSE;
DWORD dwType;
DWORD dwSize;
HKEY hkey;
// first check the per-machine location.
if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
{
char szValueData[MAX_PATH];
dwSize = sizeof(szValueData);
bRet = (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)szValueData, &dwSize) == ERROR_SUCCESS);
RegCloseKey(hkey);
}
return bRet;
}
/*
BOOL IsTermsrvRunning()
{
BOOL fResult = TRUE; // assume the service is running
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (hSCManager)
{
SC_HANDLE hSCService = OpenService(hSCManager, TEXT("TermService"), SERVICE_QUERY_CONFIG);
if (hSCService)
{
SERVICE_STATUS ServiceStatus;
if (QueryServiceStatus(hSCService, &ServiceStatus))
{
if ((ServiceStatus.dwCurrentState == SERVICE_START_PENDING) ||
(ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
(ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING))
{
fResult = FALSE;
}
}
}
CloseServiceHandle(hSCManager);
}
return fResult;
}
*/
#if (_WIN32_WINNT >= 0x0500)
// Have to use a LoadLibrary/GetProcAddress thunk since we are part of stock4.lib/stock.lib,
// and we can't require users of stocklib to delayload netapi32.dll
typedef NET_API_STATUS (* NETGETJOININFORMATION) (LPCWSTR, LPWSTR*, PNETSETUP_JOIN_STATUS);
NET_API_STATUS NT5_NetGetJoinInformation(LPCWSTR pszServer, LPWSTR* ppszNameBuffer, PNETSETUP_JOIN_STATUS BufferType)
{
static NETGETJOININFORMATION s_pfn = (NETGETJOININFORMATION)-1;
if (s_pfn == (NETGETJOININFORMATION)-1)
{
if (IsOS(OS_WIN2000ORGREATER))
{
s_pfn = (NETGETJOININFORMATION)GetProcAddress(LoadLibrary(TEXT("netapi32")), "NetGetJoinInformation");
}
else
{
s_pfn = NULL;
}
}
if (s_pfn)
{
return s_pfn(pszServer, ppszNameBuffer, BufferType);
}
else
{
return ERROR_PROC_NOT_FOUND;
}
}
typedef NET_API_STATUS (* NETAPIBUFFERFREE) (void*);
NET_API_STATUS NT5_NetApiBufferFree(LPVOID pv)
{
static NETAPIBUFFERFREE s_pfn = (NETAPIBUFFERFREE)-1;
if (s_pfn == (NETAPIBUFFERFREE)-1)
{
if (IsOS(OS_WIN2000ORGREATER))
{
s_pfn = (NETAPIBUFFERFREE)GetProcAddress(GetModuleHandle(TEXT("netapi32")), "NetApiBufferFree");
}
else
{
s_pfn = NULL;
}
}
if (s_pfn)
{
return s_pfn(pv);
}
else
{
return ERROR_PROC_NOT_FOUND;
}
}
#endif // (_WIN32_WINNT >= 0x0500)
// checks to see if this machine is a member of a domain or not
// NOTE: this will always return FALSE on downlevel platforms (older than win2k)
BOOL IsMachineDomainMember()
{
// don't call NetGetJoinInformation if we are part of stock4.lib
#if (_WIN32_WINNT >= 0x0500)
static BOOL s_bIsDomainMember = FALSE;
static BOOL s_bDomainCached = FALSE;
if (IsOS(OS_WIN2000ORGREATER) && !s_bDomainCached)
{
LPWSTR pwszDomain;
NETSETUP_JOIN_STATUS njs;
NET_API_STATUS nas;
nas = NT5_NetGetJoinInformation(NULL, &pwszDomain, &njs);
if (nas == NERR_Success)
{
if (pwszDomain)
{
NT5_NetApiBufferFree(pwszDomain);
}
if (njs == NetSetupDomainName)
{
// we are joined to a domain!
s_bIsDomainMember = TRUE;
}
}
s_bDomainCached = TRUE;
}
return s_bIsDomainMember;
#else
return FALSE;
#endif
}
typedef LONG (WINAPI *PFNTQUERYINFORMATIONPROCESS) (HANDLE ProcessHandle, int ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
// this function checks to see if we are a 32-bit process running on a 64-bit platform
BOOL RunningOnWow64()
{
static BOOL bRunningOnWow64 = (BOOL)-1;
if (bRunningOnWow64 == (BOOL)-1)
{
PFNTQUERYINFORMATIONPROCESS pfn = (PFNTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationProcess");
if (pfn)
{
LONG lStatus;
ULONG_PTR Wow64Info;
#define ProcessWow64Information 26 // stolen from ntpsapi.h
lStatus = pfn(GetCurrentProcess(), ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL);
if ((lStatus >= 0) && Wow64Info)
{
bRunningOnWow64 = TRUE;
}
else
{
bRunningOnWow64 = FALSE;
}
}
else
{
bRunningOnWow64 = FALSE;
}
}
return bRunningOnWow64;
}
BOOL ShouldShowServerAdminUI()
{
DWORD dw = FALSE;
HKEY hk;
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\Advanced"), 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS)
{
DWORD cb = sizeof(dw);
RegQueryValueEx(hk, TEXT("ServerAdminUI"), NULL, NULL, (LPBYTE)&dw, &cb); // preinitialized dw for failure
RegCloseKey(hk);
}
return dw;
}
BOOL IsApplianceServer()
{
static BOOL s_bRet = (BOOL)-1;
// Cache the value since it should not change normally. If any of the
// following code fails, just assume it is not an appliance server.
if (s_bRet == (BOOL)-1)
{
HKEY hkey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "System\\WPA\\ApplianceServer", 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
{
DWORD dwType;
DWORD dwValue;
DWORD dwSize = sizeof(dwValue);
if (RegQueryValueExA(hkey, "Installed", NULL, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS)
{
if ((dwType == REG_DWORD) && (dwValue != 0))
{
s_bRet = TRUE;
}
}
RegCloseKey(hkey);
}
}
if (s_bRet == (BOOL)-1)
{
s_bRet = FALSE;
}
return s_bRet;
}
/*----------------------------------------------------------
Purpose: Returns TRUE/FALSE if the platform is the given OS_ value.
*/
STDAPI_(BOOL) IsOS(DWORD dwOS)
{
BOOL bRet;
static OSVERSIONINFOEXA s_osvi = {0};
static BOOL s_bVersionCached = FALSE;
if (!s_bVersionCached)
{
s_bVersionCached = TRUE;
s_osvi.dwOSVersionInfoSize = sizeof(s_osvi);
if (!GetVersionExA((OSVERSIONINFOA*)&s_osvi))
{
// If it failed, it must be a down level platform
s_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
GetVersionExA((OSVERSIONINFOA*)&s_osvi);
}
}
switch (dwOS)
{
case OS_TERMINALCLIENT:
// WARNING: this will only return TRUE for REMOTE TS sessions (eg you are comming in via tsclient).
// If you want to see if TS is enabled or if the user is on the TS console, the use one of the other flags.
bRet = GetSystemMetrics(SM_REMOTESESSION);
break;
case OS_WIN2000TERMINAL:
// WARNING: this flag is VERY ambiguous... you probably want to use one of
// OS_TERMINALSERVER, OS_TERMINALREMOTEADMIN, or OS_PERSONALTERMINALSERVER instead.
RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use one of OS_TERMINALSERVER, OS_TERMINALREMOTEADMIN, or OS_PERSONALTERMINALSERVER instead !");
bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
s_osvi.dwMajorVersion >= 5);
break;
case OS_TERMINALSERVER:
// NOTE: be careful about using OS_TERMINALSERVER. It will only return true for nt server boxes
// configured in what used to be called "Applications Server" mode in the win2k days. It is now simply called
// "Terminal Server" (hence the name of this flag).
bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
!(VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask));
#ifdef DEBUG
if (bRet)
{
// all "Terminal Server" machines have to be server (cannot be per/pro)
ASSERT(VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType);
}
#endif
break;
case OS_TERMINALREMOTEADMIN:
// this checks to see if TS has been installed in the "Remote Administration" mode. This is
// the default for server installs on win2k and whistler
bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
(VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask));
break;
case OS_PERSONALTERMINALSERVER:
bRet = ((VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask) &&
!(VER_SUITE_TERMINAL & s_osvi.wSuiteMask));
break;
case OS_FASTUSERSWITCHING:
bRet = (((VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS) & s_osvi.wSuiteMask) &&
IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
"AllowMultipleTSSessions"));
break;
case OS_FRIENDLYLOGONUI:
bRet = ((VER_NT_WORKSTATION == s_osvi.wProductType) &&
!IsMachineDomainMember() &&
!IsWinlogonRegValuePresent(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
"GinaDLL") &&
IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
"LogonType"));
break;
case OS_DOMAINMEMBER:
bRet = IsMachineDomainMember();
ASSERT(VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId); // has to be a NT machine to be on a domain!
break;
case 4: // used to be OS_NT5, is the same as OS_WIN2000ORGREATER so use that instead
case OS_WIN2000ORGREATER:
bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
s_osvi.dwMajorVersion >= 5);
break;
// NOTE: The flags in this section are bogus and SHOULD NOT BE USED
// (but the ie4 shell32 uses them, so don't RIP on downlevel platforms)
case OS_WIN2000PRO:
RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_PROFESSIONAL instead of OS_WIN2000PRO !");
bRet = (VER_NT_WORKSTATION == s_osvi.wProductType &&
s_osvi.dwMajorVersion == 5);
break;
case OS_WIN2000ADVSERVER:
RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_ADVSERVER instead of OS_WIN2000ADVSERVER !");
bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
s_osvi.dwMajorVersion == 5 &&
(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
!(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
break;
case OS_WIN2000DATACENTER:
RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_DATACENTER instead of OS_WIN2000DATACENTER !");
bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
s_osvi.dwMajorVersion == 5 &&
(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
break;
case OS_WIN2000SERVER:
RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_SERVER instead of OS_WIN2000SERVER !");
bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
!(VER_SUITE_DATACENTER & s_osvi.wSuiteMask) &&
!(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
s_osvi.dwMajorVersion == 5);
break;
// END bogus Flags
case OS_EMBEDDED:
bRet = (VER_SUITE_EMBEDDEDNT & s_osvi.wSuiteMask);
break;
case OS_WINDOWS:
bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId);
break;
case OS_NT:
bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId);
break;
case OS_WIN95:
bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
s_osvi.dwMajorVersion >= 4);
break;
case OS_WIN95GOLD:
bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion == 0 &&
LOWORD(s_osvi.dwBuildNumber) == 950);
break;
case OS_WIN98ORGREATER:
bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
(s_osvi.dwMajorVersion > 4 ||
s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 10));
break;
case OS_WIN98_GOLD:
bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion == 10 &&
LOWORD(s_osvi.dwBuildNumber) == 1998);
break;
case OS_MILLENNIUMORGREATER:
bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
((s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 90) ||
s_osvi.dwMajorVersion > 4));
break;
case OS_NT4:
bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
s_osvi.dwMajorVersion >= 4);
break;
case OS_WHISTLERORGREATER:
bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
((s_osvi.dwMajorVersion > 5) ||
(s_osvi.dwMajorVersion == 5 && (s_osvi.dwMinorVersion > 0 ||
(s_osvi.dwMinorVersion == 0 && LOWORD(s_osvi.dwBuildNumber) > 2195)))));
break;
case OS_PERSONAL:
bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
(VER_SUITE_PERSONAL & s_osvi.wSuiteMask));
break;
case OS_PROFESSIONAL:
bRet = ((VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId) &&
(VER_NT_WORKSTATION == s_osvi.wProductType));
break;
case OS_DATACENTER:
bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
break;
case OS_ADVSERVER:
bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
!(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
break;
case OS_SERVER:
// NOTE: be careful! this specifically means Server -- will return false for Avanced Server and Datacenter machines
bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
!(VER_SUITE_DATACENTER & s_osvi.wSuiteMask) &&
!(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
!(VER_SUITE_BLADE & s_osvi.wSuiteMask) &&
!(VER_SUITE_SMALLBUSINESS & s_osvi.wSuiteMask) &&
!(VER_SUITE_SMALLBUSINESS_RESTRICTED & s_osvi.wSuiteMask));
break;
case OS_BLADE:
// Blade has a direct suite mask
bRet = (VER_SUITE_BLADE & s_osvi.wSuiteMask);
break;
case OS_SMALLBUSINESSSERVER:
// SBS also has a direct suite mask
bRet = (VER_SUITE_SMALLBUSINESS_RESTRICTED & s_osvi.wSuiteMask);
break;
case OS_ANYSERVER:
// this is for people who want to know if this is ANY type of NT server machine (eg dtc, ads, or srv)
bRet = ((VER_NT_SERVER == s_osvi.wProductType) || (VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType));
break;
case OS_WOW6432:
bRet = RunningOnWow64();
break;
#if (_WIN32_WINNT >= 0x0501)
case OS_TABLETPC:
bRet = GetSystemMetrics(SM_TABLETPC);
break;
case OS_MEDIACENTER:
bRet = GetSystemMetrics(SM_MEDIACENTER);
break;
case OS_APPLIANCE:
bRet = IsApplianceServer();
break;
#endif
case OS_SERVERADMINUI:
// Note that it is possible to have server admin UI on a non-server machine.
// This is to prevent "surprises" when an admin's profile roams to a non-server.
// Otherwise the user gets a mix of admin settings (Start Menu, full path in
// title bar, etc.) and nonadmin settings (hide taskbar icons, folder sniffing).
//
bRet = ShouldShowServerAdminUI();
break;
default:
bRet = FALSE;
break;
}
return bRet;
}