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.
 
 
 
 
 
 

935 lines
19 KiB

// 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;
}