windows-nt/Source/XPSP1/NT/admin/cys/win32/adinstallationunit.cpp
2020-09-26 16:20:57 +08:00

371 lines
9.4 KiB
C++

// Copyright (c) 1997-2001 Microsoft Corporation
//
// File: ADInstallationUnit.cpp
//
// Synopsis: Defines a ADInstallationUnit
// This object has the knowledge for installing
// Active Directory
//
// History: 02/08/2001 JeffJon Created
#include "pch.h"
#include "resource.h"
#include "InstallationUnitProvider.h"
#include "state.h"
#define CYS_DCPROMO_COMMAND_LINE L"dcpromo.exe"
// Exit codes borrowed from DCPromo.cpp
enum DCPromoExitCodes
{
// the operation failed.
EXIT_CODE_UNSUCCESSFUL = 0,
// the operation succeeded
EXIT_CODE_SUCCESSFUL = 1,
// the operation succeeded, and the user opted not to have the wizard
// restart the machine, either manually or by specifying
// RebootOnSuccess=NoAndNoPromptEither in the answerfile
EXIT_CODE_SUCCESSFUL_NO_REBOOT = 2,
// the operation failed, but the machine needs to be rebooted anyway
EXIT_CODE_UNSUCCESSFUL_NEEDS_REBOOT = 3
};
// Finish page help
static PCWSTR CYS_AD_FINISH_PAGE_HELP = L"cys.chm::/cys_configuring_domain_controller.htm";
ADInstallationUnit::ADInstallationUnit() :
isExpressPathInstall(false),
InstallationUnit(
IDS_DOMAIN_CONTROLLER_TYPE,
IDS_DOMAIN_CONTROLLER_DESCRIPTION,
CYS_AD_FINISH_PAGE_HELP,
DC_INSTALL)
{
LOG_CTOR(ADInstallationUnit);
}
ADInstallationUnit::~ADInstallationUnit()
{
LOG_DTOR(ADInstallationUnit);
}
InstallationReturnType
ADInstallationUnit::InstallService(HANDLE logfileHandle, HWND hwnd)
{
LOG_FUNCTION(ADInstallationUnit::InstallService);
InstallationReturnType result = INSTALL_SUCCESS_REBOOT;
do
{
// Set the rerun state to false since DCPromo requires a reboot
State::GetInstance().SetRerunWizard(false);
if (IsExpressPathInstall())
{
result = InstallServiceExpressPath(logfileHandle, hwnd);
break;
}
// Set the home regkey so that we go through post boot operations
bool regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
CYS_HOME_VALUE,
CYS_HOME_REGKEY_DCPROMO_VALUE,
HKEY_LOCAL_MACHINE,
true);
ASSERT(regkeyResult);
// Run dcpromo.exe
String commandline(CYS_DCPROMO_COMMAND_LINE);
DWORD exitCode = 0;
HRESULT hr = CreateAndWaitForProcess(commandline, exitCode);
if (FAILED(hr) ||
exitCode == EXIT_CODE_UNSUCCESSFUL ||
exitCode == EXIT_CODE_UNSUCCESSFUL_NEEDS_REBOOT)
{
CYS_APPEND_LOG(String::load(IDS_LOG_DOMAIN_CONTROLLER_HEADING));
CYS_APPEND_LOG(String::load(IDS_LOG_DOMAIN_CONTROLLER_INSTALL));
CYS_APPEND_LOG(String::load(IDS_LOG_WIZARD_CANCELLED));
result = INSTALL_FAILURE;
break;
}
} while (false);
LOG_INSTALL_RETURN(result);
return result;
}
InstallationReturnType
ADInstallationUnit::InstallServiceExpressPath(HANDLE /*logfileHandle*/, HWND /*hwnd*/)
{
LOG_FUNCTION(ADInstallationUnit::InstallServiceExpressPath);
InstallationReturnType result = INSTALL_SUCCESS_REBOOT;
// All these regkeys need to be set before we launch DCPromo because DCPromo
// will reboot the machine
// First set the home regkey to FirstServer so that we finish up the installation
// after reboot
bool regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
CYS_HOME_VALUE,
CYS_HOME_REGKEY_FIRST_SERVER_VALUE,
HKEY_LOCAL_MACHINE,
true);
ASSERT(regkeyResult);
// Set the the first DC regkey
regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
CYS_FIRST_DC_VALUE,
CYS_FIRST_DC_VALUE_SET,
HKEY_LOCAL_MACHINE,
true);
ASSERT(regkeyResult);
// Set the key so CYS runs again
String emptyString;
regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
emptyString,
CYS_HOME_RUN_KEY_RUN_AGAIN,
HKEY_CURRENT_USER,
true);
ASSERT(regkeyResult);
// set the key so CYS has to run again
regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
CYS_HOME_REGKEY_MUST_RUN,
CYS_HOME_RUN_KEY_RUN_AGAIN,
HKEY_LOCAL_MACHINE,
true);
ASSERT(regkeyResult);
// set the key to let the reboot know what the domain DNS name is
regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
CYS_HOME_REGKEY_DOMAINDNS,
GetNewDomainDNSName(),
HKEY_LOCAL_MACHINE,
true);
ASSERT(regkeyResult);
// set the key to let the reboot know what the IP address is
regkeyResult = SetRegKeyValue(
CYS_HOME_REGKEY,
CYS_HOME_REGKEY_DOMAINIP,
InstallationUnitProvider::GetInstance().GetDNSInstallationUnit().GetStaticIPAddressString(),
HKEY_LOCAL_MACHINE,
true);
ASSERT(regkeyResult);
do
{
// Create answer file for DCPromo
String answerFilePath;
bool answerFileResult = CreateAnswerFileForDCPromo(answerFilePath);
if (!answerFileResult)
{
ASSERT(answerFileResult);
result = INSTALL_FAILURE;
break;
}
String commandline = String::format(
L"dcpromo /answer:%1",
answerFilePath.c_str());
DWORD exitCode = 0;
HRESULT hr = CreateAndWaitForProcess(commandline, exitCode);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to launch DCPromo: hr = %1!x!",
hr));
result = INSTALL_FAILURE;
break;
}
// We can't do anything else here because DCPromo will reboot
} while (false);
LOG_INSTALL_RETURN(result);
return result;
}
bool
ADInstallationUnit::CreateAnswerFileForDCPromo(String& answerFilePath)
{
LOG_FUNCTION(ADInstallationUnit::CreateAnswerFileForDCPromo);
bool result = true;
String answerFileText = L"[DCInstall]\r\n";
answerFileText += L"ReplicaOrNewDomain=Domain\r\n";
answerFileText += L"TreeOrChild=Tree\r\n";
answerFileText += L"CreateOrJoin=Create\r\n";
answerFileText += L"DomainNetbiosName=";
answerFileText += GetNewDomainNetbiosName();
answerFileText += L"\r\n";
answerFileText += L"NewDomainDNSName=";
answerFileText += GetNewDomainDNSName();
answerFileText += L"\r\n";
answerFileText += L"DNSOnNetwork=No\r\n";
answerFileText += L"DatabasePath=%systemroot%\\tds\r\n";
answerFileText += L"LogPath=%systemroot%\\tds\r\n";
answerFileText += L"SYSVOLPath=%systemroot%\\sysvol\r\n";
answerFileText += L"SiteName=Default-First-Site\r\n";
answerFileText += L"RebootOnSuccess=Yes\r\n";
answerFileText += L"AutoConfigDNS=Yes\r\n";
answerFileText += L"AllowAnonymousAccess=Yes\r\n";
answerFileText += L"SafeModeAdminPassword=";
answerFileText += GetSafeModeAdminPassword();
answerFileText += L"\r\n";
String sysFolder = Win::GetSystemDirectory();
answerFilePath = sysFolder + L"\\dcpromo.inf";
// create the answer file for DCPromo
LOG(String::format(
L"Creating answer file at: %1",
answerFilePath.c_str()));
HRESULT hr = CreateTempFile(answerFilePath, answerFileText);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to create answer file for DCPromo: hr = %1!x!",
hr));
result = false;
}
LOG_BOOL(result);
return result;
}
bool
ADInstallationUnit::IsServiceInstalled()
{
LOG_FUNCTION(ADInstallationUnit::IsServiceInstalled);
bool result = State::GetInstance().IsDC();
LOG_BOOL(result);
return result;
}
String
ADInstallationUnit::GetServiceDescription()
{
LOG_FUNCTION(ADInstallationUnit::GetServiceDescription);
unsigned int resourceID = static_cast<unsigned int>(-1);
if (IsServiceInstalled())
{
resourceID = IDS_DOMAIN_CONTROLLER_DESCRIPTION_INSTALLED;
}
else
{
resourceID = descriptionID;
}
ASSERT(resourceID != static_cast<unsigned int>(-1));
return String::load(resourceID);
}
bool
ADInstallationUnit::GetFinishText(String& message)
{
LOG_FUNCTION(ADInstallationUnit::GetFinishText);
message = String::load(IDS_DC_FINISH_TEXT);
LOG_BOOL(true);
return true;
}
void
ADInstallationUnit::SetExpressPathInstall(bool isExpressPath)
{
LOG_FUNCTION2(
ADInstallationUnit::SetExpressPathInstall,
(isExpressPath) ? L"true" : L"false");
isExpressPathInstall = isExpressPath;
}
bool
ADInstallationUnit::IsExpressPathInstall() const
{
LOG_FUNCTION(ADInstallationUnit::IsExpressPathInstall);
return isExpressPathInstall;
}
void
ADInstallationUnit::SetNewDomainDNSName(const String& newDomain)
{
LOG_FUNCTION2(
ADInstallationUnit::SetNewDomainDNSName,
newDomain);
domain = newDomain;
}
void
ADInstallationUnit::SetNewDomainNetbiosName(const String& newNetbios)
{
LOG_FUNCTION2(
ADInstallationUnit::SetNewDomainNetbiosName,
newNetbios);
netbios = newNetbios;
}
void
ADInstallationUnit::SetSafeModeAdminPassword(const String& newPassword)
{
LOG_FUNCTION(ADInstallationUnit::SetSafeModeAdminPassword);
password = newPassword;
}