Source code of Windows XP (NT5)
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.

1390 lines
36 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 EncodedString& 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. WCHAR* cleartext = password.GetDecodedCopy();
  104. HRESULT hr =
  105. MyNetJoinDomain(
  106. domain.c_str(),
  107. massagedUserName.c_str(),
  108. cleartext,
  109. flags);
  110. ::ZeroMemory(cleartext, sizeof(WCHAR) * password.GetLength());
  111. delete[] cleartext;
  112. LOG_HRESULT(hr);
  113. if (FAILED(hr))
  114. {
  115. State& state = State::GetInstance();
  116. state.SetOperationResultsMessage(
  117. String::format(IDS_UNABLE_TO_JOIN_DOMAIN, domainDNSName.c_str()));
  118. throw DS::Error(hr, IDS_JOIN_DOMAIN_FAILED);
  119. }
  120. }
  121. DWORD
  122. MyDsRoleCancel(DSROLE_SERVEROP_HANDLE& handle)
  123. {
  124. LOG(L"Calling DsRoleCancel");
  125. LOG(L"lpServer : (null)");
  126. DWORD status = ::DsRoleCancel(0, handle);
  127. LOG(String::format(L"Error 0x%1!X! (!0 => error)", status));
  128. return status;
  129. }
  130. DWORD
  131. MyDsRoleGetDcOperationProgress(
  132. DSROLE_SERVEROP_HANDLE& handle,
  133. DSROLE_SERVEROP_STATUS*& status)
  134. {
  135. // LOG(L"Calling DsRoleGetDcOperationProgress");
  136. status = 0;
  137. DWORD err = ::DsRoleGetDcOperationProgress(0, handle, &status);
  138. // LOG(
  139. // String::format(
  140. // L"Error 0x%1!X! (!0 => error, 0x%2!X! = ERROR_IO_PENDING)",
  141. // err,
  142. // ERROR_IO_PENDING));
  143. // if (status)
  144. // {
  145. // LOG(
  146. // String::format(
  147. // L"OperationStatus : 0x%1!X!",
  148. // status->OperationStatus));
  149. // LOG(status->CurrentOperationDisplayString);
  150. // }
  151. // DWORD err = ERROR_IO_PENDING;
  152. // status = new DSROLE_SERVEROP_STATUS;
  153. // status->CurrentOperationDisplayString = L"proceeding";
  154. // status->OperationStatus = 0;
  155. return err;
  156. }
  157. void
  158. DoProgressLoop(
  159. DSROLE_SERVEROP_HANDLE& handle,
  160. ProgressDialog& progressDialog)
  161. throw (DS::Error)
  162. {
  163. LOG_FUNCTION(DoProgressLoop);
  164. State& state = State::GetInstance();
  165. if (state.GetOperation() == State::DEMOTE)
  166. {
  167. // not cancelable -- turn off the cancel button.
  168. progressDialog.UpdateButton(String());
  169. }
  170. else
  171. {
  172. // turn on the cancel button.
  173. progressDialog.UpdateButton(IDS_PROGRESS_CANCEL);
  174. }
  175. DWORD netErr = 0;
  176. bool criticalComplete = false;
  177. bool buttonUpdatedToFinishLater = false;
  178. String lastMessage;
  179. ProgressDialog::WaitCode cancelButton;
  180. do
  181. {
  182. // wait 1500ms or for the user to hit cancel
  183. cancelButton = progressDialog.WaitForButton(1500);
  184. // get the current status of the operation
  185. DSROLE_SERVEROP_STATUS* status = 0;
  186. netErr = MyDsRoleGetDcOperationProgress(handle, status);
  187. if (netErr != ERROR_SUCCESS && netErr != ERROR_IO_PENDING)
  188. {
  189. // operation complete
  190. break;
  191. }
  192. if (!status)
  193. {
  194. LOG(L"Operation status not returned!");
  195. ASSERT(false);
  196. continue;
  197. }
  198. // update the message display
  199. String message = status->CurrentOperationDisplayString;
  200. if (message != lastMessage)
  201. {
  202. progressDialog.UpdateText(message);
  203. lastMessage = message;
  204. }
  205. // save the status flags for later use.
  206. ULONG statusFlags = status->OperationStatus;
  207. ::DsRoleFreeMemory(status);
  208. do
  209. {
  210. if (cancelButton != ProgressDialog::PRESSED)
  211. {
  212. break;
  213. }
  214. // if we make it here, user pressed the cancel button
  215. LOG(L"DoProgressLoop: handling cancel");
  216. ASSERT(state.GetOperation() != State::DEMOTE);
  217. if (criticalComplete)
  218. {
  219. // inform the user that the install is done, and that they're
  220. // cancelling the non-critical replication.
  221. popup.Info(
  222. progressDialog.GetHWND(),
  223. String::load(IDS_CANCEL_NON_CRITICAL_REPLICATION));
  224. // this should return ERROR_SUCCESS, and the promotion will
  225. // be considered complete.
  226. progressDialog.UpdateText(IDS_CANCELLING_REPLICATION);
  227. netErr = MyDsRoleCancel(handle);
  228. // fall out of the inner, then the outer, loop. Then we will
  229. // get the operation results, which should indicate that the
  230. // promotion is complete, and non-critical replication was
  231. // canceled.
  232. break;
  233. }
  234. // Still doing promote, verify that the user really wants to roll
  235. // back to server state.
  236. if (
  237. popup.MessageBox(
  238. progressDialog.GetHWND(),
  239. String::load(IDS_CANCEL_PROMOTE),
  240. MB_YESNO | MB_ICONWARNING) == IDYES)
  241. {
  242. // this should return ERROR_SUCCESS, and the promotion will
  243. // be rolled back.
  244. progressDialog.UpdateText(IDS_CANCELLING);
  245. netErr = MyDsRoleCancel(handle);
  246. // fall out of the inner, then the outer, loop. Then we will
  247. // get the operation results, which should indicate that the
  248. // promotion was cancelled as a failure code. We handle this
  249. // failure code in the same manner as all others.
  250. break;
  251. }
  252. // user decided to press on. reset the cancel button
  253. progressDialog.UpdateButton(IDS_PROGRESS_CANCEL);
  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_SET_ROLE_AS_DC_FAILED);
  397. }
  398. }
  399. void
  400. EmptyFolder(const String& path)
  401. throw (DS::Error)
  402. {
  403. LOG_FUNCTION2(EmptyFolder, path);
  404. ASSERT(!path.empty());
  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. if (wild[wild.length() - 1] != L'\\')
  414. {
  415. wild += L"\\";
  416. }
  417. wild += L"*.*";
  418. FS::Iterator iter(
  419. wild,
  420. FS::Iterator::INCLUDE_FILES
  421. | FS::Iterator::RETURN_FULL_PATHS);
  422. HRESULT hr = S_OK;
  423. String current;
  424. while ((hr = iter.GetCurrent(current)) == S_OK)
  425. {
  426. LOG(String::format(L"Deleting %1", current.c_str()));
  427. hr = Win::DeleteFile(current);
  428. if (FAILED(hr))
  429. {
  430. int msgId = IDS_EMPTY_DIR_FAILED;
  431. if (hr == Win32ToHresult(ERROR_ACCESS_DENIED))
  432. {
  433. msgId = IDS_EMPTY_DIR_FAILED_ACCESS_DENIED;
  434. }
  435. throw
  436. DS::Error(
  437. S_OK, // so as not to trigger credentials dialog
  438. String::format(
  439. msgId,
  440. GetErrorMessage(hr).c_str(),
  441. path.c_str()),
  442. String::load(IDS_ERROR_PREPARING_OPERATION));
  443. }
  444. hr = iter.Increment();
  445. BREAK_ON_FAILED_HRESULT(hr);
  446. }
  447. }
  448. }
  449. HRESULT
  450. SetupPaths()
  451. {
  452. LOG_FUNCTION(SetupPaths);
  453. State& state = State::GetInstance();
  454. String dbPath = state.GetDatabasePath();
  455. String logPath = state.GetLogPath();
  456. String sysvolPath = state.GetSYSVOLPath();
  457. ASSERT(!dbPath.empty());
  458. ASSERT(!logPath.empty());
  459. ASSERT(!sysvolPath.empty());
  460. HRESULT hr = S_OK;
  461. do
  462. {
  463. if (FS::PathExists(dbPath))
  464. {
  465. EmptyFolder(dbPath);
  466. }
  467. else
  468. {
  469. hr = FS::CreateFolder(dbPath);
  470. BREAK_ON_FAILED_HRESULT(hr);
  471. }
  472. if (FS::PathExists(logPath))
  473. {
  474. EmptyFolder(logPath);
  475. }
  476. else
  477. {
  478. hr = FS::CreateFolder(logPath);
  479. BREAK_ON_FAILED_HRESULT(hr);
  480. }
  481. if (FS::PathExists(sysvolPath))
  482. {
  483. EmptyFolder(sysvolPath);
  484. }
  485. else
  486. {
  487. hr = FS::CreateFolder(sysvolPath);
  488. BREAK_ON_FAILED_HRESULT(hr);
  489. }
  490. }
  491. while (0);
  492. return hr;
  493. }
  494. // Sets the promotion flags based on options set in the unattended execution
  495. // answerfile.
  496. //
  497. // state - IN reference to the global State object
  498. //
  499. // flags - IN/OUT promote API flags, may be modified on exit
  500. void
  501. SetAnswerFilePromoteFlags(
  502. State& state,
  503. ULONG& flags)
  504. {
  505. LOG_FUNCTION(SetAnswerFilePromoteFlags);
  506. if (state.UsingAnswerFile())
  507. {
  508. // set flags based on unattended execution options
  509. // if the safe mode admin password is not specified, then we set a
  510. // flag to cause the promote APIs to copy the current local admin
  511. // password.
  512. EncodedString safeModePassword = state.GetSafeModeAdminPassword();
  513. if (safeModePassword.IsEmpty() && state.RunHiddenUnattended())
  514. {
  515. // user did not supply a safemode password, and he did not have
  516. // an opportunity to do so (if the wizard went interactive)
  517. if (!state.IsSafeModeAdminPwdOptionPresent())
  518. {
  519. // the safe mode pwd key is not present in the answerfile
  520. flags |= DSROLE_DC_DEFAULT_REPAIR_PWD;
  521. }
  522. }
  523. String option =
  524. state.GetAnswerFileOption(State::OPTION_CRITICAL_REPLICATION_ONLY);
  525. if (option.icompare(State::VALUE_YES) == 0)
  526. {
  527. flags |= DSROLE_DC_CRITICAL_REPLICATION_ONLY;
  528. }
  529. }
  530. LOG(String::format(L"0x%1!X!", flags));
  531. }
  532. void
  533. DS::CreateReplica(ProgressDialog& progressDialog, bool invokeForUpgrade)
  534. throw (DS::Error)
  535. {
  536. LOG_FUNCTION(DS::CreateReplica);
  537. State& state = State::GetInstance();
  538. String domain = state.GetReplicaDomainDNSName();
  539. String dbPath = state.GetDatabasePath();
  540. String logPath = state.GetLogPath();
  541. String sysvolPath = state.GetSYSVOLPath();
  542. String site = state.GetSiteName();
  543. String username = state.GetUsername();
  544. String replicationDc = state.GetReplicationPartnerDC();
  545. String sourcePath = state.GetReplicationSourcePath();
  546. bool useSourcePath = state.ReplicateFromMedia();
  547. EncodedString syskey = state.GetSyskey();
  548. EncodedString safeModePassword = state.GetSafeModeAdminPassword();
  549. EncodedString password = state.GetPassword();
  550. bool useCurrentUserCreds = username.empty();
  551. ULONG flags =
  552. DSROLE_DC_FORCE_TIME_SYNC
  553. | DSROLE_DC_CREATE_TRUST_AS_REQUIRED;
  554. if (invokeForUpgrade)
  555. {
  556. flags |= DSROLE_DC_DOWNLEVEL_UPGRADE;
  557. }
  558. if (state.GetDomainControllerReinstallFlag())
  559. {
  560. flags |= DSROLE_DC_ALLOW_DC_REINSTALL;
  561. }
  562. SetAnswerFilePromoteFlags(state, flags);
  563. if (useSourcePath)
  564. {
  565. if (state.GetRestoreGc())
  566. {
  567. flags |= DSROLE_DC_REQUEST_GC;
  568. }
  569. }
  570. ASSERT(!domain.empty());
  571. if (!useCurrentUserCreds)
  572. {
  573. String user_domain = state.GetUserDomainName();
  574. username = MassageUserName(user_domain, username);
  575. }
  576. HRESULT hr = S_OK;
  577. do
  578. {
  579. hr = SetupPaths();
  580. BREAK_ON_FAILED_HRESULT(hr);
  581. LOG(L"Calling DsRoleDcAsReplica");
  582. LOG( L"lpServer : (null)");
  583. LOG(String::format(L"lpDnsDomainName : %1", domain.c_str()));
  584. LOG(String::format(L"lpReplicaServer : %1", replicationDc.empty() ? L"(null)" : replicationDc.c_str()));
  585. LOG(String::format(L"lpSiteName : %1", site.empty() ? L"(null)" : site.c_str()));
  586. LOG(String::format(L"lpDsDatabasePath : %1", dbPath.c_str()));
  587. LOG(String::format(L"lpDsLogPath : %1", logPath.c_str()));
  588. LOG(String::format(L"lpRestorePath : %1", useSourcePath ? sourcePath.c_str() : L"(null)"));
  589. LOG(String::format(L"lpSystemVolumeRootPath : %1", sysvolPath.c_str()));
  590. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  591. LOG(String::format(L"Options : 0x%1!X!", flags));
  592. WCHAR* safeModePasswordCopy = 0;
  593. if (!safeModePassword.IsEmpty())
  594. {
  595. safeModePasswordCopy = safeModePassword.GetDecodedCopy();
  596. }
  597. WCHAR* passwordCopy = 0;
  598. if (!useCurrentUserCreds)
  599. {
  600. passwordCopy = password.GetDecodedCopy();
  601. }
  602. // The api wants to scribble over the syskey, so we make a copy for
  603. // it to do so.
  604. WCHAR* syskeyCopy = 0;
  605. if (useSourcePath && !syskey.IsEmpty())
  606. {
  607. syskeyCopy = syskey.GetDecodedCopy();
  608. }
  609. DSROLE_SERVEROP_HANDLE handle = 0;
  610. hr =
  611. Win32ToHresult(
  612. ::DsRoleDcAsReplica(
  613. 0, // this server
  614. domain.c_str(),
  615. // possibly empty, e.g. if we didn't join a domain...
  616. replicationDc.empty() ? 0 : replicationDc.c_str(),
  617. site.empty() ? 0 : site.c_str(),
  618. dbPath.c_str(),
  619. logPath.c_str(),
  620. useSourcePath ? sourcePath.c_str() : 0,
  621. sysvolPath.c_str(),
  622. syskeyCopy,
  623. (useCurrentUserCreds ? 0 : username.c_str()),
  624. passwordCopy,
  625. safeModePasswordCopy,
  626. flags,
  627. &handle));
  628. if (safeModePasswordCopy)
  629. {
  630. ::ZeroMemory(
  631. safeModePasswordCopy,
  632. sizeof(WCHAR) * safeModePassword.GetLength());
  633. delete[] safeModePasswordCopy;
  634. }
  635. if (passwordCopy)
  636. {
  637. ::ZeroMemory(passwordCopy, sizeof(WCHAR) * password.GetLength());
  638. delete[] passwordCopy;
  639. }
  640. // the copy of the syskey has already been scribbled on, so just
  641. // delete it.
  642. delete[] syskeyCopy;
  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_SET_ROLE_AS_DC_FAILED);
  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. EncodedString password = state.GetPassword();
  667. EncodedString safeModePassword = state.GetSafeModeAdminPassword();
  668. EncodedString 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.GetDecodedCopy();
  735. }
  736. WCHAR* adminPasswordCopy = 0;
  737. if (!adminPassword.IsEmpty())
  738. {
  739. adminPasswordCopy = adminPassword.GetDecodedCopy();
  740. }
  741. WCHAR* passwordCopy = 0;
  742. if (!useCurrentUserCreds)
  743. {
  744. passwordCopy = password.GetDecodedCopy();
  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. ::ZeroMemory(
  769. safeModePasswordCopy,
  770. sizeof(WCHAR) * safeModePassword.GetLength());
  771. delete[] safeModePasswordCopy;
  772. }
  773. if (adminPasswordCopy)
  774. {
  775. ::ZeroMemory(
  776. adminPasswordCopy,
  777. sizeof(WCHAR) * adminPassword.GetLength());
  778. delete[] adminPasswordCopy;
  779. }
  780. if (passwordCopy)
  781. {
  782. ::ZeroMemory(passwordCopy, sizeof(WCHAR) * password.GetLength());
  783. delete[] passwordCopy;
  784. }
  785. DoProgressLoop(handle, progressDialog);
  786. }
  787. while (0);
  788. if (FAILED(hr))
  789. {
  790. throw DS::Error(hr, IDS_SET_ROLE_AS_DC_FAILED);
  791. }
  792. }
  793. void
  794. DS::UpgradeBDC(ProgressDialog& progressDialog)
  795. throw (DS::Error)
  796. {
  797. LOG_FUNCTION(DS::UpgradeBDC);
  798. // seems non-intuitive to abort the upgrade to do the upgrade, but here
  799. // the abort removes dcpromo autostart, and turns the machine into a
  800. // standalone server. Then we proceed to make it a replica.
  801. DS::AbortBDCUpgrade(true);
  802. DS::CreateReplica(progressDialog, true);
  803. }
  804. void
  805. DS::UpgradePDC(ProgressDialog& progressDialog)
  806. throw (DS::Error)
  807. {
  808. LOG_FUNCTION(DS::UpgradePDC);
  809. State& state = State::GetInstance();
  810. ASSERT(state.GetRunContext() == State::PDC_UPGRADE);
  811. String domain = state.GetNewDomainDNSName();
  812. String site = state.GetSiteName();
  813. String dbPath = state.GetDatabasePath();
  814. String logPath = state.GetLogPath();
  815. String sysvolPath = state.GetSYSVOLPath();
  816. String parent = state.GetParentDomainDnsName();
  817. String username = state.GetUsername();
  818. EncodedString password = state.GetPassword();
  819. EncodedString safeModePassword = state.GetSafeModeAdminPassword();
  820. State::Operation operation = state.GetOperation();
  821. bool useParent =
  822. ( operation == State::TREE
  823. || operation == State::CHILD);
  824. bool useCurrentUserCreds = username.empty();
  825. ULONG flags = DSROLE_DC_CREATE_TRUST_AS_REQUIRED;
  826. if (state.GetDomainReinstallFlag())
  827. {
  828. flags |= DSROLE_DC_ALLOW_DOMAIN_REINSTALL;
  829. }
  830. if (state.GetDomainControllerReinstallFlag())
  831. {
  832. flags |= DSROLE_DC_ALLOW_DC_REINSTALL;
  833. }
  834. if (state.GetSetForestVersionFlag())
  835. {
  836. flags |= DSROLE_DC_SET_FOREST_CURRENT;
  837. }
  838. if (operation == State::TREE)
  839. {
  840. flags |= DSROLE_DC_TRUST_AS_ROOT | DSROLE_DC_FORCE_TIME_SYNC;
  841. ASSERT(!parent.empty());
  842. }
  843. else if (operation == State::CHILD)
  844. {
  845. flags |= DSROLE_DC_FORCE_TIME_SYNC;
  846. ASSERT(!parent.empty());
  847. }
  848. SetAnswerFilePromoteFlags(state, flags);
  849. if (state.ShouldAllowAnonymousAccess())
  850. {
  851. flags |= DSROLE_DC_ALLOW_ANONYMOUS_ACCESS;
  852. }
  853. #ifdef DBG
  854. ASSERT(!domain.empty());
  855. // parent may be empty
  856. if (operation == State::FOREST)
  857. {
  858. ASSERT(!site.empty());
  859. }
  860. #endif
  861. if (!useCurrentUserCreds)
  862. {
  863. String userDomain = state.GetUserDomainName();
  864. username = MassageUserName(userDomain, username);
  865. }
  866. HRESULT hr = S_OK;
  867. do
  868. {
  869. hr = SetupPaths();
  870. BREAK_ON_FAILED_HRESULT(hr);
  871. LOG(L"Calling DsRoleUpgradeDownlevelServer");
  872. LOG(String::format(L"lpDnsDomainName : %1", domain.c_str()));
  873. LOG(String::format(L"lpSiteName : %1", site.empty() ? L"(null)" : site.c_str()));
  874. LOG(String::format(L"lpDsDatabasePath : %1", dbPath.c_str()));
  875. LOG(String::format(L"lpDsLogPath : %1", logPath.c_str()));
  876. LOG(String::format(L"lpSystemVolumeRootPath : %1", sysvolPath.c_str()));
  877. LOG(String::format(L"lpParentDnsDomainName : %1", useParent ? parent.c_str() : L"(null)"));
  878. LOG( L"lpParentServer : (null)");
  879. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  880. LOG(String::format(L"Options : 0x%1!X!", flags));
  881. WCHAR* safeModePasswordCopy = 0;
  882. if (!safeModePassword.IsEmpty())
  883. {
  884. safeModePasswordCopy = safeModePassword.GetDecodedCopy();
  885. }
  886. WCHAR* passwordCopy = 0;
  887. if (!useCurrentUserCreds)
  888. {
  889. passwordCopy = password.GetDecodedCopy();
  890. }
  891. DSROLE_SERVEROP_HANDLE handle = 0;
  892. hr =
  893. Win32ToHresult(
  894. ::DsRoleUpgradeDownlevelServer(
  895. domain.c_str(),
  896. site.empty() ? 0 : site.c_str(),
  897. dbPath.c_str(),
  898. logPath.c_str(),
  899. sysvolPath.c_str(),
  900. (useParent ? parent.c_str() : 0),
  901. 0, // let API pick a server
  902. (useCurrentUserCreds ? 0 : username.c_str()),
  903. passwordCopy,
  904. safeModePasswordCopy,
  905. flags,
  906. &handle));
  907. BREAK_ON_FAILED_HRESULT(hr);
  908. if (safeModePasswordCopy)
  909. {
  910. ::ZeroMemory(
  911. safeModePasswordCopy,
  912. sizeof(WCHAR) * safeModePassword.GetLength());
  913. delete[] safeModePasswordCopy;
  914. }
  915. if (passwordCopy)
  916. {
  917. ::ZeroMemory(passwordCopy, sizeof(WCHAR) * password.GetLength());
  918. delete[] passwordCopy;
  919. }
  920. DoProgressLoop(handle, progressDialog);
  921. }
  922. while (0);
  923. if (FAILED(hr))
  924. {
  925. throw DS::Error(hr, IDS_UPGRADE_DC_FAILED);
  926. }
  927. }
  928. void
  929. DS::DemoteDC(ProgressDialog& progressDialog)
  930. throw (DS::Error)
  931. {
  932. LOG_FUNCTION(DS::DemoteDC);
  933. State& state = State::GetInstance();
  934. String username = state.GetUsername();
  935. bool useCurrentUserCreds = username.empty();
  936. bool isLastDc = state.IsLastDCInDomain();
  937. EncodedString adminPassword= state.GetAdminPassword();
  938. EncodedString password = state.GetPassword();
  939. if (!useCurrentUserCreds)
  940. {
  941. String userDomain = state.GetUserDomainName();
  942. username = MassageUserName(userDomain, username);
  943. }
  944. ULONG options = DSROLE_DC_CREATE_TRUST_AS_REQUIRED;
  945. if (isLastDc)
  946. {
  947. options |= DSROLE_DC_DELETE_PARENT_TRUST;
  948. }
  949. LOG(L"Calling DsRoleDemoteDc");
  950. LOG( L"lpServer : (null)");
  951. LOG( L"lpDnsDomainName : (null)");
  952. LOG(String::format(L"ServerRole : %1", isLastDc ? L"DsRoleServerStandalone" : L"DsRoleServerMember"));
  953. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  954. LOG(String::format(L"Options : 0x%1!X!", options));
  955. LOG(String::format(L"fLastDcInDomain : %1", isLastDc ? L"true" : L"false"));
  956. WCHAR* adminPasswordCopy = 0;
  957. if (!adminPassword.IsEmpty())
  958. {
  959. adminPasswordCopy = adminPassword.GetDecodedCopy();
  960. }
  961. WCHAR* passwordCopy = 0;
  962. if (!useCurrentUserCreds)
  963. {
  964. passwordCopy = password.GetDecodedCopy();
  965. }
  966. DSROLE_SERVEROP_HANDLE handle = 0;
  967. HRESULT hr =
  968. Win32ToHresult(
  969. ::DsRoleDemoteDc(
  970. 0, // this server
  971. 0, // "default" domain hosted by this server
  972. isLastDc ? DsRoleServerStandalone : DsRoleServerMember,
  973. (useCurrentUserCreds ? 0 : username.c_str()),
  974. passwordCopy,
  975. options,
  976. isLastDc ? TRUE : FALSE,
  977. adminPasswordCopy,
  978. &handle));
  979. LOG_HRESULT(hr);
  980. if (adminPasswordCopy)
  981. {
  982. ::ZeroMemory(
  983. adminPasswordCopy,
  984. sizeof(WCHAR) * adminPassword.GetLength());
  985. delete[] adminPasswordCopy;
  986. }
  987. if (passwordCopy)
  988. {
  989. ::ZeroMemory(passwordCopy, sizeof(WCHAR) * password.GetLength());
  990. delete[] passwordCopy;
  991. }
  992. if (SUCCEEDED(hr))
  993. {
  994. DoProgressLoop(handle, progressDialog);
  995. }
  996. else
  997. {
  998. throw DS::Error(hr, IDS_DEMOTE_DC_FAILED);
  999. }
  1000. }
  1001. void
  1002. DS::AbortBDCUpgrade(bool abortForReplica)
  1003. throw (DS::Error)
  1004. {
  1005. LOG_FUNCTION(DS::AbortBDCUpgrade);
  1006. State& state = State::GetInstance();
  1007. ASSERT(state.GetRunContext() == State::BDC_UPGRADE);
  1008. String username = state.GetUsername();
  1009. bool useCurrentUserCreds = username.empty();
  1010. EncodedString adminPassword = state.GetAdminPassword();
  1011. EncodedString password = state.GetPassword();
  1012. if (!useCurrentUserCreds)
  1013. {
  1014. String userDomain = state.GetUserDomainName();
  1015. username = MassageUserName(userDomain, username);
  1016. }
  1017. ULONG options =
  1018. abortForReplica ? DSROLEP_ABORT_FOR_REPLICA_INSTALL : 0;
  1019. LOG(L"Calling DsRoleAbortDownlevelServerUpgrade");
  1020. LOG(String::format(L"lpAccount : %1", useCurrentUserCreds ? L"(null)" : username.c_str()));
  1021. LOG(String::format(L"Options : 0x%1!X!", options));
  1022. WCHAR* adminPasswordCopy = 0;
  1023. if (!adminPassword.IsEmpty())
  1024. {
  1025. adminPasswordCopy = adminPassword.GetDecodedCopy();
  1026. }
  1027. WCHAR* passwordCopy = 0;
  1028. if (!useCurrentUserCreds)
  1029. {
  1030. passwordCopy = password.GetDecodedCopy();
  1031. }
  1032. HRESULT hr =
  1033. Win32ToHresult(
  1034. ::DsRoleAbortDownlevelServerUpgrade(
  1035. adminPasswordCopy,
  1036. (useCurrentUserCreds ? 0 : username.c_str()),
  1037. passwordCopy,
  1038. options));
  1039. LOG_HRESULT(hr);
  1040. if (adminPasswordCopy)
  1041. {
  1042. ::ZeroMemory(
  1043. adminPasswordCopy,
  1044. sizeof(WCHAR) * adminPassword.GetLength());
  1045. delete[] adminPasswordCopy;
  1046. }
  1047. if (passwordCopy)
  1048. {
  1049. ::ZeroMemory(passwordCopy, sizeof(WCHAR) * password.GetLength());
  1050. delete[] passwordCopy;
  1051. }
  1052. if (FAILED(hr))
  1053. {
  1054. throw DS::Error(hr, IDS_ABORT_UPGRADE_FAILED);
  1055. }
  1056. }
  1057. DS::PriorServerRole
  1058. DS::GetPriorServerRole(bool& isUpgrade)
  1059. {
  1060. LOG_FUNCTION(DS::GetPriorServerRole);
  1061. isUpgrade = false;
  1062. DSROLE_UPGRADE_STATUS_INFO* info = 0;
  1063. HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info);
  1064. if (SUCCEEDED(hr) && info)
  1065. {
  1066. isUpgrade =
  1067. ( (info->OperationState & DSROLE_UPGRADE_IN_PROGRESS)
  1068. ? true
  1069. : false );
  1070. DSROLE_SERVER_STATE state = info->PreviousServerState;
  1071. ::DsRoleFreeMemory(info);
  1072. switch (state)
  1073. {
  1074. case DsRoleServerPrimary:
  1075. {
  1076. return PDC;
  1077. }
  1078. case DsRoleServerBackup:
  1079. {
  1080. return BDC;
  1081. }
  1082. case DsRoleServerUnknown:
  1083. default:
  1084. {
  1085. return UNKNOWN;
  1086. }
  1087. }
  1088. }
  1089. return UNKNOWN;
  1090. }