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.

1472 lines
39 KiB

  1. // Copyright (c) 1997-1999 Microsoft Corporation
  2. //
  3. // DS API wrappers
  4. //
  5. // 12-16-97 sburns
  6. #include "headers.hxx"
  7. #include "ds.hpp"
  8. #include "resource.h"
  9. #include "state.hpp"
  10. #include "common.hpp"
  11. #include "ProgressDialog.hpp"
  12. // CODEWORK: remove the exception throwing architecture.
  13. DS::Error::Error(HRESULT hr_, int summaryResID)
  14. :
  15. Win::Error(hr_, summaryResID)
  16. {
  17. }
  18. DS::Error::Error(HRESULT hr_, const String& msg, const String& sum)
  19. :
  20. Win::Error(hr_, msg, sum)
  21. {
  22. }
  23. bool
  24. DS::IsDomainNameInUse(const String& domainName)
  25. {
  26. LOG_FUNCTION(DS::IsDomainNameInUse);
  27. ASSERT(!domainName.empty());
  28. bool result = false;
  29. if (!domainName.empty())
  30. {
  31. HRESULT hr = MyNetValidateName(domainName, ::NetSetupNonExistentDomain);
  32. if (hr == Win32ToHresult(ERROR_DUP_NAME))
  33. {
  34. result = true;
  35. }
  36. }
  37. LOG(
  38. String::format(
  39. L"The domain name %1 %2 in use.",
  40. domainName.c_str(),
  41. result ? L"is" : L"is NOT"));
  42. return result;
  43. }
  44. bool
  45. DS::DisjoinDomain()
  46. throw (DS::Error)
  47. {
  48. LOG_FUNCTION(DS::DisjoinDomain);
  49. // make 1st attempt assuming that the current user has account
  50. // deletion priv on the domain.
  51. LOG(L"Calling NetUnjoinDomain (w/ account delete)");
  52. HRESULT hr =
  53. Win32ToHresult(
  54. ::NetUnjoinDomain(
  55. 0, // this server
  56. 0, // current account,
  57. 0, // current password
  58. NETSETUP_ACCT_DELETE));
  59. LOG_HRESULT(hr);
  60. if (FAILED(hr))
  61. {
  62. // make another attempt, not removing the computer account
  63. LOG(L"Calling NetUnjoinDomain again, w/o account delete");
  64. hr = Win32ToHresult(::NetUnjoinDomain(0, 0, 0, 0));
  65. LOG_HRESULT(hr);
  66. if (SUCCEEDED(hr))
  67. {
  68. // the unjoin was successful, but the computer account was
  69. // left behind.
  70. return false;
  71. }
  72. }
  73. if (FAILED(hr))
  74. {
  75. throw DS::Error(hr, IDS_DISJOIN_DOMAIN_FAILED);
  76. }
  77. return true;
  78. }
  79. void
  80. DS::JoinDomain(
  81. const String& domainDNSName,
  82. const String& dcName,
  83. const String& userName,
  84. const EncryptedString& password,
  85. const String& userDomainName)
  86. throw (DS::Error)
  87. {
  88. LOG_FUNCTION(DS::JoinDomain);
  89. ASSERT(!domainDNSName.empty());
  90. ASSERT(!userName.empty());
  91. // password may be empty
  92. ULONG flags =
  93. NETSETUP_JOIN_DOMAIN
  94. | NETSETUP_ACCT_CREATE
  95. | NETSETUP_DOMAIN_JOIN_IF_JOINED
  96. | NETSETUP_ACCT_DELETE;
  97. String massagedUserName = MassageUserName(userDomainName, userName);
  98. String domain = domainDNSName;
  99. if (!dcName.empty())
  100. {
  101. domain += L"\\" + dcName;
  102. }
  103. HRESULT hr =
  104. MyNetJoinDomain(
  105. domain.c_str(),
  106. massagedUserName.c_str(),
  107. password,
  108. flags);
  109. LOG_HRESULT(hr);
  110. if (FAILED(hr))
  111. {
  112. State& state = State::GetInstance();
  113. state.SetOperationResultsMessage(
  114. String::format(IDS_UNABLE_TO_JOIN_DOMAIN, domainDNSName.c_str()));
  115. throw DS::Error(hr, IDS_JOIN_DOMAIN_FAILED);
  116. }
  117. }
  118. DWORD
  119. MyDsRoleCancel(DSROLE_SERVEROP_HANDLE& handle)
  120. {
  121. LOG(L"Calling DsRoleCancel");
  122. LOG(L"lpServer : (null)");
  123. DWORD status = ::DsRoleCancel(0, handle);
  124. LOG(String::format(L"Error 0x%1!X! (!0 => error)", status));
  125. return status;
  126. }
  127. DWORD
  128. MyDsRoleGetDcOperationProgress(
  129. DSROLE_SERVEROP_HANDLE& handle,
  130. DSROLE_SERVEROP_STATUS*& status)
  131. {
  132. // LOG(L"Calling DsRoleGetDcOperationProgress");
  133. status = 0;
  134. DWORD err = ::DsRoleGetDcOperationProgress(0, handle, &status);
  135. // LOG(
  136. // String::format(
  137. // L"Error 0x%1!X! (!0 => error, 0x%2!X! = ERROR_IO_PENDING)",
  138. // err,
  139. // ERROR_IO_PENDING));
  140. // if (status)
  141. // {
  142. // LOG(
  143. // String::format(
  144. // L"OperationStatus : 0x%1!X!",
  145. // status->OperationStatus));
  146. // LOG(status->CurrentOperationDisplayString);
  147. // }
  148. // DWORD err = ERROR_IO_PENDING;
  149. // status = new DSROLE_SERVEROP_STATUS;
  150. // status->CurrentOperationDisplayString = L"proceeding";
  151. // status->OperationStatus = 0;
  152. return err;
  153. }
  154. void
  155. DoProgressLoop(
  156. DSROLE_SERVEROP_HANDLE& handle,
  157. ProgressDialog& progressDialog)
  158. throw (DS::Error)
  159. {
  160. LOG_FUNCTION(DoProgressLoop);
  161. State& state = State::GetInstance();
  162. if (state.GetOperation() == State::DEMOTE)
  163. {
  164. // not cancelable -- turn off the cancel button.
  165. progressDialog.UpdateButton(String());
  166. }
  167. else
  168. {
  169. // turn on the cancel button.
  170. progressDialog.UpdateButton(IDS_PROGRESS_CANCEL);
  171. }
  172. DWORD netErr = 0;
  173. bool criticalComplete = false;
  174. bool buttonUpdatedToFinishLater = false;
  175. String lastMessage;
  176. ProgressDialog::WaitCode cancelButton;
  177. do
  178. {
  179. // wait 1500ms or for the user to hit cancel
  180. cancelButton = progressDialog.WaitForButton(1500);
  181. // get the current status of the operation
  182. DSROLE_SERVEROP_STATUS* status = 0;
  183. netErr = MyDsRoleGetDcOperationProgress(handle, status);
  184. if (netErr != ERROR_SUCCESS && netErr != ERROR_IO_PENDING)
  185. {
  186. // operation complete
  187. break;
  188. }
  189. if (!status)
  190. {
  191. LOG(L"Operation status not returned!");
  192. ASSERT(false);
  193. continue;
  194. }
  195. // update the message display
  196. String message = status->CurrentOperationDisplayString;
  197. if (message != lastMessage)
  198. {
  199. progressDialog.UpdateText(message);
  200. lastMessage = message;
  201. }
  202. // save the status flags for later use.
  203. ULONG statusFlags = status->OperationStatus;
  204. ::DsRoleFreeMemory(status);
  205. do
  206. {
  207. if (cancelButton != ProgressDialog::PRESSED)
  208. {
  209. break;
  210. }
  211. // if we make it here, user pressed the cancel button
  212. LOG(L"DoProgressLoop: handling cancel");
  213. ASSERT(state.GetOperation() != State::DEMOTE);
  214. if (criticalComplete)
  215. {
  216. // inform the user that the install is done, and that they're
  217. // cancelling the non-critical replication.
  218. popup.Info(
  219. progressDialog.GetHWND(),
  220. String::load(IDS_CANCEL_NON_CRITICAL_REPLICATION));
  221. // this should return ERROR_SUCCESS, and the promotion will
  222. // be considered complete.
  223. progressDialog.UpdateText(IDS_CANCELLING_REPLICATION);
  224. progressDialog.UpdateAnimation(IDR_AVI_DEMOTE);
  225. netErr = MyDsRoleCancel(handle);
  226. // fall out of the inner, then the outer, loop. Then we will
  227. // get the operation results, which should indicate that the
  228. // promotion is complete, and non-critical replication was
  229. // canceled.
  230. break;
  231. }
  232. // Still doing promote, verify that the user really wants to roll
  233. // back to server state.
  234. if (
  235. popup.MessageBox(
  236. progressDialog.GetHWND(),
  237. String::load(IDS_CANCEL_PROMOTE),
  238. MB_YESNO | MB_ICONWARNING) == IDYES)
  239. {
  240. // this should return ERROR_SUCCESS, and the promotion will
  241. // be rolled back.
  242. progressDialog.UpdateText(IDS_CANCELLING);
  243. progressDialog.UpdateAnimation(IDR_AVI_DEMOTE);
  244. netErr = MyDsRoleCancel(handle);
  245. // fall out of the inner, then the outer, loop. Then we will
  246. // get the operation results, which should indicate that the
  247. // promotion was cancelled as a failure code. We handle this
  248. // failure code in the same manner as all others.
  249. break;
  250. }
  251. // user decided to press on. reset the cancel button
  252. progressDialog.UpdateButton(IDS_PROGRESS_CANCEL);
  253. progressDialog.RevertToOriginalAnimation();
  254. buttonUpdatedToFinishLater = false;
  255. }
  256. while (0);
  257. criticalComplete =
  258. criticalComplete
  259. || statusFlags & DSROLE_CRITICAL_OPERATIONS_COMPLETED;
  260. if (criticalComplete)
  261. {
  262. if (cancelButton == ProgressDialog::PRESSED)
  263. {
  264. // we add this message without actually checking the operation
  265. // results flags because for all we know, the replication will
  266. // finish before we get around to checking. It is still correct
  267. // to say the the replication has stopped, and will start after
  268. // reboot. This is always the case.
  269. state.AddFinishMessage(
  270. String::load(IDS_NON_CRITICAL_REPLICATION_CANCELED));
  271. }
  272. else
  273. {
  274. if (!buttonUpdatedToFinishLater)
  275. {
  276. progressDialog.UpdateButton(IDS_FINISH_REPLICATION_LATER);
  277. buttonUpdatedToFinishLater = true;
  278. }
  279. }
  280. }
  281. }
  282. while (netErr == ERROR_IO_PENDING);
  283. progressDialog.UpdateButton(String());
  284. buttonUpdatedToFinishLater = false;
  285. LOG(L"Progress loop complete.");
  286. if (netErr == ERROR_SUCCESS)
  287. {
  288. // we successfully endured the wait. let's see how it turned out.
  289. DSROLE_SERVEROP_RESULTS* results;
  290. LOG(L"Calling DsRoleGetDcOperationResults");
  291. netErr = ::DsRoleGetDcOperationResults(0, handle, &results);
  292. LOG(String::format(L"Error 0x%1!X! (!0 => error)", netErr));
  293. if (netErr == ERROR_SUCCESS)
  294. {
  295. // we got the results
  296. ASSERT(results);
  297. if (results)
  298. {
  299. LOG(L"Operation results:");
  300. LOG(
  301. String::format(
  302. L"OperationStatus : 0x%1!X! !0 => error",
  303. results->OperationStatus));
  304. LOG(
  305. String::format(
  306. L"DisplayString : %1",
  307. results->OperationStatusDisplayString));
  308. LOG(
  309. String::format(
  310. L"ServerInstalledSite : %1",
  311. results->ServerInstalledSite));
  312. LOG(
  313. String::format(
  314. L"OperationResultsFlags: 0x%1!X!",
  315. results->OperationResultsFlags));
  316. netErr = results->OperationStatus;
  317. // here, netErr will be some error code if the promote was
  318. // cancelled and successfully rolled back. Since it may be
  319. // possible that the cancel was too late (e.g. the user took
  320. // too long to confirm the cancel), the promote may have
  321. // finished. If that's the case, tell the user that the cancel
  322. // failed.
  323. if (
  324. netErr == ERROR_SUCCESS
  325. && cancelButton == ProgressDialog::PRESSED)
  326. {
  327. // the promote finished, and the cancel button was pressed.
  328. if (!criticalComplete) // 363590
  329. {
  330. // we didn't find out if the non-critical replication phase
  331. // started. So the cancel button still said 'Cancel', and
  332. // yet, the operation finished. so, this means that the
  333. // promote simply completed before the cancel was received.
  334. popup.Info(
  335. progressDialog.GetHWND(),
  336. IDS_CANCEL_TOO_LATE);
  337. }
  338. }
  339. String message =
  340. results->OperationStatusDisplayString
  341. ? results->OperationStatusDisplayString
  342. : L"";
  343. String site =
  344. results->ServerInstalledSite
  345. ? results->ServerInstalledSite
  346. : L"";
  347. progressDialog.UpdateText(message);
  348. if (!site.empty())
  349. {
  350. state.SetInstalledSite(site);
  351. }
  352. if (!message.empty())
  353. {
  354. state.SetOperationResultsMessage(message);
  355. }
  356. state.SetOperationResultsFlags(results->OperationResultsFlags);
  357. if (
  358. results->OperationResultsFlags
  359. & DSROLE_NON_FATAL_ERROR_OCCURRED)
  360. {
  361. state.AddFinishMessage(
  362. String::load(IDS_NON_FATAL_ERRORS_OCCURRED));
  363. }
  364. if (
  365. (results->OperationResultsFlags
  366. & DSROLE_NON_CRITICAL_REPL_NOT_FINISHED)
  367. && cancelButton != ProgressDialog::PRESSED )
  368. {
  369. // cancel not pressed and critial replication bombed
  370. state.AddFinishMessage(
  371. String::load(IDS_NON_CRITICAL_REPL_FAILED));
  372. }
  373. if (
  374. results->OperationResultsFlags
  375. & DSROLE_IFM_RESTORED_DATABASE_FILES_MOVED)
  376. {
  377. LOG(L"restored files were moved");
  378. if (netErr != ERROR_SUCCESS)
  379. {
  380. // only need to mention this in the case of a fatal failure;
  381. // e.g. don't add this finish text if non-fatal errors
  382. // occurred.
  383. // NTRAID#NTBUG9-330378-2001/02/28-sburns
  384. state.AddFinishMessage(
  385. String::load(IDS_MUST_RESTORE_IFM_FILES_AGAIN));
  386. }
  387. }
  388. ::DsRoleFreeMemory(results);
  389. }
  390. }
  391. }
  392. if (netErr != ERROR_SUCCESS)
  393. {
  394. // couldn't get progress updates, or couldn't get results,
  395. // or result was a failure
  396. throw DS::Error(Win32ToHresult(netErr), IDS_WIZARD_TITLE);
  397. }
  398. }
  399. void
  400. EmptyFolder(const String& path)
  401. throw (DS::Error)
  402. {
  403. LOG_FUNCTION2(EmptyFolder, path);
  404. ASSERT(FS::PathExists(path));
  405. // check for files/subfolders once again (we checked the first time on
  406. // validating the path), in case something has written to the folder
  407. // since we validated it last.
  408. if (!FS::IsFolderEmpty(path))
  409. {
  410. // nuke the files in the directory
  411. LOG(String::format(L"Emptying %1", path.c_str()));
  412. String wild = path;
  413. // REVIEW: wild[wild.length() - 1] is the same as *(wild.rbegin())
  414. // which is cheaper?
  415. if (wild[wild.length() - 1] != L'\\')
  416. {
  417. wild += L"\\";
  418. }
  419. wild += L"*.*";
  420. FS::Iterator iter(
  421. wild,
  422. FS::Iterator::INCLUDE_FILES
  423. | FS::Iterator::RETURN_FULL_PATHS);
  424. HRESULT hr = S_OK;
  425. String current;
  426. while ((hr = iter.GetCurrent(current)) == S_OK)
  427. {
  428. LOG(String::format(L"Deleting %1", current.c_str()));
  429. hr = Win::DeleteFile(current);
  430. if (FAILED(hr))
  431. {
  432. int msgId = IDS_EMPTY_DIR_FAILED;
  433. if (hr == Win32ToHresult(ERROR_ACCESS_DENIED))
  434. {
  435. msgId = IDS_EMPTY_DIR_FAILED_ACCESS_DENIED;
  436. }
  437. throw
  438. DS::Error(
  439. S_OK, // so as not to trigger credentials dialog
  440. String::format(
  441. msgId,
  442. GetErrorMessage(hr).c_str(),
  443. path.c_str()),
  444. String::load(IDS_ERROR_PREPARING_OPERATION));
  445. }
  446. hr = iter.Increment();
  447. BREAK_ON_FAILED_HRESULT(hr);
  448. }
  449. }
  450. }
  451. HRESULT
  452. SetupPaths()
  453. {
  454. LOG_FUNCTION(SetupPaths);
  455. State& state = State::GetInstance();
  456. String dbPath = state.GetDatabasePath();
  457. String logPath = state.GetLogPath();
  458. String sysvolPath = state.GetSYSVOLPath();
  459. ASSERT(!dbPath.empty());
  460. ASSERT(!logPath.empty());
  461. ASSERT(!sysvolPath.empty());
  462. HRESULT hr = S_OK;
  463. do
  464. {
  465. if (FS::PathExists(dbPath))
  466. {
  467. EmptyFolder(dbPath);
  468. }
  469. else
  470. {
  471. hr = FS::CreateFolder(dbPath);
  472. BREAK_ON_FAILED_HRESULT(hr);
  473. }
  474. if (FS::PathExists(logPath))
  475. {
  476. EmptyFolder(logPath);
  477. }
  478. else
  479. {
  480. hr = FS::CreateFolder(logPath);
  481. BREAK_ON_FAILED_HRESULT(hr);
  482. }
  483. if (FS::PathExists(sysvolPath))
  484. {
  485. EmptyFolder(sysvolPath);
  486. }
  487. else
  488. {
  489. hr = FS::CreateFolder(sysvolPath);
  490. BREAK_ON_FAILED_HRESULT(hr);
  491. }
  492. }
  493. while (0);
  494. return hr;
  495. }
  496. // Sets the promotion flags based on options set in the unattended execution
  497. // answerfile.
  498. //
  499. // state - IN reference to the global State object
  500. //
  501. // flags - IN/OUT promote API flags, may be modified on exit
  502. void
  503. SetAnswerFilePromoteFlags(
  504. State& state,
  505. ULONG& flags)
  506. {
  507. LOG_FUNCTION(SetAnswerFilePromoteFlags);
  508. if (state.UsingAnswerFile())
  509. {
  510. // set flags based on unattended execution options
  511. // if the safe mode admin password is not specified, then we set a
  512. // flag to cause the promote APIs to copy the current local admin
  513. // password.
  514. EncryptedString safeModePassword = state.GetSafeModeAdminPassword();
  515. if (safeModePassword.IsEmpty() && state.RunHiddenUnattended())
  516. {
  517. // user did not supply a safemode password, and he did not have
  518. // an opportunity to do so (if the wizard went interactive)
  519. if (!state.IsSafeModeAdminPwdOptionPresent())
  520. {
  521. // the safe mode pwd key is not present in the answerfile
  522. flags |= DSROLE_DC_DEFAULT_REPAIR_PWD;
  523. }
  524. }
  525. String option =
  526. state.GetAnswerFileOption(
  527. AnswerFile::OPTION_CRITICAL_REPLICATION_ONLY);
  528. if (option.icompare(AnswerFile::VALUE_YES) == 0)
  529. {
  530. flags |= DSROLE_DC_CRITICAL_REPLICATION_ONLY;
  531. }
  532. }
  533. LOG(String::format(L"0x%1!X!", flags));
  534. }
  535. void
  536. DS::CreateReplica(ProgressDialog& progressDialog, bool invokeForUpgrade)
  537. throw (DS::Error)
  538. {
  539. LOG_FUNCTION(DS::CreateReplica);
  540. State& state = State::GetInstance();
  541. String domain = state.GetReplicaDomainDNSName();
  542. String dbPath = state.GetDatabasePath();
  543. String logPath = state.GetLogPath();
  544. String sysvolPath = state.GetSYSVOLPath();
  545. String site = state.GetSiteName();
  546. String username = state.GetUsername();
  547. String replicationDc = state.GetReplicationPartnerDC();
  548. String sourcePath = state.GetReplicationSourcePath();
  549. bool useSourcePath = state.ReplicateFromMedia();
  550. EncryptedString syskey = state.GetSyskey();
  551. EncryptedString safeModePassword = state.GetSafeModeAdminPassword();
  552. EncryptedString password = state.GetPassword();
  553. bool useCurrentUserCreds = username.empty();
  554. ULONG flags =
  555. DSROLE_DC_FORCE_TIME_SYNC
  556. | DSROLE_DC_CREATE_TRUST_AS_REQUIRED;
  557. if (invokeForUpgrade)
  558. {
  559. flags |= DSROLE_DC_DOWNLEVEL_UPGRADE;
  560. }
  561. if (state.GetDomainControllerReinstallFlag())
  562. {
  563. flags |= DSROLE_DC_ALLOW_DC_REINSTALL;
  564. }
  565. SetAnswerFilePromoteFlags(state, flags);
  566. if (useSourcePath)
  567. {
  568. if (state.GetRestoreGc())
  569. {
  570. flags |= DSROLE_DC_REQUEST_GC;
  571. }
  572. }
  573. ASSERT(!domain.empty());
  574. if (!useCurrentUserCreds)
  575. {
  576. String user_domain = state.GetUserDomainName();
  577. username = MassageUserName(user_domain, username);
  578. }
  579. HRESULT hr = S_OK;
  580. do
  581. {
  582. hr = SetupPaths();
  583. BREAK_ON_FAILED_HRESULT(hr);
  584. LOG(L"Calling DsRoleDcAsReplica");
  585. LOG( L"lpServer : (null)");
  586. LOG(String::format(L"lpDnsDomainName : %1", domain.c_str()));
  587. LOG(String::format(L"lpReplicaServer : %1", replicationDc.empty() ? L"(null)" : replicationDc.c_str()));
  588. LOG(String::format(L"lpSiteName : %1", site.empty() ? L"(null)" : site.c_str()));
  589. LOG(String::format(L"lpDsDatabasePath : %1", dbPath.c_str()));
  590. LOG(String::format(L"lpDsLogPath : %1", logPath.c_str()));
  591. LOG(String::format(L"lpRestorePath : %1", useSourcePath ? sourcePath.c_str() : L"(null)"));
  592. LOG(String::format(L"lpSystemVolumeRootPath : %1", sysvolPath.c_str()));
  593. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  594. LOG(String::format(L"Options : 0x%1!X!", flags));
  595. WCHAR* safeModePasswordCopy = 0;
  596. if (!safeModePassword.IsEmpty())
  597. {
  598. safeModePasswordCopy = safeModePassword.GetClearTextCopy();
  599. }
  600. WCHAR* passwordCopy = 0;
  601. if (!useCurrentUserCreds)
  602. {
  603. passwordCopy = password.GetClearTextCopy();
  604. }
  605. // The api wants to scribble over the syskey, so we make a copy for
  606. // it to do so.
  607. WCHAR* syskeyCopy = 0;
  608. if (useSourcePath && !syskey.IsEmpty())
  609. {
  610. syskeyCopy = syskey.GetClearTextCopy();
  611. }
  612. DSROLE_SERVEROP_HANDLE handle = 0;
  613. hr =
  614. Win32ToHresult(
  615. ::DsRoleDcAsReplica(
  616. 0, // this server
  617. domain.c_str(),
  618. // possibly empty, e.g. if we didn't join a domain...
  619. replicationDc.empty() ? 0 : replicationDc.c_str(),
  620. site.empty() ? 0 : site.c_str(),
  621. dbPath.c_str(),
  622. logPath.c_str(),
  623. useSourcePath ? sourcePath.c_str() : 0,
  624. sysvolPath.c_str(),
  625. syskeyCopy,
  626. (useCurrentUserCreds ? 0 : username.c_str()),
  627. passwordCopy,
  628. safeModePasswordCopy,
  629. flags,
  630. &handle));
  631. if (safeModePasswordCopy)
  632. {
  633. safeModePassword.DestroyClearTextCopy(safeModePasswordCopy);
  634. }
  635. if (passwordCopy)
  636. {
  637. password.DestroyClearTextCopy(passwordCopy);
  638. }
  639. if (syskeyCopy)
  640. {
  641. syskey.DestroyClearTextCopy(syskeyCopy);
  642. }
  643. BREAK_ON_FAILED_HRESULT(hr);
  644. DoProgressLoop(handle, progressDialog);
  645. }
  646. while (0);
  647. if (FAILED(hr))
  648. {
  649. throw DS::Error(hr, IDS_WIZARD_TITLE);
  650. }
  651. }
  652. void
  653. DS::CreateNewDomain(ProgressDialog& progressDialog)
  654. throw (DS::Error)
  655. {
  656. LOG_FUNCTION(DS::CreateNewDomain);
  657. State& state = State::GetInstance();
  658. String domain = state.GetNewDomainDNSName();
  659. String flatName = state.GetNewDomainNetbiosName();
  660. String site = state.GetSiteName();
  661. String dbPath = state.GetDatabasePath();
  662. String logPath = state.GetLogPath();
  663. String sysvolPath = state.GetSYSVOLPath();
  664. String parent = state.GetParentDomainDnsName();
  665. String username = state.GetUsername();
  666. EncryptedString password = state.GetPassword();
  667. EncryptedString safeModePassword = state.GetSafeModeAdminPassword();
  668. EncryptedString adminPassword = state.GetAdminPassword();
  669. State::Operation operation = state.GetOperation();
  670. bool useParent =
  671. ( operation == State::TREE
  672. || operation == State::CHILD);
  673. bool useCurrentUserCreds = username.empty();
  674. ULONG flags =
  675. DSROLE_DC_CREATE_TRUST_AS_REQUIRED
  676. | DSROLE_DC_FORCE_TIME_SYNC;
  677. if (state.GetDomainReinstallFlag())
  678. {
  679. flags |= DSROLE_DC_ALLOW_DOMAIN_REINSTALL;
  680. }
  681. if (state.GetDomainControllerReinstallFlag())
  682. {
  683. flags |= DSROLE_DC_ALLOW_DC_REINSTALL;
  684. }
  685. if (operation == State::TREE)
  686. {
  687. flags |= DSROLE_DC_TRUST_AS_ROOT;
  688. ASSERT(!parent.empty());
  689. }
  690. SetAnswerFilePromoteFlags(state, flags);
  691. if (state.ShouldAllowAnonymousAccess())
  692. {
  693. flags |= DSROLE_DC_ALLOW_ANONYMOUS_ACCESS;
  694. }
  695. if (operation == State::FOREST)
  696. {
  697. flags |= DSROLE_DC_NO_NET;
  698. ASSERT(!site.empty());
  699. }
  700. #ifdef DBG
  701. else if (operation == State::CHILD)
  702. {
  703. ASSERT(!parent.empty());
  704. }
  705. ASSERT(!domain.empty());
  706. ASSERT(!flatName.empty());
  707. // parent may be empty
  708. #endif
  709. if (!useCurrentUserCreds)
  710. {
  711. String userDomain = state.GetUserDomainName();
  712. username = MassageUserName(userDomain, username);
  713. }
  714. HRESULT hr = S_OK;
  715. do
  716. {
  717. hr = SetupPaths();
  718. BREAK_ON_FAILED_HRESULT(hr);
  719. LOG(L"Calling DsRoleDcAsDc");
  720. LOG( L"lpServer : (null)");
  721. LOG(String::format(L"lpDnsDomainName : %1", domain.c_str()));
  722. LOG(String::format(L"lpFlatDomainName : %1", flatName.c_str()));
  723. LOG(String::format(L"lpSiteName : %1", site.empty() ? L"(null)" : site.c_str()));
  724. LOG(String::format(L"lpDsDatabasePath : %1", dbPath.c_str()));
  725. LOG(String::format(L"lpDsLogPath : %1", logPath.c_str()));
  726. LOG(String::format(L"lpSystemVolumeRootPath : %1", sysvolPath.c_str()));
  727. LOG(String::format(L"lpParentDnsDomainName : %1", useParent ? parent.c_str() : L"(null)"));
  728. LOG( L"lpParentServer : (null)");
  729. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  730. LOG(String::format(L"Options : 0x%1!X!", flags));
  731. WCHAR* safeModePasswordCopy = 0;
  732. if (!safeModePassword.IsEmpty())
  733. {
  734. safeModePasswordCopy = safeModePassword.GetClearTextCopy();
  735. }
  736. WCHAR* adminPasswordCopy = 0;
  737. if (!adminPassword.IsEmpty())
  738. {
  739. adminPasswordCopy = adminPassword.GetClearTextCopy();
  740. }
  741. WCHAR* passwordCopy = 0;
  742. if (!useCurrentUserCreds)
  743. {
  744. passwordCopy = password.GetClearTextCopy();
  745. }
  746. DSROLE_SERVEROP_HANDLE handle = 0;
  747. hr =
  748. Win32ToHresult(
  749. DsRoleDcAsDc(
  750. 0, // this server
  751. domain.c_str(),
  752. flatName.c_str(),
  753. adminPasswordCopy,
  754. site.empty() ? 0 : site.c_str(),
  755. dbPath.c_str(),
  756. logPath.c_str(),
  757. sysvolPath.c_str(),
  758. (useParent ? parent.c_str() : 0),
  759. 0, // let API pick a server
  760. (useCurrentUserCreds ? 0 : username.c_str()),
  761. passwordCopy,
  762. safeModePasswordCopy,
  763. flags,
  764. &handle));
  765. BREAK_ON_FAILED_HRESULT(hr);
  766. if (safeModePasswordCopy)
  767. {
  768. safeModePassword.DestroyClearTextCopy(safeModePasswordCopy);
  769. }
  770. if (adminPasswordCopy)
  771. {
  772. adminPassword.DestroyClearTextCopy(adminPasswordCopy);
  773. }
  774. if (passwordCopy)
  775. {
  776. password.DestroyClearTextCopy(passwordCopy);
  777. }
  778. DoProgressLoop(handle, progressDialog);
  779. }
  780. while (0);
  781. if (FAILED(hr))
  782. {
  783. throw DS::Error(hr, IDS_WIZARD_TITLE);
  784. }
  785. }
  786. void
  787. DS::UpgradeBDC(ProgressDialog& progressDialog)
  788. throw (DS::Error)
  789. {
  790. LOG_FUNCTION(DS::UpgradeBDC);
  791. // seems non-intuitive to abort the upgrade to do the upgrade, but here
  792. // the abort removes dcpromo autostart, and turns the machine into a
  793. // standalone server. Then we proceed to make it a replica.
  794. DS::AbortBDCUpgrade(true);
  795. DS::CreateReplica(progressDialog, true);
  796. }
  797. void
  798. DS::UpgradePDC(ProgressDialog& progressDialog)
  799. throw (DS::Error)
  800. {
  801. LOG_FUNCTION(DS::UpgradePDC);
  802. State& state = State::GetInstance();
  803. ASSERT(state.GetRunContext() == State::PDC_UPGRADE);
  804. String domain = state.GetNewDomainDNSName();
  805. String site = state.GetSiteName();
  806. String dbPath = state.GetDatabasePath();
  807. String logPath = state.GetLogPath();
  808. String sysvolPath = state.GetSYSVOLPath();
  809. String parent = state.GetParentDomainDnsName();
  810. String username = state.GetUsername();
  811. EncryptedString password = state.GetPassword();
  812. EncryptedString safeModePassword = state.GetSafeModeAdminPassword();
  813. State::Operation operation = state.GetOperation();
  814. bool useParent =
  815. ( operation == State::TREE
  816. || operation == State::CHILD);
  817. bool useCurrentUserCreds = username.empty();
  818. ULONG flags = DSROLE_DC_CREATE_TRUST_AS_REQUIRED;
  819. if (state.GetDomainReinstallFlag())
  820. {
  821. flags |= DSROLE_DC_ALLOW_DOMAIN_REINSTALL;
  822. }
  823. if (state.GetDomainControllerReinstallFlag())
  824. {
  825. flags |= DSROLE_DC_ALLOW_DC_REINSTALL;
  826. }
  827. if (state.GetSetForestVersionFlag())
  828. {
  829. flags |= DSROLE_DC_SET_FOREST_CURRENT;
  830. }
  831. if (operation == State::TREE)
  832. {
  833. flags |= DSROLE_DC_TRUST_AS_ROOT | DSROLE_DC_FORCE_TIME_SYNC;
  834. ASSERT(!parent.empty());
  835. }
  836. else if (operation == State::CHILD)
  837. {
  838. flags |= DSROLE_DC_FORCE_TIME_SYNC;
  839. ASSERT(!parent.empty());
  840. }
  841. SetAnswerFilePromoteFlags(state, flags);
  842. if (state.ShouldAllowAnonymousAccess())
  843. {
  844. flags |= DSROLE_DC_ALLOW_ANONYMOUS_ACCESS;
  845. }
  846. #ifdef DBG
  847. ASSERT(!domain.empty());
  848. // parent may be empty
  849. if (operation == State::FOREST)
  850. {
  851. ASSERT(!site.empty());
  852. }
  853. #endif
  854. if (!useCurrentUserCreds)
  855. {
  856. String userDomain = state.GetUserDomainName();
  857. username = MassageUserName(userDomain, username);
  858. }
  859. HRESULT hr = S_OK;
  860. do
  861. {
  862. hr = SetupPaths();
  863. BREAK_ON_FAILED_HRESULT(hr);
  864. LOG(L"Calling DsRoleUpgradeDownlevelServer");
  865. LOG(String::format(L"lpDnsDomainName : %1", domain.c_str()));
  866. LOG(String::format(L"lpSiteName : %1", site.empty() ? L"(null)" : site.c_str()));
  867. LOG(String::format(L"lpDsDatabasePath : %1", dbPath.c_str()));
  868. LOG(String::format(L"lpDsLogPath : %1", logPath.c_str()));
  869. LOG(String::format(L"lpSystemVolumeRootPath : %1", sysvolPath.c_str()));
  870. LOG(String::format(L"lpParentDnsDomainName : %1", useParent ? parent.c_str() : L"(null)"));
  871. LOG( L"lpParentServer : (null)");
  872. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  873. LOG(String::format(L"Options : 0x%1!X!", flags));
  874. WCHAR* safeModePasswordCopy = 0;
  875. if (!safeModePassword.IsEmpty())
  876. {
  877. safeModePasswordCopy = safeModePassword.GetClearTextCopy();
  878. }
  879. WCHAR* passwordCopy = 0;
  880. if (!useCurrentUserCreds)
  881. {
  882. passwordCopy = password.GetClearTextCopy();
  883. }
  884. DSROLE_SERVEROP_HANDLE handle = 0;
  885. hr =
  886. Win32ToHresult(
  887. ::DsRoleUpgradeDownlevelServer(
  888. domain.c_str(),
  889. site.empty() ? 0 : site.c_str(),
  890. dbPath.c_str(),
  891. logPath.c_str(),
  892. sysvolPath.c_str(),
  893. (useParent ? parent.c_str() : 0),
  894. 0, // let API pick a server
  895. (useCurrentUserCreds ? 0 : username.c_str()),
  896. passwordCopy,
  897. safeModePasswordCopy,
  898. flags,
  899. &handle));
  900. BREAK_ON_FAILED_HRESULT(hr);
  901. if (safeModePasswordCopy)
  902. {
  903. safeModePassword.DestroyClearTextCopy(safeModePasswordCopy);
  904. }
  905. if (passwordCopy)
  906. {
  907. password.DestroyClearTextCopy(passwordCopy);
  908. }
  909. DoProgressLoop(handle, progressDialog);
  910. }
  911. while (0);
  912. if (FAILED(hr))
  913. {
  914. throw DS::Error(hr, IDS_UPGRADE_DC_FAILED);
  915. }
  916. }
  917. // Converts the list of ndncs into a form more easily digestible by the demote
  918. // API: an array of null-terminated arrays of WCHAR, with the last element a
  919. // null. The result must be deallocated by DeallocateAppPartitionList.
  920. //
  921. // entryCount - out, receieves the number of strings allocated.
  922. PCWSTR*
  923. AllocateAppPartitionList(int& entryCount)
  924. {
  925. LOG_FUNCTION(AllocateAppPartitionList);
  926. const StringList& ndncList = State::GetInstance().GetAppPartitionList();
  927. entryCount = 0;
  928. if (!ndncList.size())
  929. {
  930. // empty list
  931. return 0;
  932. }
  933. PWSTR* result = new PWSTR[ndncList.size() + 1];
  934. // REVIEWED-2002/02/26-sburns correct byte count passed.
  935. ::ZeroMemory(result, (ndncList.size() + 1) * sizeof PWSTR);
  936. for (
  937. StringList::iterator i = ndncList.begin();
  938. i != ndncList.end();
  939. ++i)
  940. {
  941. ASSERT(i->length());
  942. size_t len = i->length() + 1;
  943. result[entryCount] = new WCHAR[len];
  944. // REVIEWED-2002/02/26-sburns correct byte count passed.
  945. ::ZeroMemory(result[entryCount], len * sizeof WCHAR);
  946. i->copy(result[entryCount], len - 1);
  947. ++entryCount;
  948. }
  949. return const_cast<PCWSTR*>(result);
  950. }
  951. void
  952. DeallocateAppPartitionList(PCWSTR*& partitionList)
  953. {
  954. LOG_FUNCTION(DeallocateAppPartitionList);
  955. if (partitionList)
  956. {
  957. PCWSTR* listCopy = partitionList;
  958. while (*listCopy)
  959. {
  960. delete *listCopy;
  961. // *listCopy = 0;
  962. ++listCopy;
  963. }
  964. delete partitionList;
  965. partitionList = 0;
  966. }
  967. }
  968. void
  969. DS::DemoteDC(ProgressDialog& progressDialog)
  970. throw (DS::Error)
  971. {
  972. LOG_FUNCTION(DS::DemoteDC);
  973. State& state = State::GetInstance();
  974. String username = state.GetUsername();
  975. bool useCurrentUserCreds = username.empty();
  976. bool isLastDc = state.IsLastDCInDomain();
  977. bool isForcedDemotion = state.IsForcedDemotion();
  978. EncryptedString adminPassword= state.GetAdminPassword();
  979. EncryptedString password = state.GetPassword();
  980. if (!useCurrentUserCreds)
  981. {
  982. String userDomain = state.GetUserDomainName();
  983. username = MassageUserName(userDomain, username);
  984. }
  985. ULONG options = DSROLE_DC_CREATE_TRUST_AS_REQUIRED;
  986. if (isLastDc)
  987. {
  988. options |= DSROLE_DC_DELETE_PARENT_TRUST;
  989. }
  990. if (isForcedDemotion)
  991. {
  992. // Update our list of application partitions so that we can remove
  993. // all of them
  994. state.IsLastAppPartitionReplica();
  995. options |= DSROLE_DC_FORCE_DEMOTE;
  996. // pretend to be the last DC if we're forcing the demotion.
  997. isLastDc = true;
  998. }
  999. int appPartitionCount = 0;
  1000. PCWSTR* appPartitionList = AllocateAppPartitionList(appPartitionCount);
  1001. #ifdef LOGGING_BUILD
  1002. LOG(L"Calling DsRoleDemoteDc");
  1003. LOG( L"lpServer : (null)");
  1004. LOG( L"lpDnsDomainName : (null)");
  1005. LOG(String::format(L"ServerRole : %1", isLastDc ? L"DsRoleServerStandalone" : L"DsRoleServerMember"));
  1006. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  1007. LOG(String::format(L"Options : 0x%1!X!", options));
  1008. LOG(String::format(L"fLastDcInDomain : %1", isLastDc ? L"true" : L"false"));
  1009. LOG(String::format(L"cRemoteNCs : %1!d!", appPartitionCount));
  1010. for (int i = 0; i < appPartitionCount; ++i)
  1011. {
  1012. LOG(String::format(L"pszRemoveNCs : %1", appPartitionList[i]));
  1013. }
  1014. #endif // LOGGING_BUILD
  1015. WCHAR* adminPasswordCopy = 0;
  1016. if (!adminPassword.IsEmpty())
  1017. {
  1018. adminPasswordCopy = adminPassword.GetClearTextCopy();
  1019. }
  1020. WCHAR* passwordCopy = 0;
  1021. if (!useCurrentUserCreds)
  1022. {
  1023. passwordCopy = password.GetClearTextCopy();
  1024. }
  1025. DSROLE_SERVEROP_HANDLE handle = 0;
  1026. HRESULT hr =
  1027. Win32ToHresult(
  1028. ::DsRoleDemoteDc(
  1029. 0, // this server
  1030. 0, // "default" domain hosted by this server
  1031. isLastDc ? DsRoleServerStandalone : DsRoleServerMember,
  1032. (useCurrentUserCreds ? 0 : username.c_str()),
  1033. passwordCopy,
  1034. options,
  1035. isLastDc ? TRUE : FALSE,
  1036. appPartitionCount,
  1037. appPartitionList,
  1038. adminPasswordCopy,
  1039. &handle));
  1040. LOG_HRESULT(hr);
  1041. DeallocateAppPartitionList(appPartitionList);
  1042. if (adminPasswordCopy)
  1043. {
  1044. adminPassword.DestroyClearTextCopy(adminPasswordCopy);
  1045. }
  1046. if (passwordCopy)
  1047. {
  1048. password.DestroyClearTextCopy(passwordCopy);
  1049. }
  1050. if (SUCCEEDED(hr))
  1051. {
  1052. DoProgressLoop(handle, progressDialog);
  1053. }
  1054. else
  1055. {
  1056. throw DS::Error(hr, IDS_DEMOTE_DC_FAILED);
  1057. }
  1058. }
  1059. void
  1060. DS::AbortBDCUpgrade(bool abortForReplica)
  1061. throw (DS::Error)
  1062. {
  1063. LOG_FUNCTION(DS::AbortBDCUpgrade);
  1064. State& state = State::GetInstance();
  1065. ASSERT(state.GetRunContext() == State::BDC_UPGRADE);
  1066. String username = state.GetUsername();
  1067. bool useCurrentUserCreds = username.empty();
  1068. EncryptedString adminPassword = state.GetAdminPassword();
  1069. EncryptedString password = state.GetPassword();
  1070. if (!useCurrentUserCreds)
  1071. {
  1072. String userDomain = state.GetUserDomainName();
  1073. username = MassageUserName(userDomain, username);
  1074. }
  1075. ULONG options =
  1076. abortForReplica ? DSROLEP_ABORT_FOR_REPLICA_INSTALL : 0;
  1077. LOG(L"Calling DsRoleAbortDownlevelServerUpgrade");
  1078. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  1079. LOG(String::format(L"Options : 0x%1!X!", options));
  1080. WCHAR* adminPasswordCopy = 0;
  1081. if (!adminPassword.IsEmpty())
  1082. {
  1083. adminPasswordCopy = adminPassword.GetClearTextCopy();
  1084. }
  1085. WCHAR* passwordCopy = 0;
  1086. if (!useCurrentUserCreds)
  1087. {
  1088. passwordCopy = password.GetClearTextCopy();
  1089. }
  1090. HRESULT hr =
  1091. Win32ToHresult(
  1092. ::DsRoleAbortDownlevelServerUpgrade(
  1093. adminPasswordCopy,
  1094. (useCurrentUserCreds ? 0 : username.c_str()),
  1095. passwordCopy,
  1096. options));
  1097. LOG_HRESULT(hr);
  1098. if (adminPasswordCopy)
  1099. {
  1100. adminPassword.DestroyClearTextCopy(adminPasswordCopy);
  1101. }
  1102. if (passwordCopy)
  1103. {
  1104. password.DestroyClearTextCopy(passwordCopy);
  1105. }
  1106. if (FAILED(hr))
  1107. {
  1108. throw DS::Error(hr, IDS_ABORT_UPGRADE_FAILED);
  1109. }
  1110. }
  1111. DS::PriorServerRole
  1112. DS::GetPriorServerRole(bool& isUpgrade)
  1113. {
  1114. LOG_FUNCTION(DS::GetPriorServerRole);
  1115. isUpgrade = false;
  1116. DSROLE_UPGRADE_STATUS_INFO* info = 0;
  1117. HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info);
  1118. if (SUCCEEDED(hr) && info)
  1119. {
  1120. isUpgrade =
  1121. ( (info->OperationState & DSROLE_UPGRADE_IN_PROGRESS)
  1122. ? true
  1123. : false );
  1124. DSROLE_SERVER_STATE state = info->PreviousServerState;
  1125. ::DsRoleFreeMemory(info);
  1126. switch (state)
  1127. {
  1128. case DsRoleServerPrimary:
  1129. {
  1130. return PDC;
  1131. }
  1132. case DsRoleServerBackup:
  1133. {
  1134. return BDC;
  1135. }
  1136. case DsRoleServerUnknown:
  1137. default:
  1138. {
  1139. return UNKNOWN;
  1140. }
  1141. }
  1142. }
  1143. return UNKNOWN;
  1144. }