Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1095 lines
27 KiB

  1. // Copyright (c) 1997-1999 Microsoft Corporation
  2. //
  3. // domain controller promotion wizard, Mark II
  4. //
  5. // 12-12-97 sburns
  6. #include "headers.hxx"
  7. #include "common.hpp"
  8. #include "adpass.hpp"
  9. #include "ApplicationPartitionPage.hpp"
  10. #include "ApplicationPartitionConfirmationPage.hpp"
  11. #include "BadComputerNameDialog.hpp"
  12. #include "CheckDomainUpgradedPage.hpp"
  13. #include "CheckPortAvailability.hpp"
  14. #include "ChildPage.hpp"
  15. #include "CredentialsPage.hpp"
  16. #include "ConfirmationPage.hpp"
  17. #include "DemotePage.hpp"
  18. #include "DynamicDnsPage.hpp"
  19. #include "ConfigureDnsClientPage.hpp"
  20. #include "DnsOnNetPage.hpp"
  21. #include "FailurePage.hpp"
  22. #include "finish.hpp"
  23. #include "ForcedDemotionPage.hpp"
  24. #include "ForestPage.hpp"
  25. #include "ForestVersionPage.hpp"
  26. #include "GcConfirmationPage.hpp"
  27. #include "NetbiosNamePage.hpp"
  28. #include "NewDomainPage.hpp"
  29. #include "NewSitePage.hpp"
  30. #include "NonDomainNc.hpp"
  31. #include "NonRfcComputerNameDialog.hpp"
  32. #include "PathsPage.hpp"
  33. #include "Paths2Page.hpp"
  34. #include "PickSitePage.hpp"
  35. #include "rasfixup.hpp"
  36. // #include "ReadmePage.hpp"
  37. #include "RebootDialog.hpp"
  38. #include "ReplicaOrNewDomainPage.hpp"
  39. #include "ReplicateFromMediaPage.hpp"
  40. #include "ReplicaPage.hpp"
  41. #include "ReplicaOrMemberPage.hpp"
  42. #include "resource.h"
  43. #include "safemode.hpp"
  44. #include "SecureCommWarningPage.hpp"
  45. #include "state.hpp"
  46. #include "InstallTcpIpPage.hpp"
  47. #include "TreePage.hpp"
  48. #include "WelcomePage.hpp"
  49. #include <ntverp.h>
  50. HINSTANCE hResourceModuleHandle = 0;
  51. const wchar_t* HELPFILE_NAME = 0; // no context help available
  52. // don't change this: it is also the name of a mutex that the net id ui
  53. // uses to determine if dcpromo is running.
  54. const wchar_t* RUNTIME_NAME = L"dcpromoui";
  55. DWORD DEFAULT_LOGGING_OPTIONS =
  56. Log::OUTPUT_TO_FILE
  57. | Log::OUTPUT_FUNCCALLS
  58. | Log::OUTPUT_LOGS
  59. | Log::OUTPUT_ERRORS
  60. | Log::OUTPUT_HEADER;
  61. // a system modal popup thingy
  62. Popup popup(IDS_WIZARD_TITLE, true);
  63. // this is the mutex that indicates the dcpromo is running.
  64. HANDLE dcpromoRunningMutex = INVALID_HANDLE_VALUE;
  65. // these are the valid exit codes returned from the dcpromo.exe process
  66. enum ExitCode
  67. {
  68. // the operation failed.
  69. EXIT_CODE_UNSUCCESSFUL = 0,
  70. // the operation succeeded
  71. EXIT_CODE_SUCCESSFUL = 1,
  72. // the operation succeeded, and the user opted not to have the wizard
  73. // restart the machine, either manually or by specifying
  74. // RebootOnSuccess=NoAndNoPromptEither in the answerfile
  75. EXIT_CODE_SUCCESSFUL_NO_REBOOT = 2,
  76. // the operation failed, but the machine needs to be rebooted anyway
  77. EXIT_CODE_UNSUCCESSFUL_NEEDS_REBOOT = 3
  78. };
  79. // Checks the platform and os version number. Returns the resource ID of the
  80. // string to present to the user if platform/os ver requirements are not met,
  81. // or 0 if they are met.
  82. unsigned
  83. CheckPlatform()
  84. {
  85. LOG_FUNCTION(CheckPlatform);
  86. unsigned retval = 0;
  87. Computer::Role role = State::GetInstance().GetComputer().GetRole();
  88. switch (role)
  89. {
  90. case Computer::STANDALONE_WORKSTATION:
  91. case Computer::MEMBER_WORKSTATION:
  92. {
  93. retval = IDS_WORKSTATION_NOT_SUPPORTED;
  94. break;
  95. }
  96. case Computer::STANDALONE_SERVER:
  97. case Computer::MEMBER_SERVER:
  98. case Computer::PRIMARY_CONTROLLER:
  99. case Computer::BACKUP_CONTROLLER:
  100. {
  101. // check OS version
  102. OSVERSIONINFOEX info;
  103. HRESULT hr = Win::GetVersionEx(info);
  104. BREAK_ON_FAILED_HRESULT(hr);
  105. if (
  106. // require the same version for which we were built.
  107. // NTRAID#NTBUG9-591686-2002/04/12-sburns
  108. info.dwPlatformId != VER_PLATFORM_WIN32_NT
  109. || !( info.dwMajorVersion == VER_PRODUCTMAJORVERSION
  110. && info.dwMinorVersion == VER_PRODUCTMINORVERSION))
  111. {
  112. retval = IDS_NT51_REQUIRED;
  113. break;
  114. }
  115. if (
  116. // if a web blade ...
  117. info.wSuiteMask & VER_SUITE_BLADE
  118. // or, an appliance ...
  119. || (info.wSuiteMask & VER_SUITE_EMBEDDED_RESTRICTED
  120. // that is not advanced or data center server ...
  121. && !(info.wSuiteMask & (VER_SUITE_ENTERPRISE | VER_SUITE_DATACENTER)) ) )
  122. {
  123. // .. then don't allow promotion.
  124. // NTRAID#NTBUG9-195265-2001/04/03-sburns
  125. // NTRAID#NTBUG9-590937-2002/04/15-sburns
  126. retval = IDS_WEB_BLADE_NOT_SUPPORTED;
  127. break;
  128. }
  129. break;
  130. }
  131. default:
  132. {
  133. ASSERT(false);
  134. break;
  135. }
  136. }
  137. return retval;
  138. }
  139. // Checks the role change state of the machine. Returns the resource ID of
  140. // the string to present to the user if the state is such that another role
  141. // change cannot be attempted, or 0 if a role change attempt may proceed.
  142. unsigned
  143. CheckRoleChangeState()
  144. {
  145. LOG_FUNCTION(CheckRoleChangeState);
  146. unsigned retval = 0;
  147. // check to see if a role change has taken place, or is in progress.
  148. DSROLE_OPERATION_STATE_INFO* info = 0;
  149. HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info);
  150. if (SUCCEEDED(hr) && info)
  151. {
  152. switch (info->OperationState)
  153. {
  154. case DsRoleOperationIdle:
  155. {
  156. // do nothing
  157. break;
  158. }
  159. case DsRoleOperationActive:
  160. {
  161. // a role change operation is underway
  162. retval = IDS_ROLE_CHANGE_IN_PROGRESS;
  163. break;
  164. }
  165. case DsRoleOperationNeedReboot:
  166. {
  167. // a role change has already taken place, need to reboot before
  168. // attempting another.
  169. retval = IDS_ROLE_CHANGE_NEEDS_REBOOT;
  170. break;
  171. }
  172. default:
  173. {
  174. ASSERT(false);
  175. break;
  176. }
  177. }
  178. ::DsRoleFreeMemory(info);
  179. }
  180. return retval;
  181. }
  182. // Checks for the presence of at least 1 logical drive formatted with NTFS5.
  183. // Returns the resource ID of the string to present to the user if no such
  184. // drive is found (which implies that the user will not be able to pick a
  185. // sysvol path that is formatted w/ NTFS5, which implies that proceeding would
  186. // be a waste of time.
  187. unsigned
  188. CheckForNtfs5()
  189. {
  190. LOG_FUNCTION(CheckForNtfs5);
  191. if (GetFirstNtfs5HardDrive().empty())
  192. {
  193. return IDS_NO_NTFS5_DRIVES;
  194. }
  195. return 0;
  196. }
  197. // Checks if the machine is running in safeboot mode. You can't run dcpromo
  198. // while in safeboot mode.
  199. unsigned
  200. CheckSafeBootMode()
  201. {
  202. LOG_FUNCTION(CheckSafeBootMode);
  203. static const String
  204. SAFEBOOT_KEY(L"System\\CurrentControlSet\\Control\\Safeboot\\Option");
  205. do
  206. {
  207. RegistryKey key;
  208. HRESULT hr = key.Open(HKEY_LOCAL_MACHINE, SAFEBOOT_KEY);
  209. BREAK_ON_FAILED_HRESULT(hr);
  210. DWORD mode = 0;
  211. hr = key.GetValue(L"OptionValue", mode);
  212. if (mode)
  213. {
  214. return IDS_SAFEBOOT_MODE;
  215. }
  216. }
  217. while (0);
  218. return 0;
  219. }
  220. unsigned
  221. CheckCertService()
  222. {
  223. LOG_FUNCTION(CheckCertService);
  224. // If not a downlevel DC upgrade, then refuse to run until cert service
  225. // is removed. 356399
  226. State::RunContext context = State::GetInstance().GetRunContext();
  227. if (context != State::BDC_UPGRADE && context != State::PDC_UPGRADE)
  228. {
  229. if (NTService(L"CertSvc").IsInstalled())
  230. {
  231. return IDS_CERT_SERVICE_IS_INSTALLED;
  232. }
  233. }
  234. return 0;
  235. }
  236. unsigned
  237. CheckWindirSpace()
  238. {
  239. LOG_FUNCTION(CheckWindirSpace);
  240. // if you change this, change the error message resource too.
  241. static const unsigned WINDIR_MIN_SPACE_MB = 20;
  242. String windir = Win::GetSystemWindowsDirectory();
  243. if (!CheckDiskSpace(windir, 20))
  244. {
  245. return IDS_WINDIR_LOW_SPACE;
  246. }
  247. return 0;
  248. }
  249. // NTRAID#NTBUG9-199759-2000/10/27-sburns
  250. unsigned
  251. CheckComputerWasRenamedAndNeedsReboot()
  252. {
  253. LOG_FUNCTION(CheckComputerWasRenamedAndNeedsReboot);
  254. if (ComputerWasRenamedAndNeedsReboot())
  255. {
  256. return IDS_NAME_CHANGE_NEEDS_REBOOT;
  257. }
  258. return 0;
  259. }
  260. // Start the Network Identification UI (aka Computer Name UI). After calling
  261. // this function, the app must not initiate a role change. It should
  262. // terminate.
  263. void
  264. LaunchNetId()
  265. {
  266. LOG_FUNCTION(LaunchNetId);
  267. ASSERT(dcpromoRunningMutex != INVALID_HANDLE_VALUE);
  268. // net id ui attempts acquisition of our mutex to determine if we are
  269. // running. So, before starting the net id ui, we need to close the
  270. // mutex. Otherwise, we would create a race condition between the start of
  271. // the net id ui and the closure of this app. (And yes, cynical reader, I
  272. // did think of that before actually encountering a problem.)
  273. do
  274. {
  275. Win::CloseHandle(dcpromoRunningMutex);
  276. // It would be extraordinarily unlikely, but in case the mutex close
  277. // fails, we're gonna start the net id ui anyway and risk the race
  278. // condition.
  279. String sys32Folder = Win::GetSystemDirectory();
  280. PROCESS_INFORMATION procInfo;
  281. // REVIEWED-2002/02/25-sburns correct byte count passed
  282. ::ZeroMemory(&procInfo, sizeof procInfo);
  283. STARTUPINFO startup;
  284. // REVIEWED-2002/02/25-sburns correct byte count passed
  285. ::ZeroMemory(&startup, sizeof startup);
  286. LOG(L"Calling CreateProcess");
  287. String commandLine(L"shell32.dll,Control_RunDLL sysdm.cpl,,1");
  288. // REVIEWED-2002/02/26-sburns wrapper requires full path to app
  289. HRESULT hr =
  290. Win::CreateProcess(
  291. sys32Folder + L"\\rundll32.exe",
  292. commandLine,
  293. 0,
  294. String(),
  295. startup,
  296. procInfo);
  297. BREAK_ON_FAILED_HRESULT(hr);
  298. Win::CloseHandle(procInfo.hThread);
  299. Win::CloseHandle(procInfo.hProcess);
  300. }
  301. while (0);
  302. }
  303. // Return false if the local machine's dns hostname is bad, also pop up an
  304. // error dialog. Return true if the name is OK. A bad name is one we believe
  305. // will have problems being registered in DNS after a promotion. The user
  306. // must fix a bad name before proceeding.
  307. bool
  308. IsComputerNameOk()
  309. {
  310. LOG_FUNCTION(IsComputerNameOk);
  311. bool result = true;
  312. do
  313. {
  314. State& state = State::GetInstance();
  315. State::RunContext context = state.GetRunContext();
  316. if (
  317. context == State::BDC_UPGRADE
  318. || context == State::PDC_UPGRADE
  319. || context == State::NT5_DC
  320. || !IsTcpIpInstalled() )
  321. {
  322. // If the machine is already a DC, then we don't worry about the name.
  323. //
  324. // If the machine is a downlevel DC undergoing upgrade, then the name
  325. // can't be changed until dcpromo is complete. So, we say nothing now,
  326. // but remind the user to rename the machine in the Finish Page.
  327. //
  328. // If TCP/IP is not installed, then the machine has no hostname
  329. // to check. In this case, we will check for that with the
  330. // InstallTcpIpPage
  331. ASSERT(result == true);
  332. break;
  333. }
  334. // Then check the computer name to ensure that it can be registered in
  335. // DNS.
  336. String hostname =
  337. Win::GetComputerNameEx(::ComputerNamePhysicalDnsHostname);
  338. DNS_STATUS status =
  339. MyDnsValidateName(hostname, ::DnsNameHostnameLabel);
  340. switch (status)
  341. {
  342. case DNS_ERROR_NON_RFC_NAME:
  343. {
  344. // Don't pester the user if we're running unattended
  345. // NTRAID#NTBUG9-538475-2002/04/19-sburns
  346. if (state.RunHiddenUnattended())
  347. {
  348. LOG(L"skipping non-RFC computer name warning");
  349. // continue on with the non-rfc name
  350. ASSERT(result == true);
  351. break;
  352. }
  353. INT_PTR dlgResult =
  354. NonRfcComputerNameDialog(hostname).ModalExecute(0);
  355. switch (dlgResult)
  356. {
  357. case NonRfcComputerNameDialog::CONTINUE:
  358. {
  359. // continue on with the non-rfc name
  360. ASSERT(result == true);
  361. break;
  362. }
  363. default:
  364. {
  365. // close the wizard and rename.
  366. result = false;
  367. // after calling this, we must not allow any promote
  368. // operation. We will fall out of this function, then
  369. // end the app.
  370. LaunchNetId();
  371. break;
  372. }
  373. }
  374. break;
  375. }
  376. case DNS_ERROR_NUMERIC_NAME:
  377. {
  378. result = false;
  379. String message =
  380. String::format(
  381. IDS_COMPUTER_NAME_IS_NUMERIC,
  382. hostname.c_str());
  383. BadComputerNameDialog(message).ModalExecute(0);
  384. break;
  385. }
  386. case DNS_ERROR_INVALID_NAME_CHAR:
  387. case ERROR_INVALID_NAME:
  388. {
  389. result = false;
  390. String message =
  391. String::format(
  392. IDS_COMPUTER_NAME_HAS_BAD_CHARS,
  393. hostname.c_str());
  394. BadComputerNameDialog(message).ModalExecute(0);
  395. break;
  396. }
  397. case ERROR_SUCCESS:
  398. default:
  399. {
  400. break;
  401. }
  402. }
  403. }
  404. while (0);
  405. LOG(result ? L"true" : L"false");
  406. return result;
  407. }
  408. // Reboots the machine with the special dcpromo reason codes
  409. // NTRAID#NTBUG9-689581-2002/08/19-sburns
  410. HRESULT
  411. DcpromoReboot()
  412. {
  413. LOG_FUNCTION(DcpromoReboot);
  414. HRESULT hr = S_OK;
  415. AutoTokenPrivileges privs(SE_SHUTDOWN_NAME);
  416. hr = privs.Enable();
  417. DWORD minorReason = SHTDN_REASON_MINOR_DC_PROMOTION;
  418. switch (State::GetInstance().GetOperation())
  419. {
  420. case State::REPLICA:
  421. case State::FOREST:
  422. case State::TREE:
  423. case State::CHILD:
  424. {
  425. // do nothing
  426. break;
  427. }
  428. case State::DEMOTE:
  429. case State::ABORT_BDC_UPGRADE:
  430. {
  431. // we treat abort bdc upgrade as a demotion because it is one,
  432. // in the sense that the machine was once a DC and now it is not.
  433. minorReason = SHTDN_REASON_MINOR_DC_DEMOTION;
  434. break;
  435. }
  436. case State::NONE:
  437. default:
  438. {
  439. // we're insane.
  440. ASSERT(false);
  441. LOG(L"unknown operation!");
  442. return E_UNEXPECTED;
  443. }
  444. }
  445. BOOL succeeded =
  446. ::InitiateSystemShutdownEx(
  447. 0,
  448. const_cast<PWSTR>(String::load(IDS_REBOOT_MESSAGE).c_str()),
  449. // zero timeout -- BAM! you're dead! -- this to avoid a winlogon
  450. // race condition.
  451. // NTRAID#NTBUG9-727439-2002/10/24-sburns
  452. 0, // 15,
  453. FALSE,
  454. TRUE,
  455. SHTDN_REASON_FLAG_PLANNED
  456. | SHTDN_REASON_MAJOR_OPERATINGSYSTEM
  457. | minorReason);
  458. if (!succeeded)
  459. {
  460. hr = Win::GetLastErrorAsHresult();
  461. }
  462. LOG_HRESULT(hr);
  463. if (FAILED(hr))
  464. {
  465. popup.Error(
  466. Win::GetDesktopWindow(),
  467. hr,
  468. IDS_CANT_REBOOT);
  469. }
  470. return hr;
  471. }
  472. // NTRAID#NTBUG9-346120-2001/04/04-sburns
  473. ExitCode
  474. HandleRebootCases()
  475. {
  476. LOG_FUNCTION(HandleRebootCases);
  477. // There are two possible reasons for needing to reboot the machine:
  478. // the operation was successful, or the operation failed, but in the
  479. // attempt the machine's joined state changed.
  480. State& state = State::GetInstance();
  481. ExitCode exitCode =
  482. (state.GetOperationResultsCode() == State::SUCCESS)
  483. ? EXIT_CODE_SUCCESSFUL
  484. : EXIT_CODE_UNSUCCESSFUL_NEEDS_REBOOT;
  485. switch (exitCode)
  486. {
  487. case EXIT_CODE_SUCCESSFUL:
  488. {
  489. if (state.RunHiddenUnattended())
  490. {
  491. String option =
  492. state.GetAnswerFileOption(AnswerFile::OPTION_REBOOT);
  493. if (option.icompare(AnswerFile::VALUE_YES) == 0)
  494. {
  495. ASSERT(exitCode == EXIT_CODE_SUCCESSFUL);
  496. HRESULT hr = DcpromoReboot();
  497. if (FAILED(hr))
  498. {
  499. exitCode = EXIT_CODE_SUCCESSFUL_NO_REBOOT;
  500. }
  501. break;
  502. }
  503. else if (option.icompare(AnswerFile::VALUE_NO_DONT_PROMPT) == 0)
  504. {
  505. // user opted not to reboot the machine via answerfile
  506. LOG(L"Not rebooting, and not prompting either");
  507. exitCode = EXIT_CODE_SUCCESSFUL_NO_REBOOT;
  508. break;
  509. }
  510. }
  511. RebootDialog dlg(false);
  512. if (dlg.ModalExecute(0))
  513. {
  514. // user opted to reboot the machine
  515. HRESULT hr = DcpromoReboot();
  516. if (FAILED(hr))
  517. {
  518. exitCode = EXIT_CODE_SUCCESSFUL_NO_REBOOT;
  519. }
  520. }
  521. else
  522. {
  523. // user opted not to reboot the machine
  524. exitCode = EXIT_CODE_SUCCESSFUL_NO_REBOOT;
  525. }
  526. break;
  527. }
  528. case EXIT_CODE_UNSUCCESSFUL_NEEDS_REBOOT:
  529. {
  530. // If the operation failed, then the wizard has gone into interactive
  531. // mode.
  532. RebootDialog dlg(true);
  533. if (dlg.ModalExecute(0))
  534. {
  535. // user opted to reboot the machine
  536. exitCode = EXIT_CODE_UNSUCCESSFUL;
  537. HRESULT hr = DcpromoReboot();
  538. if (FAILED(hr))
  539. {
  540. exitCode = EXIT_CODE_UNSUCCESSFUL_NEEDS_REBOOT;
  541. }
  542. }
  543. else
  544. {
  545. // user opted not to reboot the machine
  546. ASSERT(exitCode == EXIT_CODE_UNSUCCESSFUL_NEEDS_REBOOT);
  547. }
  548. break;
  549. }
  550. default:
  551. {
  552. ASSERT(false);
  553. break;
  554. }
  555. }
  556. return exitCode;
  557. }
  558. ExitCode
  559. RunWizard()
  560. {
  561. LOG_FUNCTION(RunWizard);
  562. Wizard wiz(
  563. IDS_WIZARD_TITLE,
  564. IDB_BANNER16,
  565. IDB_BANNER256,
  566. IDB_WATERMARK16,
  567. IDB_WATERMARK256);
  568. // Welcome must be first
  569. wiz.AddPage(new WelcomePage());
  570. // These are not in any particular order...
  571. // CODEWORK: Someday it might be useful to split this into two separate
  572. // sets of pages for promote and demote.
  573. wiz.AddPage(new AdminPasswordPage());
  574. wiz.AddPage(new ApplicationPartitionPage());
  575. wiz.AddPage(new ApplicationPartitionConfirmationPage());
  576. wiz.AddPage(new CheckDomainUpgradedPage());
  577. wiz.AddPage(new ChildPage());
  578. wiz.AddPage(new ConfigureDnsClientPage());
  579. wiz.AddPage(new ConfirmationPage());
  580. wiz.AddPage(new CredentialsPage());
  581. wiz.AddPage(new DemotePage());
  582. wiz.AddPage(new DnsOnNetPage());
  583. wiz.AddPage(new DynamicDnsPage());
  584. wiz.AddPage(new FailurePage());
  585. wiz.AddPage(new FinishPage());
  586. wiz.AddPage(new ForcedDemotionPage());
  587. wiz.AddPage(new ForestPage());
  588. wiz.AddPage(new ForestVersionPage());
  589. wiz.AddPage(new GcConfirmationPage());
  590. wiz.AddPage(new InstallTcpIpPage());
  591. wiz.AddPage(new NetbiosNamePage());
  592. wiz.AddPage(new NewDomainPage());
  593. wiz.AddPage(new NewSitePage());
  594. wiz.AddPage(new Paths2Page());
  595. wiz.AddPage(new PathsPage());
  596. wiz.AddPage(new PickSitePage());
  597. wiz.AddPage(new RASFixupPage());
  598. // wiz.AddPage(new ReadmePage());
  599. wiz.AddPage(new ReplicaOrMemberPage());
  600. wiz.AddPage(new ReplicaOrNewDomainPage());
  601. wiz.AddPage(new ReplicaPage());
  602. wiz.AddPage(new ReplicateFromMediaPage());
  603. wiz.AddPage(new SafeModePasswordPage());
  604. wiz.AddPage(new SecureCommWarningPage());
  605. wiz.AddPage(new TreePage());
  606. ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
  607. switch (wiz.ModalExecute(Win::GetDesktopWindow()))
  608. {
  609. case -1:
  610. {
  611. popup.Error(
  612. Win::GetDesktopWindow(),
  613. E_FAIL,
  614. IDS_PROP_SHEET_FAILED);
  615. break;
  616. }
  617. case ID_PSREBOOTSYSTEM:
  618. {
  619. exitCode = HandleRebootCases();
  620. break;
  621. }
  622. default:
  623. {
  624. // do nothing.
  625. break;
  626. }
  627. }
  628. return exitCode;
  629. }
  630. // NTRAID#NTBUG9-350777-2001/04/24-sburns
  631. bool
  632. ShouldCancelBecauseMachineIsAppServer()
  633. {
  634. LOG_FUNCTION(ShouldCancelBecauseMachineIsAppServer);
  635. bool result = false;
  636. do
  637. {
  638. State& state = State::GetInstance();
  639. State::RunContext context = state.GetRunContext();
  640. if (context == State::NT5_DC)
  641. {
  642. // already a DC: nothing to gripe about.
  643. break;
  644. }
  645. OSVERSIONINFOEX info;
  646. HRESULT hr = Win::GetVersionEx(info);
  647. BREAK_ON_FAILED_HRESULT(hr);
  648. // you're running app server if you're running terminal server and
  649. // not single user terminal server.
  650. bool isAppServer =
  651. (info.wSuiteMask & VER_SUITE_TERMINAL)
  652. && !(info.wSuiteMask & VER_SUITE_SINGLEUSERTS);
  653. if (isAppServer)
  654. {
  655. // warn the user that promotion will whack the ts policy settings
  656. LOG(L"machine has app server installed");
  657. if (!state.RunHiddenUnattended())
  658. {
  659. if (
  660. popup.MessageBox(
  661. Win::GetDesktopWindow(),
  662. IDS_APP_SERVER_WARNING,
  663. MB_OKCANCEL) == IDCANCEL)
  664. {
  665. // user wishes to bail out.
  666. result = true;
  667. break;
  668. }
  669. }
  670. }
  671. }
  672. while (0);
  673. LOG_BOOL(result);
  674. return result;
  675. }
  676. ExitCode
  677. Start()
  678. {
  679. LOG_FUNCTION(Start);
  680. ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
  681. unsigned id = 0;
  682. do
  683. {
  684. // do the admin check first of all, cause others may fail for non-admin
  685. // 292749
  686. id = IsCurrentUserAdministrator() ? 0 : IDS_NOT_ADMIN;
  687. if (id)
  688. {
  689. break;
  690. }
  691. // If cert service is installed, we will probably break it on promote
  692. // or demote.
  693. // 324653
  694. id = CheckCertService();
  695. if (id)
  696. {
  697. break;
  698. }
  699. id = CheckSafeBootMode();
  700. if (id)
  701. {
  702. break;
  703. }
  704. // do the role change check before the platform check, as the platform
  705. // check may be unreliable after a demote.
  706. id = CheckRoleChangeState();
  707. if (id)
  708. {
  709. break;
  710. }
  711. id = CheckPlatform();
  712. if (id)
  713. {
  714. break;
  715. }
  716. id = CheckForNtfs5();
  717. if (id)
  718. {
  719. break;
  720. }
  721. id = CheckWindirSpace();
  722. if (id)
  723. {
  724. break;
  725. }
  726. id = CheckComputerWasRenamedAndNeedsReboot();
  727. if (id)
  728. {
  729. break;
  730. }
  731. }
  732. while(0);
  733. do
  734. {
  735. if (id)
  736. {
  737. popup.Error(
  738. Win::GetDesktopWindow(),
  739. String::load(id));
  740. break;
  741. }
  742. if (!IsComputerNameOk())
  743. {
  744. break;
  745. }
  746. if (ShouldCancelBecauseMachineIsAppServer())
  747. {
  748. break;
  749. }
  750. // NTRAID#NTBUG9-129955-2000/11/02-sburns left commented out until
  751. // PM decides what the real fix to this bug is.
  752. // if (!AreRequiredPortsAvailable())
  753. // {
  754. // break;
  755. // }
  756. exitCode = RunWizard();
  757. }
  758. while (0);
  759. LOG(String::format(L"exitCode = %1!d!", static_cast<int>(exitCode)));
  760. return exitCode;
  761. }
  762. void
  763. ShowCommandLineHelp()
  764. {
  765. // CODEWORK: replace this with WinHelp, someday
  766. popup.MessageBox(Win::GetDesktopWindow(), IDS_COMMAND_LINE_HELP, MB_OK);
  767. }
  768. int WINAPI
  769. WinMain(
  770. HINSTANCE hInstance,
  771. HINSTANCE /* hPrevInstance */ ,
  772. PSTR /* lpszCmdLine */ ,
  773. int /* nCmdShow */)
  774. {
  775. hResourceModuleHandle = hInstance;
  776. ExitCode exitCode = EXIT_CODE_UNSUCCESSFUL;
  777. try
  778. {
  779. HRESULT hr =
  780. // ISSUE-2002/02/25-sburns This is a global named object. See
  781. // NTRAID#NTBUG9-525195-2002/02/25-sburns
  782. Win::CreateMutex(
  783. 0,
  784. true,
  785. // The mutex name has the "Global" prefix so ts users will see it.
  786. // NTRAID#NTBUG9-404808-2001/05/29-sburns
  787. // If you ever change this, change IsDcpromoRunning in
  788. // burnslib\src\dsutil.cpp too.
  789. // NTRAID#NTBUG9-498351-2001/11/21-sburns
  790. String(L"Global\\") + RUNTIME_NAME,
  791. dcpromoRunningMutex);
  792. if (hr == Win32ToHresult(ERROR_ALREADY_EXISTS))
  793. {
  794. // Close the mutex so that the truly clueless admin won't get confused
  795. // that the popup we're about to raise should be closed before he tries
  796. // to launch the wizard again. Sheesh!
  797. // NTRAID#NTBUG9-404808-2001/05/29-sburns (bis)
  798. Win::CloseHandle(dcpromoRunningMutex);
  799. popup.Error(Win::GetDesktopWindow(), IDS_ALREADY_RUNNING);
  800. }
  801. else
  802. {
  803. AutoCoInitialize coInit;
  804. hr = coInit.Result();
  805. ASSERT(SUCCEEDED(hr));
  806. // change structure instance name so as not to accidentally offend
  807. // the sensibilities of the delicate reader.
  808. // NTRAID#NTBUG9-382719-2001/05/01-sburns
  809. INITCOMMONCONTROLSEX init_structure_not_to_contain_a_naughty_word;
  810. init_structure_not_to_contain_a_naughty_word.dwSize =
  811. sizeof(init_structure_not_to_contain_a_naughty_word);
  812. init_structure_not_to_contain_a_naughty_word.dwICC =
  813. ICC_ANIMATE_CLASS | ICC_USEREX_CLASSES;
  814. BOOL init =
  815. ::InitCommonControlsEx(&init_structure_not_to_contain_a_naughty_word);
  816. ASSERT(init);
  817. State::Init();
  818. if (State::GetInstance().NeedsCommandLineHelp())
  819. {
  820. ShowCommandLineHelp();
  821. }
  822. else
  823. {
  824. exitCode = Start();
  825. }
  826. State::Destroy();
  827. }
  828. }
  829. catch (Error& err)
  830. {
  831. popup.Error(Win::GetDesktopWindow(), err.GetMessage());
  832. }
  833. catch (...)
  834. {
  835. LOG(L"unhandled exception caught");
  836. popup.Error(Win::GetDesktopWindow(), IDS_UNHANDLED_EXCEPTION);
  837. }
  838. return static_cast<int>(exitCode);
  839. }