|
|
// Copyright (c) 2001 Microsoft Corporation
//
// File: state.cpp
//
// Synopsis: Defines the state object that is global
// to CYS. It holds the network and OS/SKU info
//
// History: 02/02/2001 JeffJon Created
#include "pch.h"
#include "state.h"
#include "cys.h"
static State* stateInstance = 0;
State::State() : dhcpServerAvailableOnAllNics(true), dhcpAvailabilityRetrieved(false), hasStateBeenRetrieved(false), rerunWizard(true), isRebootScenario(false), productSKU(CYS_SERVER), hasNTFSDrive(false), localComputer(), computerName(), domainDNSName(), domainNetbiosName(), wizardStartPage(0) { LOG_CTOR(State); HRESULT unused = localComputer.Refresh(); ASSERT(SUCCEEDED(unused));
RetrievePlatform(); }
void State::Destroy() { LOG_FUNCTION(State::Destroy);
if (stateInstance) { delete stateInstance; stateInstance = 0; } }
State& State::GetInstance() { if (!stateInstance) { stateInstance = new State(); }
ASSERT(stateInstance);
return *stateInstance; }
bool State::IsRemoteSession() const { LOG_FUNCTION(State::IsRemoteSession);
bool result = Win::GetSystemMetrics(SM_REMOTESESSION) ? true : false;
LOG_BOOL(result);
return result; }
bool State::IsWindowsSetupRunning() const { LOG_FUNCTION(State::IsWindowsSetupRunning);
bool result = false;
// Try to create a mutex for the default
// sysoc inf file. If it already exists
// then we know SYSOCMGR is running
static const String mutexName = L"Global\\sysoc";
HANDLE mutexHandle = INVALID_HANDLE_VALUE;
HRESULT hr = Win::CreateMutex( 0, true, mutexName, mutexHandle);
if (hr == Win32ToHresult(ERROR_ALREADY_EXISTS)) { // SysOCMGR is running
result = true; }
if (mutexHandle != INVALID_HANDLE_VALUE) { // Close the handle
Win::CloseHandle(mutexHandle); }
LOG_BOOL(result);
return result; }
bool State::IsDC() const { LOG_FUNCTION(State::IsDC);
bool result = localComputer.IsDomainController();
LOG_BOOL(result);
return result; }
bool State::IsDCPromoRunning() const { LOG_FUNCTION(State::IsDCPromoRunning);
// Uses the IsDcpromoRunning from Burnslib
bool result = IsDcpromoRunning();
LOG_BOOL(result);
return result; }
bool State::IsDCPromoPendingReboot() const { LOG_FUNCTION(State::IsDCPromoPendingReboot);
bool result = false;
do { // Uses the IsDcpromoRunning from Burnslib
if (!IsDcpromoRunning()) { // this test is redundant if dcpromo is running, so only
// perform it when dcpromo is not running.
DSROLE_OPERATION_STATE_INFO* info = 0; HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info); if (SUCCEEDED(hr) && info) { if (info->OperationState == DsRoleOperationNeedReboot) { result = true; }
::DsRoleFreeMemory(info); } }
} while (false);
LOG_BOOL(result);
return result; }
bool State::IsJoinedToDomain() const { LOG_FUNCTION(State::IsJoinedToDomain);
bool result = localComputer.IsJoinedToDomain();
LOG_BOOL(result);
return result; }
bool State::IsUpgradeState() const { LOG_FUNCTION(State::IsUpgradeState);
bool result = false;
do { DSROLE_UPGRADE_STATUS_INFO* info = 0; HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info); if (FAILED(hr)) { LOG(String::format( L"MyDsRoleGetPrimaryDomainInformation(0): hr = 0x%1!x!", hr));
break; }
if (info && info->OperationState == DSROLE_UPGRADE_IN_PROGRESS) { result = true; }
::DsRoleFreeMemory(info); } while (false);
LOG_BOOL(result);
return result; }
bool State::IsFirstDC() const { LOG_FUNCTION(State::IsFirstDC);
DWORD value = 0; bool result = GetRegKeyValue(CYS_FIRST_DC_REGKEY, CYS_FIRST_DC_VALUE, value); if (value != 1) { result = false; }
LOG_BOOL(result);
return result; }
unsigned int State::GetNICCount() const { return adapterConfiguration.GetNICCount(); }
unsigned int State::GetNonModemNICCount() { unsigned int result = 0;
for ( unsigned int index = 0; index < GetNICCount(); ++index) { NetworkInterface* nic = GetNIC(index);
if (nic && !nic->IsModem()) { ++result; } }
LOG( String::format( L"Non-modem NIC count: %1!d!", result));
return result; }
NetworkInterface* State::GetNIC(unsigned int nicIndex) { LOG_FUNCTION2( State::GetNIC, String::format( L"%1!d!", nicIndex));
return adapterConfiguration.GetNIC(nicIndex); }
NetworkInterface* State::GetNICFromName(const String& name, bool& found) { LOG_FUNCTION2( State::GetNICFromName, name.c_str());
return adapterConfiguration.GetNICFromName(name, found); }
NetworkInterface* State::GetLocalNICFromRegistry() { LOG_FUNCTION(State::GetLocalNICFromRegistry);
// Read the local NIC GUID from the registry
String nicName; NetworkInterface* nic = 0;
if (!GetRegKeyValue( CYS_FIRST_DC_REGKEY, CYS_FIRST_DC_LOCAL_NIC, nicName)) { LOG(L"Failed to read LocalNIC regkey, using default local NIC");
nic = State::GetInstance().GetLocalNIC();
if (nic) { nicName = nic->GetName(); } } SetLocalNIC(nicName, false);
if (!nic) { nic = GetLocalNIC(); } return nic; }
bool State::RetrieveMachineConfigurationInformation( HWND progressStatic, bool doDHCPCheck, int nicInfoResID, int osInfoResID, int defaultConnectionResID, int detectSettingsResID) { LOG_FUNCTION(State::RetrieveMachineConfigurationInformation);
ASSERT(!hasStateBeenRetrieved);
// This is used to get the minimal information needed to
// determine if we should enable the express path
// This should probably just be changed to gather the
// information and let the page decide what to do
if (progressStatic) { Win::SetWindowText( progressStatic, String::load(nicInfoResID)); }
HRESULT hr = RetrieveNICInformation(); if (SUCCEEDED(hr)) {
// Only bother to check for a DHCP server on the network if we are not
// a DC, not a DNS server, not a DHCP server and have at least one NIC.
// Right now we only use this info for determining whether or not to
// show the Express path option
if (!(IsDC() || IsUpgradeState()) && (GetNICCount() > 0) && doDHCPCheck) { CheckDhcpServer( progressStatic, defaultConnectionResID, detectSettingsResID); } }
if (progressStatic) { Win::SetWindowText( progressStatic, String::load(osInfoResID)); }
RetrieveProductSKU(); RetrievePlatform();
// Retrieve the drive information (quotas enabled, partition types, etc.)
RetrieveDriveInformation();
hasStateBeenRetrieved = true; return true; }
DWORD State::RetrieveProductSKU() { LOG_FUNCTION(State::RetrieveProductSKU);
// I am making the assumption that we are on a
// Server SKU if GetVersionEx fails
productSKU = CYS_UNSUPPORTED_SKU;
OSVERSIONINFOEX info; HRESULT hr = Win::GetVersionEx(info); if (SUCCEEDED(hr)) { LOG(String::format( L"wSuiteMask = 0x%1!x!", info.wSuiteMask)); LOG(String::format( L"wProductType = 0x%1!x!", info.wProductType));
do { if (info.wProductType == VER_NT_SERVER || info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
if (info.wSuiteMask & VER_SUITE_DATACENTER) { // datacenter
productSKU = CYS_DATACENTER_SERVER; break; } else if (info.wSuiteMask & VER_SUITE_ENTERPRISE) { // advanced server
productSKU = CYS_ADVANCED_SERVER; break; } else if (info.wSuiteMask & VER_SUITE_SMALLBUSINESS || info.wSuiteMask & VER_SUITE_BACKOFFICE || info.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED || info.wSuiteMask & VER_SUITE_EMBEDDEDNT || info.wSuiteMask & VER_SUITE_BLADE) { // Unsupported server
productSKU = CYS_UNSUPPORTED_SKU; break; } else { // default to standard server
productSKU = CYS_SERVER; } break; }
// All other SKUs are unsupported
productSKU = CYS_UNSUPPORTED_SKU;
} while (false); } LOG(String::format(L"Product SKU = 0x%1!x!", productSKU ));
return productSKU; }
void State::RetrievePlatform() { LOG_FUNCTION(State::RetrievePlatform);
// I am making the assumption that we are not on a
// 64bit machine if GetSystemInfo fails
SYSTEM_INFO info; Win::GetSystemInfo(info);
switch (info.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_IA64: case PROCESSOR_ARCHITECTURE_AMD64: platform = CYS_64BIT; break;
default: platform = CYS_32BIT; break; }
LOG(String::format(L"Platform = 0x%1!x!", platform));
return; }
HRESULT State::RetrieveNICInformation() { ASSERT(!hasStateBeenRetrieved);
HRESULT hr = S_OK;
if (!adapterConfiguration.IsInitialized()) { hr = adapterConfiguration.Initialize(); }
LOG_HRESULT(hr);
return hr; }
void State::CheckDhcpServer( HWND progressStatic, int defaultConnectionNameResID, int detectSettingsResID) { LOG_FUNCTION(State::CheckDhcpServer);
// This should loop through all network interfaces
// seeing if we can obtain a lease on any of them
for (unsigned int idx = 0; idx < GetNICCount(); ++idx) { NetworkInterface* nic = GetNIC(idx);
if (!nic) { continue; }
// Update the text on the NetDetectProgressDialog
String progress = String::format( detectSettingsResID, nic->GetFriendlyName( String::load(defaultConnectionNameResID)).c_str());
if (progressStatic) { Win::SetWindowText(progressStatic, progress); }
// Now try to renew the lease
if (!nic->CanDetectDHCPServer()) { dhcpServerAvailableOnAllNics = false;
// Don't break because we need to retrieve the
// avialability of a DHCP server on all NICs
} } dhcpAvailabilityRetrieved = true;
LOG_BOOL(dhcpServerAvailableOnAllNics); }
bool State::HasNTFSDrive() const { LOG_FUNCTION(State::HasNTFSDrive);
return hasNTFSDrive; }
void State::RetrieveDriveInformation() { LOG_FUNCTION(State::RetrieveDriveInformation);
do { // Get a list of the valid drives
StringVector dl; HRESULT hr = FS::GetValidDrives(std::back_inserter(dl)); if (FAILED(hr)) { LOG(String::format(L"Failed to GetValidDrives: hr = %1!x!", hr)); break; }
// Loop through the list
ASSERT(dl.size()); for ( StringVector::iterator i = dl.begin(); i != dl.end(); ++i) { // look for the NTFS partition
FS::FSType fsType = FS::GetFileSystemType(*i); if (fsType == FS::NTFS5 || fsType == FS::NTFS4) { // found one. good to go
LOG(String::format(L"%1 is NTFS", i->c_str()));
hasNTFSDrive = true; break; } } } while (false);
LOG_BOOL(hasNTFSDrive);
return; }
/*
void State::SetRerunWizard(bool rerun) { LOG_FUNCTION2( State::SetRerunWizard, rerun ? L"true" : L"false");
rerunWizard = rerun; } */
bool State::SetHomeRegkey(const String& newKeyValue) { LOG_FUNCTION2( State::SetHomeRegkey, newKeyValue);
bool result = SetRegKeyValue( CYS_HOME_REGKEY, CYS_HOME_VALUE, newKeyValue, HKEY_LOCAL_MACHINE, true); ASSERT(result);
LOG_BOOL(result);
return result; }
bool State::GetHomeRegkey(String& keyValue) const { LOG_FUNCTION(State::GetHomeRegkey);
bool result = GetRegKeyValue( CYS_HOME_REGKEY, CYS_HOME_VALUE, keyValue);
LOG_BOOL(result);
return result; }
String State::GetComputerName() { LOG_FUNCTION(State::GetComputerName);
if (computerName.empty()) { computerName = Win::GetComputerNameEx(ComputerNameDnsHostname); }
LOG(computerName); return computerName; }
String State::GetDomainDNSName() { LOG_FUNCTION(State::GetDomainDNSName);
if (domainDNSName.empty()) { domainDNSName = localComputer.GetDomainDnsName(); }
LOG(domainDNSName); return domainDNSName; }
String State::GetDomainNetbiosName() { LOG_FUNCTION(State::GetDomainNetbiosName);
if (domainNetbiosName.empty()) { domainNetbiosName = localComputer.GetDomainNetbiosName(); }
LOG(domainNetbiosName); return domainNetbiosName; }
bool State::HasDNSServerOnAnyNicToForwardTo() { LOG_FUNCTION(State::HasDNSServerOnAnyNicToForwardTo);
// A valid DNS server is considered to be any DNS
// server defined on any NIC that does not point
// to itself for resolution. The reason I consider
// a DNS server that points to itself as invalid is
// because this routine is used to determine if the
// DNS server can be used as a forwarder. Since DNS
// servers cannot forward to themselves I consider
// this an invalid DNS server.
// Also consider the "next available" IP address to
// be invalid because chances are the "next available"
// IP address will be used as the static IP address
// of this server in the express path.
bool result = false;
DWORD nextAvailableAddress = GetNextAvailableIPAddress( CYS_DEFAULT_IPADDRESS, CYS_DEFAULT_SUBNETMASK);
for (unsigned int idx = 0; idx < GetNICCount(); ++idx) { IPAddressList dnsServers;
NetworkInterface* nic = GetNIC(idx);
if (!nic) { continue; }
nic->GetDNSServers(dnsServers);
if (dnsServers.empty()) { continue; }
// Only return true if there is a DNS server in the list
// and the IP address is not the local machine
DWORD ipaddress = nic->GetIPAddress(0);
for (IPAddressList::iterator itr = dnsServers.begin(); itr != dnsServers.end(); ++itr) { DWORD currentServer = *itr;
if (ipaddress != currentServer && ipaddress != nextAvailableAddress) { LOG(String::format( L"Found valid server: %1", IPAddressToString(currentServer).c_str()));
result = true; break; } }
if (result) { break; } }
LOG_BOOL(result); return result; }
void State::SetLocalNIC( String guid, bool setInRegistry) { LOG_FUNCTION2( State::SetLocalNIC, guid.c_str());
LOG_BOOL(setInRegistry); adapterConfiguration.SetLocalNIC(guid, setInRegistry); }
NetworkInterface* State::GetLocalNIC() { LOG_FUNCTION(State::GetLocalNIC);
return adapterConfiguration.GetLocalNIC(); }
bool State::IsRebootScenario() const { LOG_FUNCTION(State::IsRebootScenario);
LOG_BOOL(isRebootScenario); return isRebootScenario; }
void State::SetRebootScenario(bool reboot) { LOG_FUNCTION(State::SetRebootScenario); LOG_BOOL(reboot);
isRebootScenario = reboot; }
bool State::ShouldRunMYS() const { LOG_FUNCTION(State::ShouldRunMYS);
bool result = false;
do { // First check to be sure this is a supported SKU
if (!::IsSupportedSku()) { break; }
// Now check the startup flags
if (!::IsStartupFlagSet()) { break; }
// Check the policy setting
if (!::ShouldShowMYSAccordingToPolicy()) { // The policy is enabled so that means don't show MYS
break; }
// everything passed so we should run MYS
result = true; } while (false);
LOG_BOOL(result);
return result; }
DWORD State::GetNextAvailableIPAddress( DWORD startAddress, DWORD subnetMask) { LOG_FUNCTION2( State::GetNextAvailableIPAddress, IPAddressToString(startAddress));
DWORD result = startAddress; DWORD currentAddress = startAddress;
bool isIPInUse = false;
do { isIPInUse = false;
// Check to see if the IP address
// is in use on any NIC. If it is
// then increment and try all the NICs
// again.
for ( unsigned int index = 0; index < GetNICCount(); ++index) { NetworkInterface* nic = GetNIC(index);
if (nic) { bool isInUseOnThisNIC = nic->IsIPAddressInUse( currentAddress, subnetMask);
isIPInUse = isIPInUse || isInUseOnThisNIC; }
if (isIPInUse) { break; } }
if (isIPInUse) { ++currentAddress;
if ((currentAddress & subnetMask) != (startAddress & subnetMask)) { // REVIEW_JEFFJON : what should the behavior be if there are
// no available addresses? Is this likely to happen?
// Since we couldn't find an available address in this subnet
// use the start address
currentAddress = startAddress; break; } } } while (isIPInUse);
result = currentAddress;
LOG(IPAddressToString(result));
return result; }
|