// 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" #include "NonDomainNc.hpp" 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(); // +1 for null-termination paranoia WCHAR buf[MAX_PATH + 1]; // REVIEWED-2002/02/28-sburns correct byte count passed. ::ZeroMemory(buf, (MAX_PATH + 1) * sizeof WCHAR); HRESULT hr = ::SHGetFolderPath( 0, CSIDL_COMMON_ADMINTOOLS, 0, SHGFP_TYPE_CURRENT, buf); if (SUCCEEDED(hr)) { result = buf; } return hr; } // Sets result = true if the registry option to not configure the dns client // to point to itself is absent or non-zero, false otherwise. // NTRAID#NTBUG9-446484-2001/10/11-sburns void InitDnsClientConfigFlag(bool& result) { LOG_FUNCTION(InitDnsClientConfigFlag); result = true; do { static String keyname = String(REG_ADMIN_RUNTIME_OPTIONS) + RUNTIME_NAME; RegistryKey key; HRESULT hr = key.Open(HKEY_LOCAL_MACHINE, keyname); BREAK_ON_FAILED_HRESULT(hr); DWORD mode = 0; hr = key.GetValue(L"ConfigureDnsClient", mode); BREAK_ON_FAILED_HRESULT(hr); result = mode ? true : false; } while (0); LOG_BOOL(result); } State::State() : adminPassword(), allowAnonAccess(false), answerFile(0), autoConfigDns(false), computer(), context(), dbPath(), domainsInForest(), failureMessage(), finishMessages(), installedSite(), isAdvancedMode(false), isBackupGc(false), isDnsOnNet(true), #ifdef DBG isExitOnFailureMode(false), #endif isForcedDemotion(false), 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(), shouldConfigDnsClient(true), siteName(), splash(0), sourcePath(), sysvolPath(), syskey(), syskeyLocation(STORED), useCurrentCredentials(false), userDomain(), userForest(), username() { LOG_CTOR(State); 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(); 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); } #ifdef DBG // check for /ExitOnFailure // NTRAID#NTBUG9-416968-2001/06/14-sburns static const wchar_t* EXIT_ON_FAIL = L"ExitOnFailure"; if (args.find(EXIT_ON_FAIL) != args.end()) { LOG(L"Enabling exit-on-failure mode"); isExitOnFailureMode = true; args.erase(EXIT_ON_FAIL); } #endif // check for /forceremoval // NTRAID#NTBUG9-496409-2001/11/29-sburns static const wchar_t* FORCE = L"forceremoval"; if (args.find(FORCE) != args.end()) { LOG(L"Enabling forced demotion mode"); isForcedDemotion = true; args.erase(FORCE); } // 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; } } // 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); // Set the current directory to the root directory. This is to make the // pathname normalization on the paths pages seem less astonishing. It // will cause normalization to be relative to the root directory, // rather than the user's home directory (which is typically the current // directory when the app is launched from Start->Run) // NTRAID#NTBUG9-470687-2001/09/21-sburns String curdir; hr = Win::GetCurrentDirectory(curdir); if (SUCCEEDED(hr)) { // NTRAID#NTBUG9-547394-2002/03/26-sburns switch (FS::GetPathSyntax(curdir)) { case FS::SYNTAX_ABSOLUTE_DRIVE: { // this is the typical case. break; } default: { curdir = Win::GetSystemWindowsDirectory(); break; } } hr = Win::SetCurrentDirectory(curdir.substr(0, 3)); ASSERT(SUCCEEDED(hr)); LOG_HRESULT(hr); } InitDnsClientConfigFlag(shouldConfigDnsClient); IfmHandle = NULL; } void State::SetupAnswerFile( const String& filename, bool isDefaultAnswerfile) { LOG_FUNCTION2(State::SetupAnswerFile, filename); String f = Win::ExpandEnvironmentStrings(filename); f = FS::NormalizePath(f); LOG(L"answerfile resolved to: " + f); if (FS::PathExists(f)) { // file found. LOG(L"answerfile found"); answerFile = new AnswerFile(f); splash = new UnattendSplashDialog( context == State::NT5_DC ? IDS_DEMOTE_SPLASH_MESSAGE : IDS_PROMOTE_SPLASH_MESSAGE); 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); FreeIfmHandle(); 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; } String State::GetAnswerFileOption(const String& option) const { LOG_FUNCTION2(GetAnswerFileOption, option); ASSERT(UsingAnswerFile()); String result; if (answerFile) { result = answerFile->GetOption(option); } return result; } EncryptedString State::GetEncryptedAnswerFileOption(const String& option) const { LOG_FUNCTION2(GetEncryptedAnswerFileOption, option); ASSERT(UsingAnswerFile()); EncryptedString result; if (answerFile) { result = answerFile->GetEncryptedOption(option); } 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::SetIfmHandle(DSROLE_IFM_OPERATION_HANDLE IfmHandleIn) { ASSERT(IfmHandle == NULL || IfmHandleIn == 0); if (IfmHandle) { // need to free any existing handle ::DsRoleIfmHandleFree(0, // this server &IfmHandle); IfmHandle = NULL; } IfmHandle = IfmHandleIn; } 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; } EncryptedString 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 EncryptedString& 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 EncryptedString& password) { LOG_FUNCTION(State::SetAdminPassword); adminPassword = password; } EncryptedString 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 (size_t 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; } EncryptedString State::GetSafeModeAdminPassword() const { LOG_FUNCTION(State::GetSafeModeAdminPassword); // don't trace the password! return safeModeAdminPassword; } void State::SetSafeModeAdminPassword(const EncryptedString& 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 EncryptedString& syskey_) { // don't log the syskey! LOG_FUNCTION(State::SetSyskey); ASSERT(!syskey_.IsEmpty()); syskey = syskey_; } EncryptedString 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->IsSafeModeAdminPwdOptionPresent(); } 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; } // NTRAID#NTBUG9-416968-2001/06/14-sburns #ifdef DBG if (IsExitOnFailureMode()) { // don't allow retry on failure in this mode. This will cause the // retry logic in the promote thread to be skipped. // LOG(L"exit-on-failure mode trumps retry"); result = false; } #endif 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; } // NTRAID#NTBUG9-416968-2001/06/14-sburns #ifdef DBG bool State::IsExitOnFailureMode() const { LOG_FUNCTION2( State::IsExitOnFailureMode, isExitOnFailureMode ? L"true" : L"false"); return isExitOnFailureMode; } #endif bool State::IsLastAppPartitionReplica() { LOG_FUNCTION(State::IsLastAppPartitionReplica); bool result = false; partitionList.clear(); do { RunContext context = GetInstance().GetRunContext(); if (context != State::NT5_DC) { // not a DC, so can't be replica of any NCs LOG(L"not a DC"); break; } // Find any non-domain NCs for which this DC is the last replica HRESULT hr = IsLastNonDomainNamingContextReplica(partitionList); if (FAILED(hr)) { LOG(L"Failed to determine if the machine is last replica of NDNCs"); ASSERT(result == false); // This is not an error condition that we'll deal with here. We // will end up passing an empty list to the demote API, which will // then fail, and we will catch the failure. break; } if (hr == S_FALSE) { LOG(L"Not last replica of non-domain NCs"); ASSERT(result == false); break; } result = true; // there should be at least one DN in the list. ASSERT(partitionList.size()); } while (0); LOG(result ? L"true" : L"false"); return result; } const StringList& State::GetAppPartitionList() const { LOG_FUNCTION(State::GetAppPartitionList); return partitionList; } // Returns true if the registry option to not configure the dns client to // point to itself is absent or non-zero, false otherwise. // NTRAID#NTBUG9-446484-2001/10/11-sburns bool State::ShouldConfigDnsClient() const { LOG_FUNCTION(State::ShouldConfigDnsClient); LOG_BOOL(shouldConfigDnsClient); return shouldConfigDnsClient; } // NTRAID#NTBUG9-496409-2001/11/29-sburns bool State::IsForcedDemotion() const { LOG_FUNCTION2( State::IsForcedDemotion, isForcedDemotion ? L"true" : L"false"); return isForcedDemotion; }