mirror of https://github.com/tongzx/nt5src
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.
1778 lines
31 KiB
1778 lines
31 KiB
// 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;
|
|
}
|