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.
 
 
 
 
 
 

966 lines
25 KiB

// Copyright (c) 2001 Microsoft Corporation
//
// File: DNSInstallationUnit.cpp
//
// Synopsis: Defines a DNSInstallationUnit
// This object has the knowledge for installing the
// DNS service
//
// History: 02/05/2001 JeffJon Created
#include "pch.h"
#include "resource.h"
#include "DNSInstallationUnit.h"
#include "InstallationUnitProvider.h"
#include "NetworkInterface.h"
// Finish page help
static PCWSTR CYS_DNS_FINISH_PAGE_HELP = L"cys.chm::/dns_server_role.htm";
static PCWSTR CYS_DNS_MILESTONE_HELP = L"cys.chm::/dns_server_role.htm#dnssrvsummary";
static PCWSTR CYS_DNS_AFTER_FINISH_HELP = L"cys.chm::/dns_server_role.htm#dnssrvcompletion";
DNSInstallationUnit::DNSInstallationUnit() :
staticIPAddress(CYS_DEFAULT_IPADDRESS),
subnetMask(CYS_DEFAULT_SUBNETMASK),
forwarderIPAddress(0),
manualForwarder(false),
dnsRoleResult(DNS_SUCCESS),
installedDescriptionID(IDS_DNS_SERVER_DESCRIPTION_INSTALLED),
ExpressPathInstallationUnitBase(
IDS_DNS_SERVER_TYPE,
IDS_DNS_SERVER_DESCRIPTION,
IDS_DNS_FINISH_TITLE,
IDS_DNS_FINISH_UNINSTALL_TITLE,
IDS_DNS_FINISH_MESSAGE,
IDS_DNS_INSTALL_FAILED,
IDS_DNS_UNINSTALL_MESSAGE,
IDS_DNS_UNINSTALL_FAILED,
IDS_DNS_UNINSTALL_WARNING,
IDS_DNS_UNINSTALL_CHECKBOX,
CYS_DNS_FINISH_PAGE_HELP,
CYS_DNS_MILESTONE_HELP,
CYS_DNS_AFTER_FINISH_HELP,
DNS_SERVER)
{
LOG_CTOR(DNSInstallationUnit);
}
DNSInstallationUnit::~DNSInstallationUnit()
{
LOG_DTOR(DNSInstallationUnit);
}
InstallationReturnType
DNSInstallationUnit::InstallService(HANDLE logfileHandle, HWND hwnd)
{
LOG_FUNCTION(DNSInstallationUnit::InstallService);
InstallationReturnType result = INSTALL_SUCCESS;
if (IsExpressPathInstall())
{
result = ExpressPathInstall(logfileHandle, hwnd);
LOG_INSTALL_RETURN(result);
return result;
}
dnsRoleResult = DNS_SUCCESS;
// Log the DNS header
CYS_APPEND_LOG(String::load(IDS_LOG_DNS_HEADER));
UpdateInstallationProgressText(hwnd, IDS_DNS_INSTALL_PROGRESS);
// Create the inf and unattend files that are used by the
// Optional Component Manager
String infFileText;
String unattendFileText;
CreateInfFileText(infFileText, IDS_DNS_INF_WINDOW_TITLE);
CreateUnattendFileText(unattendFileText, CYS_DNS_SERVICE_NAME);
// Install the service through the Optional Component Manager
String additionalArgs = L"/z:netoc_show_unattended_messages";
// We are ignoring the ocmresult because it doesn't matter
// with respect to whether the role is installed or not
InstallServiceWithOcManager(
infFileText,
unattendFileText,
additionalArgs);
if (IsServiceInstalled())
{
// Log the successful installation
LOG(L"DNS was installed successfully");
CYS_APPEND_LOG(String::load(IDS_LOG_SERVER_START_DNS));
// Wait for the service to enter the running state
NTService serviceObject(CYS_DNS_SERVICE_NAME);
HRESULT hr = serviceObject.WaitForServiceState(SERVICE_RUNNING);
if (FAILED(hr))
{
// This is a config failure because as far as we are concerned the
// service was installed properly.
dnsRoleResult = DNS_SERVICE_START_FAILURE;
LOG(String::format(
L"The DNS service failed to start in a timely fashion: %1!x!",
hr));
CYS_APPEND_LOG(String::load(IDS_LOG_DNS_SERVICE_TIMEOUT));
result = INSTALL_FAILURE;
}
else
{
// Run the DNS Wizard
UpdateInstallationProgressText(hwnd, IDS_DNS_CONFIG_PROGRESS);
String resultText;
HRESULT unused = S_OK;
if (ExecuteWizard(hwnd, CYS_DNS_SERVICE_NAME, resultText, unused))
{
// Check to be sure the wizard finished completely
String configWizardResults;
if (ReadConfigWizardRegkeys(configWizardResults))
{
// The Configure DNS Server Wizard completed successfully
LOG(L"The Configure DNS Server Wizard completed successfully");
CYS_APPEND_LOG(String::load(IDS_LOG_DNS_COMPLETED_SUCCESSFULLY));
}
else
{
// The Configure DNS Server Wizard did not finish successfully
dnsRoleResult = DNS_CONFIG_FAILURE;
result = INSTALL_FAILURE;
if (!configWizardResults.empty())
{
// An error was returned via the regkey
LOG(String::format(
L"The Configure DNS Server Wizard returned the error: %1",
configWizardResults.c_str()));
String formatString = String::load(IDS_LOG_DNS_WIZARD_ERROR);
CYS_APPEND_LOG(String::format(formatString, configWizardResults.c_str()));
}
else
{
// The Configure DNS Server Wizard was cancelled by the user
LOG(L"The Configure DNS Server Wizard was cancelled by the user");
CYS_APPEND_LOG(String::load(IDS_LOG_DNS_WIZARD_CANCELLED));
}
}
}
else
{
dnsRoleResult = DNS_INSTALL_FAILURE;
// Show an error
LOG(L"DNS could not be installed.");
if (!resultText.empty())
{
CYS_APPEND_LOG(resultText);
}
}
}
}
else
{
dnsRoleResult = DNS_INSTALL_FAILURE;
// Log the failure
LOG(L"DNS failed to install");
CYS_APPEND_LOG(String::load(IDS_LOG_DNS_SERVER_FAILED));
result = INSTALL_FAILURE;
}
LOG_INSTALL_RETURN(result);
return result;
}
UnInstallReturnType
DNSInstallationUnit::UnInstallService(HANDLE logfileHandle, HWND hwnd)
{
LOG_FUNCTION(DNSInstallationUnit::UnInstallService);
UnInstallReturnType result = UNINSTALL_SUCCESS;
// Log the DNS header
CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_DNS_HEADER));
UpdateInstallationProgressText(hwnd, IDS_DNS_UNINSTALL_PROGRESS);
String infFileText;
String unattendFileText;
CreateInfFileText(infFileText, IDS_DNS_INF_WINDOW_TITLE);
CreateUnattendFileText(unattendFileText, CYS_DNS_SERVICE_NAME, false);
// NTRAID#NTBUG9-736557-2002/11/13-JeffJon
// Pass the /w switch to sysocmgr when uninstalling
// so that if a situation occurs in which a reboot
// is required, the user will be prompted.
String additionalArgs = L"/w";
// We are ignoring the ocmresult because it doesn't matter
// with respect to whether the role is installed or not
InstallServiceWithOcManager(
infFileText,
unattendFileText,
additionalArgs);
if (IsServiceInstalled())
{
CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_DNS_FAILED));
result = UNINSTALL_FAILURE;
}
else
{
CYS_APPEND_LOG(String::load(IDS_LOG_UNINSTALL_DNS_SUCCESS));
}
LOG_UNINSTALL_RETURN(result);
return result;
}
void
DNSInstallationUnit::SetForwardersForExpressPath()
{
LOG_FUNCTION(DNSInstallationUnit::SetForwardersForExpressPath);
// If the forwarders were set manually write them
// to the registry so that we can set
// a forwarder after the reboot
// Note: this will write a zero entry if the user
// chose not to forward. The code run after reboot
// needs to handle this properly
if (IsManualForwarder())
{
if (!SetRegKeyValue(
CYS_FIRST_DC_REGKEY,
CYS_FIRST_DC_FORWARDER,
forwarderIPAddress,
HKEY_LOCAL_MACHINE,
true))
{
LOG(L"Failed to set forwarder regkey");
}
}
else
{
// Write the current DNS servers as forwarders to the registry
// so that we don't have problems after the reboot
IPAddressList forwarders;
GetForwarders(forwarders);
if (forwarders.empty())
{
LOG(L"No DNS servers set on any NIC");
}
else
{
// Format the IP addresses into a string for storage
// in the registry
String ipList;
for (IPAddressList::iterator itr = forwarders.begin();
itr != forwarders.end();
++itr)
{
if (!ipList.empty())
{
ipList += L" ";
}
ipList += String::format(
L"%1",
IPAddressToString(*itr).c_str());
}
if (!SetRegKeyValue(
CYS_FIRST_DC_REGKEY,
CYS_FIRST_DC_AUTOFORWARDER,
ipList,
HKEY_LOCAL_MACHINE,
true))
{
LOG(L"We failed to set the forwarders regkey.");
}
}
}
}
InstallationReturnType
DNSInstallationUnit::ExpressPathInstall(HANDLE logfileHandle, HWND hwnd)
{
LOG_FUNCTION(DNSInstallationUnit::ExpressPathInstall);
InstallationReturnType result = INSTALL_SUCCESS;
do
{
String netshPath = GetNetshPath();
String commandLine;
HRESULT hr = S_OK;
UpdateInstallationProgressText(hwnd, IDS_DNS_CLIENT_CONFIG_PROGRESS);
// We ignore if the NIC is found or not because the function will return
// the first NIC if the correct NIC is not found. We can then use this
// to setup the network
NetworkInterface* nic = State::GetInstance().GetLocalNIC();
if (!nic)
{
LOG(L"Couldn't find the NIC so fail");
result = INSTALL_FAILURE;
CYS_APPEND_LOG(
String::load(IDS_EXPRESS_DNS_LOG_STATIC_IP_FAILED));
InstallationUnitProvider::GetInstance().
GetExpressInstallationUnit().SetExpressRoleResult(
ExpressInstallationUnit::EXPRESS_DNS_FAILURE);
break;
}
// set static IP address and subnet mask
String friendlyName =
nic->GetFriendlyName(
String::load(IDS_LOCAL_AREA_CONNECTION));
if (nic->IsDHCPEnabled() ||
nic->GetIPAddress(0) == 0)
{
// invoke netsh and wait for it to terminate
String availableIPAddress = IPAddressToString(
nic->GetNextAvailableIPAddress(
CYS_DEFAULT_IPADDRESS,
CYS_DEFAULT_SUBNETMASK));
commandLine =
String::format(
L"interface ip set address "
L"name=\"%1\" source=static addr=%2 mask=%3 gateway=none",
friendlyName.c_str(),
availableIPAddress.c_str(),
CYS_DEFAULT_SUBNETMASK_STRING);
DWORD exitCode1 = 0;
hr = ::CreateAndWaitForProcess(
netshPath,
commandLine,
exitCode1,
true);
if (FAILED(hr) || exitCode1)
{
LOG(String::format(
L"Failed to set the static IP address and subnet mask: exitCode = %1!x!",
exitCode1));
result = INSTALL_FAILURE;
CYS_APPEND_LOG(
String::load(IDS_EXPRESS_DNS_LOG_STATIC_IP_FAILED));
InstallationUnitProvider::GetInstance().
GetExpressInstallationUnit().SetExpressRoleResult(
ExpressInstallationUnit::EXPRESS_DNS_FAILURE);
break;
}
ASSERT(SUCCEEDED(hr));
// NTRAID#NTBUG9-638337-2002/06/13-JeffJon
// Now that the IP address was set, write it to a regkey so
// that we can compare it to the IP address on reboot and
// give a failure if they are different.
if (!SetRegKeyValue(
CYS_FIRST_DC_REGKEY,
CYS_FIRST_DC_STATIC_IP,
availableIPAddress,
HKEY_LOCAL_MACHINE,
true))
{
LOG(L"Failed to set the static IP regkey");
}
CYS_APPEND_LOG(
String::format(
IDS_EXPRESS_IPADDRESS_SUCCESS,
availableIPAddress.c_str()));
CYS_APPEND_LOG(
String::format(
IDS_EXPRESS_SUBNETMASK_SUCCESS,
CYS_DEFAULT_SUBNETMASK_STRING));
// Set the IP address and subnet mask on the NetworkInterface object
nic->SetIPAddress(
StringToIPAddress(availableIPAddress),
availableIPAddress);
nic->SetSubnetMask(
CYS_DEFAULT_SUBNETMASK,
CYS_DEFAULT_SUBNETMASK_STRING);
}
// NTRAID#NTBUG9-664171-2002/07/15-JeffJon
// The forwarders must be read and set after setting the static
// IP address or else we may be adding multiple entries for
// the new static IP address in the forwarders list
SetForwardersForExpressPath();
// set DNS server address to same address as the private NIC of
// local machine for all NICs. In most cases this will be 192.168.0.1
// netsh does not allow the dns server address to be the loopback address.
for (unsigned int nicIndex = 0;
nicIndex < State::GetInstance().GetNICCount();
++nicIndex)
{
NetworkInterface* currentNIC = State::GetInstance().GetNIC(nicIndex);
if (!currentNIC)
{
continue;
}
// First check to be sure the IP address isn't already in the list
bool okToAddDNSServer = true;
IPAddressList dnsServers;
currentNIC->GetDNSServers(dnsServers);
for (IPAddressList::iterator itr = dnsServers.begin();
itr != dnsServers.end();
++itr)
{
if (itr &&
*itr == nic->GetIPAddress(0))
{
okToAddDNSServer = false;
break;
}
}
// Add the IP address to the DNS servers since it
// isn't already in the list
if (okToAddDNSServer)
{
String currentFriendlyName =
currentNIC->GetFriendlyName(
String::load(IDS_LOCAL_AREA_CONNECTION));
commandLine =
String::format(
L"interface ip set dns name=\"%1\" source=static addr=%2",
currentFriendlyName.c_str(),
nic->GetStringIPAddress(0).c_str());
DWORD exitCode2 = 0;
hr = ::CreateAndWaitForProcess(
netshPath,
commandLine,
exitCode2,
true);
if (FAILED(hr) || exitCode2)
{
LOG(String::format(
L"Failed to set the preferred DNS server IP address: exitCode = %1!x!",
exitCode2));
// This should really only be considered a failure for the "local" NIC
if (currentFriendlyName.icompare(friendlyName) == 0)
{
result = INSTALL_FAILURE;
InstallationUnitProvider::GetInstance().
GetExpressInstallationUnit().SetExpressRoleResult(
ExpressInstallationUnit::EXPRESS_DNS_FAILURE);
break;
}
}
}
}
if (result != INSTALL_FAILURE)
{
CYS_APPEND_LOG(
String::format(
IDS_EXPRESS_DNSSERVER_SUCCESS,
nic->GetStringIPAddress(0).c_str()));
}
} while (false);
LOG_INSTALL_RETURN(result);
return result;
}
bool
DNSInstallationUnit::ReadConfigWizardRegkeys(String& configWizardResults) const
{
LOG_FUNCTION(DNSInstallationUnit::ReadConfigWizardRegkeys);
bool result = false;
do
{
DWORD value = 0;
result = GetRegKeyValue(
DNS_WIZARD_CONFIG_REGKEY,
DNS_WIZARD_CONFIG_VALUE,
value);
if (result &&
value != 0)
{
// The Configure DNS Server Wizard succeeded
result = true;
break;
}
// Since there was a failure (or the wizard was cancelled)
// get the display string to log
GetRegKeyValue(
DNS_WIZARD_RESULT_REGKEY,
DNS_WIZARD_RESULT_VALUE,
configWizardResults);
} while (false);
LOG_BOOL(result);
return result;
}
bool
DNSInstallationUnit::GetMilestoneText(String& message)
{
LOG_FUNCTION(DNSInstallationUnit::GetMilestoneText);
message = String::load(IDS_DNS_FINISH_TEXT);
LOG_BOOL(true);
return true;
}
bool
DNSInstallationUnit::GetUninstallMilestoneText(String& message)
{
LOG_FUNCTION(DNSInstallationUnit::GetUninstallMilestoneText);
message = String::load(IDS_DNS_UNINSTALL_TEXT);
LOG_BOOL(true);
return true;
}
String
DNSInstallationUnit::GetUninstallWarningText()
{
LOG_FUNCTION(DNSInstallationUnit::GetUninstallWarningText);
unsigned int messageID = uninstallMilestoneWarningID;
if (State::GetInstance().IsDC())
{
messageID = IDS_DNS_UNINSTALL_WARNING_ISDC;
}
return String::load(messageID);
}
void
DNSInstallationUnit::SetStaticIPAddress(DWORD ipaddress)
{
LOG_FUNCTION2(
DNSInstallationUnit::SetStaticIPAddress,
IPAddressToString(ipaddress).c_str());
staticIPAddress = ipaddress;
}
void
DNSInstallationUnit::SetSubnetMask(DWORD mask)
{
LOG_FUNCTION2(
DNSInstallationUnit::SetSubnetMask,
IPAddressToString(mask).c_str());
subnetMask = mask;
}
String
DNSInstallationUnit::GetStaticIPAddressString()
{
LOG_FUNCTION(DNSInstallationUnit::GetStaticIPAddressString);
String result = IPAddressToString(GetStaticIPAddress());
LOG(result);
return result;
}
String
DNSInstallationUnit::GetSubnetMaskString()
{
LOG_FUNCTION(DNSInstallationUnit::GetSubnetMaskString);
String result = IPAddressToString(GetSubnetMask());
LOG(result);
return result;
}
DWORD
DNSInstallationUnit::GetStaticIPAddress()
{
LOG_FUNCTION(DNSInstallationUnit::GetStaticIPAddress);
// Get the IP address from the NIC only if it
// is a static IP address else use the default
NetworkInterface* nic = State::GetInstance().GetNIC(0);
if (nic &&
!nic->IsDHCPEnabled())
{
staticIPAddress = nic->GetIPAddress(0);
}
return staticIPAddress;
}
DWORD
DNSInstallationUnit::GetSubnetMask()
{
LOG_FUNCTION(DNSInstallationUnit::GetSubnetMask);
// Get the subnet mask from the NIC only if it
// is a static IP address else use the default
NetworkInterface* nic = State::GetInstance().GetNIC(0);
if (nic &&
!nic->IsDHCPEnabled())
{
subnetMask = nic->GetSubnetMask(0);
}
return subnetMask;
}
void
DNSInstallationUnit::SetForwarder(DWORD forwarderAddress)
{
LOG_FUNCTION2(
DNSInstallationUnit::SetForwarder,
String::format(L"%1!x!", forwarderAddress));
forwarderIPAddress = forwarderAddress;
manualForwarder = true;
}
void
DNSInstallationUnit::GetForwarders(IPAddressList& forwarders) const
{
LOG_FUNCTION(DNSInstallationUnit::GetForwarders);
// clear out the list to start
forwarders.clear();
if (IsManualForwarder() &&
forwarderIPAddress != 0)
{
DWORD forwarderInDisplayOrder = ConvertIPAddressOrder(forwarderIPAddress);
LOG(
String::format(
L"Adding manual forwarder to list: %1",
IPAddressToString(forwarderInDisplayOrder).c_str()));
// Forwarder was assigned through the UI
forwarders.push_back(forwarderIPAddress);
}
else if (IsManualForwarder() &&
forwarderIPAddress == 0)
{
// The user chose not to forward
LOG(L"User chose not to foward");
// Do nothing. Need to check the list returned
// to make sure there is a valid address
}
else
{
LOG(L"No user defined forwarder. Trying to detect through NICs");
// No forwarder assigned through the UI so
// search the NICs
for (unsigned int idx = 0; idx < State::GetInstance().GetNICCount(); ++idx)
{
NetworkInterface* nic = State::GetInstance().GetNIC(idx);
// Add the DNS servers from this NIC
if (nic)
{
nic->GetDNSServers(forwarders);
}
}
// Make sure there are no forwarders that are the same as
// the IP addresses of any of the NICs
for (unsigned int idx = 0; idx < State::GetInstance().GetNICCount(); ++idx)
{
NetworkInterface* nic = State::GetInstance().GetNIC(idx);
if (!nic)
{
continue;
}
for (DWORD ipidx = 0; ipidx < nic->GetIPAddressCount(); ++ipidx)
{
DWORD ipaddress = nic->GetIPAddress(ipidx);
for (IPAddressList::iterator itr = forwarders.begin();
itr != forwarders.end();
++itr)
{
if (ipaddress == *itr)
{
// The forwarder matches a local IP address
// so remove it
LOG(String::format(
L"Can't put the local IP address in the forwarders list: %1",
IPAddressToString(*itr).c_str()));
forwarders.erase(itr);
break;
}
}
if (forwarders.empty())
{
// It's possible that we removed the last forwarder
// so break out if we did
break;
}
}
if (forwarders.empty())
{
// It's possible that we removed the last forwarder
// so break out if we did
break;
}
}
}
}
bool
DNSInstallationUnit::IsManualForwarder() const
{
LOG_FUNCTION(DNSInstallationUnit::IsManualForwarder);
LOG_BOOL(manualForwarder);
return manualForwarder;
}
String
DNSInstallationUnit::GetServiceDescription()
{
LOG_FUNCTION(DNSInstallationUnit::GetServiceDescription);
String result;
unsigned int resultID = descriptionID;
if (GetStatus() == STATUS_COMPLETED)
{
resultID = installedDescriptionID;
}
result = String::load(resultID);
ASSERT(!result.empty());
return result;
}
void
DNSInstallationUnit::ServerRoleLinkSelected(int linkIndex, HWND /*hwnd*/)
{
LOG_FUNCTION2(
DNSInstallationUnit::ServerRoleLinkSelected,
String::format(
L"linkIndex = %1!d!",
linkIndex));
if (IsServiceInstalled())
{
ASSERT(linkIndex == 0);
LaunchMYS();
}
else
{
ASSERT(linkIndex == 0);
LOG(L"Showing configuration help");
ShowHelp(CYS_DNS_FINISH_PAGE_HELP);
}
}
void
DNSInstallationUnit::FinishLinkSelected(int linkIndex, HWND /*hwnd*/)
{
LOG_FUNCTION2(
DNSInstallationUnit::FinishLinkSelected,
String::format(
L"linkIndex = %1!d!",
linkIndex));
if (installing)
{
if (linkIndex == 0 &&
IsServiceInstalled())
{
if (dnsRoleResult == DNS_SUCCESS)
{
LOG("Showing after checklist");
ShowHelp(CYS_DNS_AFTER_FINISH_HELP);
}
else if (dnsRoleResult == DNS_SERVICE_START_FAILURE)
{
LOG(L"Launching Services console");
LaunchMMCConsole(L"services.msc");
}
else
{
LOG(L"Launching DNS snapin");
LaunchMMCConsole(L"dnsmgmt.msc");
}
}
else
{
LOG(L"Showing configuration help");
ShowHelp(CYS_DNS_FINISH_PAGE_HELP);
}
}
}
String
DNSInstallationUnit::GetFinishText()
{
LOG_FUNCTION(DNSInstallationUnit::GetFinishText);
unsigned int messageID = finishMessageID;
if (installing)
{
InstallationReturnType result = GetInstallResult();
if (result != INSTALL_SUCCESS &&
result != INSTALL_SUCCESS_REBOOT &&
result != INSTALL_SUCCESS_PROMPT_REBOOT)
{
if (dnsRoleResult == DNS_INSTALL_FAILURE)
{
messageID = finishInstallFailedMessageID;
}
else if (dnsRoleResult == DNS_SERVICE_START_FAILURE)
{
messageID = IDS_DNS_SERVICE_START_FAILED;
}
else
{
messageID = IDS_DNS_CONFIG_FAILED;
}
}
}
else
{
messageID = finishUninstallMessageID;
UnInstallReturnType result = GetUnInstallResult();
if (result != UNINSTALL_SUCCESS &&
result != UNINSTALL_SUCCESS_REBOOT &&
result != UNINSTALL_SUCCESS_PROMPT_REBOOT)
{
messageID = finishUninstallFailedMessageID;
}
}
return String::load(messageID);
}