Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

765 lines
21 KiB

/*++
Copyright (C) Microsoft Corporation, 1996 - 1997
All rights reserved.
Module Name:
compinfo.hxx
Abstract:
Local and remote computer information detection.
Author:
10/17/95 <adamk> created.
Steve Kiraly (SteveKi) 21-Jan-1996 used for downlevel server detection
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
#include "compinfo.hxx"
#include "persist.hxx"
TCHAR const PROCESSOR_ARCHITECTURE_NAME_INTEL[] = TEXT("Intel");
TCHAR const PROCESSOR_ARCHITECTURE_NAME_UNKNOWN[] = TEXT("(unknown)");
TCHAR const ENVIRONMENT_IA64[] = TEXT("Windows IA64");
TCHAR const ENVIRONMENT_INTEL[] = TEXT("Windows NT x86");
TCHAR const ENVIRONMENT_WINDOWS[] = TEXT("Windows 4.0");
TCHAR const ENVIRONMENT_UNKNOWN[] = TEXT("(unknown)");
TCHAR const ENVIRONMENT_NATIVE[] = TEXT("");
TCHAR const c_szProductOptionsPath[] = TEXT( "System\\CurrentControlSet\\Control\\ProductOptions" );
TCHAR const c_szProductOptions[] = TEXT( "ProductType" );
TCHAR const c_szWorkstation[] = TEXT( "WINNT" );
TCHAR const c_szServer1[] = TEXT( "SERVERNT" );
TCHAR const c_szServer2[] = TEXT( "LANMANNT" );
TCHAR const c_szNetApi32Dll[] = TEXT( "netapi32.dll" );
CHAR const c_szNetServerGetInfo[] = "NetServerGetInfo";
CHAR const c_szNetApiBufferFree[] = "NetApiBufferFree";
CComputerInfo::
CComputerInfo(
IN LPCTSTR pComputerName
) : ComputerName( pComputerName),
ProductOption( kNtUnknown ),
OSIsDebugVersion( FALSE ),
ProcessorArchitecture( 0 ),
ProcessorCount( 0 )
{
DBGMSG( DBG_TRACE, ( "CComputerInfo::ctor\n" ) );
memset( &OSInfo, 0, sizeof( OSInfo ) );
}
CComputerInfo::~CComputerInfo()
{
DBGMSG( DBG_TRACE, ( "CComputerInfo::dtor\n" ) );
}
LPCTSTR CComputerInfo::GetProcessorArchitectureName() const
{
SPLASSERT(IsInfoValid());
switch (ProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_INTEL:
{
return PROCESSOR_ARCHITECTURE_NAME_INTEL;
}
default:
{
return PROCESSOR_ARCHITECTURE_NAME_UNKNOWN;
}
}
}
LPCTSTR CComputerInfo::GetProcessorArchitectureDirectoryName() const
{
SPLASSERT(IsInfoValid());
switch (ProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_INTEL:
{
return TEXT("i386");
}
default:
{
return PROCESSOR_ARCHITECTURE_NAME_UNKNOWN;
}
}
}
LPCTSTR CComputerInfo::GetNativeEnvironment() const
{
SPLASSERT(IsInfoValid());
switch (ProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_INTEL:
{
if (IsRunningWindows95())
{
return ENVIRONMENT_WINDOWS;
}
else
{
return ENVIRONMENT_INTEL;
}
}
default:
{
SPLASSERT(FALSE);
return ENVIRONMENT_UNKNOWN;
}
}
}
BOOL CComputerInfo::IsInfoValid() const
{
// if OSInfo.dwOSVersionInfoSize is not zero, then the info has been retrieved
return (BOOL) (OSInfo.dwOSVersionInfoSize != 0);
}
BOOL CComputerInfo::IsRunningWindowsNT() const
{
return (OSInfo.dwPlatformId & VER_PLATFORM_WIN32_NT);
}
BOOL CComputerInfo::IsRunningWindows95() const
{
return (OSInfo.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS);
}
DWORD CComputerInfo::GetOSBuildNumber() const
{
// Build number is the low word of dwBuildNumber
return (OSInfo.dwBuildNumber & 0xFFFF);
}
WORD CComputerInfo::GetProcessorArchitecture() const
{
return ProcessorArchitecture;
}
DWORD CComputerInfo::GetSpoolerVersion() const
{
DWORD BuildNumber = GetOSBuildNumber();
DWORD SpoolerVersion;
// Windows NT 4.0 (and beyond)
if (BuildNumber > 1057)
{
SpoolerVersion = 2;
}
// Windows NT 3.5 and 3.51
else if (BuildNumber > 511)
{
SpoolerVersion = 1;
}
// Windows NT 3.1
else
{
SpoolerVersion = 0;
}
return SpoolerVersion;
}
BOOL CComputerInfo::GetInfo()
{
// NOTE: OSInfo.dwOSVersionInfoSize must be non-zero after the info is retrieved.
DWORD ErrorCode = ERROR_SUCCESS;
LPTSTR pCPUName = NULL;
LPTSTR pBuildNumberText = NULL;
LPTSTR pVersionText = NULL;
LPTSTR pCSDVersionText = NULL;
LPTSTR pOSTypeText = NULL;
// set size of version info structure
OSInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if( ComputerName.bEmpty() )
{
SYSTEM_INFO SystemInfo;
// get operating system info
if (!GetVersionEx(&OSInfo))
{
ErrorCode = GetLastError();
goto CleanUp;
}
// get hardware info
GetSystemInfo(&SystemInfo);
ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
ProcessorCount = SystemInfo.dwNumberOfProcessors;
}
else
{
REGISTRY_KEY_INFO RegistryKeyInfo;
// determine operating system
// if this key is found, then the OS is Windows NT
// if this key cannot be found, then the OS is Windows 95
// otherwise, it is an error
pBuildNumberText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
TEXT("CurrentBuildNumber"));
if (GetLastError() == ERROR_CANTOPEN)
{
// operating system is Windows 95
OSInfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
// get OS version
pVersionText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
TEXT("Version"));
if (GetLastError() != ERROR_SUCCESS)
{
ErrorCode = GetLastError();
goto CleanUp;
}
// parse OS version
OSInfo.dwMajorVersion = 0;
OSInfo.dwMinorVersion = 0;
OSInfo.dwBuildNumber = 0;
//
// The version string is of the form "X.X" The following
// code is used to isolate the major and minor verison
// to place in dwords respectivly.
//
LPTSTR p;
OSInfo.dwMajorVersion = _tcstoul( pVersionText, &p, 10);
//
// We know the conversion will stop at the '.' if it did
// skip past the '.' and do the minor version conversion.
//
if( *p == TEXT('.') )
{
p++;
OSInfo.dwMinorVersion = _tcstoul(p, &p, 10);
}
//
// We know the conversion will stop at the '.' if it did
// skip past the '.' and do the build number conversion.
//
if( *p == TEXT('.') )
{
p++;
OSInfo.dwBuildNumber = _tcstoul(p, NULL, 10);
}
// get CSD version
OSInfo.szCSDVersion[0] = TEXT('\0');
// processor must be Intel
ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
// processor count must be 1
ProcessorCount = 1;
}
else if (GetLastError() == ERROR_SUCCESS)
{
// operating system is Windows NT
OSInfo.dwPlatformId = VER_PLATFORM_WIN32_NT;
// parse build number (which was just retrieved)
OSInfo.dwBuildNumber = _tcstoul(pBuildNumberText, NULL, 10);
// get OS version
pVersionText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
TEXT("CurrentVersion"));
if (GetLastError() != ERROR_SUCCESS)
{
ErrorCode = GetLastError();
goto CleanUp;
}
//
// parse OS version
//
OSInfo.dwMajorVersion = 0;
OSInfo.dwMinorVersion = 0;
//
// The version string is of the form "X.X" The following
// code is used to isolate the major and minor verison
// to place in dwords respectivly.
//
LPTSTR p;
OSInfo.dwMajorVersion = _tcstoul( pVersionText, &p, 10);
//
// We know the conversion will stop at the '.' if it did
// skip past the '.' and do the minor version conversion.
//
if( *p == TEXT('.') )
{
p++;
OSInfo.dwMinorVersion = _tcstoul(p, NULL, 10);
}
// get CSD version
OSInfo.szCSDVersion[0] = TEXT('\0');
pCSDVersionText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
TEXT("CSDVersion"));
if (GetLastError() == ERROR_SUCCESS)
{
StringCchCopy(OSInfo.szCSDVersion, ARRAYSIZE(OSInfo.szCSDVersion), pCSDVersionText);
}
// get name of cpu
pCPUName = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
TEXT("Identifier"));
if (GetLastError() != ERROR_SUCCESS)
{
ErrorCode = GetLastError();
goto CleanUp;
}
// determine processor architecture from cpu name
if (!_tcsnicmp(pCPUName, TEXT("80386-"), 6)
|| !_tcsnicmp(pCPUName, TEXT("80486-"), 6)
|| !_tcsnicmp(pCPUName, TEXT("x86 "), 4))
{
ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
}
else if(!_tcsnicmp(pCPUName, TEXT("IA64"), 4))
{
ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64;
}
else
{
SPLASSERT(FALSE);
ProcessorArchitecture = 0;
}
// get processor count
// On Windows NT, this can be determined by the number of subkeys of the following
// registry key.
if (!GetRegistryKeyInfo(ComputerName, HKEY_LOCAL_MACHINE,
TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor"),
&RegistryKeyInfo))
{
ErrorCode = GetLastError();
goto CleanUp;
}
ProcessorCount = RegistryKeyInfo.NumSubKeys;
}
else
{
ErrorCode = GetLastError();
goto CleanUp;
}
}
// determine whether OS is retail or debug
OSIsDebugVersion = FALSE;
if (OSInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
// get OS type
pOSTypeText = AllocateRegistryString(ComputerName,
HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
TEXT("CurrentType"));
if (GetLastError() != ERROR_SUCCESS)
{
ErrorCode = GetLastError();
goto CleanUp;
}
// if the type text contains the word "Checked",
// then it is a debug build
OSIsDebugVersion = (_tcsstr(pOSTypeText, TEXT("Checked")) != NULL);
}
CleanUp:
if (pCPUName)
{
GlobalFree(pCPUName);
}
if (pBuildNumberText)
{
GlobalFree(pBuildNumberText);
}
if (pVersionText)
{
GlobalFree(pVersionText);
}
if (pCSDVersionText)
{
GlobalFree(pCSDVersionText);
}
if (pOSTypeText)
{
GlobalFree(pOSTypeText);
}
if (ErrorCode)
{
SetLastError(ErrorCode);
return FALSE;
}
else
{
return TRUE;
}
}
BOOL
CComputerInfo::
GetProductInfo(
VOID
)
{
//
// If the request is for the local machine, do not access the net.
//
if( ComputerName.bEmpty() )
{
ProductOption = GetLocalProductInfo();
}
else
{
ProductOption = GetRemoteProductInfo();
}
DBGMSG( DBG_TRACE, ("CComputerInfo::GetPoductInfo %d\n", ProductOption ) );
return ProductOption != kNtUnknown;
}
BOOL
CComputerInfo::
IsRunningNtServer(
VOID
) const
{
return ProductOption == kNtServer;
}
BOOL
CComputerInfo::
IsRunningNtWorkstation(
VOID
) const
{
return ProductOption == kNtWorkstation;
}
CComputerInfo::ProductType
CComputerInfo::
GetLocalProductInfo(
VOID
)
{
TStatusB bStatus;
TString strProduct;
ProductType Option = kNtUnknown;
TPersist Product( c_szProductOptionsPath, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
bStatus DBGCHK = VALID_OBJ( Product );
if( bStatus )
{
bStatus DBGCHK = Product.bRead( c_szProductOptions, strProduct );
if( bStatus )
{
if( !_tcsicmp( c_szWorkstation, strProduct ) )
{
Option = kNtWorkstation;
}
else if( !_tcsicmp( c_szServer1, strProduct ) || !_tcsicmp( c_szServer2, strProduct ) )
{
Option = kNtServer;
}
else
{
Option = kNtUnknown;
}
}
}
return Option;
}
CComputerInfo::ProductType
CComputerInfo::
GetRemoteProductInfo(
VOID
)
{
ProductType Option = kNtUnknown;
TLibrary Lib( c_szNetApi32Dll );
if( VALID_OBJ( Lib ) )
{
typedef NET_API_STATUS (*pf_NetServerGetInfo)(LPCTSTR servername,DWORD level,LPBYTE *bufptr);
typedef NET_API_STATUS (*pf_NetApiBufferFree)(LPVOID Buffer);
pf_NetServerGetInfo pfNetServerGetInfo = (pf_NetServerGetInfo)Lib.pfnGetProc( c_szNetServerGetInfo );
pf_NetApiBufferFree pfNetApiBufferFree = (pf_NetApiBufferFree)Lib.pfnGetProc( c_szNetApiBufferFree );
PSERVER_INFO_101 si101 = NULL;
if( pfNetServerGetInfo && pfNetApiBufferFree )
{
//
// Get the server info
//
if( pfNetServerGetInfo( ComputerName, 101, (LPBYTE *)&si101 ) == NERR_Success )
{
DBGMSG( DBG_TRACE, ("Server_Info_101.sv101_type %x\n", si101->sv101_type ) );
DWORD dwType = si101->sv101_type;
//
// If the server type is NT and a server.
//
if( dwType & ( SV_TYPE_SERVER_NT | SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL ) )
{
Option = kNtServer;
}
//
// If the server type is NT and a workstation.
//
else if( (dwType & ( SV_TYPE_NT | SV_TYPE_WORKSTATION )) == ( SV_TYPE_NT | SV_TYPE_WORKSTATION ) )
{
Option = kNtWorkstation;
}
else
{
Option = kNtUnknown;
}
//
// Release the server info structure.
//
pfNetApiBufferFree( si101 );
}
}
}
return Option;
}
////////////////////////////////////////////////////////////////////////////////
//
// AllocateRegistryString returns a copy of the string value stored at the
// specified registry key. The registry can be on either a remote machine or
// the local machine.
//
// Parameter Description
// -----------------------------------------------------------------------------
// pServerName Name of server on which registry resides.
// hRegistryRoot Registry root (i.e. HKEY_LOCAL_MACHINE). See RegConnectRegistry
// for acceptable values.
// pKeyName Name of registry key.
// pValueName Name of registry value. The value must be of type REG_SZ.
//
// Returns:
// If successful, the function returns a pointer to a copy of the string.
// If the function fails, GetLastError() will return an error code other than
// ERROR_SUCCESS, and NULL is returned from the function.
// Revision History:
// 10/17/95 <adamk> created.
//
LPTSTR
CComputerInfo::
AllocateRegistryString(
LPCTSTR pServerName,
HKEY hRegistryRoot,
LPCTSTR pKeyName,
LPCTSTR pValueName
)
{
DWORD ErrorCode = 0;
HKEY hRegistry = 0;
HKEY hRegistryKey = 0;
DWORD RegistryValueType = 0;
DWORD cbSize = 0;
DWORD cchSize = 0;
LPTSTR pString = NULL;
// connect to the registry of the specified machine
if (ErrorCode = RegConnectRegistry((LPTSTR) pServerName, hRegistryRoot, &hRegistry))
{
goto CleanUp;
}
// open the registry key
if (ErrorCode = RegOpenKeyEx(hRegistry, pKeyName, 0, KEY_QUERY_VALUE, &hRegistryKey))
{
goto CleanUp;
}
// query the value's type and size
if(ErrorCode = RegQueryValueEx(hRegistryKey, pValueName, NULL, &RegistryValueType, NULL,
&cbSize))
{
goto CleanUp;
}
// make sure the value is a string
if (RegistryValueType != REG_SZ)
{
ErrorCode = ERROR_INVALID_PARAMETER;
goto CleanUp;
}
//
// cbSize is the requested size of the buffer in bytes.
// allocate two more characters - one to make sure the
// cbSize / sizeof(TCHAR) is rounded up properly and one
// for a zero terminator to cover the case where the
// data is not properly zero terminated when written.
//
cchSize = cbSize / sizeof(TCHAR) + 2;
cbSize = cchSize * sizeof(TCHAR);
if (!(pString = (LPTSTR) GlobalAlloc(GMEM_FIXED, cbSize)))
{
ErrorCode = GetLastError();
goto CleanUp;
}
if (ErrorCode = RegQueryValueEx(hRegistryKey, pValueName, NULL, &RegistryValueType,
(LPBYTE) pString, &cbSize))
{
ErrorCode = GetLastError();
goto CleanUp;
}
else
{
//
// RegQueryValueEx may not zero terminate the buffer if the
// data in the registry is not zero terminated. Make sure it
// is properly zero terminated.
//
pString[cchSize-1] = 0;
}
CleanUp:
if (hRegistryKey)
{
RegCloseKey(hRegistryKey);
}
if (hRegistry)
{
RegCloseKey(hRegistry);
}
if (ErrorCode && pString)
{
GlobalFree(pString);
pString = NULL;
}
SetLastError (ErrorCode);
return pString;
}
////////////////////////////////////////////////////////////////////////////////
//
// GetRegistrySubKeyCount returns the number of subkeys that the specified
// registry key contains. The registry can be on either a remote machine or
// the local machine.
//
// Parameter Description
// -----------------------------------------------------------------------------
// pServerName Name of server on which registry resides.
// hRegistryRoot Registry root (i.e. HKEY_LOCAL_MACHINE). See RegConnectRegistry
// for acceptable values.
// pKeyName Name of registry key.
//
// Returns:
// If successful, the function returns the number of subkeys and GetLastError()
// will return ERROR_SUCCESS. Otherwise, GetLastError() return the error code
// indicating the reason for the failure.
// Revision History:
// 10/23/95 <adamk> created.
//
BOOL
CComputerInfo::
GetRegistryKeyInfo(
LPCTSTR pServerName,
HKEY hRegistryRoot,
LPCTSTR pKeyName,
REGISTRY_KEY_INFO *pKeyInfo
)
{
DWORD ErrorCode = 0;
HKEY hRegistry = 0;
HKEY hRegistryKey = 0;
// connect to the registry of the specified machine
if (ErrorCode = RegConnectRegistry((LPTSTR) pServerName, hRegistryRoot, &hRegistry))
{
goto CleanUp;
}
// open the registry key
if (ErrorCode = RegOpenKeyEx(hRegistry, pKeyName, 0, KEY_QUERY_VALUE, &hRegistryKey))
{
goto CleanUp;
}
// get the key info
if (ErrorCode = RegQueryInfoKey(hRegistryKey, NULL, 0, 0, &pKeyInfo->NumSubKeys,
&pKeyInfo->MaxSubKeyLength, &pKeyInfo->MaxClassLength, &pKeyInfo->NumValues,
&pKeyInfo->MaxValueNameLength, &pKeyInfo->MaxValueDataLength,
&pKeyInfo->SecurityDescriptorLength, &pKeyInfo->LastWriteTime))
{
goto CleanUp;
}
CleanUp:
if (hRegistryKey)
{
RegCloseKey(hRegistryKey);
}
if (hRegistry)
{
RegCloseKey(hRegistry);
}
if (ErrorCode)
{
SetLastError(ErrorCode);
return FALSE;
}
else
{
return TRUE;
}
}