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.

3400 lines
110 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. threadman.c
  5. Abstract:
  6. Implementation of the thread and thread management routines
  7. Author:
  8. Mac McLain (MacM) Feb 10, 1997
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <setpch.h>
  14. #include <dssetp.h>
  15. #include <dsgetdc.h>
  16. #include <lmcons.h>
  17. #include <lmapibuf.h>
  18. #include <lmsname.h>
  19. #include <loadfn.h>
  20. #include <lsarpc.h>
  21. #include <db.h>
  22. #include <lsasrvmm.h>
  23. #include <lsaisrv.h>
  24. #include <lmaccess.h>
  25. #include <netsetp.h>
  26. #include <samrpc.h> // for samisrv.h
  27. #include <samisrv.h> // for nlrepl.h
  28. #include <nlrepl.h> // for I_NetNotifyDsChange
  29. #include <Lmshare.h> // for NetShareDel()
  30. #include <autoenr.h> // for CertAutoRemove()
  31. #include "secure.h"
  32. #include "services.h"
  33. #include "upgrade.h"
  34. #include "trustdom.h"
  35. #include "sysvol.h"
  36. #include "lsa.h"
  37. #include "ds.h"
  38. #include "threadman.h"
  39. // forward from setutl.h
  40. DWORD
  41. DsRolepDeregisterNetlogonDnsRecords(
  42. PNTDS_DNS_RR_INFO pInfo
  43. );
  44. //
  45. // Helpful macros
  46. //
  47. #define DSROLEP_MAKE_DNS_RELATIVE(name) \
  48. if(name) { \
  49. DWORD _StripAbsoluteLength_ = wcslen( name ); \
  50. if ( *(name + _StripAbsoluteLength_ - 1 ) == L'.' ) { \
  51. *(name + _StripAbsoluteLength_ - 1 ) = UNICODE_NULL; \
  52. } \
  53. }
  54. #define DSROLEP_ALLOC_AND_COPY_STRING_EXIT( dest, src, label ) \
  55. if ( (src) ) { \
  56. (dest) = RtlAllocateHeap( RtlProcessHeap(), 0, (wcslen( (src) ) + 1) * sizeof( WCHAR ) ); \
  57. if ( !(dest) ) { \
  58. goto label; \
  59. } else { \
  60. wcscpy((dest), (src)); \
  61. } \
  62. } else { \
  63. (dest) = NULL; \
  64. }
  65. #define DSROLEP_ALLOC_AND_COPY_UNICODE_STRING_EXIT( dest, src, label ) \
  66. if ( (src) && (src)->Buffer ) { \
  67. (dest)->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, (src)->MaximumLength ); \
  68. if ( (dest)->Buffer == NULL ) { \
  69. goto label; \
  70. } else { \
  71. (dest)->Length = (src)->Length; \
  72. (dest)->MaximumLength = (src)->MaximumLength; \
  73. RtlCopyMemory( (dest)->Buffer, (src)->Buffer, (src)->MaximumLength ); \
  74. } \
  75. } else { \
  76. RtlZeroMemory( (dest), sizeof( UNICODE_STRING ) ); \
  77. }
  78. //
  79. // Function definitions
  80. //
  81. DWORD
  82. DsRolepBuildPromoteArgumentBlock(
  83. IN LPWSTR DnsDomainName,
  84. IN LPWSTR FlatDomainName,
  85. IN LPWSTR SiteName,
  86. IN LPWSTR DsDatabasePath,
  87. IN LPWSTR DsLogPath,
  88. IN LPWSTR RestorePath,
  89. IN LPWSTR SystemVolumeRootPath,
  90. IN PUNICODE_STRING Bootkey,
  91. IN LPWSTR Parent,
  92. IN LPWSTR Server,
  93. IN LPWSTR Account,
  94. IN PUNICODE_STRING Password,
  95. IN PUNICODE_STRING DomainAdminPassword,
  96. IN PUNICODE_STRING SafeModePassword,
  97. IN ULONG Options,
  98. IN UCHAR PasswordSeed,
  99. IN OUT PDSROLEP_OPERATION_PROMOTE_ARGS *Promote
  100. )
  101. /*++
  102. Routine Description:
  103. Builds an argument structure to pass into one of the promote worker functions. Since the
  104. rpc call will return before the thread completes, we'll have to copy all our argument strings.
  105. Since parameters may be changed through out the course of promotion, we assume allocations
  106. are made from the process heap.
  107. Resultant argument block should be freed via DsRolepFreeArgumentBlock
  108. Arguments:
  109. DnsDomainName - Dns domain name of the domain to install
  110. FlatDomainName - Flat (NetBIOS) domain name of the domain to install
  111. SiteName - Name of the site this DC should belong to
  112. DsDatabasePath - Absolute path on the local machine where the Ds DIT should go
  113. DsLogPath - Absolute path on the local machine where the Ds log files should go
  114. RestorePath - Location of a restored database.
  115. SystemVolumeRootPath - Absolute path on the local machine to be the root of the system
  116. volume root path.
  117. Bootkey - Needed when you don't have the key in the registry or on a disk
  118. cbBootkey - size of the bootkey
  119. Parent - Optional. Parent domain name
  120. Server -- Optional. Replica partner or server in parent domain
  121. Account - User account to use when setting up as a child domain
  122. Password - Password to use with the above account
  123. DomainAdminPassword - Password to set the domain administartor account
  124. Options - Options to control the creation of the domain
  125. PasswordSeed - Seed used to hide the passwords
  126. Promote - Where the allocated argument block is returned
  127. Returns:
  128. ERROR_SUCCESS - Success
  129. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  130. --*/
  131. {
  132. DWORD WinError = ERROR_NOT_ENOUGH_MEMORY;
  133. *Promote = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( DSROLEP_OPERATION_PROMOTE_ARGS ) );
  134. if ( *Promote == NULL ) {
  135. goto BuildPromoteDone;
  136. }
  137. RtlZeroMemory( *Promote, sizeof( DSROLEP_OPERATION_PROMOTE_ARGS ) );
  138. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->DnsDomainName, DnsDomainName, BuildPromoteDone );
  139. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->FlatDomainName, FlatDomainName, BuildPromoteDone );
  140. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->SiteName, SiteName, BuildPromoteDone );
  141. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->DsDatabasePath, DsDatabasePath, BuildPromoteDone );
  142. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->DsLogPath, DsLogPath, BuildPromoteDone );
  143. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->RestorePath, RestorePath, BuildPromoteDone );
  144. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->SysVolRootPath, SystemVolumeRootPath, BuildPromoteDone );
  145. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->Parent, Parent, BuildPromoteDone );
  146. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->Server, Server, BuildPromoteDone );
  147. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Promote)->Account, Account, BuildPromoteDone );
  148. DSROLEP_ALLOC_AND_COPY_UNICODE_STRING_EXIT( &((*Promote)->Password), Password,
  149. BuildPromoteDone );
  150. DSROLEP_ALLOC_AND_COPY_UNICODE_STRING_EXIT( &((*Promote)->DomainAdminPassword),
  151. DomainAdminPassword, BuildPromoteDone );
  152. DSROLEP_ALLOC_AND_COPY_UNICODE_STRING_EXIT( &((*Promote)->SafeModePassword),
  153. SafeModePassword, BuildPromoteDone );
  154. DSROLEP_ALLOC_AND_COPY_UNICODE_STRING_EXIT( &((*Promote)->Bootkey),
  155. Bootkey, BuildPromoteDone );
  156. (*Promote)->Options = Options;
  157. (*Promote)->Decode = PasswordSeed;
  158. WinError = DsRolepGetImpersonationToken( &(*Promote)->ImpersonateToken );
  159. BuildPromoteDone:
  160. if ( WinError != ERROR_SUCCESS ) {
  161. DsRolepFreeArgumentBlock( Promote, TRUE );
  162. }
  163. return( WinError );
  164. }
  165. DWORD
  166. DsRolepBuildDemoteArgumentBlock(
  167. IN DSROLE_SERVEROP_DEMOTE_ROLE ServerRole,
  168. IN LPWSTR DnsDomainName,
  169. IN LPWSTR Account,
  170. IN PUNICODE_STRING Password,
  171. IN ULONG Options,
  172. IN BOOL LastDcInDomain,
  173. IN PUNICODE_STRING AdminPassword,
  174. IN UCHAR PasswordSeed,
  175. IN OUT PDSROLEP_OPERATION_DEMOTE_ARGS *Demote
  176. )
  177. /*++
  178. Routine Description:
  179. Builds an argument structure to pass into the demote worker functions. Since the rpc call
  180. will return before the thread completes, we'll have to copy all our argument strings.
  181. Resultant argument block should be freed via DsRolepFreeArgumentBlock
  182. Arguments:
  183. ServerRole - New role for the server
  184. DnsDomainName - Dns domain name of the domain to uninstall. NULL means all of them
  185. Account - User account to use when setting up as a child domain
  186. Password - Password to use with the above account
  187. Options - Options to control the creation of the domain
  188. LastDcInDomain - If TRUE, the Dc being demoted is the last Dc in the domain.
  189. AdminPassword - Password to set on the administrator account if it is a new install
  190. PasswordSeed - Seed used to hide the passwords
  191. Demote - Where the allocated argument block is returned
  192. Returns:
  193. ERROR_SUCCESS - Success
  194. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  195. --*/
  196. {
  197. DWORD WinError = ERROR_NOT_ENOUGH_MEMORY;
  198. *Demote = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( DSROLEP_OPERATION_DEMOTE_ARGS ) );
  199. if ( *Demote == NULL ) {
  200. goto BuildDemoteDone;
  201. }
  202. RtlZeroMemory( *Demote, sizeof( DSROLEP_OPERATION_DEMOTE_ARGS ) );
  203. (*Demote)->ServerRole = ServerRole;
  204. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Demote)->DomainName, DnsDomainName, BuildDemoteDone );
  205. DSROLEP_ALLOC_AND_COPY_STRING_EXIT( (*Demote)->Account, Account, BuildDemoteDone );
  206. DSROLEP_ALLOC_AND_COPY_UNICODE_STRING_EXIT( &((*Demote)->Password), Password, BuildDemoteDone );
  207. (*Demote)->LastDcInDomain = ( LastDcInDomain != 0 );
  208. DSROLEP_ALLOC_AND_COPY_UNICODE_STRING_EXIT( &((*Demote)->AdminPassword),
  209. AdminPassword,
  210. BuildDemoteDone );
  211. (*Demote)->Options = Options;
  212. (*Demote)->Decode = PasswordSeed;
  213. WinError = DsRolepGetImpersonationToken( & (*Demote)->ImpersonateToken );
  214. BuildDemoteDone:
  215. if ( WinError != ERROR_SUCCESS ) {
  216. DsRolepFreeArgumentBlock( Demote, FALSE );
  217. }
  218. return( WinError );
  219. }
  220. VOID
  221. DsRolepFreeArgumentBlock(
  222. IN PVOID *ArgumentBlock,
  223. IN BOOLEAN Promote
  224. )
  225. /*++
  226. Routine Description:
  227. Frees an arugment block allocated via DsRolepBuildPromote/DemoteArgumentBlock
  228. Since parameters may be changed through out the course of promotion, we assume allocations
  229. are made from the process heap.
  230. Arguments:
  231. ArgumentBlock - Argument block to free
  232. Promote - If TRUE, this is a promote argument block. If FALSE, it's a demote arg block
  233. Returns:
  234. VOID
  235. --*/
  236. {
  237. PDSROLEP_OPERATION_PROMOTE_ARGS PromoteArg;
  238. PDSROLEP_OPERATION_DEMOTE_ARGS Demote;
  239. PVOID HeapHandle = RtlProcessHeap();
  240. if ( !ArgumentBlock ) {
  241. return;
  242. }
  243. //
  244. // Free it all
  245. //
  246. if ( Promote ) {
  247. PromoteArg = ( PDSROLEP_OPERATION_PROMOTE_ARGS )*ArgumentBlock;
  248. RtlFreeHeap( HeapHandle, 0, PromoteArg->DnsDomainName );
  249. RtlFreeHeap( HeapHandle, 0, PromoteArg->FlatDomainName );
  250. RtlFreeHeap( HeapHandle, 0, PromoteArg->SiteName );
  251. RtlFreeHeap( HeapHandle, 0, PromoteArg->DsDatabasePath );
  252. RtlFreeHeap( HeapHandle, 0, PromoteArg->DsLogPath );
  253. RtlFreeHeap( HeapHandle, 0, PromoteArg->SysVolRootPath );
  254. RtlFreeHeap( HeapHandle, 0, PromoteArg->Parent );
  255. RtlFreeHeap( HeapHandle, 0, PromoteArg->Server );
  256. RtlFreeHeap( HeapHandle, 0, PromoteArg->Account );
  257. RtlFreeHeap( HeapHandle, 0, PromoteArg->Password.Buffer );
  258. RtlFreeHeap( HeapHandle, 0, PromoteArg->DomainAdminPassword.Buffer );
  259. if ( PromoteArg->ImpersonateToken ) {
  260. NtClose( PromoteArg->ImpersonateToken );
  261. }
  262. } else {
  263. Demote = ( PDSROLEP_OPERATION_DEMOTE_ARGS )*ArgumentBlock;
  264. RtlFreeHeap( HeapHandle, 0, Demote->Account );
  265. RtlFreeHeap( HeapHandle, 0, Demote->Password.Buffer );
  266. RtlFreeHeap( HeapHandle, 0, Demote->DomainName );
  267. RtlFreeHeap( HeapHandle, 0, Demote->AdminPassword.Buffer );
  268. if ( Demote->ImpersonateToken ) {
  269. NtClose( Demote->ImpersonateToken );
  270. }
  271. }
  272. RtlFreeHeap( HeapHandle, 0, *ArgumentBlock );
  273. }
  274. DWORD
  275. DsRolepSpinWorkerThread(
  276. IN DSROLEP_OPERATION_TYPE Operation,
  277. IN PVOID ArgumentBlock
  278. )
  279. /*++
  280. Routine Description:
  281. This function actually creates the worker thread that will do the promot/demote
  282. Arguments:
  283. Operation - Demote, Promote as DC, or Promote as Replica
  284. ArgumentBlock - Block of arguments appropriate for the operation
  285. Returns:
  286. ERROR_SUCCESS - Success
  287. INVALID_PARAMETER - An unexpected operation type encounterd
  288. --*/
  289. {
  290. DWORD WinError = ERROR_SUCCESS, IgnoreError;
  291. NTSTATUS NtStatus;
  292. DWORD ThreadId;
  293. //
  294. // The basic premise is that we'll utilize the Completion event to indicate when
  295. // the thread is full initialized.
  296. //
  297. NtStatus = NtResetEvent( DsRolepCurrentOperationHandle.CompletionEvent, NULL );
  298. WinError = RtlNtStatusToDosError( NtStatus );
  299. if ( ERROR_SUCCESS == WinError ) {
  300. switch ( Operation) {
  301. case DSROLEP_OPERATION_DC:
  302. DsRolepCurrentOperationHandle.OperationThread = CreateThread(
  303. NULL,
  304. 0,
  305. ( LPTHREAD_START_ROUTINE )DsRolepThreadPromoteDc,
  306. ArgumentBlock,
  307. 0,
  308. &ThreadId );
  309. break;
  310. case DSROLEP_OPERATION_REPLICA:
  311. DsRolepCurrentOperationHandle.OperationThread = CreateThread(
  312. NULL,
  313. 0,
  314. ( LPTHREAD_START_ROUTINE )DsRolepThreadPromoteReplica,
  315. ArgumentBlock,
  316. 0,
  317. &ThreadId );
  318. break;
  319. case DSROLEP_OPERATION_DEMOTE:
  320. DsRolepCurrentOperationHandle.OperationThread = CreateThread(
  321. NULL,
  322. 0,
  323. ( LPTHREAD_START_ROUTINE )DsRolepThreadDemote,
  324. ArgumentBlock,
  325. 0,
  326. &ThreadId );
  327. break;
  328. default:
  329. DsRoleDebugOut(( DEB_ERROR,
  330. "Unexpected operation %lu encountered\n", Operation ));
  331. WinError = ERROR_INVALID_PARAMETER;
  332. break;
  333. }
  334. //
  335. // Check for failure
  336. //
  337. if ( WinError == ERROR_SUCCESS &&
  338. DsRolepCurrentOperationHandle.OperationThread == NULL ) {
  339. WinError = GetLastError();
  340. }
  341. //
  342. // If it worked, wait for the thread to indicate its ready
  343. //
  344. if ( WinError == ERROR_SUCCESS ) {
  345. if ( WaitForSingleObject( DsRolepCurrentOperationHandle.CompletionEvent,
  346. INFINITE ) == WAIT_FAILED ) {
  347. WinError = GetLastError();
  348. } else {
  349. NtResetEvent( DsRolepCurrentOperationHandle.CompletionEvent, NULL );
  350. }
  351. }
  352. }
  353. if ( WinError == ERROR_SUCCESS ) {
  354. DsRoleDebugOut(( DEB_TRACE,
  355. "Thread %lu successfully started\n", ThreadId ));
  356. } else {
  357. DsRolepLogPrint(( DEB_ERROR,
  358. "Thread %lu unsuccessfully started: %lu\n", ThreadId, WinError ));
  359. }
  360. return( WinError );
  361. }
  362. DWORD
  363. DsRolepThreadPromoteDc(
  364. IN PVOID ArgumentBlock
  365. )
  366. /*++
  367. Routine Description:
  368. This function actually "promotes" a server to a dc of an new domain. Additionally, this
  369. domain can be set up as a child of an existing domain. This is accomplished by:
  370. Installing the Ds as a replica
  371. Setting the DnsDomainTree LSA information
  372. Optionally configuring it as a child of an existing domain
  373. Configuring the KDC
  374. Arguments:
  375. ArgumentBlock - Block of arguments appropriate for the operation
  376. Returns:
  377. ERROR_SUCCESS - Success
  378. --*/
  379. {
  380. DWORD WinError = ERROR_SUCCESS;
  381. DWORD IgnoreError;
  382. PWSTR ParentDc = NULL;
  383. PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
  384. PDSROLEP_OPERATION_PROMOTE_ARGS PromoteArgs = ( PDSROLEP_OPERATION_PROMOTE_ARGS )ArgumentBlock;
  385. DSROLEP_DOMAIN_POLICY_INFO BackupDomainPolicyInfo;
  386. ULONG FindOptions;
  387. GUID DomainGuid;
  388. PWSTR InstalledSite = NULL;
  389. PSID NewDomainSid = NULL;
  390. PPOLICY_DNS_DOMAIN_INFO ParentDnsDomainInfo = NULL;
  391. PWSTR DnsDomainTreeName = NULL;
  392. //
  393. // BOOLEAN's to maintain state
  394. //
  395. // N.B. The order of these booleans is the order in which they
  396. // are changed -- please maintain order and make sure that
  397. // the PromoteUndo section undoes them in the reverse order
  398. //
  399. BOOLEAN IPCConnection = FALSE; // resource -- release on exit
  400. BOOLEAN RestartNetlogon = FALSE;
  401. BOOLEAN SysVolCreated = FALSE;
  402. BOOLEAN CleanupNetlogon = FALSE; // nothing to undo
  403. BOOLEAN DsInstalled = FALSE;
  404. BOOLEAN DsRunning = FALSE;
  405. BOOLEAN DomainPolicyInfoChanged = FALSE;
  406. BOOLEAN DomainServicesChanged = FALSE;
  407. BOOLEAN DomainControllerServicesChanged = FALSE;
  408. BOOLEAN TrustCreated = FALSE;
  409. BOOLEAN ProductTypeChanged = FALSE;
  410. //
  411. // Init the stack space
  412. //
  413. RtlZeroMemory(&BackupDomainPolicyInfo, sizeof(BackupDomainPolicyInfo));
  414. //
  415. // Set our event to indicate we're starting
  416. //
  417. NtSetEvent( DsRolepCurrentOperationHandle.CompletionEvent, NULL );
  418. //
  419. // If we have an existing domain in the forest to install from and we
  420. // weren't given a site or source server name, we need to make a dsgetdc
  421. // name.
  422. //
  423. if ( PromoteArgs->Server ) {
  424. ParentDc = PromoteArgs->Server;
  425. }
  426. if ( PromoteArgs->Parent != NULL &&
  427. ( (PromoteArgs->Server == NULL)
  428. || (PromoteArgs->SiteName == NULL) ) ) {
  429. DsRolepLogPrint(( DEB_TRACE,
  430. "No source DC or no site name specified. Searching for dc in domain %ws: ( DS_REQUIRED | WRITABLE )\n",
  431. PromoteArgs->Parent ));
  432. DSROLEP_CURRENT_OP1( DSROLEEVT_SEARCH_DC, PromoteArgs->Parent );
  433. FindOptions = DS_DIRECTORY_SERVICE_REQUIRED | DS_WRITABLE_REQUIRED | DS_FORCE_REDISCOVERY;
  434. WinError = DsGetDcName(NULL,
  435. PromoteArgs->Parent,
  436. NULL,
  437. NULL,
  438. FindOptions,
  439. &DomainControllerInfo );
  440. if ( ERROR_SUCCESS != WinError ) {
  441. DsRolepLogPrint(( DEB_TRACE,
  442. "Couldn't find domain controller in domain %ws (error: %d)\n",
  443. ParentDc,
  444. WinError ));
  445. if ( PromoteArgs->Server == NULL ) {
  446. //
  447. // This is a fatal error if we can't find a dc in the parent domain
  448. // If we have a server, then we can derive a site name later on if
  449. // necessary
  450. //
  451. DSROLEP_FAIL1( WinError, DSROLERES_FIND_DC, PromoteArgs->Parent );
  452. DsRolepLogPrint(( DEB_ERROR,
  453. "Failed to find a dc for %ws: %lu\n",
  454. PromoteArgs->Parent,
  455. WinError ));
  456. goto PromoteUndo;
  457. }
  458. //
  459. // This isn't fatal since we are a source server
  460. //
  461. DsRolepLogPrint(( DEB_TRACE, "Using supplied domain controller: %ws\n", ParentDc ));
  462. WinError = ERROR_SUCCESS;
  463. } else {
  464. //
  465. // The dsgetdcname succeeded
  466. //
  467. if ( PromoteArgs->Server == NULL ) {
  468. //
  469. // Use the found domain controller
  470. //
  471. DSROLEP_CURRENT_OP2( DSROLEEVT_FOUND_DC,
  472. PromoteArgs->Parent,
  473. ParentDc );
  474. DsRolepLogPrint(( DEB_TRACE_DS, "No user specified source DC\n" ));
  475. ParentDc = DomainControllerInfo->DomainControllerName;
  476. }
  477. //
  478. // Determine the site that we are going to be installed in
  479. // the results of the parent query
  480. //
  481. if ( PromoteArgs->SiteName == NULL ) {
  482. DsRolepLogPrint(( DEB_TRACE_DS, "No user specified site\n" ));
  483. PromoteArgs->SiteName = DomainControllerInfo->ClientSiteName;
  484. if ( (PromoteArgs->SiteName == NULL)
  485. && (!_wcsicmp(ParentDc, DomainControllerInfo->DomainControllerName)) ) {
  486. DsRolepLogPrint(( DEB_TRACE_DS, "This machine is not in a configured site ... using source DC's site.\n" ));
  487. PromoteArgs->SiteName = DomainControllerInfo->DcSiteName;
  488. } else {
  489. //
  490. // We can't find a site. That's ok -- the ds will find one for
  491. // us
  492. //
  493. }
  494. }
  495. if ( PromoteArgs->SiteName ) {
  496. DSROLEP_CURRENT_OP2( DSROLEEVT_FOUND_SITE,
  497. PromoteArgs->SiteName,
  498. PromoteArgs->Parent );
  499. } else {
  500. DsRolepLogPrint(( DEB_TRACE_DS, "This machine is not in a configured site\n" ));
  501. }
  502. }
  503. } else {
  504. //
  505. // The caller supplied both the source server and site name
  506. //
  507. ParentDc = PromoteArgs->Server;
  508. DsRolepLogPrint(( DEB_TRACE, "Using supplied domain controller: %ws\n", ParentDc ));
  509. DsRolepLogPrint(( DEB_TRACE, "Using supplied site: %ws\n", PromoteArgs->SiteName ));
  510. }
  511. //
  512. // Ok, we have determined the our source domain controller and destination
  513. // site
  514. //
  515. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  516. //
  517. // Force the time synch
  518. //
  519. if ( ParentDc
  520. && FLAG_ON( PromoteArgs->Options, DSROLE_DC_FORCE_TIME_SYNC ) ) {
  521. WinError = DsRolepForceTimeSync( PromoteArgs->ImpersonateToken,
  522. ParentDc );
  523. if ( ERROR_SUCCESS != WinError ) {
  524. DsRolepLogPrint(( DEB_WARN, "Time sync with %ws failed with %d\n",
  525. ParentDc,
  526. WinError ));
  527. //
  528. // This is not a fatal error
  529. //
  530. WinError = ERROR_SUCCESS;
  531. }
  532. }
  533. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  534. //
  535. // If we are setting up a child domain, establish a session first
  536. //
  537. if ( ParentDc ) {
  538. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  539. WinError = ImpNetpManageIPCConnect( PromoteArgs->ImpersonateToken,
  540. ParentDc,
  541. PromoteArgs->Account,
  542. PromoteArgs->Password.Buffer,
  543. NETSETUPP_CONNECT_IPC );
  544. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  545. if ( ERROR_SUCCESS != WinError ) {
  546. DSROLEP_FAIL1( WinError, DSROLERES_NET_USE, ParentDc );
  547. DsRolepLogPrint(( DEB_ERROR,
  548. "Failed to establish the session with %ws: 0x%lx\n", ParentDc,
  549. WinError ));
  550. goto PromoteUndo;
  551. }
  552. IPCConnection = TRUE;
  553. }
  554. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  555. //
  556. // If we have a parent dc, get the LSA policy from it
  557. //
  558. //
  559. // Strip the trailing '.' from the Dns name if we happen to have an absolute name
  560. //
  561. DSROLEP_MAKE_DNS_RELATIVE( PromoteArgs->DnsDomainName );
  562. DnsDomainTreeName = PromoteArgs->DnsDomainName;
  563. if ( ParentDc ) {
  564. NTSTATUS Status;
  565. UNICODE_STRING ParentServer;
  566. HANDLE ParentPolicy = NULL;
  567. OBJECT_ATTRIBUTES ObjectAttributes;
  568. DSROLEP_CURRENT_OP1( DSROLEEVT_MACHINE_POLICY, ParentDc );
  569. RtlInitUnicodeString( &ParentServer, ParentDc );
  570. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  571. Status = ImpLsaOpenPolicy( PromoteArgs->ImpersonateToken,
  572. &ParentServer,
  573. &ObjectAttributes,
  574. MAXIMUM_ALLOWED,
  575. &ParentPolicy );
  576. if ( NT_SUCCESS( Status ) ) {
  577. Status = ImpLsaQueryInformationPolicy( PromoteArgs->ImpersonateToken,
  578. ParentPolicy,
  579. PolicyDnsDomainInformation,
  580. &ParentDnsDomainInfo );
  581. ImpLsaClose( PromoteArgs->ImpersonateToken, ParentPolicy );
  582. }
  583. //
  584. // We'll have to build it as a NULL terminated string
  585. //
  586. if ( NT_SUCCESS( Status ) && ParentDnsDomainInfo->DnsForestName.Length ) {
  587. if ( ParentDnsDomainInfo->DnsForestName.Buffer[
  588. ParentDnsDomainInfo->DnsForestName.Length / sizeof( WCHAR ) ] == UNICODE_NULL ) {
  589. DnsDomainTreeName = ( PWSTR )ParentDnsDomainInfo->DnsForestName.Buffer;
  590. } else {
  591. DnsDomainTreeName = RtlAllocateHeap(
  592. RtlProcessHeap(), 0,
  593. ParentDnsDomainInfo->DnsForestName.Length + sizeof( WCHAR ) );
  594. if ( DnsDomainTreeName == NULL ) {
  595. Status = STATUS_INSUFFICIENT_RESOURCES;
  596. } else {
  597. RtlCopyMemory( DnsDomainTreeName,
  598. ParentDnsDomainInfo->DnsForestName.Buffer,
  599. ParentDnsDomainInfo->DnsForestName.Length );
  600. DnsDomainTreeName[ ParentDnsDomainInfo->DnsForestName.Length /
  601. sizeof( WCHAR ) ] = UNICODE_NULL;
  602. }
  603. }
  604. }
  605. WinError = RtlNtStatusToDosError( Status );
  606. DSROLEP_FAIL1( WinError, DSROLERES_POLICY_READ_REMOTE, ParentDc );
  607. if ( ERROR_SUCCESS != WinError ) {
  608. goto PromoteUndo;
  609. }
  610. }
  611. //
  612. // If we are doing a root install, make sure we were given the forest root
  613. // as our parent
  614. //
  615. if ( FLAG_ON( PromoteArgs->Options, DSROLE_DC_TRUST_AS_ROOT ) ) {
  616. DSROLEP_MAKE_DNS_RELATIVE( PromoteArgs->Parent );
  617. DSROLEP_MAKE_DNS_RELATIVE( DnsDomainTreeName );
  618. if ( _wcsicmp( PromoteArgs->Parent, DnsDomainTreeName ) ) {
  619. //
  620. // Names don't match... We can't allow this...
  621. //
  622. DsRolepLogPrint(( DEB_ERROR,
  623. "Tried to specify domain %ws as a forest root but "
  624. "%ws is the actual root\n",
  625. PromoteArgs->Parent,
  626. DnsDomainTreeName ));
  627. WinError = ERROR_INVALID_DOMAINNAME;
  628. DSROLEP_FAIL1( WinError, DSROLERES_NOT_FOREST_ROOT, PromoteArgs->Parent );
  629. goto PromoteUndo;
  630. }
  631. }
  632. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  633. //
  634. // Make a back up of the local policy...
  635. //
  636. WinError = DsRolepBackupDomainPolicyInfo( NULL, &BackupDomainPolicyInfo );
  637. if ( ERROR_SUCCESS != WinError ) {
  638. DSROLEP_FAIL0( WinError, DSROLERES_POLICY_READ_LOCAL );
  639. goto PromoteUndo;
  640. }
  641. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  642. //
  643. // Stop netlogon
  644. //
  645. DSROLEP_CURRENT_OP1( DSROLEEVT_STOP_SERVICE, SERVICE_NETLOGON );
  646. WinError = DsRolepStopNetlogon( &RestartNetlogon );
  647. if ( ERROR_SUCCESS != WinError ) {
  648. DsRolepLogPrint(( DEB_WARN, "Failed to stop NETLOGON (%d)\n", WinError ));
  649. goto PromoteUndo;
  650. }
  651. DsRolepLogPrint(( DEB_TRACE, "Stopped NETLOGON\n" ));
  652. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  653. //
  654. // Create the system volume information so we can seed the system volume while the Ds is
  655. // installing
  656. //
  657. DSROLEP_CURRENT_OP1( DSROLEEVT_CREATE_SYSVOL, PromoteArgs->SysVolRootPath );
  658. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  659. WinError = DsRolepCreateSysVolPath( PromoteArgs->SysVolRootPath,
  660. PromoteArgs->DnsDomainName,
  661. ParentDc,
  662. PromoteArgs->Account,
  663. PromoteArgs->Password.Buffer,
  664. PromoteArgs->SiteName,
  665. TRUE );
  666. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  667. DSROLEP_CURRENT_OP1( DSROLEEVT_SVSETUP, PromoteArgs->SysVolRootPath );
  668. if ( WinError != ERROR_SUCCESS ) {
  669. DsRolepLogPrint(( DEB_ERROR, "Failed to create the system volume (%d)\n", WinError ));
  670. goto PromoteUndo;
  671. }
  672. SysVolCreated = TRUE;
  673. DsRolepLogPrint(( DEB_TRACE, "Created the system volume\n" ));
  674. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  675. //
  676. // Setup the Ds
  677. //
  678. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  679. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->DomainAdminPassword );
  680. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->SafeModePassword );
  681. WinError = DsRolepInstallDs( PromoteArgs->DnsDomainName,
  682. PromoteArgs->FlatDomainName,
  683. DnsDomainTreeName,
  684. PromoteArgs->SiteName,
  685. PromoteArgs->DsDatabasePath,
  686. PromoteArgs->DsLogPath,
  687. PromoteArgs->RestorePath,
  688. PromoteArgs->SysVolRootPath,
  689. &(PromoteArgs->Bootkey),
  690. PromoteArgs->DomainAdminPassword.Buffer,
  691. PromoteArgs->Parent,
  692. ParentDc,
  693. PromoteArgs->Account,
  694. PromoteArgs->Password.Buffer,
  695. PromoteArgs->SafeModePassword.Buffer,
  696. PromoteArgs->Parent,
  697. PromoteArgs->Options,
  698. FALSE,
  699. PromoteArgs->ImpersonateToken,
  700. &InstalledSite,
  701. &DomainGuid,
  702. &NewDomainSid );
  703. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  704. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->DomainAdminPassword );
  705. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->SafeModePassword );
  706. if ( ERROR_SUCCESS != WinError ) {
  707. DsRolepLogPrint(( DEB_ERROR, "Failed to install the directory service (%d)\n", WinError ));
  708. goto PromoteUndo;
  709. }
  710. DsRunning = TRUE;
  711. DsInstalled = TRUE;
  712. DsRolepLogPrint(( DEB_TRACE, "Installed the directory service\n", WinError ));
  713. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  714. //
  715. // Set the LSA domain policy
  716. //
  717. WinError = DsRolepSetLsaDomainPolicyInfo( PromoteArgs->DnsDomainName,
  718. PromoteArgs->FlatDomainName,
  719. DnsDomainTreeName,
  720. &DomainGuid,
  721. NewDomainSid,
  722. NTDS_INSTALL_DOMAIN,
  723. &BackupDomainPolicyInfo );
  724. if ( ERROR_SUCCESS != WinError ) {
  725. DsRolepLogPrint(( DEB_ERROR, "Failed to set the LSA policy (%d)\n", WinError ));
  726. DSROLEP_FAIL0( WinError, DSROLERES_POLICY_WRITE_LOCAL );
  727. goto PromoteUndo;
  728. }
  729. DomainPolicyInfoChanged = TRUE;
  730. DsRolepLogPrint(( DEB_TRACE, "Set the LSA policy\n"));
  731. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  732. //
  733. // Configure the domain relative services
  734. //
  735. WinError = DsRolepConfigureDomainServices( DSROLEP_SERVICES_ON );
  736. if ( WinError != ERROR_SUCCESS ) {
  737. DsRolepLogPrint(( DEB_ERROR, "Failed to configure the domain services (%d)\n", WinError ));
  738. goto PromoteUndo;
  739. }
  740. DomainServicesChanged = TRUE;
  741. DsRolepLogPrint(( DEB_TRACE, "Configured the domain services\n" ));
  742. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  743. //
  744. // Configure the domain controller relative services
  745. //
  746. WinError = DsRolepConfigureDomainControllerServices( DSROLEP_SERVICES_ON );
  747. if ( WinError != ERROR_SUCCESS ) {
  748. DsRolepLogPrint(( DEB_ERROR, "Failed to configure the domain controller services (%d)\n", WinError ));
  749. goto PromoteUndo;
  750. }
  751. DomainControllerServicesChanged = TRUE;
  752. DsRolepLogPrint(( DEB_TRACE, "Configured the domain controller services\n" ));
  753. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  754. //
  755. // Finally, upgrade the Lsa to the Ds.
  756. //
  757. WinError = DsRolepUpgradeLsaToDs( TRUE );
  758. if ( ERROR_SUCCESS != WinError ) {
  759. DSROLEP_FAIL0( WinError, DSROLERES_LSA_UPGRADE );
  760. DsRolepLogOnFailure( WinError,
  761. DsRolepLogPrint(( DEB_TRACE,
  762. "Upgrade of the LSA into the DS failed with %lu\n",
  763. WinError )) );
  764. goto PromoteUndo;
  765. }
  766. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  767. //
  768. // Create the trust objects and set the DnsDomainTree information
  769. //
  770. if ( ParentDc ) {
  771. WinError = DsRolepCreateTrustedDomainObjects( PromoteArgs->ImpersonateToken,
  772. ParentDc,
  773. PromoteArgs->DnsDomainName,
  774. ParentDnsDomainInfo,
  775. PromoteArgs->Options );
  776. if ( WinError != ERROR_SUCCESS ) {
  777. DsRolepLogPrint(( DEB_ERROR, "Failed to create trusted domain objects (%d)\n", WinError ));
  778. goto PromoteUndo;
  779. }
  780. TrustCreated = TRUE;
  781. DsRolepLogPrint(( DEB_TRACE, "Created trusted domain objects\n" ));
  782. }
  783. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  784. //
  785. // Create the GPO for policy
  786. //
  787. WinError = ( *DsrSceDcPromoCreateGPOsInSysvolEx )( PromoteArgs->ImpersonateToken,
  788. PromoteArgs->DnsDomainName,
  789. PromoteArgs->SysVolRootPath,
  790. FLAG_ON( PromoteArgs->Options,
  791. DSROLE_DC_DOWNLEVEL_UPGRADE ) ?
  792. SCE_PROMOTE_FLAG_UPGRADE :
  793. 0,
  794. DsRolepStringUpdateCallback );
  795. if ( ERROR_SUCCESS != WinError ) {
  796. DSROLEP_FAIL1( WinError, DSROLERES_GPO_CREATION, PromoteArgs->DnsDomainName );
  797. DsRolepLogOnFailure( WinError,
  798. DsRolepLogPrint(( DEB_TRACE,
  799. "Creation of GPO failed with %lu\n",
  800. WinError )) );
  801. goto PromoteUndo;
  802. }
  803. DsRolepLogPrint(( DEB_TRACE,
  804. "Created GPO\n" ));
  805. //
  806. // Stop the Ds
  807. //
  808. DsRolepStopDs( DsRunning );
  809. DsRunning = FALSE;
  810. //
  811. // If the install succeeded, make sure to save off the new site name
  812. //
  813. WinError = DsRolepSetOperationHandleSiteName( InstalledSite );
  814. if ( WinError != ERROR_SUCCESS ) {
  815. DsRolepLogPrint(( DEB_ERROR, "Failed to copy site name (%d)\n", WinError ));
  816. goto PromoteUndo;
  817. }
  818. //
  819. // If we update it, NULL out the local parameter so we don't attempt to delete it
  820. //
  821. InstalledSite = NULL;
  822. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  823. //
  824. // Set the computers Dns domain name
  825. //
  826. DSROLEP_CURRENT_OP1( DSROLEEVT_SET_COMPUTER_DNS, PromoteArgs->DnsDomainName );
  827. WinError = NetpSetDnsComputerNameAsRequired( PromoteArgs->DnsDomainName );
  828. if ( ERROR_SUCCESS != WinError ) {
  829. DsRolepLogOnFailure( WinError,
  830. DsRolepLogPrint(( DEB_TRACE,
  831. "NetpSetDnsComputerNameAsRequired to %ws failed with %lu\n",
  832. PromoteArgs->DnsDomainName,
  833. WinError )) );
  834. DSROLEP_FAIL1( WinError, DSROLERES_SET_COMPUTER_DNS, PromoteArgs->DnsDomainName );
  835. goto PromoteUndo;
  836. }
  837. //
  838. // Restart netlogon if it was stopped and if a failure occurred
  839. //
  840. //
  841. // Complete the sysvol replication
  842. //
  843. WinError = DsRolepFinishSysVolPropagation( TRUE, TRUE );
  844. if ( ERROR_SUCCESS != WinError ) {
  845. DsRolepLogPrint(( DEB_ERROR, "Failed to complete system volume replication (%d)\n", WinError ));
  846. goto PromoteUndo;
  847. }
  848. DsRolepLogPrint(( DEB_TRACE, "Completed system volume replication\n"));
  849. //
  850. // Next, set the sysvol path for netlogon
  851. //
  852. WinError = DsRolepSetNetlogonSysVolPath( PromoteArgs->SysVolRootPath,
  853. PromoteArgs->DnsDomainName,
  854. ( BOOLEAN )FLAG_ON( PromoteArgs->Options,
  855. DSROLE_DC_DOWNLEVEL_UPGRADE ),
  856. &CleanupNetlogon );
  857. if ( ERROR_SUCCESS != WinError ) {
  858. DsRolepLogPrint(( DEB_ERROR, "Failed to set system volume path for NETLOGON (%d)\n", WinError ));
  859. goto PromoteUndo;
  860. }
  861. DsRolepLogPrint(( DEB_TRACE, "Set system volume path for NETLOGON\n" ));
  862. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  863. //
  864. // Set the machine role
  865. //
  866. WinError = DsRolepSetProductType( DSROLEP_MT_MEMBER );
  867. if ( ERROR_SUCCESS != WinError ) {
  868. DsRolepLogPrint(( DEB_ERROR, "Failed to set the product type (%d)\n", WinError ));
  869. goto PromoteUndo;
  870. }
  871. ProductTypeChanged = TRUE;
  872. DsRolepLogPrint(( DEB_TRACE, "Set the product type\n" ));
  873. //
  874. // Set the security on the dc files
  875. //
  876. WinError = DsRolepSetDcSecurity( PromoteArgs->ImpersonateToken,
  877. PromoteArgs->SysVolRootPath,
  878. PromoteArgs->DsDatabasePath,
  879. PromoteArgs->DsLogPath,
  880. ( BOOLEAN )FLAG_ON( PromoteArgs->Options,
  881. DSROLE_DC_DOWNLEVEL_UPGRADE ),
  882. FALSE );
  883. if ( ERROR_SUCCESS != WinError ) {
  884. DsRolepLogPrint(( DEB_ERROR, "Failed to set security on domain controller (%d)\n", WinError ));
  885. goto PromoteUndo;
  886. }
  887. DsRolepLogPrint(( DEB_TRACE, "Set security on domain controller\n"));
  888. DsRolepSetCriticalOperationsDone();
  889. //
  890. // From here to do the end, perform, and only perform, non critical
  891. // operations
  892. //
  893. //
  894. // Indicate that we are no longer doing upgrades, if applicable
  895. //
  896. if ( FLAG_ON( PromoteArgs->Options, DSROLE_DC_DOWNLEVEL_UPGRADE ) ) {
  897. WinError = DsRolepDeleteUpgradeInfo();
  898. DsRolepLogOnFailure( WinError,
  899. DsRolepLogPrint(( DEB_WARN,
  900. "Failed to cleanup upgrade info (%d)\n",
  901. WinError )) );
  902. if (ERROR_SUCCESS == WinError) {
  903. DsRolepLogPrint(( DEB_TRACE,
  904. "Removed upgrade info\n" ));
  905. }
  906. // This error isn't interesting to propogate
  907. WinError = ERROR_SUCCESS;
  908. }
  909. //
  910. // Remove any old netlogon stuff if we got that far
  911. //
  912. if ( CleanupNetlogon ) {
  913. WinError = DsRolepCleanupOldNetlogonInformation();
  914. DsRolepLogOnFailure( WinError,
  915. DsRolepLogPrint(( DEB_WARN,
  916. "Failed to cleanup old netlogon information (%d)\n",
  917. WinError )) );
  918. if (ERROR_SUCCESS == WinError) {
  919. DsRolepLogPrint(( DEB_TRACE,
  920. "Removed old netlogon information\n" ));
  921. }
  922. // This error isn't interesting to propogate
  923. WinError = ERROR_SUCCESS;
  924. }
  925. //
  926. // Set the default logon domain to the current domain name
  927. //
  928. WinError = DsRolepSetLogonDomain( PromoteArgs->FlatDomainName, FALSE );
  929. if ( ERROR_SUCCESS != WinError ) {
  930. DsRolepLogOnFailure( WinError,
  931. DsRolepLogPrint(( DEB_WARN,
  932. "Failed to set default logon domain to %ws (%d)\n",
  933. PromoteArgs->FlatDomainName,
  934. WinError )) );
  935. if (ERROR_SUCCESS == WinError) {
  936. DsRolepLogPrint(( DEB_TRACE,
  937. "Set default logon domain to %ws\n",
  938. PromoteArgs->FlatDomainName ));
  939. }
  940. //
  941. // This is no reason to fail
  942. //
  943. WinError = ERROR_SUCCESS;
  944. }
  945. //
  946. // Notify the time server we have completed the promotion
  947. //
  948. {
  949. DWORD dwTimeFlags = W32TIME_PROMOTE;
  950. if ( FLAG_ON( PromoteArgs->Options, DSROLE_DC_TRUST_AS_ROOT )
  951. || (NULL == PromoteArgs->Parent) ) {
  952. //
  953. // Any tree root, including the root of the forest
  954. // should have this flag.
  955. //
  956. dwTimeFlags |= W32TIME_PROMOTE_FIRST_DC_IN_TREE;
  957. }
  958. (*DsrW32TimeDcPromo)( dwTimeFlags );
  959. }
  960. //
  961. // By this time, we have successfully completed the promotion operation
  962. //
  963. ASSERT( ERROR_SUCCESS == WinError );
  964. PromoteExit:
  965. // The DS should not be running at this point
  966. ASSERT( FALSE == DsRunning );
  967. //
  968. // Release any resources
  969. //
  970. //
  971. // Tear down the session to the parent, if we have one
  972. //
  973. if ( IPCConnection ) {
  974. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  975. IgnoreError = ImpNetpManageIPCConnect( PromoteArgs->ImpersonateToken,
  976. ParentDc,
  977. PromoteArgs->Account,
  978. PromoteArgs->Password.Buffer,
  979. (NETSETUPP_DISCONNECT_IPC | NETSETUPP_USE_LOTS_FORCE));
  980. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  981. if ( IgnoreError != ERROR_SUCCESS ) {
  982. DsRolepLogPrint(( DEB_WARN,
  983. "Failed to destroy the session with %ws: 0x%lx\n", ParentDc,
  984. IgnoreError ));
  985. }
  986. IPCConnection = FALSE;
  987. }
  988. if ( ParentDnsDomainInfo ) {
  989. if ( DnsDomainTreeName != ParentDnsDomainInfo->DnsForestName.Buffer ) {
  990. RtlFreeHeap( RtlProcessHeap(), 0, DnsDomainTreeName );
  991. }
  992. LsaFreeMemory( ParentDnsDomainInfo );
  993. }
  994. if ( InstalledSite ) {
  995. RtlFreeHeap( RtlProcessHeap(), 0, InstalledSite );
  996. }
  997. if ( NewDomainSid ) {
  998. RtlFreeHeap( RtlProcessHeap(), 0, NewDomainSid );
  999. }
  1000. DsRolepFreeDomainPolicyInfo( &BackupDomainPolicyInfo );
  1001. if ( DomainControllerInfo != NULL ) {
  1002. if ( PromoteArgs->SiteName == DomainControllerInfo->DcSiteName ||
  1003. PromoteArgs->SiteName == DomainControllerInfo->ClientSiteName ) {
  1004. PromoteArgs->SiteName = NULL;
  1005. }
  1006. NetApiBufferFree( DomainControllerInfo );
  1007. }
  1008. DsRolepFreeArgumentBlock( &ArgumentBlock, TRUE );
  1009. //
  1010. // Reset our operation handle and set the final operation status
  1011. //
  1012. DsRolepSetOperationDone( DSROLEP_OP_PROMOTION, WinError );
  1013. ExitThread( WinError );
  1014. return( WinError );
  1015. PromoteUndo:
  1016. //
  1017. // Something must have failed if we are undoing
  1018. //
  1019. ASSERT( WinError != ERROR_SUCCESS );
  1020. if ( ProductTypeChanged ) {
  1021. IgnoreError = DsRolepSetProductType( DSROLEP_MT_STANDALONE );
  1022. DsRolepLogOnFailure( IgnoreError,
  1023. DsRolepLogPrint(( DEB_WARN,
  1024. "Failed to rollback product type (%d)\n",
  1025. IgnoreError )) );
  1026. ProductTypeChanged = FALSE;
  1027. }
  1028. if ( TrustCreated ) {
  1029. IgnoreError = DsRolepRemoveTrustedDomainObjects( PromoteArgs->ImpersonateToken,
  1030. ParentDc,
  1031. ParentDnsDomainInfo,
  1032. FLAG_ON( PromoteArgs->Options,
  1033. DSROLE_DC_PARENT_TRUST_EXISTS ) ?
  1034. 0 :
  1035. DSROLE_DC_DELETE_PARENT_TRUST );
  1036. DsRolepLogOnFailure( IgnoreError,
  1037. DsRolepLogPrint(( DEB_WARN,
  1038. "Failed to rollback trusted domain object creations (%d)\n",
  1039. IgnoreError )) );
  1040. TrustCreated = FALSE;
  1041. }
  1042. if ( DomainControllerServicesChanged ) {
  1043. IgnoreError = DsRolepConfigureDomainControllerServices( DSROLEP_SERVICES_REVERT );
  1044. DsRolepLogOnFailure( IgnoreError,
  1045. DsRolepLogPrint(( DEB_WARN,
  1046. "Failed to rollback domain controller services configuration (%d)\n",
  1047. IgnoreError )) );
  1048. DomainControllerServicesChanged = FALSE;
  1049. }
  1050. if ( DomainServicesChanged ) {
  1051. IgnoreError = DsRolepConfigureDomainServices( DSROLEP_SERVICES_REVERT );
  1052. DsRolepLogOnFailure( IgnoreError,
  1053. DsRolepLogPrint(( DEB_WARN,
  1054. "Failed to rollback domain services configuration (%d)\n",
  1055. IgnoreError )) );
  1056. DomainServicesChanged = FALSE;
  1057. }
  1058. if ( DomainPolicyInfoChanged ) {
  1059. IgnoreError = DsRolepRestoreDomainPolicyInfo(&BackupDomainPolicyInfo);
  1060. DsRolepLogOnFailure( IgnoreError,
  1061. DsRolepLogPrint(( DEB_WARN,
  1062. "Failed to rollback domain policy information (%d)\n",
  1063. IgnoreError )) );
  1064. DomainPolicyInfoChanged = FALSE;
  1065. }
  1066. if ( DsRunning ) {
  1067. IgnoreError = DsRolepStopDs( DsRunning );
  1068. DsRolepLogOnFailure( IgnoreError,
  1069. DsRolepLogPrint(( DEB_WARN,
  1070. "Failed to stop the directory service (%d)\n",
  1071. IgnoreError )) );
  1072. DsRunning = FALSE;
  1073. }
  1074. if ( DsInstalled ) {
  1075. IgnoreError = DsRolepUninstallDs( );
  1076. DsRolepLogOnFailure( IgnoreError,
  1077. DsRolepLogPrint(( DEB_WARN,
  1078. "Failed to rollback directory service installation (%d)\n",
  1079. IgnoreError )) );
  1080. DsInstalled = FALSE;
  1081. }
  1082. if ( SysVolCreated ) {
  1083. IgnoreError = DsRolepFinishSysVolPropagation( FALSE, TRUE );
  1084. DsRolepLogOnFailure( IgnoreError,
  1085. DsRolepLogPrint(( DEB_WARN,
  1086. "Failed to abort system volume installation (%d)\n",
  1087. IgnoreError )) );
  1088. IgnoreError = DsRolepRemoveSysVolPath( PromoteArgs->SysVolRootPath,
  1089. PromoteArgs->DnsDomainName,
  1090. &DomainGuid );
  1091. DsRolepLogOnFailure( IgnoreError,
  1092. DsRolepLogPrint(( DEB_WARN,
  1093. "Failed to remove system volume path (%d)\n",
  1094. IgnoreError )) );
  1095. SysVolCreated = FALSE;
  1096. }
  1097. if ( RestartNetlogon ) {
  1098. IgnoreError = DsRolepStartNetlogon();
  1099. DsRolepLogOnFailure( IgnoreError,
  1100. DsRolepLogPrint(( DEB_WARN,
  1101. "Failed to restart netlogon (%d)\n",
  1102. IgnoreError )) );
  1103. RestartNetlogon = FALSE;
  1104. }
  1105. //
  1106. // We are finished the undo -- exit the thread
  1107. //
  1108. ASSERT( ERROR_SUCCESS != WinError );
  1109. goto PromoteExit;
  1110. }
  1111. DWORD
  1112. DsRolepThreadPromoteReplica(
  1113. IN PVOID ArgumentBlock
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. This function actually "promotes" a server to a replica of an existing domain. This is
  1118. accomplished by:
  1119. Installing the Ds as a replica
  1120. Setting the DnsDomainTree LSA information
  1121. Configuring the KDC
  1122. Required are the Dns domain name and the name of a replica within the domain, and the
  1123. Db and Log paths
  1124. Arguments:
  1125. ArgumentBlock - Block of arguments appropriate for the operation
  1126. Returns:
  1127. ERROR_SUCCESS - Success
  1128. --*/
  1129. {
  1130. DWORD WinError = ERROR_SUCCESS, IgnoreError;
  1131. PDSROLEP_OPERATION_PROMOTE_ARGS PromoteArgs = (PDSROLEP_OPERATION_PROMOTE_ARGS)ArgumentBlock;
  1132. PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
  1133. DSROLEP_DOMAIN_POLICY_INFO BackupDomainPolicyInfo;
  1134. ULONG FindOptions = 0;
  1135. GUID DomainGuid;
  1136. PWSTR InstalledSite = NULL, ReplicaServer = NULL;
  1137. PSID NewDomainSid = NULL;
  1138. WCHAR LocalMachineAccountName[ MAX_COMPUTERNAME_LENGTH + 2 ];
  1139. ULONG Length = MAX_COMPUTERNAME_LENGTH + 1;
  1140. //
  1141. // BOOLEAN's to maintain state
  1142. //
  1143. // N.B. The order of these booleans is the order in which they
  1144. // are changed -- please maintain order and make sure that
  1145. // the PromoteUndo section undoes them in the reverse order
  1146. //
  1147. BOOLEAN IPCConnection = FALSE; // resource -- release on exit
  1148. BOOLEAN RestartNetlogon = FALSE;
  1149. BOOLEAN SysVolCreated = FALSE;
  1150. BOOLEAN DsInstalled = FALSE;
  1151. BOOLEAN DsRunning = FALSE;
  1152. BOOLEAN DomainPolicyInfoChanged = FALSE;
  1153. BOOLEAN DomainControllerServicesChanged = FALSE;
  1154. BOOLEAN ProductTypeChanged = FALSE;
  1155. RtlZeroMemory(&BackupDomainPolicyInfo, sizeof(BackupDomainPolicyInfo));
  1156. //
  1157. // Set our event to indicate we're starting
  1158. //
  1159. NtSetEvent( DsRolepCurrentOperationHandle.CompletionEvent, NULL );
  1160. //
  1161. // Get the account name
  1162. //
  1163. if ( GetComputerName( LocalMachineAccountName, &Length ) == FALSE ) {
  1164. WinError = GetLastError();
  1165. DsRolepLogPrint(( DEB_ERROR, "Failed to get computer name (%d)\n", WinError ));
  1166. goto PromoteUndo;
  1167. } else {
  1168. wcscat( LocalMachineAccountName, L"$" );
  1169. }
  1170. //
  1171. // Strip the trailing '.' from the Dns name if we happen to have an absolute name
  1172. //
  1173. DSROLEP_MAKE_DNS_RELATIVE( PromoteArgs->DnsDomainName );
  1174. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1175. if (PromoteArgs->Server) {
  1176. if ( FLAG_ON( PromoteArgs->Options, DSROLE_DC_FORCE_TIME_SYNC ) ) {
  1177. WinError = DsRolepForceTimeSync( PromoteArgs->ImpersonateToken,
  1178. PromoteArgs->Server );
  1179. if ( ERROR_SUCCESS != WinError ) {
  1180. // the machine object was moved
  1181. DsRolepLogPrint(( DEB_WARN, "Time sync with %ws failed with %d\n",
  1182. PromoteArgs->Server,
  1183. WinError ));
  1184. WinError = ERROR_SUCCESS;
  1185. }
  1186. }
  1187. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1188. //
  1189. // Start a connection to the ReplicaServer
  1190. //
  1191. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  1192. WinError = ImpNetpManageIPCConnect( PromoteArgs->ImpersonateToken,
  1193. PromoteArgs->Server,
  1194. PromoteArgs->Account,
  1195. PromoteArgs->Password.Buffer,
  1196. NETSETUPP_CONNECT_IPC );
  1197. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  1198. if ( WinError != ERROR_SUCCESS ) {
  1199. DSROLEP_FAIL1( WinError, DSROLERES_NET_USE, PromoteArgs->Server );
  1200. DsRolepLogPrint(( DEB_ERROR,
  1201. "Failed to establish the session with %ws: 0x%lx\n", PromoteArgs->Server,
  1202. WinError ));
  1203. goto PromoteUndo;
  1204. }
  1205. ReplicaServer = PromoteArgs->Server;
  1206. IPCConnection = TRUE;
  1207. }
  1208. //
  1209. // Find the server that holds the machine account for this machine
  1210. //
  1211. FindOptions = DS_DIRECTORY_SERVICE_REQUIRED | DS_WRITABLE_REQUIRED | DS_FORCE_REDISCOVERY |
  1212. DS_RETURN_DNS_NAME;
  1213. WinError = ImpDsRolepDsGetDcForAccount( PromoteArgs->ImpersonateToken,
  1214. PromoteArgs->Server,
  1215. PromoteArgs->DnsDomainName,
  1216. LocalMachineAccountName,
  1217. FindOptions,
  1218. UF_WORKSTATION_TRUST_ACCOUNT |
  1219. UF_SERVER_TRUST_ACCOUNT,
  1220. &DomainControllerInfo );
  1221. if ( ERROR_SUCCESS != WinError ) {
  1222. DsRolepLogPrint(( DEB_ERROR, "Failed to get domain controller for account %ws (%d)\n", LocalMachineAccountName, WinError ));
  1223. DSROLEP_FAIL1( WinError, DSROLERES_FIND_DC, PromoteArgs->DnsDomainName );
  1224. goto PromoteUndo;
  1225. }
  1226. //
  1227. // Determine source server
  1228. //
  1229. if ( NULL == PromoteArgs->Server ) {
  1230. //
  1231. // No server was passed -- use the result of the dsgetdc
  1232. //
  1233. ReplicaServer = DomainControllerInfo->DomainControllerName;
  1234. } else {
  1235. ReplicaServer = PromoteArgs->Server;
  1236. if ( !DnsNameCompare_W(*(PromoteArgs->Server)==L'\\'?(PromoteArgs->Server)+2:PromoteArgs->Server,
  1237. *(DomainControllerInfo->DomainControllerName)==L'\\'?(DomainControllerInfo->DomainControllerName)+2:DomainControllerInfo->DomainControllerName ) ) {
  1238. WinError = ERROR_DS_UNWILLING_TO_PERFORM;
  1239. DsRolepLogPrint(( DEB_ERROR, "DsGetDcForAccount Failed to get the requested domain controller %ws for account %ws (%d)\n",
  1240. PromoteArgs->Server,
  1241. LocalMachineAccountName,
  1242. WinError));
  1243. DSROLEP_FAIL3( WinError,
  1244. DSROLERES_FAILED_FIND_REQUESTED_DC,
  1245. PromoteArgs->Server,
  1246. LocalMachineAccountName,
  1247. DomainControllerInfo->DomainControllerName );
  1248. goto PromoteUndo;
  1249. }
  1250. }
  1251. //
  1252. // Determine destination site
  1253. //
  1254. if ( PromoteArgs->SiteName == NULL ) {
  1255. PromoteArgs->SiteName = DomainControllerInfo->ClientSiteName;
  1256. if ( PromoteArgs->SiteName == NULL ) {
  1257. PromoteArgs->SiteName = DomainControllerInfo->DcSiteName;
  1258. }
  1259. }
  1260. DSROLEP_CURRENT_OP2( DSROLEEVT_FOUND_SITE,
  1261. PromoteArgs->SiteName,
  1262. ReplicaServer );
  1263. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1264. if (!IPCConnection) {
  1265. //
  1266. // Force the time synch
  1267. //
  1268. DsRolepLogPrint(( DEB_TRACE, "Forcing time sync\n"));
  1269. if ( FLAG_ON( PromoteArgs->Options, DSROLE_DC_FORCE_TIME_SYNC ) ) {
  1270. WinError = DsRolepForceTimeSync( PromoteArgs->ImpersonateToken,
  1271. ReplicaServer );
  1272. if ( ERROR_SUCCESS != WinError ) {
  1273. // the machine object was moved
  1274. DsRolepLogPrint(( DEB_WARN, "Time sync with %ws failed with %d\n",
  1275. ReplicaServer,
  1276. WinError ));
  1277. WinError = ERROR_SUCCESS;
  1278. }
  1279. }
  1280. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1281. //
  1282. // Attempt to start a RDR connection because we will need one later on
  1283. //
  1284. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  1285. WinError = ImpNetpManageIPCConnect( PromoteArgs->ImpersonateToken,
  1286. ReplicaServer,
  1287. PromoteArgs->Account,
  1288. PromoteArgs->Password.Buffer,
  1289. NETSETUPP_CONNECT_IPC );
  1290. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  1291. if ( WinError != ERROR_SUCCESS ) {
  1292. DSROLEP_FAIL1( WinError, DSROLERES_NET_USE, ReplicaServer );
  1293. DsRolepLogPrint(( DEB_ERROR,
  1294. "Failed to establish the session with %ws: 0x%lx\n", ReplicaServer,
  1295. WinError ));
  1296. goto PromoteUndo;
  1297. }
  1298. IPCConnection = TRUE;
  1299. }
  1300. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1301. //
  1302. // Stop netlogon
  1303. //
  1304. DSROLEP_CURRENT_OP1( DSROLEEVT_STOP_SERVICE, SERVICE_NETLOGON );
  1305. WinError = DsRolepStopNetlogon( &RestartNetlogon );
  1306. if ( ERROR_SUCCESS != WinError ) {
  1307. DsRolepLogPrint(( DEB_ERROR, "Failed to stop NETLOGON (%d)\n", WinError ));
  1308. goto PromoteUndo;
  1309. }
  1310. DsRolepLogPrint(( DEB_TRACE, "Stopped NETLOGON\n" ));
  1311. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1312. //
  1313. // Create the system volume information
  1314. //
  1315. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  1316. WinError = DsRolepCreateSysVolPath( PromoteArgs->SysVolRootPath,
  1317. PromoteArgs->DnsDomainName,
  1318. ReplicaServer,
  1319. PromoteArgs->Account,
  1320. PromoteArgs->Password.Buffer,
  1321. PromoteArgs->SiteName,
  1322. FALSE );
  1323. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  1324. if ( ERROR_SUCCESS != WinError ) {
  1325. DsRolepLogPrint(( DEB_ERROR, "Failed to create system volume path (%d)\n", WinError ));
  1326. goto PromoteUndo;
  1327. }
  1328. DsRolepLogPrint(( DEB_TRACE, "Created system volume path\n" ));
  1329. SysVolCreated = TRUE;
  1330. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1331. //
  1332. // Setup the Ds
  1333. //
  1334. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->DomainAdminPassword );
  1335. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  1336. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->SafeModePassword );
  1337. WinError = DsRolepInstallDs( PromoteArgs->DnsDomainName,
  1338. PromoteArgs->FlatDomainName,
  1339. NULL, // DnsTreeRoot not used for replica installs
  1340. PromoteArgs->SiteName,
  1341. PromoteArgs->DsDatabasePath,
  1342. PromoteArgs->DsLogPath,
  1343. PromoteArgs->RestorePath,
  1344. PromoteArgs->SysVolRootPath,
  1345. &(PromoteArgs->Bootkey),
  1346. PromoteArgs->DomainAdminPassword.Buffer,
  1347. PromoteArgs->Parent,
  1348. ReplicaServer,
  1349. PromoteArgs->Account,
  1350. PromoteArgs->Password.Buffer,
  1351. PromoteArgs->SafeModePassword.Buffer,
  1352. PromoteArgs->DnsDomainName,
  1353. PromoteArgs->Options,
  1354. TRUE,
  1355. PromoteArgs->ImpersonateToken,
  1356. &InstalledSite,
  1357. &DomainGuid,
  1358. &NewDomainSid );
  1359. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  1360. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->DomainAdminPassword );
  1361. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->SafeModePassword );
  1362. if ( ERROR_SUCCESS != WinError ) {
  1363. DsRolepLogPrint(( DEB_ERROR, "Failed to install to Directory Service (%d)\n", WinError ));
  1364. goto PromoteUndo;
  1365. }
  1366. DsRunning = TRUE;
  1367. DsInstalled = TRUE;
  1368. DsRolepLogPrint(( DEB_TRACE, "Installed Directory Service\n" ));
  1369. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1370. //
  1371. // Set the lsa domain information to reflect the new security database
  1372. // that was brought in. The Set below does not set the DnsDomainInformation,
  1373. // since the flat name is not yet known. The DnsDomainInformation gets
  1374. // set by the DsRolepSetLsaInformationForReplica call following.
  1375. //
  1376. WinError = DsRolepBackupDomainPolicyInfo( NULL, &BackupDomainPolicyInfo );
  1377. if ( ERROR_SUCCESS != WinError ) {
  1378. DsRolepLogPrint(( DEB_ERROR, "Failed to make backup of LSA policy (%d)\n", WinError ));
  1379. DSROLEP_FAIL0( WinError, DSROLERES_POLICY_READ_LOCAL );
  1380. goto PromoteUndo;
  1381. }
  1382. WinError = DsRolepSetLsaDomainPolicyInfo( PromoteArgs->DnsDomainName,
  1383. PromoteArgs->FlatDomainName,
  1384. NULL,
  1385. &DomainGuid,
  1386. NewDomainSid,
  1387. NTDS_INSTALL_REPLICA,
  1388. &BackupDomainPolicyInfo );
  1389. if ( ERROR_SUCCESS != WinError ) {
  1390. DSROLEP_FAIL0( WinError, DSROLERES_POLICY_WRITE_LOCAL );
  1391. goto PromoteUndo;
  1392. }
  1393. DomainPolicyInfoChanged = TRUE;
  1394. DsRolepLogPrint(( DEB_TRACE, "Wrote the LSA policy information for the local machine\n" ));
  1395. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1396. //
  1397. // This extra call is necessary to get the dns tree information
  1398. //
  1399. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  1400. WinError = DsRolepSetLsaInformationForReplica( PromoteArgs->ImpersonateToken,
  1401. ReplicaServer,
  1402. PromoteArgs->Account,
  1403. PromoteArgs->Password.Buffer );
  1404. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  1405. if ( ERROR_SUCCESS != WinError ) {
  1406. DSROLEP_FAIL1( WinError, DSROLERES_POLICY_READ_REMOTE, ReplicaServer );
  1407. goto PromoteUndo;
  1408. }
  1409. DsRolepLogPrint(( DEB_TRACE, "Read the LSA policy information from %ws\n",
  1410. ReplicaServer ));
  1411. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1412. //
  1413. // Configure the services for a domain controller
  1414. //
  1415. WinError = DsRolepConfigureDomainControllerServices( DSROLEP_SERVICES_ON );
  1416. if ( ERROR_SUCCESS != WinError ) {
  1417. DsRolepLogPrint(( DEB_ERROR, "Failed to configure domain controller services (%d)\n", WinError ));
  1418. goto PromoteUndo;
  1419. }
  1420. DomainControllerServicesChanged = TRUE;
  1421. DsRolepLogPrint(( DEB_TRACE, "Configured domain controller services\n" ));
  1422. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, PromoteUndo );
  1423. //
  1424. // Set the computers Dns domain name
  1425. //
  1426. DSROLEP_CURRENT_OP1( DSROLEEVT_SET_COMPUTER_DNS, PromoteArgs->DnsDomainName );
  1427. WinError = NetpSetDnsComputerNameAsRequired( PromoteArgs->DnsDomainName );
  1428. if ( ERROR_SUCCESS != WinError ) {
  1429. DsRolepLogOnFailure( WinError,
  1430. DsRolepLogPrint(( DEB_TRACE,
  1431. "NetpSetDnsComputerNameAsRequired to %ws failed with %lu\n",
  1432. PromoteArgs->DnsDomainName,
  1433. WinError )) );
  1434. DSROLEP_FAIL1( WinError, DSROLERES_SET_COMPUTER_DNS, PromoteArgs->DnsDomainName );
  1435. goto PromoteUndo;
  1436. }
  1437. DsRolepLogPrint(( DEB_TRACE, "Set the computer's Dns domain name to %ws.\n",
  1438. PromoteArgs->DnsDomainName ));
  1439. //
  1440. // Complete the sysvol replication
  1441. //
  1442. if ( SysVolCreated ) {
  1443. WinError = DsRolepFinishSysVolPropagation( TRUE, TRUE );
  1444. if ( ERROR_SUCCESS != WinError ) {
  1445. DsRolepLogPrint(( DEB_ERROR, "Failed to complete system volume replication (%d)\n", WinError ));
  1446. goto PromoteUndo;
  1447. }
  1448. DsRolepLogPrint(( DEB_TRACE, "Completed system volume replication\n" ));
  1449. }
  1450. //
  1451. // Set the machine role
  1452. //
  1453. WinError = DsRolepSetProductType( DSROLEP_MT_MEMBER );
  1454. if ( ERROR_SUCCESS != WinError ) {
  1455. DsRolepLogPrint(( DEB_ERROR, "Failed to set the product type (%d)\n", WinError ));
  1456. goto PromoteUndo;
  1457. }
  1458. DsRolepLogPrint(( DEB_TRACE, "Set the product type\n" ));
  1459. ProductTypeChanged = TRUE;
  1460. //
  1461. // Save off the new site name
  1462. //
  1463. WinError = DsRolepSetOperationHandleSiteName( InstalledSite );
  1464. if ( ERROR_SUCCESS != WinError ) {
  1465. DsRolepLogPrint(( DEB_ERROR, "Failed to set the operation handle(%d)\n", WinError ));
  1466. goto PromoteUndo;
  1467. }
  1468. //
  1469. // If we update it, NULL out the local parameter so we don't attempt to delete it
  1470. //
  1471. InstalledSite = NULL;
  1472. //
  1473. // Next, set the sysvol path for netlogon
  1474. //
  1475. WinError = DsRolepSetNetlogonSysVolPath( PromoteArgs->SysVolRootPath,
  1476. PromoteArgs->DnsDomainName,
  1477. FALSE,
  1478. NULL );
  1479. if ( ERROR_SUCCESS != WinError ) {
  1480. DsRolepLogPrint(( DEB_ERROR, "Failed to set the system volume path for NETLOGON (%d)\n", WinError ));
  1481. goto PromoteUndo;
  1482. }
  1483. DsRolepLogPrint(( DEB_TRACE, "Set the system volume path for NETLOGON\n" ));
  1484. //
  1485. // Finally, set the security on the dc files
  1486. //
  1487. WinError = DsRolepSetDcSecurity( PromoteArgs->ImpersonateToken,
  1488. PromoteArgs->SysVolRootPath,
  1489. PromoteArgs->DsDatabasePath,
  1490. PromoteArgs->DsLogPath,
  1491. ( BOOLEAN )FLAG_ON( PromoteArgs->Options,
  1492. DSROLE_DC_DOWNLEVEL_UPGRADE ),
  1493. TRUE );
  1494. if ( ERROR_SUCCESS != WinError ) {
  1495. DsRolepLogPrint(( DEB_ERROR, "Failed to set security for the domain controller (%d)\n", WinError ));
  1496. goto PromoteUndo;
  1497. }
  1498. DsRolepLogPrint(( DEB_TRACE, "Set security for the domain controller\n" ));
  1499. //
  1500. // We have done all operations for the promotion; now continue replicating
  1501. // ds information until done, or cancelled
  1502. //
  1503. DsRolepLogPrint(( DEB_TRACE, "Replicating non critical information\n" ));
  1504. DsRolepSetCriticalOperationsDone();
  1505. if ( !FLAG_ON( PromoteArgs->Options, DSROLE_DC_CRITICAL_REPLICATION_ONLY ) ) {
  1506. //in the Install From Media case we do not want to do a full sync of the
  1507. //Non-Critical objects
  1508. if ((PromoteArgs->RestorePath != NULL)) {
  1509. WinError = (*DsrNtdsInstallReplicateFull) ( DsRolepStringUpdateCallback, PromoteArgs->ImpersonateToken, NTDS_IFM_PROMOTION );
  1510. } else {
  1511. WinError = (*DsrNtdsInstallReplicateFull) ( DsRolepStringUpdateCallback, PromoteArgs->ImpersonateToken, 0 );
  1512. }
  1513. if ( WinError != ERROR_SUCCESS ) {
  1514. //
  1515. // Error code doesn't matter, but we'll log it anyway
  1516. //
  1517. DsRolepLogOnFailure( WinError,
  1518. DsRolepLogPrint(( DEB_WARN,
  1519. "Non critical replication returned %lu\n", WinError )) );
  1520. if (ERROR_SUCCESS == WinError) {
  1521. DsRolepLogPrint(( DEB_TRACE, "Replicating non critical information (Complete)\n" ));
  1522. }
  1523. if ( ERROR_SUCCESS != WinError ) {
  1524. DSROLEP_SET_NON_CRIT_REPL_ERROR();
  1525. }
  1526. WinError = ERROR_SUCCESS;
  1527. }
  1528. } else {
  1529. DsRolepLogPrint(( DEB_TRACE, "User specified to not replicate non-critical data\n" ));
  1530. }
  1531. //
  1532. // Indicate that we are no longer doing upgrades, if applicable
  1533. //
  1534. if ( FLAG_ON( PromoteArgs->Options, DSROLE_DC_DOWNLEVEL_UPGRADE ) ) {
  1535. WinError = DsRolepDeleteUpgradeInfo();
  1536. DsRolepLogOnFailure( WinError,
  1537. DsRolepLogPrint(( DEB_WARN,
  1538. "Failed to remove upgrade information (%d)\n",
  1539. WinError )) );
  1540. // This error isn't interesting to propogate
  1541. WinError = ERROR_SUCCESS;
  1542. }
  1543. //
  1544. // Remove any old netlogon stuff if we got that far
  1545. //
  1546. WinError = DsRolepCleanupOldNetlogonInformation();
  1547. if ( (FLAG_ON( PromoteArgs->Options, DSROLE_DC_DOWNLEVEL_UPGRADE )) && ERROR_SUCCESS != WinError ) {
  1548. if (ERROR_SUCCESS == WinError) {
  1549. DsRolepLogPrint(( DEB_TRACE, "Removed any old netlogon information\n" ));
  1550. }
  1551. DsRolepLogOnFailure( WinError,
  1552. DsRolepLogPrint(( DEB_WARN,
  1553. "Failed to clean up old netlogon information (%d)\n",
  1554. WinError )) );
  1555. }
  1556. WinError = ERROR_SUCCESS;
  1557. //
  1558. // Set the default logon domain to the current domain name
  1559. //
  1560. //
  1561. // We'll have to get it from the backed up policy information, since it isn't actually
  1562. // passed in
  1563. //
  1564. WinError = DsRolepSetLogonDomain(
  1565. ( PWSTR )BackupDomainPolicyInfo.DnsDomainInfo->Name.Buffer,
  1566. FALSE );
  1567. if ( ERROR_SUCCESS != WinError ) {
  1568. PWCHAR bufDnsDomainInfo = NULL;
  1569. bufDnsDomainInfo = (WCHAR*)malloc(BackupDomainPolicyInfo.DnsDomainInfo->Name.Length+1);
  1570. if (bufDnsDomainInfo) {
  1571. CopyMemory(bufDnsDomainInfo,
  1572. BackupDomainPolicyInfo.DnsDomainInfo->Name.Buffer,
  1573. BackupDomainPolicyInfo.DnsDomainInfo->Name.Length);
  1574. bufDnsDomainInfo[BackupDomainPolicyInfo.DnsDomainInfo->Name.Length/sizeof(WCHAR)] = L'\0';
  1575. DsRolepLogOnFailure( WinError,
  1576. DsRolepLogPrint(( DEB_WARN,
  1577. "Failed to set default logon domain to %ws (%d)\n",
  1578. bufDnsDomainInfo,
  1579. WinError )) );
  1580. if (ERROR_SUCCESS == WinError) {
  1581. DsRolepLogPrint(( DEB_TRACE, "Set default logon domain to %ws\n",
  1582. bufDnsDomainInfo ));
  1583. }
  1584. free(bufDnsDomainInfo);
  1585. }
  1586. //
  1587. // This is not worth failing for
  1588. //
  1589. WinError = ERROR_SUCCESS;
  1590. }
  1591. //
  1592. // Stop the ds
  1593. //
  1594. DsRolepStopDs( DsRunning );
  1595. DsRunning = FALSE;
  1596. DsRolepLogPrint(( DEB_TRACE, "Stopped the DS\n" ));
  1597. //
  1598. // Notify the time server we have completed the promotion
  1599. //
  1600. (*DsrW32TimeDcPromo)( W32TIME_PROMOTE );
  1601. //
  1602. // Set Netlogon registry key during DCPromo to ensure that kerberos is talking
  1603. // to a DC w/ new User AccountControl flag
  1604. //
  1605. IgnoreError = NetpStoreIntialDcRecord(DomainControllerInfo);
  1606. if ( IgnoreError != ERROR_SUCCESS ) {
  1607. DsRolepLogPrint(( DEB_WARN,
  1608. "Failed to set Netlogon registry key during DCPromo %ws\r\n",
  1609. IgnoreError ));
  1610. }
  1611. //
  1612. // At this point we have succeeded the promotion
  1613. //
  1614. ASSERT( ERROR_SUCCESS == WinError );
  1615. PromoteExit:
  1616. //
  1617. // Released acquired resources
  1618. //
  1619. if ( IPCConnection ) {
  1620. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  1621. IgnoreError = ImpNetpManageIPCConnect( PromoteArgs->ImpersonateToken,
  1622. ReplicaServer,
  1623. PromoteArgs->Account,
  1624. PromoteArgs->Password.Buffer,
  1625. (NETSETUPP_DISCONNECT_IPC | NETSETUPP_USE_LOTS_FORCE ) );
  1626. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  1627. if ( IgnoreError != ERROR_SUCCESS ) {
  1628. DsRolepLogPrint(( DEB_ERROR,
  1629. "Failed to destroy the session with %ws: 0x%lx\n", ReplicaServer,
  1630. IgnoreError ));
  1631. }
  1632. IPCConnection = FALSE;
  1633. }
  1634. if ( DomainControllerInfo != NULL ) {
  1635. if ( PromoteArgs->SiteName == DomainControllerInfo->ClientSiteName ||
  1636. PromoteArgs->SiteName == DomainControllerInfo->DcSiteName ) {
  1637. PromoteArgs->SiteName = NULL;
  1638. }
  1639. NetApiBufferFree( DomainControllerInfo );
  1640. }
  1641. RtlFreeHeap( RtlProcessHeap(), 0, InstalledSite );
  1642. RtlFreeHeap( RtlProcessHeap(), 0, NewDomainSid );
  1643. DsRolepFreeDomainPolicyInfo(&BackupDomainPolicyInfo);
  1644. //
  1645. // Reset our operation handle
  1646. //
  1647. DsRolepSetOperationDone( DSROLEP_OP_PROMOTION, WinError );
  1648. DsRolepFreeArgumentBlock( &ArgumentBlock, TRUE );
  1649. ExitThread( WinError );
  1650. return( WinError );
  1651. PromoteUndo:
  1652. //
  1653. // Something must have failed to have gotten us here
  1654. //
  1655. ASSERT( ERROR_SUCCESS != WinError );
  1656. if ( ProductTypeChanged ) {
  1657. IgnoreError = DsRolepSetProductType( DSROLEP_MT_STANDALONE );
  1658. DsRolepLogOnFailure( IgnoreError,
  1659. DsRolepLogPrint(( DEB_WARN,
  1660. "Failed to rollback product type (%d)\n",
  1661. IgnoreError )) );
  1662. ProductTypeChanged = FALSE;
  1663. }
  1664. if ( DomainControllerServicesChanged ) {
  1665. IgnoreError = DsRolepConfigureDomainControllerServices( DSROLEP_SERVICES_REVERT );
  1666. DsRolepLogOnFailure( IgnoreError,
  1667. DsRolepLogPrint(( DEB_WARN,
  1668. "Failed to rollback domain controller services configuration (%d)\n",
  1669. IgnoreError )) );
  1670. DomainControllerServicesChanged = FALSE;
  1671. }
  1672. if ( DomainPolicyInfoChanged ) {
  1673. IgnoreError = DsRolepRestoreDomainPolicyInfo(&BackupDomainPolicyInfo);
  1674. DsRolepLogOnFailure( IgnoreError,
  1675. DsRolepLogPrint(( DEB_WARN,
  1676. "Failed to restore domain policy information (%d)\n",
  1677. IgnoreError )) );
  1678. DomainPolicyInfoChanged = FALSE;
  1679. }
  1680. if ( DsRunning ) {
  1681. IgnoreError = DsRolepStopDs( DsRunning );
  1682. DsRolepLogOnFailure( IgnoreError,
  1683. DsRolepLogPrint(( DEB_WARN,
  1684. "Failed to stop the directory service (%d)\n",
  1685. IgnoreError )) );
  1686. DsRunning = FALSE;
  1687. }
  1688. if ( DsInstalled ) {
  1689. IgnoreError = DsRolepUninstallDs( );
  1690. DsRolepLogOnFailure( IgnoreError,
  1691. DsRolepLogPrint(( DEB_WARN,
  1692. "Failed to undo the directory service installation (%d)\n",
  1693. IgnoreError )) );
  1694. DsInstalled = FALSE;
  1695. }
  1696. if ( SysVolCreated ) {
  1697. IgnoreError = DsRolepFinishSysVolPropagation( FALSE, TRUE );
  1698. DsRolepLogOnFailure( IgnoreError,
  1699. DsRolepLogPrint(( DEB_WARN,
  1700. "Failed to abort system volume installation (%d)\n",
  1701. IgnoreError )) );
  1702. IgnoreError = DsRolepRemoveSysVolPath( PromoteArgs->SysVolRootPath,
  1703. PromoteArgs->DnsDomainName,
  1704. &DomainGuid );
  1705. DsRolepLogOnFailure( IgnoreError,
  1706. DsRolepLogPrint(( DEB_WARN,
  1707. "Failed to remove system volume path (%d)\n",
  1708. IgnoreError )) );
  1709. SysVolCreated = FALSE;
  1710. }
  1711. if ( RestartNetlogon ) {
  1712. IgnoreError = DsRolepStartNetlogon();
  1713. DsRolepLogOnFailure( IgnoreError,
  1714. DsRolepLogPrint(( DEB_WARN,
  1715. "Failed to restart NETLOGON (%d)\n",
  1716. IgnoreError )) );
  1717. RestartNetlogon = FALSE;
  1718. }
  1719. //
  1720. // That's it -- terminate the operation
  1721. //
  1722. ASSERT( ERROR_SUCCESS != WinError );
  1723. goto PromoteExit;
  1724. }
  1725. DWORD
  1726. DsRolepThreadDemote(
  1727. IN PVOID ArgumentBlock
  1728. )
  1729. /*++
  1730. Routine Description:
  1731. This function actually "demotes" a dc to standalone or member server. This is
  1732. accomplished by:
  1733. Uninstalling the Ds
  1734. Configuring the KDC
  1735. Changing the product type
  1736. Removing the system volume tree
  1737. Required is the new server role
  1738. Arguments:
  1739. ArgumentBlock - Block of arguments appropriate for the operation
  1740. Returns:
  1741. ERROR_SUCCESS - Success
  1742. ERROR_NO_SUCH_DOMAIN - The local domain information could not be located
  1743. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  1744. ERROR_DS_CANT_ON_NON_LEAF - The domain is not a leaf domain
  1745. --*/
  1746. {
  1747. DWORD WinError = ERROR_SUCCESS, IgnoreError;
  1748. NET_API_STATUS NetStatus = ERROR_SUCCESS;
  1749. PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
  1750. PDSROLEP_OPERATION_DEMOTE_ARGS DemoteArgs = ( PDSROLEP_OPERATION_DEMOTE_ARGS )ArgumentBlock;
  1751. DSROLEP_DOMAIN_POLICY_INFO BackupDomainPolicyInfo;
  1752. PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
  1753. HANDLE Policy = NULL;
  1754. NTSTATUS Status;
  1755. PWSTR ParentDomainName = NULL, CurrentDomain = NULL, SupportDc = NULL;
  1756. PWSTR SupportDomain = NULL;
  1757. OBJECT_ATTRIBUTES ObjectAttributes;
  1758. ULONG ServicesOffFlags = DSROLEP_SERVICES_OFF | DSROLEP_SERVICES_STOP;
  1759. ULONG ServicesOnFlags = DSROLEP_SERVICES_REVERT;
  1760. PNTDS_DNS_RR_INFO pDnsRRInfo = NULL;
  1761. ULONG Flags = 0;
  1762. PSEC_WINNT_AUTH_IDENTITY Credentials = NULL;
  1763. //
  1764. // BOOLEAN's to maintain state
  1765. //
  1766. // N.B. The order of these booleans is the order in which they
  1767. // are changed -- please maintain order and make sure that
  1768. // the DemoteUndo section undoes them in the reverse order
  1769. //
  1770. BOOLEAN IPCConnection = FALSE; // resource -- release on exit
  1771. BOOLEAN DsPrepareDemote = FALSE;
  1772. BOOLEAN FrsDemote = FALSE;
  1773. BOOLEAN NotifiedNetlogonToDeregister = FALSE;
  1774. BOOLEAN RestartNetlogon = FALSE;
  1775. BOOLEAN DomainControllerServicesChanged = FALSE;
  1776. BOOLEAN DomainServicesChanged = FALSE;
  1777. BOOLEAN Unrollable = FALSE; // at this point, don't
  1778. // try to rollback
  1779. //
  1780. // Set our event to indicate we're starting
  1781. //
  1782. NtSetEvent( DsRolepCurrentOperationHandle.CompletionEvent, NULL );
  1783. //
  1784. // Get the current domain information, potentially the parent Domain and see if
  1785. // we are valid to be demoted
  1786. //
  1787. DSROLEP_CURRENT_OP0( DSROLEEVT_LOCAL_POLICY );
  1788. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  1789. Status = LsaOpenPolicy( NULL,
  1790. &ObjectAttributes,
  1791. POLICY_VIEW_LOCAL_INFORMATION,
  1792. &Policy );
  1793. if ( NT_SUCCESS( Status ) ) {
  1794. Status = LsaQueryInformationPolicy( Policy,
  1795. PolicyDnsDomainInformation,
  1796. &DnsDomainInfo );
  1797. }
  1798. if ( !NT_SUCCESS( Status ) ) {
  1799. WinError = RtlNtStatusToDosError( Status );
  1800. DSROLEP_FAIL0( WinError, DSROLERES_POLICY_READ_LOCAL );
  1801. goto DemoteUndo;
  1802. }
  1803. if ( DemoteArgs->DomainName == NULL ) {
  1804. CurrentDomain = DnsDomainInfo->DnsDomainName.Buffer;
  1805. } else {
  1806. //
  1807. // Strip the trailing '.' from the Dns name if we happen to have an absolute name
  1808. //
  1809. DSROLEP_MAKE_DNS_RELATIVE( DemoteArgs->DomainName );
  1810. CurrentDomain = DemoteArgs->DomainName;
  1811. }
  1812. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  1813. //
  1814. // Determine whether it is legal to demote this domain. Also, get the parent Dns domain name
  1815. //
  1816. if ( DemoteArgs->LastDcInDomain ) {
  1817. PLSAPR_FOREST_TRUST_INFO ForestTrustInfo = NULL;
  1818. PLSAPR_TREE_TRUST_INFO OwnEntry = NULL, ParentEntry = NULL;
  1819. Status = LsaIQueryForestTrustInfo( Policy,
  1820. &ForestTrustInfo );
  1821. WinError = RtlNtStatusToDosError( Status );
  1822. if ( WinError == ERROR_SUCCESS ) {
  1823. //
  1824. // Check the root
  1825. //
  1826. if ( RtlCompareUnicodeString(
  1827. ( PUNICODE_STRING )&ForestTrustInfo->RootTrust.DnsDomainName,
  1828. &DnsDomainInfo->DnsDomainName,
  1829. TRUE ) == 0 ) {
  1830. OwnEntry = &ForestTrustInfo->RootTrust;
  1831. ParentEntry = NULL;
  1832. } else {
  1833. //
  1834. // Find our own entry in the list and our parent...
  1835. //
  1836. DsRolepFindSelfAndParentInForest( ForestTrustInfo,
  1837. &ForestTrustInfo->RootTrust,
  1838. &DnsDomainInfo->DnsDomainName,
  1839. &ParentEntry,
  1840. &OwnEntry );
  1841. }
  1842. if ( OwnEntry == NULL ) {
  1843. WinError = ERROR_NO_SUCH_DOMAIN;
  1844. } else {
  1845. //
  1846. // If we have children, it's an error
  1847. //
  1848. if ( OwnEntry->Children != 0 ) {
  1849. WCHAR *BufOwnEntry = NULL;
  1850. DsRolepUnicodestringtowstr( BufOwnEntry, OwnEntry->DnsDomainName )
  1851. if (BufOwnEntry) {
  1852. DsRolepLogPrint(( DEB_TRACE,
  1853. "We ( %ws ) think we have %lu children\n",
  1854. BufOwnEntry,
  1855. OwnEntry->Children ));
  1856. free(BufOwnEntry);
  1857. } else {
  1858. DsRolepLogPrint(( DEB_TRACE,
  1859. "We think we have %lu children: Can display string ERROR_NOT_ENOUGH_MEMORY\n",
  1860. OwnEntry->Children ));
  1861. }
  1862. WinError = ERROR_DS_CANT_ON_NON_LEAF;
  1863. }
  1864. //
  1865. // Copy off our parent information
  1866. //
  1867. if ( WinError == ERROR_SUCCESS && ParentEntry != NULL ) {
  1868. WCHAR *BufOwnEntry = NULL;
  1869. DsRolepUnicodestringtowstr( BufOwnEntry, OwnEntry->DnsDomainName )
  1870. if (BufOwnEntry) {
  1871. DsRolepLogPrint((DEB_TRACE,
  1872. "Domain %ws is our parent parent\n",
  1873. BufOwnEntry));
  1874. free(BufOwnEntry);
  1875. } else {
  1876. DsRolepLogPrint(( DEB_TRACE,
  1877. "Domain (?) is our parent parent: Can display domain string ERROR_NOT_ENOUGH_MEMORY\n"));
  1878. }
  1879. ParentDomainName = RtlAllocateHeap(
  1880. RtlProcessHeap(), 0,
  1881. ParentEntry->DnsDomainName.Length + sizeof( WCHAR ) );
  1882. if ( ParentDomainName == NULL ) {
  1883. WinError = ERROR_NOT_ENOUGH_MEMORY;
  1884. } else {
  1885. RtlCopyMemory( ParentDomainName,
  1886. ParentEntry->DnsDomainName.Buffer,
  1887. ParentEntry->DnsDomainName.Length );
  1888. ParentDomainName[
  1889. ParentEntry->DnsDomainName.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
  1890. }
  1891. }
  1892. }
  1893. }
  1894. LsaIFreeForestTrustInfo( ForestTrustInfo );
  1895. if ( ERROR_SUCCESS != WinError ) {
  1896. DSROLEP_FAIL1( WinError, DSROLERES_LEAF_DOMAIN, CurrentDomain );
  1897. goto DemoteUndo;
  1898. }
  1899. }
  1900. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  1901. //
  1902. // Locate a Dc to help with the demotion
  1903. //
  1904. if ( DemoteArgs->LastDcInDomain ) {
  1905. SupportDomain = ParentDomainName;
  1906. } else {
  1907. SupportDomain = CurrentDomain;
  1908. }
  1909. //
  1910. // If this is the last domain in the enterprise, there will be no
  1911. // parent domain and possibly no replicas to assist.
  1912. //
  1913. // Note: netlogon is still running, so use the avoid self flag
  1914. //
  1915. if ( SupportDomain ) {
  1916. DSROLEP_CURRENT_OP1( DSROLEEVT_SEARCH_DC, SupportDomain );
  1917. if ( !DemoteArgs->LastDcInDomain )
  1918. {
  1919. //
  1920. // Demoting a replica - find someone with our machine account
  1921. //
  1922. ULONG FindOptions = DS_DIRECTORY_SERVICE_REQUIRED |
  1923. DS_WRITABLE_REQUIRED |
  1924. DS_FORCE_REDISCOVERY |
  1925. DS_AVOID_SELF;
  1926. WCHAR LocalMachineAccountName[ MAX_COMPUTERNAME_LENGTH + 2 ];
  1927. ULONG Length = sizeof(LocalMachineAccountName) / sizeof(LocalMachineAccountName[0]);
  1928. //
  1929. // Get the account name
  1930. //
  1931. if ( GetComputerName( LocalMachineAccountName, &Length ) == FALSE ) {
  1932. WinError = GetLastError();
  1933. DsRolepLogPrint(( DEB_ERROR, "Failed to get computer name (%d)\n", WinError ));
  1934. goto DemoteUndo;
  1935. } else {
  1936. wcscat( LocalMachineAccountName, L"$" );
  1937. WinError = DsRolepDsGetDcForAccount( NULL,
  1938. SupportDomain,
  1939. LocalMachineAccountName,
  1940. FindOptions,
  1941. UF_WORKSTATION_TRUST_ACCOUNT |
  1942. UF_SERVER_TRUST_ACCOUNT,
  1943. &DomainControllerInfo );
  1944. }
  1945. } else {
  1946. WinError = DsGetDcName( NULL, SupportDomain, NULL, NULL,
  1947. DS_DIRECTORY_SERVICE_REQUIRED |
  1948. DS_WRITABLE_REQUIRED |
  1949. DS_AVOID_SELF |
  1950. DS_FORCE_REDISCOVERY,
  1951. &DomainControllerInfo );
  1952. }
  1953. if ( ERROR_SUCCESS != WinError ) {
  1954. DsRolepLogPrint(( DEB_ERROR,
  1955. "Failed to find a domain controller for %ws: %lu\n",
  1956. SupportDomain, WinError ));
  1957. DSROLEP_FAIL1( WinError, DSROLERES_FIND_DC, SupportDomain );
  1958. goto DemoteUndo;
  1959. }
  1960. SupportDc = DomainControllerInfo->DomainControllerName;
  1961. if ( *SupportDc == L'\\' ) {
  1962. SupportDc += 2;
  1963. }
  1964. DsRolepLogPrint(( DEB_TRACE_DS, "Support Dc in %ws is %ws\n",
  1965. SupportDomain,
  1966. SupportDc ));
  1967. DSROLEP_CURRENT_OP2( DSROLEEVT_FOUND_DC,
  1968. SupportDc,
  1969. SupportDomain );
  1970. }
  1971. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  1972. //
  1973. // Attempt to establish a RDR session with our support DC
  1974. // if necessary
  1975. //
  1976. if ( SupportDc ) {
  1977. //
  1978. // Impersonate to get logon id of caller
  1979. //
  1980. RtlRunDecodeUnicodeString( DemoteArgs->Decode, &DemoteArgs->Password );
  1981. WinError = ImpNetpManageIPCConnect( DemoteArgs->ImpersonateToken,
  1982. SupportDc,
  1983. DemoteArgs->Account,
  1984. DemoteArgs->Password.Buffer,
  1985. NETSETUPP_CONNECT_IPC );
  1986. RtlRunEncodeUnicodeString( &DemoteArgs->Decode, &DemoteArgs->Password );
  1987. if ( ERROR_SUCCESS != WinError ) {
  1988. DSROLEP_FAIL1( WinError, DSROLERES_NET_USE, SupportDc );
  1989. DsRolepLogPrint(( DEB_ERROR,
  1990. "Failed to establish the session with %ws: 0x%lx\n", SupportDc,
  1991. WinError ));
  1992. goto DemoteUndo;
  1993. }
  1994. IPCConnection = TRUE;
  1995. }
  1996. //
  1997. // Prepare the ds for demotion
  1998. //
  1999. DSROLE_GET_SETUP_FUNC( WinError, DsrNtdsPrepareForDemotion );
  2000. ASSERT( ERROR_SUCCESS == WinError );
  2001. RtlRunDecodeUnicodeString( DemoteArgs->Decode, &DemoteArgs->Password );
  2002. WinError = DsRolepCreateAuthIdentForCreds(DemoteArgs->Account,
  2003. DemoteArgs->Password.Buffer,
  2004. &Credentials);
  2005. if ( ERROR_SUCCESS == WinError ) {
  2006. if ( DemoteArgs->LastDcInDomain ) {
  2007. Flags |= NTDS_LAST_DC_IN_DOMAIN;
  2008. }
  2009. Flags |= DsRolepDemoteFlagsToNtdsFlags( DemoteArgs->Options );
  2010. DSROLEP_CURRENT_OP0( DSROLEEVT_PREPARE_DEMOTION );
  2011. WinError = ( *DsrNtdsPrepareForDemotion ) ( Flags,
  2012. SupportDc,
  2013. Credentials,
  2014. DsRolepStringUpdateCallback,
  2015. DsRolepStringErrorUpdateCallback,
  2016. DemoteArgs->ImpersonateToken,
  2017. &pDnsRRInfo );
  2018. RtlRunEncodeUnicodeString( &DemoteArgs->Decode, &DemoteArgs->Password );
  2019. if ( ERROR_SUCCESS != WinError ) {
  2020. DsRolepLogPrint(( DEB_ERROR, "Failed to prepare the Directory Service for uninstallation (%d)\n", WinError ));
  2021. goto DemoteUndo;
  2022. }
  2023. DsPrepareDemote = TRUE;
  2024. } else {
  2025. DsRolepLogPrint(( DEB_ERROR, "Failed to create authentication credentials (%d)\n", WinError ));
  2026. goto DemoteUndo;
  2027. }
  2028. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  2029. //
  2030. // Start the sysvol demotions
  2031. //
  2032. RtlRunDecodeUnicodeString( DemoteArgs->Decode, &DemoteArgs->Password );
  2033. WinError = ( *DsrNtFrsApi_PrepareForDemotionUsingCredW ) ( Credentials,
  2034. DemoteArgs->ImpersonateToken,
  2035. DsRolepStringErrorUpdateCallback );
  2036. RtlRunEncodeUnicodeString( &DemoteArgs->Decode, &DemoteArgs->Password );
  2037. if ( ERROR_SUCCESS != WinError ) {
  2038. DsRolepLogPrint(( DEB_ERROR, "Failed to get computer name (%d)\n", WinError ));
  2039. DSROLEP_FAIL0( WinError, DSROLERES_SYSVOL_DEMOTION );
  2040. goto DemoteUndo;
  2041. }
  2042. WinError = ( *DsrNtFrsApi_StartDemotionW )( CurrentDomain,
  2043. DsRolepStringErrorUpdateCallback );
  2044. if ( ERROR_SUCCESS != WinError ) {
  2045. DsRolepLogPrint(( DEB_ERROR,
  2046. "Failed to start system volume demotion on domain (%d)\n",
  2047. WinError ));
  2048. DSROLEP_FAIL0( WinError, DSROLERES_SYSVOL_DEMOTION );
  2049. goto DemoteUndo;
  2050. }
  2051. // At this point we have signalled one frs replica set to be demote so
  2052. // we must wait on it
  2053. FrsDemote = TRUE;
  2054. WinError = ( *DsrNtFrsApi_StartDemotionW )( L"ENTERPRISE",
  2055. DsRolepStringErrorUpdateCallback );
  2056. if ( WinError != ERROR_SUCCESS ) {
  2057. DsRolepLogPrint(( DEB_ERROR,
  2058. "Failed to start system volume demotion on enterprise (%d)\n",
  2059. WinError ));
  2060. DSROLEP_FAIL0( WinError, DSROLERES_SYSVOL_DEMOTION );
  2061. goto DemoteUndo;
  2062. }
  2063. DsRolepLogPrint(( DEB_TRACE,
  2064. "Started system volume demotion on enterprise\n" ));
  2065. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  2066. //
  2067. // Note that if a failure occurs after we uninstall the Ds, than we will not attempt to
  2068. // reinstall it, since we don't have enough information to do so. In that case, the machine
  2069. // will be in a somewhat inconsistent state. However, some errors are acceptable:
  2070. //
  2071. // Failure to delete the trusted domain object - Continuable
  2072. // Stoping the KDC - Continuable
  2073. //
  2074. //
  2075. // Also, note that "uninstalling the DS" also sets the LSA account domain
  2076. // sid and the server role so no errors should be returned to the caller
  2077. // after uninstalling the DS. The machine will become the new role on the
  2078. // next reboot.
  2079. //
  2080. WinError = DsRolepBackupDomainPolicyInfo( NULL, &BackupDomainPolicyInfo );
  2081. if ( ERROR_SUCCESS != WinError ) {
  2082. DsRolepLogPrint(( DEB_ERROR,
  2083. "Failed to backup LSA domain policy (%d)\n",
  2084. WinError ));
  2085. DSROLEP_FAIL0( WinError, DSROLERES_POLICY_READ_LOCAL );
  2086. goto DemoteUndo;
  2087. }
  2088. DsRolepLogPrint(( DEB_TRACE,
  2089. "Read the LSA policy information from the local machine\n" ));
  2090. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  2091. //
  2092. // Set netlogon we are demoting so it will deregister the DNS records
  2093. //
  2094. Status = I_NetNotifyDsChange( NlDcDemotionInProgress );
  2095. if ( !NT_SUCCESS( Status ) ) {
  2096. WinError = RtlNtStatusToDosError( Status );
  2097. DsRolepLogPrint(( DEB_ERROR,
  2098. "Failed to tell NETLOGON to deregister records (%d)\n",
  2099. WinError ));
  2100. goto DemoteUndo;
  2101. }
  2102. DsRolepLogPrint(( DEB_TRACE,
  2103. "Informed NETLOGON to deregister records\n" ));
  2104. NotifiedNetlogonToDeregister = TRUE;
  2105. //
  2106. // Stop netlogon
  2107. //
  2108. WinError = DsRolepStopNetlogon( &RestartNetlogon );
  2109. if ( ERROR_SUCCESS != WinError ) {
  2110. DsRolepLogPrint(( DEB_ERROR,
  2111. "Failed to stop NETLOGON (%d)\n",
  2112. WinError ));
  2113. goto DemoteUndo;
  2114. }
  2115. DsRolepLogPrint(( DEB_TRACE,
  2116. "Stopped NETLOGON\n" ));
  2117. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  2118. //
  2119. // Disable the domain controller services
  2120. //
  2121. WinError = DsRolepConfigureDomainControllerServices( ServicesOffFlags );
  2122. if ( ERROR_SUCCESS != WinError ) {
  2123. DsRolepLogPrint(( DEB_ERROR,
  2124. "Failed to configure domain controller services (%d)\n",
  2125. WinError ));
  2126. goto DemoteUndo;
  2127. }
  2128. DsRolepLogPrint(( DEB_TRACE,
  2129. "Configured domain controller services\n" ));
  2130. DomainControllerServicesChanged = TRUE;
  2131. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  2132. //
  2133. // Disable the domain related services if necessary
  2134. //
  2135. if ( DemoteArgs->ServerRole == DsRoleServerStandalone ) {
  2136. WinError = DsRolepConfigureDomainServices( ServicesOffFlags );
  2137. if ( ERROR_SUCCESS != WinError ) {
  2138. DsRolepLogPrint(( DEB_ERROR,
  2139. "Failed to configure domain services (%d)\n",
  2140. WinError ));
  2141. goto DemoteUndo;
  2142. }
  2143. DsRolepLogPrint(( DEB_TRACE,
  2144. "Configured domain services\n" ));
  2145. DomainServicesChanged = TRUE;
  2146. }
  2147. DSROLEP_CHECK_FOR_CANCEL_EX( WinError, DemoteUndo );
  2148. //
  2149. // Remove the Ds
  2150. //
  2151. RtlRunDecodeUnicodeString( DemoteArgs->Decode, &DemoteArgs->Password );
  2152. RtlRunDecodeUnicodeString( DemoteArgs->Decode, &DemoteArgs->AdminPassword );
  2153. WinError = DsRolepDemoteDs( CurrentDomain,
  2154. DemoteArgs->Account,
  2155. DemoteArgs->Password.Buffer,
  2156. DemoteArgs->AdminPassword.Buffer,
  2157. SupportDc,
  2158. SupportDomain,
  2159. DemoteArgs->ImpersonateToken,
  2160. DemoteArgs->LastDcInDomain );
  2161. RtlRunEncodeUnicodeString( &DemoteArgs->Decode, &DemoteArgs->Password );
  2162. RtlRunEncodeUnicodeString( &DemoteArgs->Decode, &DemoteArgs->AdminPassword );
  2163. if ( ERROR_SUCCESS != WinError ) {
  2164. DsRolepLogPrint(( DEB_ERROR,
  2165. "Failed to demote the directory service (%d)\n",
  2166. WinError ));
  2167. goto DemoteUndo;
  2168. }
  2169. DsRolepLogPrint(( DEB_TRACE, "This machine is no longer a domain controller\n" ));
  2170. //
  2171. // The operation cannot be cancelled at this point since the ds has
  2172. // been removed from the machine and from the enterprise
  2173. //
  2174. Unrollable = TRUE;
  2175. //
  2176. // Optionally remove the trust with the parent
  2177. //
  2178. if ( DemoteArgs->LastDcInDomain &&
  2179. ParentDomainName != NULL ) {
  2180. //
  2181. // Establish a session first -- should be a no-op since we already
  2182. // have a connection
  2183. //
  2184. RtlRunDecodeUnicodeString( DemoteArgs->Decode, &DemoteArgs->Password );
  2185. WinError = ImpNetpManageIPCConnect( DemoteArgs->ImpersonateToken,
  2186. SupportDc,
  2187. DemoteArgs->Account,
  2188. DemoteArgs->Password.Buffer,
  2189. NETSETUPP_CONNECT_IPC );
  2190. RtlRunEncodeUnicodeString( &DemoteArgs->Decode, &DemoteArgs->Password );
  2191. if ( WinError == ERROR_SUCCESS ) {
  2192. WinError = DsRolepDeleteParentTrustObject( DemoteArgs->ImpersonateToken,
  2193. SupportDc,
  2194. DnsDomainInfo );
  2195. if ( WinError != ERROR_SUCCESS ) {
  2196. DsRolepLogOnFailure( WinError,
  2197. DsRolepLogPrint(( DEB_WARN,
  2198. "Failed to delete the "
  2199. "trust on %ws: %lu\n",
  2200. SupportDc,
  2201. WinError )) );
  2202. if (ERROR_SUCCESS == WinError) {
  2203. DsRolepLogPrint(( DEB_TRACE,
  2204. "Deleted the trust on %ws\n",
  2205. SupportDc ));
  2206. }
  2207. }
  2208. } else {
  2209. // This is not a fatal error
  2210. DsRolepLogPrint(( DEB_WARN,
  2211. "Failed to establish the session with %ws: 0x%lx\n", SupportDc,
  2212. WinError ));
  2213. }
  2214. //
  2215. // This error is not fatal
  2216. //
  2217. if ( ERROR_SUCCESS != WinError )
  2218. {
  2219. SpmpReportEvent( TRUE,
  2220. EVENTLOG_WARNING_TYPE,
  2221. DSROLERES_FAILED_TO_DELETE_TRUST,
  2222. 0,
  2223. sizeof( ULONG ),
  2224. &WinError,
  2225. 1,
  2226. ParentDomainName );
  2227. DSROLEP_SET_NON_FATAL_ERROR( WinError );
  2228. // Error case is handled
  2229. WinError = ERROR_SUCCESS;
  2230. }
  2231. }
  2232. //
  2233. // Finish our NTFRS demotion
  2234. //
  2235. if ( FrsDemote ) {
  2236. WinError = DsRolepFinishSysVolPropagation( TRUE,
  2237. FALSE );
  2238. if ( ERROR_SUCCESS != WinError ) {
  2239. DsRolepLogOnFailure( WinError,
  2240. DsRolepLogPrint(( DEB_TRACE,
  2241. "Failed to finish system volume demotion (%d)\n",
  2242. WinError )) );
  2243. if (ERROR_SUCCESS == WinError) {
  2244. DsRolepLogPrint(( DEB_TRACE,
  2245. "Finished system volume demotion\n" ));
  2246. }
  2247. }
  2248. //
  2249. // It is not fatal if the FRS fails at this point
  2250. //
  2251. if ( ERROR_SUCCESS != WinError )
  2252. {
  2253. SpmpReportEvent( TRUE,
  2254. EVENTLOG_WARNING_TYPE,
  2255. DSROLERES_FAILED_TO_DEMOTE_FRS,
  2256. 0,
  2257. sizeof( ULONG ),
  2258. &WinError,
  2259. 0,
  2260. NULL );
  2261. DSROLEP_SET_NON_FATAL_ERROR( WinError );
  2262. }
  2263. // Reset status code
  2264. WinError = ERROR_SUCCESS;
  2265. }
  2266. //
  2267. // Call into the SCE so we can be configured to be a server
  2268. //
  2269. WinError = ( *DsrSceDcPromoteSecurityEx )( DemoteArgs->ImpersonateToken,
  2270. SCE_PROMOTE_FLAG_DEMOTE,
  2271. DsRolepStringUpdateCallback );
  2272. if ( ERROR_SUCCESS != WinError ) {
  2273. DsRolepLogOnFailure( WinError,
  2274. DsRolepLogPrint(( DEB_ERROR,
  2275. "Setting security on server files failed with %lu\n",
  2276. WinError )) );
  2277. if (ERROR_SUCCESS == WinError) {
  2278. DsRolepLogPrint(( DEB_TRACE,
  2279. "Set security on server files\n" ));
  2280. }
  2281. // This error has been handled
  2282. WinError = ERROR_SUCCESS;
  2283. }
  2284. //
  2285. // remove all trusted root certificates from DC when the machine will dis-join from the enterprise
  2286. //
  2287. if (DemoteArgs->ServerRole == DsRoleServerStandalone) {
  2288. if (!CertAutoRemove(CERT_AUTO_REMOVE_COMMIT)){
  2289. DsRolepLogPrint(( DEB_WARN,
  2290. "Failed to remove all trusted root certificates from this machine: (%d)\n",
  2291. GetLastError()));
  2292. }
  2293. }
  2294. //
  2295. // Notify the time server we have completed the demotion
  2296. //
  2297. (*DsrW32TimeDcPromo)( W32TIME_DEMOTE );
  2298. //
  2299. // At this point we have successfully completed the demotion
  2300. //
  2301. ASSERT( ERROR_SUCCESS == WinError );
  2302. //
  2303. // Clear errors components may have erroneously set while running
  2304. //
  2305. DsRolepClearErrors();
  2306. DemoteExit:
  2307. if ( Policy ) {
  2308. LsaClose( Policy );
  2309. }
  2310. if ( Credentials ) {
  2311. RtlFreeHeap( RtlProcessHeap(), 0, Credentials );
  2312. }
  2313. if ( pDnsRRInfo ) {
  2314. ( *DsrNtdsFreeDnsRRInfo )(pDnsRRInfo);
  2315. }
  2316. //
  2317. // Tear down the session to the parent, if we have one
  2318. //
  2319. if ( IPCConnection ) {
  2320. RtlRunDecodeUnicodeString( DemoteArgs->Decode, &DemoteArgs->Password );
  2321. IgnoreError = ImpNetpManageIPCConnect( DemoteArgs->ImpersonateToken,
  2322. SupportDc,
  2323. DemoteArgs->Account,
  2324. DemoteArgs->Password.Buffer,
  2325. (NETSETUPP_DISCONNECT_IPC|NETSETUPP_USE_LOTS_FORCE) );
  2326. RtlRunEncodeUnicodeString( &DemoteArgs->Decode, &DemoteArgs->Password );
  2327. if ( IgnoreError != ERROR_SUCCESS ) {
  2328. DsRolepLogPrint(( DEB_WARN,
  2329. "Failed to destroy the session with %ws: 0x%lx\n", SupportDc,
  2330. IgnoreError ));
  2331. }
  2332. IPCConnection = FALSE;
  2333. }
  2334. //Delete persistent shares
  2335. NetStatus = NetShareDel( NULL, L"SYSVOL", 0);
  2336. if(NetStatus != ERROR_SUCCESS) {
  2337. DsRolepLogPrint(( DEB_WARN,
  2338. "Failed to destroy the share SYSVOL. Failed with %d\n", NetStatus ));
  2339. }
  2340. NetStatus = NetShareDel( NULL, L"NETLOGON", 0);
  2341. if(NetStatus != ERROR_SUCCESS) {
  2342. DsRolepLogPrint(( DEB_WARN,
  2343. "Failed to destroy the share NETLOGON. Failed with %d\n", NetStatus ));
  2344. }
  2345. //
  2346. // Reset our operation handle
  2347. //
  2348. DsRolepSetOperationDone( DSROLEP_OP_DEMOTION, WinError );
  2349. DsRolepFreeArgumentBlock( &ArgumentBlock, FALSE );
  2350. LsaFreeMemory( DnsDomainInfo );
  2351. RtlFreeHeap( RtlProcessHeap(), 0, ParentDomainName );
  2352. NetApiBufferFree( DomainControllerInfo );
  2353. ExitThread( WinError );
  2354. return( WinError );
  2355. DemoteUndo:
  2356. //
  2357. // Assert that aomething went wrong if we are here
  2358. //
  2359. ASSERT( ERROR_SUCCESS != WinError );
  2360. //
  2361. // We shouldn't be here if we are in an unrollable state
  2362. //
  2363. ASSERT( FALSE == Unrollable );
  2364. if ( FrsDemote ) {
  2365. IgnoreError = DsRolepFinishSysVolPropagation( FALSE,
  2366. FALSE );
  2367. DsRolepLogOnFailure( IgnoreError,
  2368. DsRolepLogPrint(( DEB_WARN,
  2369. "Failed to abort system volume demotion (%d)\n",
  2370. IgnoreError )) );
  2371. FrsDemote = FALSE;
  2372. }
  2373. if ( NotifiedNetlogonToDeregister ) {
  2374. //
  2375. // "NlDcDemotionCompleted" sounds strange here since the demotion
  2376. // failed. However, the meaning is that netlogon should now continue
  2377. // to perform as if demotion is not running. No need to set in the
  2378. // success case since NETLOGON won't be restarted.
  2379. //
  2380. Status = I_NetNotifyDsChange( NlDcDemotionCompleted );
  2381. IgnoreError = RtlNtStatusToDosError( Status );
  2382. DsRolepLogOnFailure( IgnoreError,
  2383. DsRolepLogPrint(( DEB_WARN,
  2384. "Failed to tell NETLOGON that demotion is over (%d)\n",
  2385. IgnoreError )) );
  2386. NotifiedNetlogonToDeregister = FALSE;
  2387. }
  2388. if ( RestartNetlogon ) {
  2389. IgnoreError = DsRolepStartNetlogon();
  2390. DsRolepLogOnFailure( IgnoreError,
  2391. DsRolepLogPrint(( DEB_WARN,
  2392. "Failed to restart netlogon (%d)\n",
  2393. IgnoreError )) );
  2394. RestartNetlogon = FALSE;
  2395. }
  2396. if ( DomainControllerServicesChanged ) {
  2397. IgnoreError = DsRolepConfigureDomainControllerServices( DSROLEP_SERVICES_REVERT );
  2398. DsRolepLogOnFailure( IgnoreError,
  2399. DsRolepLogPrint(( DEB_WARN,
  2400. "Failed to rollback domain controller services configuration (%d)\n",
  2401. IgnoreError )) );
  2402. DomainControllerServicesChanged = FALSE;
  2403. }
  2404. if ( DomainServicesChanged ) {
  2405. IgnoreError = DsRolepConfigureDomainServices( DSROLEP_SERVICES_REVERT );
  2406. DsRolepLogOnFailure( IgnoreError,
  2407. DsRolepLogPrint(( DEB_WARN,
  2408. "Failed to rollback domain controller services configuration (%d)\n",
  2409. IgnoreError )) );
  2410. DomainServicesChanged = FALSE;
  2411. }
  2412. if ( DsPrepareDemote ) {
  2413. IgnoreError = ( *DsrNtdsPrepareForDemotionUndo ) ();
  2414. DsRolepLogOnFailure( IgnoreError,
  2415. DsRolepLogPrint(( DEB_WARN,
  2416. "Failed to undo directory service preparation for demotion (%d)\n",
  2417. IgnoreError )) );
  2418. DsPrepareDemote = FALSE;
  2419. }
  2420. //
  2421. // Ok -- we have rolled back, make sure we still have an error and then
  2422. // exit
  2423. //
  2424. ASSERT( ERROR_SUCCESS != WinError );
  2425. goto DemoteExit;
  2426. }