windows-nt/Source/XPSP1/NT/admin/dcpromo/exe/state.cpp

1779 lines
31 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// Copyright (C) 1997 Microsoft Corporation
//
// wizard state object
//
// 12-15-97 sburns
#include "headers.hxx"
#include "state.hpp"
#include "resource.h"
#include "ds.hpp"
#include "common.hpp"
static const String SECTION_NAME(L"DCInstall");
const String State::OPTION_NEW_DOMAIN_NAME(L"NewDomainDNSName");
const String State::OPTION_SITE_NAME(L"SiteName");
const String State::OPTION_PARENT_DOMAIN_NAME(L"ParentDomainDNSName");
const String State::OPTION_CHILD_NAME(L"ChildName");
const String State::OPTION_DNS_ON_NET(L"DNSOnNetwork");
const String State::OPTION_REPLICA_OR_NEW_DOMAIN(L"ReplicaOrNewDomain");
const String State::VALUE_DOMAIN(L"Domain");
const String State::OPTION_REPLICA_OR_MEMBER(L"ReplicaOrMember");
const String State::VALUE_REPLICA(L"Replica");
const String State::OPTION_NEW_DOMAIN(L"NewDomain");
const String State::VALUE_CHILD(L"Child");
const String State::VALUE_TREE(L"Tree");
const String State::OPTION_NEW_DOMAIN_NETBIOS_NAME(L"DomainNetbiosName");
const String State::OPTION_DATABASE_PATH(L"DatabasePath");
const String State::OPTION_LOG_PATH(L"LogPath");
const String State::OPTION_SYSVOL_PATH(L"SYSVOLPath");
const String State::OPTION_REPLICA_DOMAIN_NAME(L"ReplicaDomainDNSName");
const String State::OPTION_IS_LAST_DC(L"IsLastDCInDomain");
const String State::VALUE_YES(L"Yes");
const String State::VALUE_NO(L"No");
const String State::OPTION_ADMIN_PASSWORD(L"AdministratorPassword");
const String State::OPTION_REBOOT(L"RebootOnSuccess");
const String State::VALUE_NO_DONT_PROMPT(L"NoAndNoPromptEither");
const String State::OPTION_USERNAME(L"UserName");
const String State::OPTION_PASSWORD(L"Password");
const String State::OPTION_USER_DOMAIN(L"UserDomain");
const String State::OPTION_AUTO_CONFIG_DNS(L"AutoConfigDNS");
const String State::OPTION_ALLOW_ANON_ACCESS(L"AllowAnonymousAccess");
const String State::OPTION_REPLICATION_SOURCE(L"ReplicationSourceDC");
const String State::OPTION_SAFE_MODE_ADMIN_PASSWORD(L"SafeModeAdminPassword");
const String State::OPTION_CRITICAL_REPLICATION_ONLY(L"CriticalReplicationOnly");
const String State::OPTION_SOURCE_PATH(L"ReplicationSourcePath");
const String State::OPTION_SYSKEY(L"Syskey");
const String State::OPTION_GC_CONFIRM(L"ConfirmGc");
const String State::OPTION_SET_FOREST_VERSION("SetForestVersion");
static State* stateInstance;
void
State::Init()
{
ASSERT(!stateInstance);
stateInstance = new State;
}
void
State::Destroy()
{
delete stateInstance;
};
State&
State::GetInstance()
{
ASSERT(stateInstance);
return *stateInstance;
}
// Determines the full file path of the folder where administration (incl. DS)
// tools shortcuts are placed. On success, returns S_OK and sets result to
// the path. On failure, returns a COM error and sets results to empty.
//
// result - receives the folder path on success.
HRESULT
GetAdminToolsPath(String& result)
{
LOG_FUNCTION(GetAdminToolsPath);
result.erase();
TCHAR buf[MAX_PATH];
HRESULT hr =
::SHGetFolderPath(
0,
CSIDL_COMMON_ADMINTOOLS,
0,
SHGFP_TYPE_CURRENT,
buf);
if (SUCCEEDED(hr))
{
result = buf;
}
return hr;
}
State::State()
:
adminPassword(),
allowAnonAccess(false),
answerFile(0),
autoConfigDns(false),
computer(),
context(),
dbPath(),
domainsInForest(),
failureMessage(),
finishMessages(),
installedSite(),
isAdvancedMode(false),
isBackupGc(false),
isDnsOnNet(true),
isLastDc(false),
isUpgrade(false),
logPath(),
needsCommandLineHelp(false),
needsReboot(false),
newDomainDnsName(),
newDomainFlatName(),
operation(NONE),
operationResultsMessage(),
operationResultsStatus(FAILURE),
operationResultsFlags(0),
parentDomainDnsName(),
password(),
reinstallDomain(false),
reinstallDomainController(false),
replicaDnsDomainName(),
replicateFromMedia(false),
replicationPartnerDc(),
restoreGc(false),
runHiddenWhileUnattended(true),
safeModeAdminPassword(),
setForestVersion(false),
shortcutPath(),
siteName(),
splash(0),
sourcePath(),
sysvolPath(),
syskey(),
syskeyLocation(STORED),
useCurrentCredentials(false),
userDomain(),
userForest(),
username()
{
LOG_CTOR(State);
ArgMap args;
MapCommandLineArgs(args);
if (args.size() < 2)
{
LOG(L"no options specified");
}
else
{
// check for answerfile specification
static const wchar_t* ANSWER1 = L"answer";
static const wchar_t* ANSWER2 = L"u";
static const wchar_t* ANSWER3 = L"upgrade";
if (
args.find(ANSWER1) != args.end()
|| args.find(ANSWER2) != args.end()
|| args.find(ANSWER3) != args.end() )
{
bool isDefaultAnswerfile = false;
String filename = args[ANSWER1];
if (filename.empty())
{
filename = args[ANSWER2];
}
if (filename.empty())
{
filename = args[ANSWER3];
}
if (filename.empty())
{
// default value if none specified
filename = L"%systemdrive%\\dcpromo-ntupg.inf";
// if this file does not exist, don't pop up an error message.
isDefaultAnswerfile = true;
}
SetupAnswerFile(filename, isDefaultAnswerfile);
args.erase(ANSWER1);
args.erase(ANSWER2);
args.erase(ANSWER3);
}
// check for /adv
static const wchar_t* ADV = L"adv";
if (args.find(ADV) != args.end())
{
LOG(L"Enabling advanced mode");
isAdvancedMode = true;
args.erase(ADV);
}
// anything left over gets you command line help, (one arg will always
// remain: the name of the exe)
if (args.size() > 1)
{
LOG(L"Unrecognized command line options specified");
needsCommandLineHelp = true;
}
}
HRESULT hr = computer.Refresh();
// we're confident this will work, as the computer refers to the
// local machine.
ASSERT(SUCCEEDED(hr));
LOG_HRESULT(hr);
DetermineRunContext();
// Disable locking of the console as early as possible to narrow the
// window of opportunity for the user (or the system) to lock the
// console before a valid machine security state is reached. We do this
// early only for upgrades, because upgrades autologon and autostart
// dcpromo, and the console may sit idle for some time. 311161
if (context == PDC_UPGRADE || context == BDC_UPGRADE)
{
DisableConsoleLocking();
}
// We must call this at startup, because once a demote operation is
// complete, it may not be possible for the shell to determine this
// path. 366738
hr = GetAdminToolsPath(shortcutPath);
ASSERT(SUCCEEDED(hr));
LOG_HRESULT(hr);
}
void
State::SetupAnswerFile(const String& filename, bool isDefaultAnswerfile)
{
LOG_FUNCTION2(State::SetupAnswerFile, filename);
String f(filename);
if (f.find(L"\\") == String::npos)
{
// GetPrivateProfileString requires a path: use the current directory
// as a default path.
f = L".\\" + filename;
}
LOG(L"answerfile specified: " + f);
f = Win::ExpandEnvironmentStrings(f);
LOG(L"answerfile resolved to: " + f);
// we don't use FS::PathExist here because that function expects a
// fully-qualified path. The path we have may be relative.
DWORD unused = 0;
HRESULT hr = Win::GetFileAttributes(f, unused);
if (SUCCEEDED(hr))
{
// file found.
LOG(L"answerfile found");
answerFile = new AnswerFile(f);
splash = new UnattendSplashDialog();
splash->ModelessExecute(Win::GetDesktopWindow());
}
else
{
LOG(L"answerfile NOT found");
if (!isDefaultAnswerfile)
{
popup.Error(
Win::GetDesktopWindow(),
String::format(IDS_ANSWERFILE_NOT_FOUND, f.c_str()));
}
}
}
#ifdef LOGGING_BUILD
static const String CONTEXTS[] =
{
L"NT5_DC",
L"NT5_STANDALONE_SERVER",
L"NT5_MEMBER_SERVER",
L"BDC_UPGRADE",
L"PDC_UPGRADE"
};
#endif
void
State::DetermineRunContext()
{
LOG_FUNCTION(State::DetermineRunContext);
DS::PriorServerRole priorRole = DS::GetPriorServerRole(isUpgrade);
if (isUpgrade && priorRole != DS::UNKNOWN)
{
switch (priorRole)
{
case DS::PDC:
{
context = PDC_UPGRADE;
break;
}
case DS::BDC:
{
context = BDC_UPGRADE;
break;
}
default:
{
ASSERT(false);
break;
}
}
}
else
{
switch (computer.GetRole())
{
case Computer::STANDALONE_SERVER:
{
context = NT5_STANDALONE_SERVER;
break;
}
case Computer::MEMBER_SERVER:
{
context = NT5_MEMBER_SERVER;
break;
}
case Computer::PRIMARY_CONTROLLER:
case Computer::BACKUP_CONTROLLER:
{
// we're already an NT5 DC
context = NT5_DC;
break;
}
case Computer::STANDALONE_WORKSTATION:
case Computer::MEMBER_WORKSTATION:
default:
{
// we checked for this at startup
ASSERT(false);
break;
}
}
}
LOG(CONTEXTS[context]);
}
State::~State()
{
LOG_DTOR(State);
delete answerFile;
// closes the splash dialog, if visible.
delete splash;
}
State::RunContext
State::GetRunContext() const
{
LOG_FUNCTION2(State::GetRunContext, CONTEXTS[context]);
return context;
}
bool
State::UsingAnswerFile() const
{
return answerFile != 0;
}
bool
IsPasswordOption(const String& option)
{
if (
option.icompare(State::OPTION_PASSWORD) == 0
|| option.icompare(State::OPTION_ADMIN_PASSWORD) == 0
|| option.icompare(State::OPTION_SYSKEY) == 0
|| option.icompare(State::OPTION_SAFE_MODE_ADMIN_PASSWORD) == 0) // 142313
{
return true;
}
return false;
}
String
State::GetAnswerFileOption(const String& option) const
{
LOG_FUNCTION2(GetAnswerFileOption, option);
ASSERT(UsingAnswerFile());
String result;
if (answerFile)
{
result = answerFile->ReadKey(SECTION_NAME, option);
// wipe out passwords as they are read.
if (IsPasswordOption(option))
{
// caller should be using GetEncodedAnswerFileOption
ASSERT(false);
if (answerFile->IsKeyPresent(SECTION_NAME, option))
{
answerFile->WriteKey(SECTION_NAME, option, String());
}
}
else
{
// only trace non-password fields.
LOG(result);
}
}
return result;
}
EncodedString
State::GetEncodedAnswerFileOption(const String& option) const
{
LOG_FUNCTION2(GetEncodedAnswerFileOption, option);
ASSERT(UsingAnswerFile());
EncodedString result;
if (answerFile)
{
result = answerFile->EncodedReadKey(SECTION_NAME, option);
// wipe out passwords as they are read.
if (IsPasswordOption(option))
{
if (answerFile->IsKeyPresent(SECTION_NAME, option))
{
answerFile->WriteKey(SECTION_NAME, option, String());
}
}
else
{
// should only use the Encoded function for passwords
ASSERT(false);
}
}
return result;
}
#ifdef LOGGING_BUILD
static const String OPERATIONS[] =
{
L"NONE",
L"REPLICA",
L"FOREST",
L"TREE",
L"CHILD",
L"DEMOTE",
L"ABORT_BDC_UPGRADE"
};
#endif
void
State::SetOperation(Operation oper)
{
LOG_FUNCTION2(State::SetOperation, OPERATIONS[oper]);
operation = oper;
}
State::Operation
State::GetOperation() const
{
LOG_FUNCTION2(State::GetOperation, OPERATIONS[operation]);
// if aborting BDC upgrade, context must be BDC upgrade
ASSERT(operation == ABORT_BDC_UPGRADE ? context == BDC_UPGRADE : true);
return operation;
}
void
State::SetReplicaDomainDNSName(const String& dnsName)
{
LOG_FUNCTION2(State:::SetReplicaDomainDNSName, dnsName);
ASSERT(!dnsName.empty());
replicaDnsDomainName = dnsName;
// if the user is changing the domain to be replicated, then any
// previous replication partner DC may no longer apply.
// see ntbug9 #158726
SetReplicationPartnerDC(L"");
}
String
State::GetDatabasePath() const
{
LOG_FUNCTION2(State::GetDatabasePath, dbPath);
return dbPath;
}
String
State::GetLogPath() const
{
LOG_FUNCTION2(State::GetLogPath, logPath);
return logPath;
}
String
State::GetSYSVOLPath() const
{
LOG_FUNCTION2(State::GetSYSVOLPath, sysvolPath);
return sysvolPath;
}
void
State::SetDatabasePath(const String& path)
{
LOG_FUNCTION2(State::SetDatabasePath, path);
ASSERT(!path.empty());
dbPath = path;
}
void
State::SetLogPath(const String& path)
{
LOG_FUNCTION2(State::SetLogPath, path);
ASSERT(!path.empty());
logPath = path;
}
void
State::SetSYSVOLPath(const String& path)
{
LOG_FUNCTION2(State::SetSYSVOLPath, path);
ASSERT(!path.empty());
sysvolPath = path;
}
String
State::GetUsername() const
{
LOG_FUNCTION2(State::GetUsername, username);
// don't assert that this is !empty -- we may use existing credentials
return username;
}
EncodedString
State::GetPassword() const
{
// don't log the password...
LOG_FUNCTION(State::GetPassword);
// don't assert that this is !empty -- we may use existing credentials
return password;
}
void
State::SetUsername(const String& name)
{
LOG_FUNCTION2(State::SetUsername, name);
ASSERT(!name.empty());
username = name;
}
void
State::SetPassword(const EncodedString& password_)
{
LOG_FUNCTION(State::SetPassword);
// password_ may be empty
// ASSERT(!password_.empty());
password = password_;
}
String
State::GetReplicaDomainDNSName() const
{
LOG_FUNCTION2(
State::GetReplicaDomainDNSName,
replicaDnsDomainName);
return replicaDnsDomainName;
}
String
State::GetSiteName() const
{
LOG_FUNCTION2(State::GetSiteName, siteName);
return siteName;
}
void
State::SetSiteName(const String& site)
{
LOG_FUNCTION2(State::SetSiteName, site);
siteName = site;
}
void
State::SetOperationResults(OperationResult result)
{
LOG_FUNCTION2(
State::SetOperationResults,
String::format(L"result %1",
result == SUCCESS ? L"SUCCESS" : L"FAILURE"));
operationResultsStatus = result;
}
void
State::SetOperationResultsMessage(const String& message)
{
LOG_FUNCTION2(State::SetOperationResultsMessage, message);
operationResultsMessage = message;
}
String
State::GetParentDomainDnsName() const
{
LOG_FUNCTION2(
State::GetParentDomainDnsName,
parentDomainDnsName);
return parentDomainDnsName;
}
String
State::GetNewDomainDNSName() const
{
LOG_FUNCTION2(State::GetNewDomainDNSName, newDomainDnsName);
return newDomainDnsName;
}
String
State::GetNewDomainNetbiosName() const
{
LOG_FUNCTION2(
State::GetNewDomainNetbiosName,
newDomainFlatName);
return newDomainFlatName;
}
void
State::SetParentDomainDNSName(const String& name)
{
LOG_FUNCTION2(State::SetParentDomainDNSName, name);
ASSERT(!name.empty());
parentDomainDnsName = name;
}
void
State::SetNewDomainDNSName(const String& name)
{
LOG_FUNCTION2(State::SetNewDomainDNSName, name);
ASSERT(!name.empty());
newDomainDnsName = name;
// This will cause the flat name to be re-generated
newDomainFlatName.erase();
}
void
State::SetNewDomainNetbiosName(const String& name)
{
LOG_FUNCTION2(State::SetNewDomainNetbiosName, name);
ASSERT(!name.empty());
newDomainFlatName = name;
}
void
State::SetUserDomainName(const String& name)
{
LOG_FUNCTION2(State::SetUserDomainName, name);
// name may be empty;
userDomain = name;
}
String
State::GetUserDomainName() const
{
LOG_FUNCTION2(State::GetUserDomainName, userDomain);
return userDomain;
}
void
State::ClearHiddenWhileUnattended()
{
LOG_FUNCTION(State::ClearHiddenWhileUnattended);
runHiddenWhileUnattended = false;
// closes the splash dialog, if visible.
if (splash)
{
// this will delete splash, too
splash->SelfDestruct();
splash = 0;
}
}
bool
State::RunHiddenUnattended() const
{
// LOG_FUNCTION(State::RunHiddenUnattended);
return UsingAnswerFile() && runHiddenWhileUnattended;
}
bool
State::IsLastDCInDomain() const
{
LOG_FUNCTION2(State::IsLastDCInDomain, isLastDc ? L"true" : L"false");
return isLastDc;
}
void
State::SetIsLastDCInDomain(bool yesNo)
{
LOG_FUNCTION2(
State::SetIsLastDCInDomain,
yesNo ? L"is last dc" : L"is NOT last dc");
isLastDc = yesNo;
}
void
State::SetAdminPassword(const EncodedString& password)
{
LOG_FUNCTION(State::SetAdminPassword);
adminPassword = password;
}
EncodedString
State::GetAdminPassword() const
{
LOG_FUNCTION(State::GetAdminPassword);
return adminPassword;
}
String
State::GetOperationResultsMessage() const
{
LOG_FUNCTION2(
State::GetOperationResultsMessage,
operationResultsMessage);
return operationResultsMessage;
}
State::OperationResult
State::GetOperationResultsCode() const
{
LOG_FUNCTION2(
State::GetOperationResultsCode,
operationResultsStatus == SUCCESS ? L"SUCCESS" : L"FAILURE");
return operationResultsStatus;
}
bool
State::AutoConfigureDNS() const
{
LOG_FUNCTION2(
State::AutoConfigureDNS,
autoConfigDns ? L"true" : L"false");
return autoConfigDns;
}
void
State::SetAutoConfigureDNS(bool yesNo)
{
LOG_FUNCTION2(
State::SetAutoConfigureDNS,
yesNo ? L"true" : L"false");
autoConfigDns = yesNo;
}
bool
State::IsDNSOnNetwork() const
{
LOG_FUNCTION2(
State::IsDNSOnNetwork,
isDnsOnNet ? L"true" : L"false");
return isDnsOnNet;
}
void
State::SetDNSOnNetwork(bool yesNo)
{
LOG_FUNCTION2(
State::SetDNSOnNetwork,
yesNo ? L"true" : L"false");
isDnsOnNet = yesNo;
}
String
State::GetInstalledSite() const
{
LOG_FUNCTION2(State::GetInstalledSite, installedSite);
// should be set before we ask for it...
ASSERT(!installedSite.empty());
return installedSite;
}
void
State::SetInstalledSite(const String& site)
{
LOG_FUNCTION2(State::SetInstalledSite, site);
ASSERT(!site.empty());
installedSite = site;
}
void
State::AddFinishMessage(const String& message)
{
LOG_FUNCTION2(State::AddFinishMessage, message);
ASSERT(!message.empty());
if (finishMessages.empty())
{
finishMessages += message;
}
else
{
// add a blank line between each message
finishMessages += L"\r\n\r\n" + message;
}
}
String
State::GetFinishMessages() const
{
LOG_FUNCTION2(State::GetFinishMessages, finishMessages);
return finishMessages;
}
Computer&
State::GetComputer()
{
return computer;
}
void
State::SetFailureMessage(const String& message)
{
LOG_FUNCTION2(State::SetFailureMessage, message);
ASSERT(!message.empty());
failureMessage = message;
}
String
State::GetFailureMessage() const
{
LOG_FUNCTION2(State::GetFailureMessage, failureMessage);
return failureMessage;
}
bool
State::ShouldInstallAndConfigureDns() const
{
if (AutoConfigureDNS() || !IsDNSOnNetwork())
{
return true;
}
return false;
}
String
State::GetUserForestName() const
{
LOG_FUNCTION2(State::GetUserForestName, userForest);
ASSERT(!userForest.empty());
return userForest;
}
void
State::SetUserForestName(const String& forest)
{
LOG_FUNCTION2(State::SetUserForestName, forest);
ASSERT(!forest.empty());
userForest = forest;
}
bool
State::IsDomainInForest(const String& domain) const
{
LOG_FUNCTION2(State::IsDomainInForest, domain);
ASSERT(!domain.empty());
for (
DomainList::iterator i = domainsInForest.begin();
i != domainsInForest.end();
i++)
{
DNS_NAME_COMPARE_STATUS compare = Dns::CompareNames(*i, domain);
if (compare == DnsNameCompareEqual)
{
LOG(L"domain is in forest");
return true;
}
}
return false;
}
HRESULT
State::ReadDomains()
{
LOG_FUNCTION(State::ReadDomains);
domainsInForest.clear();
return ::ReadDomains(domainsInForest);
}
DNS_NAME_COMPARE_STATUS
State::DomainFitsInForest(const String& domain, String& conflictingDomain)
{
LOG_FUNCTION(domainFitsInForest);
ASSERT(!domain.empty());
conflictingDomain.erase();
DNS_NAME_COMPARE_STATUS relation = DnsNameCompareNotEqual;
for (
DomainList::iterator i = domainsInForest.begin();
i != domainsInForest.end();
i++)
{
relation = Dns::CompareNames(domain, *i);
switch (relation)
{
case DnsNameCompareNotEqual:
{
continue;
}
case DnsNameCompareEqual:
{
ASSERT(domain == *i);
// fall thru
}
case DnsNameCompareLeftParent:
case DnsNameCompareRightParent:
case DnsNameCompareInvalid:
default:
{
conflictingDomain = *i;
break;
}
}
break;
}
return relation;
}
bool
State::GetDomainReinstallFlag() const
{
LOG_FUNCTION2(
State::GetDomainReinstallFlag,
reinstallDomain ? L"true" : L"false");
return reinstallDomain;
}
void
State::SetDomainReinstallFlag(bool newValue)
{
LOG_FUNCTION2(
State::SetDomainReinstallFlag,
newValue ? L"true" : L"false");
reinstallDomain = newValue;
}
bool
State::ShouldAllowAnonymousAccess() const
{
LOG_FUNCTION2(
State::ShouldAllowAnonymousAccess,
allowAnonAccess ? L"true" : L"false");
return allowAnonAccess;
}
void
State::SetShouldAllowAnonymousAccess(bool yesNo)
{
LOG_FUNCTION2(
State::ShouldAllowAnonymousAccess,
yesNo ? L"true" : L"false");
allowAnonAccess = yesNo;
}
String
State::GetReplicationPartnerDC() const
{
LOG_FUNCTION2(State::GetReplicationPartnerDC, replicationPartnerDc);
return replicationPartnerDc;
}
void
State::SetReplicationPartnerDC(const String dcName)
{
LOG_FUNCTION2(State::SetReplicationPartnerDC, dcName);
replicationPartnerDc = dcName;
}
// Retrieve domain controller info for all DCs in the domain that this dc
// is a controller. (The result set should include this dc)
// Caller should free the result with DsFreeDomainControllerInfo
HRESULT
State::GetDomainControllerInfoForMyDomain(
DS_DOMAIN_CONTROLLER_INFO_2W*& info,
DWORD& dcCount)
{
LOG_FUNCTION(State::GetDomainControllerInfoForMyDomain);
// if this assertion does not hold, then the DsBind call below should
// fail.
ASSERT(GetComputer().IsDomainController());
dcCount = 0;
info = 0;
HRESULT hr = S_OK;
HANDLE hds = 0;
do
{
String domainDnsName = GetComputer().GetDomainDnsName();
String dcName = Win::GetComputerNameEx(ComputerNameDnsFullyQualified);
ASSERT(!domainDnsName.empty());
ASSERT(!dcName.empty());
// Bind to self
hr =
MyDsBind(
dcName,
domainDnsName,
hds);
BREAK_ON_FAILED_HRESULT(hr);
// find all the dc's for my domain. the list should contain dcName.
// level 2 contains the "is gc" flag
hr =
MyDsGetDomainControllerInfo(
hds,
domainDnsName,
dcCount,
info);
BREAK_ON_FAILED_HRESULT(hr);
}
while (0);
if (hds)
{
::DsUnBind(&hds);
hds = 0;
}
return hr;
}
// returns true if no other domain controller for this DCs domain can be
// found in the DS. False otherwise
bool
State::IsReallyLastDcInDomain()
{
LOG_FUNCTION(State::IsReallyLastDcInDomain);
// Assume we are alone in the universe.
bool result = true;
do
{
// find all the dc's for my domain. the list should contain dcName.
DS_DOMAIN_CONTROLLER_INFO_2W* info = 0;
DWORD count = 0;
HRESULT hr = GetDomainControllerInfoForMyDomain(info, count);
BREAK_ON_FAILED_HRESULT(hr);
ASSERT(count);
ASSERT(info);
// if there are more than 1 entry (more than the one for this dc),
// then the DS believes that there are other DCs for this domain.
if (count > 1)
{
result = false;
}
#ifdef DBG
// double check that we found ourselves.
if (result && info[0].DnsHostName)
{
LOG(info[0].DnsHostName);
String dcName =
Win::GetComputerNameEx(ComputerNameDnsFullyQualified);
ASSERT(
Dns::CompareNames(info[0].DnsHostName, dcName)
== DnsNameCompareEqual);
}
#endif
MyDsFreeDomainControllerInfo(count, info);
}
while (0);
LOG(
String::format(
L"This box %1 the sole DC for the domain",
result ? L"is" : L"is NOT"));
return result;
}
// Returns true if this computer is a global catalog
bool
State::IsGlobalCatalog()
{
LOG_FUNCTION(State::IsGlobalCatalog);
if (!GetComputer().IsDomainController())
{
// can't possibly be a GC if not a DC
return false;
}
bool result = false;
do
{
String dcName = Win::GetComputerNameEx(ComputerNameDnsFullyQualified);
// find all the dc's for my domain. the list should contain dcName.
// level 2 contains the "is gc" flag
DS_DOMAIN_CONTROLLER_INFO_2W* info = 0;
DWORD count = 0;
HRESULT hr = GetDomainControllerInfoForMyDomain(info, count);
BREAK_ON_FAILED_HRESULT(hr);
// there should be at least 1 entry (ourself)
ASSERT(count);
ASSERT(info);
for (int i = 0; i < count; i++)
{
if (info[i].DnsHostName) // 340723
{
LOG(info[i].DnsHostName);
if (
Dns::CompareNames(info[i].DnsHostName, dcName)
== DnsNameCompareEqual)
{
// we found ourselves in the list
LOG(L"found!");
result = info[i].fIsGc ? true : false;
break;
}
}
}
MyDsFreeDomainControllerInfo(count, info);
}
while (0);
LOG(
String::format(
L"This box %1 a global catalog",
result ? L"is" : L"is NOT"));
return result;
}
EncodedString
State::GetSafeModeAdminPassword() const
{
LOG_FUNCTION(State::GetSafeModeAdminPassword);
// don't trace the password!
return safeModeAdminPassword;
}
void
State::SetSafeModeAdminPassword(const EncodedString& pwd)
{
LOG_FUNCTION(State::SetSafeModeAdminPassword);
// don't trace the password!
// pwd may be empty.
safeModeAdminPassword = pwd;
}
String
State::GetAdminToolsShortcutPath() const
{
LOG_FUNCTION2(State::GetAdminToolsShortcutPath, shortcutPath);
return shortcutPath;
}
bool
State::NeedsCommandLineHelp() const
{
return needsCommandLineHelp;
}
bool
State::IsAdvancedMode() const
{
return isAdvancedMode;
}
void
State::SetReplicateFromMedia(bool yesNo)
{
LOG_FUNCTION2(
State::SetReplicateFromMedia,
yesNo ? L"true" : L"false");
replicateFromMedia = yesNo;
}
void
State::SetReplicationSourcePath(const String& path)
{
LOG_FUNCTION2(State::SetReplicationSourcePath, path);
sourcePath = path;
}
bool
State::ReplicateFromMedia() const
{
LOG_FUNCTION2(
State::ReplicateFromMedia,
replicateFromMedia ? L"true" : L"false");
return replicateFromMedia;
}
String
State::GetReplicationSourcePath() const
{
LOG_FUNCTION2(State::GetReplicationSourcePath, sourcePath);
return sourcePath;
}
void
State::SetSyskeyLocation(SyskeyLocation loc)
{
LOG_FUNCTION2(State::SetSyskeyLocation,
loc == DISK
? L"disk"
: ((loc == PROMPT) ? L"prompt" : L"stored"));
syskeyLocation = loc;
}
State::SyskeyLocation
State::GetSyskeyLocation() const
{
LOG_FUNCTION2(
State::IsSyskeyPresent,
syskeyLocation == DISK
? L"disk"
: ((syskeyLocation == PROMPT) ? L"prompt" : L"stored"));
return syskeyLocation;
}
void
State::SetIsBackupGc(bool yesNo)
{
LOG_FUNCTION2(State::SetIsBackupGc, yesNo ? L"true" : L"false");
isBackupGc = yesNo;
}
bool
State::IsBackupGc() const
{
LOG_FUNCTION2(State::IsBackupGc, isBackupGc ? L"true" : L"false");
return isBackupGc;
}
void
State::SetSyskey(const EncodedString& syskey_)
{
// don't log the syskey!
LOG_FUNCTION(State::SetSyskey);
ASSERT(!syskey_.IsEmpty());
syskey = syskey_;
}
EncodedString
State::GetSyskey() const
{
// don't log the syskey!
LOG_FUNCTION(State::GetSyskey);
return syskey;
}
void
State::SetRestoreGc(bool yesNo)
{
LOG_FUNCTION2(State::SetRestoreGc, yesNo ? L"true" : L"false");
restoreGc = yesNo;
}
bool
State::GetRestoreGc() const
{
LOG_FUNCTION2(State::GetRestoreGc, restoreGc ? L"true" : L"false");
return restoreGc;
}
bool
State::IsSafeModeAdminPwdOptionPresent() const
{
LOG_FUNCTION(State::IsSafeModeAdminPwdOptionPresent);
ASSERT(UsingAnswerFile());
bool result = false;
if (answerFile)
{
result =
answerFile->IsKeyPresent(
SECTION_NAME,
OPTION_SAFE_MODE_ADMIN_PASSWORD);
}
LOG(result ? L"true" : L"false");
return result;
}
void
State::SetDomainControllerReinstallFlag(bool newValue)
{
LOG_FUNCTION2(
State::SetDomainControllerReinstallFlag,
newValue ? L"true" : L"false");
reinstallDomainController = newValue;
}
bool
State::GetDomainControllerReinstallFlag() const
{
LOG_FUNCTION2(
State::GetDomainControllerReinstallFlag,
reinstallDomain ? L"true" : L"false");
return reinstallDomainController;
}
void
State::SetOperationResultsFlags(ULONG flags)
{
LOG_FUNCTION2(
State::SetOperationResultsFlags,
String::format(L"0x%1!X!", flags));
operationResultsFlags = flags;
}
ULONG
State::GetOperationResultsFlags() const
{
LOG_FUNCTION2(
State::GetOperationResultsFlags,
String::format(L"0x%1!X!", operationResultsFlags));
return operationResultsFlags;
}
bool
State::IsOperationRetryAllowed() const
{
LOG_FUNCTION(State::IsOperationRetryAllowed);
bool result = true;
if (operationResultsFlags & DSROLE_IFM_RESTORED_DATABASE_FILES_MOVED)
{
// don't allow the user to retry the operation again, as one consequence
// of the failure is that the moved files are now trashed. The user
// must re-restore the files in order to attempt the operation again.
// NTRAID#NTBUG9-296872-2001/01/29-sburns
LOG(L"ifm files moved, retry not allowed");
result = false;
}
LOG(result ? L"true" : L"false");
return result;
}
// needing a reboot is a "sticky" setting: there's no way to turn it off.
// if you once needed to reboot the machine, you will always need to reboot
// the machine. (at least, for now).
void
State::SetNeedsReboot()
{
LOG_FUNCTION(State::SetNeedsReboot);
needsReboot = true;
}
bool
State::GetNeedsReboot() const
{
LOG_FUNCTION2(State::GetNeedsReboot, needsReboot ? L"true" : L"false");
return needsReboot;
}
void
State::SetSetForestVersionFlag(bool setVersion)
{
LOG_FUNCTION2(
State::SetSetForestVersionFlag,
setVersion ? L"true" : L"false");
setForestVersion = setVersion;
}
bool
State::GetSetForestVersionFlag() const
{
LOG_FUNCTION2(
State::GetSetForestVersionFlag,
setForestVersion ? L"true" : L"false");
return setForestVersion;
}