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.

2779 lines
75 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dispatch.c
  5. Abstract:
  6. Implementation of the server side of the DsRole API's
  7. Author:
  8. Colin Brace (ColinBr) April 5, 1999.
  9. Environment:
  10. User Mode
  11. Revision History:
  12. Reorg'ed from code written by
  13. Mac McLain (MacM) Feb 10, 1997
  14. --*/
  15. #include <setpch.h>
  16. #include <dssetp.h>
  17. #include <dsgetdc.h>
  18. #include <samrpc.h>
  19. #include <samisrv.h>
  20. #include <lmcons.h>
  21. #include <lmapibuf.h>
  22. #include <lmaccess.h>
  23. #include <lmsname.h>
  24. #include <lsarpc.h>
  25. #include <db.h>
  26. #include <lsasrvmm.h>
  27. #include <lsaisrv.h>
  28. #include <loadfn.h>
  29. #include <lmjoin.h>
  30. #include <netsetup.h>
  31. #include <lmcons.h>
  32. #include <lmerr.h>
  33. #include <icanon.h>
  34. #include <dsrole.h>
  35. #include <dsrolep.h>
  36. #include <dsconfig.h>
  37. #include <crypt.h>
  38. #include <rc4.h>
  39. #include <md5.h>
  40. #include "secure.h"
  41. #include "threadman.h"
  42. #include "upgrade.h"
  43. #include "cancel.h"
  44. //
  45. // Static global. This flag is used to indicate that the system is installed enough to get
  46. // us going. There is no need to protect it, since it is only toggled from off to on
  47. //
  48. static BOOLEAN DsRolepSamInitialized = FALSE;
  49. //
  50. // Local forwards
  51. //
  52. DWORD
  53. DsRolepWaitForSam(
  54. VOID
  55. );
  56. DWORD
  57. DsRolepCheckFilePaths(
  58. IN LPWSTR DsDirPath,
  59. IN LPWSTR DsLogPath,
  60. IN LPWSTR SysVolPath
  61. );
  62. DWORD
  63. DsRolepIsValidProductSuite(
  64. IN BOOL fNewForest,
  65. IN BOOL fReplica,
  66. IN LPWSTR DomainName
  67. );
  68. DWORD
  69. DsRolepDecryptPasswordsWithKey(
  70. IN handle_t RpcBindingHandle,
  71. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD * EncryptedPasswords,
  72. IN ULONG Count,
  73. IN OUT UNICODE_STRING *EncodedPasswords,
  74. OUT PUCHAR Seed
  75. );
  76. VOID
  77. DsRolepFreePasswords(
  78. IN OUT UNICODE_STRING *Passwords,
  79. IN ULONG Count
  80. );
  81. DWORD
  82. DsRolepDecryptHash(
  83. IN PUNICODE_STRING BootKey
  84. );
  85. //
  86. // RPC dispatch routines
  87. //
  88. DWORD
  89. DsRolerDcAsDc(
  90. IN handle_t RpcBindingHandle,
  91. IN LPWSTR DnsDomainName,
  92. IN LPWSTR FlatDomainName,
  93. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EDomainAdminPassword, OPTIONAL
  94. IN LPWSTR SiteName OPTIONAL,
  95. IN LPWSTR DsDatabasePath,
  96. IN LPWSTR DsLogPath,
  97. IN LPWSTR SystemVolumeRootPath,
  98. IN LPWSTR ParentDnsDomainName OPTIONAL,
  99. IN LPWSTR ParentServer OPTIONAL,
  100. IN LPWSTR Account OPTIONAL,
  101. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EPassword, OPTIONAL
  102. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EDsRepairPassword, OPTIONAL
  103. IN ULONG Options,
  104. OUT PDSROLER_HANDLE DsOperationHandle)
  105. /*++
  106. Routine Description:
  107. Rpc server routine for installing a server as a DC
  108. Arguments:
  109. RpcBindingHandle - the RPC context, used to decrypt the passwords
  110. DnsDomainName - Dns domain name of the domain to install
  111. FlatDomainName - NetBIOS domain name of the domain to install
  112. EDomainAdminPassword - Encrypted password to set on the administrator account if it is a new install
  113. SiteName - Name of the site this DC should belong to
  114. DsDatabasePath - Absolute path on the local machine where the Ds DIT should go
  115. DsLogPath - Absolute path on the local machine where the Ds log files should go
  116. SystemVolumeRootPath - Absolute path on the local machine which will be the root of
  117. the system volume.
  118. ParentDnsDomainName - Optional. If present, set this domain up as a child of the
  119. specified domain
  120. Account - User account to use when setting up as a child domain
  121. EPassword - Encrypted password to use with the above account
  122. EDsRepairPassword - Encrypted password to use for the admin account of the repair mode
  123. Options - Options to control the creation of the domain
  124. DsOperationHandle - Handle to the operation is returned here.
  125. Returns:
  126. ERROR_SUCCESS - Success
  127. ERROR_INVALID_PARAMETER - A NULL return parameter was given
  128. ERROR_INVALID_STATE - This machine is not a server
  129. --*/
  130. {
  131. DWORD Win32Err = ERROR_SUCCESS;
  132. DSROLEP_MACHINE_TYPE MachineRole;
  133. PDSROLEP_OPERATION_PROMOTE_ARGS PromoteArgs;
  134. UCHAR Seed = 0;
  135. NTSTATUS Status;
  136. HANDLE Policy = NULL;
  137. OBJECT_ATTRIBUTES ObjectAttributes;
  138. PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
  139. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC ServerInfo = NULL;
  140. BOOL fHandleInit = FALSE;
  141. #define DSROLEP_DC_AS_DC_DA_PWD_INDEX 0
  142. #define DSROLEP_DC_AS_DC_PWD_INDEX 1
  143. #define DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX 2
  144. #define DSROLEP_DC_AS_DC_MAX_PWD_COUNT 3
  145. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DC_AS_DC_MAX_PWD_COUNT];
  146. UNICODE_STRING Passwords[DSROLEP_DC_AS_DC_MAX_PWD_COUNT];
  147. EncryptedPasswords[DSROLEP_DC_AS_DC_DA_PWD_INDEX] = EDomainAdminPassword;
  148. EncryptedPasswords[DSROLEP_DC_AS_DC_PWD_INDEX] = EPassword;
  149. EncryptedPasswords[DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX] = EDsRepairPassword;
  150. RtlZeroMemory( Passwords, sizeof(Passwords) );
  151. //
  152. // Do some parameter checking
  153. //
  154. if ( !DnsDomainName
  155. || !DsDatabasePath
  156. || !DsLogPath
  157. || !FlatDomainName
  158. || !SystemVolumeRootPath ) {
  159. return( ERROR_INVALID_PARAMETER );
  160. }
  161. if ( !ParentDnsDomainName
  162. && !SiteName )
  163. {
  164. // Site name must be specified when installing the root of the forest
  165. return ( ERROR_INVALID_PARAMETER );
  166. }
  167. if ( FLAG_ON( Options, DSROLE_DC_TRUST_AS_ROOT )
  168. && !ParentDnsDomainName ) {
  169. //
  170. // When installing a new tree in an existing forest,
  171. // the root domain DNS name must be present.
  172. //
  173. return ( ERROR_INVALID_PARAMETER );
  174. }
  175. if ( FLAG_ON( Options, DSROLE_DC_NO_NET )
  176. && ParentDnsDomainName ) {
  177. //
  178. // No net option when installing a child domain
  179. // does not make sense
  180. //
  181. return ( ERROR_INVALID_PARAMETER );
  182. }
  183. //
  184. // Check the access of the caller
  185. //
  186. Win32Err = DsRolepCheckPromoteAccess();
  187. if ( ERROR_SUCCESS != Win32Err ) {
  188. return Win32Err;
  189. }
  190. //
  191. // Init the logging
  192. //
  193. DsRolepInitializeLog();
  194. //
  195. // Check that the current OS configuration supports this request
  196. //
  197. Win32Err = DsRolepIsValidProductSuite((ParentDnsDomainName == NULL) ? TRUE : FALSE,
  198. FALSE,
  199. DnsDomainName);
  200. if ( ERROR_SUCCESS != Win32Err ) {
  201. goto Cleanup;
  202. }
  203. //
  204. // Dump the parameters to the log
  205. //
  206. DsRolepLogPrint(( DEB_TRACE,
  207. "Promotion request for domain controller of new domain\n" ));
  208. DsRolepLogPrint(( DEB_TRACE,
  209. "DnsDomainName %ws\n",
  210. DnsDomainName ));
  211. DsRolepLogPrint(( DEB_TRACE,
  212. "\tFlatDomainName %ws\n",
  213. FlatDomainName ));
  214. DsRolepLogPrint(( DEB_TRACE,
  215. "\tSiteName %ws\n",
  216. DsRolepDisplayOptional( SiteName ) ));
  217. DsRolepLogPrint(( DEB_TRACE,
  218. "\tSystemVolumeRootPath %ws\n",
  219. SystemVolumeRootPath ));
  220. DsRolepLogPrint(( DEB_TRACE,
  221. "\tDsDatabasePath %ws, DsLogPath %ws\n",
  222. DsDatabasePath, DsLogPath ));
  223. DsRolepLogPrint(( DEB_TRACE,
  224. "\tParentDnsDomainName %ws\n",
  225. DsRolepDisplayOptional( ParentDnsDomainName ) ));
  226. DsRolepLogPrint(( DEB_TRACE,
  227. "\tParentServer %ws\n",
  228. DsRolepDisplayOptional( ParentServer ) ));
  229. DsRolepLogPrint(( DEB_TRACE,
  230. "\tAccount %ws\n",
  231. DsRolepDisplayOptional( Account ) ));
  232. DsRolepLogPrint(( DEB_TRACE,
  233. "\tOptions %lu\n",
  234. Options ));
  235. //
  236. // Make sure that we are not a member of a domain
  237. //
  238. Win32Err = DsRolerGetPrimaryDomainInformation(NULL,
  239. DsRolePrimaryDomainInfoBasic,
  240. (PDSROLER_PRIMARY_DOMAIN_INFORMATION*)&ServerInfo);
  241. if (ERROR_SUCCESS == Win32Err) {
  242. ASSERT(ServerInfo);
  243. if(ServerInfo->MachineRole != DsRole_RoleStandaloneServer) {
  244. Win32Err = ERROR_CURRENT_DOMAIN_NOT_ALLOWED;
  245. DsRolepLogOnFailure( Win32Err,
  246. DsRolepLogPrint(( DEB_TRACE,
  247. "Verifying domain membership failed: %lu\n",
  248. Win32Err )) );
  249. goto Cleanup;
  250. }
  251. } else if (ERROR_SUCCESS == Win32Err){
  252. DsRoleFreeMemory(ServerInfo);
  253. ServerInfo = NULL;
  254. } else {
  255. DsRolepLogOnFailure( Win32Err,
  256. DsRolepLogPrint(( DEB_TRACE,
  257. "DsRoleGetPrimaryDomainInformation failed: %lu\n",
  258. Win32Err )) );
  259. goto Cleanup;
  260. }
  261. //
  262. // Verify the path names we are given
  263. //
  264. DsRolepLogPrint(( DEB_TRACE,"Validate supplied paths\n" ));
  265. Win32Err = DsRolepCheckFilePaths( DsDatabasePath,
  266. DsLogPath,
  267. SystemVolumeRootPath );
  268. if ( ERROR_SUCCESS != Win32Err ) {
  269. goto Cleanup;
  270. }
  271. //
  272. // If we are doing a parent/child setup, verify our name
  273. //
  274. if ( ParentDnsDomainName &&
  275. !FLAG_ON( Options, DSROLE_DC_TRUST_AS_ROOT ) ) {
  276. DsRolepLogPrint(( DEB_TRACE, "Child domain creation -- check the new domain name is child of parent domain name.\n" ));
  277. Win32Err = DsRolepIsDnsNameChild( ParentDnsDomainName, DnsDomainName );
  278. if ( ERROR_SUCCESS != Win32Err ) {
  279. DsRolepLogOnFailure( Win32Err,
  280. DsRolepLogPrint(( DEB_TRACE,
  281. "Verifying the child domain dns name failed: %lu\n",
  282. Win32Err )) );
  283. goto Cleanup;
  284. }
  285. }
  286. //
  287. // Validate the netbios domain name is not in use
  288. //
  289. DsRolepLogPrint(( DEB_TRACE,"Domain Creation -- check that the flat name is unique.\n" ));
  290. Win32Err = NetpValidateName( NULL,
  291. FlatDomainName,
  292. NULL,
  293. NULL,
  294. NetSetupNonExistentDomain );
  295. if ( FLAG_ON( Options, DSROLE_DC_NO_NET )
  296. && (Win32Err == ERROR_NETWORK_UNREACHABLE)) {
  297. //
  298. // See NT bug 386193. This option allows a first DC in forest
  299. // to installed with no network (useful for evaluation)
  300. //
  301. DsRolepLogPrint(( DEB_TRACE,"Ignoring network unreachable status\n" ));
  302. Win32Err = ERROR_SUCCESS;
  303. }
  304. if ( Win32Err != ERROR_SUCCESS ) {
  305. DsRolepLogOnFailure( Win32Err,
  306. DsRolepLogPrint(( DEB_TRACE,
  307. "Flat name validation of %ws failed with %lu\n",
  308. FlatDomainName,
  309. Win32Err )) );
  310. goto Cleanup;
  311. }
  312. // No workstations or domain controllers allowed
  313. Win32Err = DsRolepGetMachineType( &MachineRole );
  314. if ( Win32Err == ERROR_SUCCESS ) {
  315. switch ( MachineRole ) {
  316. case DSROLEP_MT_CLIENT:
  317. case DSROLEP_MT_MEMBER:
  318. Win32Err = ERROR_INVALID_SERVER_STATE;
  319. break;
  320. }
  321. }
  322. if ( Win32Err != ERROR_SUCCESS ) {
  323. DsRolepLogPrint(( DEB_TRACE,"This operation is not valid on a workstation or domain controller\n" ));
  324. goto Cleanup;
  325. }
  326. //
  327. // At this point, we are good to go
  328. //
  329. DsRolepLogPrint(( DEB_TRACE,"Start the worker task\n" ));
  330. //
  331. // Do our necessary initializations
  332. //
  333. Win32Err = DsRolepInitializeOperationHandle( );
  334. if ( Win32Err != ERROR_SUCCESS ) {
  335. goto Cleanup;
  336. }
  337. fHandleInit = TRUE;
  338. Win32Err = DsRolepDecryptPasswordsWithKey ( RpcBindingHandle,
  339. EncryptedPasswords,
  340. NELEMENTS(EncryptedPasswords),
  341. Passwords,
  342. &Seed );
  343. if ( ERROR_SUCCESS != Win32Err ) {
  344. goto Cleanup;
  345. }
  346. //
  347. // If everything is fine, go ahead and do the setup
  348. //
  349. Win32Err = DsRolepBuildPromoteArgumentBlock( DnsDomainName,
  350. FlatDomainName,
  351. SiteName,
  352. DsDatabasePath,
  353. DsLogPath,
  354. NULL,
  355. SystemVolumeRootPath,
  356. NULL,
  357. ParentDnsDomainName,
  358. ParentServer,
  359. Account,
  360. &Passwords[DSROLEP_DC_AS_DC_PWD_INDEX],
  361. &Passwords[DSROLEP_DC_AS_DC_DA_PWD_INDEX],
  362. &Passwords[DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX],
  363. Options,
  364. Seed,
  365. &PromoteArgs );
  366. DsRolepFreePasswords( Passwords,
  367. NELEMENTS(Passwords) );
  368. if ( Win32Err == ERROR_SUCCESS ) {
  369. Win32Err = DsRolepSpinWorkerThread( DSROLEP_OPERATION_DC,
  370. ( PVOID )PromoteArgs );
  371. //
  372. // Once the thread has started, no more errors can occur in this
  373. // function
  374. //
  375. if ( Win32Err != ERROR_SUCCESS ) {
  376. DsRolepFreeArgumentBlock( &PromoteArgs, TRUE );
  377. }
  378. }
  379. if ( Win32Err == ERROR_SUCCESS ) {
  380. *DsOperationHandle = (DSROLER_HANDLE)&DsRolepCurrentOperationHandle;
  381. }
  382. //
  383. // That's it
  384. //
  385. Cleanup:
  386. // Always reset to a known state
  387. if ( ERROR_SUCCESS != Win32Err && fHandleInit )
  388. {
  389. DsRolepResetOperationHandle( DSROLEP_IDLE );
  390. }
  391. if ( ServerInfo ) {
  392. DsRoleFreeMemory(ServerInfo);
  393. ServerInfo = NULL;
  394. }
  395. DsRolepLogPrint(( DEB_TRACE,"Request for promotion returning %lu\n", Win32Err ));
  396. return( Win32Err );
  397. }
  398. DWORD
  399. DsRolerDcAsReplica(
  400. IN handle_t RpcBindingHandle,
  401. IN LPWSTR DnsDomainName,
  402. IN LPWSTR ReplicaPartner,
  403. IN LPWSTR SiteName OPTIONAL,
  404. IN LPWSTR DsDatabasePath,
  405. IN LPWSTR DsLogPath,
  406. IN LPWSTR RestorePath OPTIONAL,
  407. IN LPWSTR SystemVolumeRootPath,
  408. IN PUNICODE_STRING Bootkey,
  409. IN LPWSTR Account,
  410. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EPassword,
  411. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EDsRepairPassword,
  412. IN ULONG Options,
  413. OUT PDSROLER_HANDLE DsOperationHandle)
  414. /*++
  415. Routine Description:
  416. Rpc server routine for installing a server a replica in an existing domain
  417. Arguments:
  418. RpcBindingHandle - the RPC context, used to decrypt the passwords
  419. DnsDomainName - Dns domain name of the domain to install into
  420. ReplicaPartner - The name of a Dc within the existing domain, against which to replicate
  421. SiteName - Name of the site this DC should belong to
  422. DsDatabasePath - Absolute path on the local machine where the Ds DIT should go
  423. DsLogPath - Absolute path on the local machine where the Ds log files should go
  424. SystemVolumeRootPath - Absolute path on the local machine which will be the root of
  425. the system volume.
  426. BootKey - needed for media installs where the password is not in the registry or on a disk
  427. cbBootKey - size of the bootkey
  428. Account - User account to use when setting up as a child domain
  429. EPassword - Encrypted password to use with the above account
  430. EDsRepairPassword - Encrypted password to use for the admin account of the repair mode
  431. Options - Options to control the creation of the domain
  432. DsOperationHandle - Handle to the operation is returned here.
  433. Returns:
  434. ERROR_SUCCESS - Success
  435. ERROR_INVALID_PARAMETER - A NULL return parameter was given
  436. ERROR_INVALID_STATE - This machine is not a server
  437. --*/
  438. {
  439. DWORD Win32Err = ERROR_SUCCESS;
  440. DSROLEP_MACHINE_TYPE MachineRole;
  441. PDSROLEP_OPERATION_PROMOTE_ARGS PromoteArgs;
  442. ULONG VerifyOptions, VerifyResults;
  443. UCHAR Seed;
  444. #define DSROLEP_DC_AS_REPLICA_PWD_INDEX 0
  445. #define DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX 1
  446. #define DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT 2
  447. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT];
  448. UNICODE_STRING Passwords[DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT];
  449. EncryptedPasswords[DSROLEP_DC_AS_REPLICA_PWD_INDEX] = EPassword;
  450. EncryptedPasswords[DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX] = EDsRepairPassword;
  451. RtlZeroMemory( Passwords, sizeof(Passwords) );
  452. //
  453. // Do some parameter checking
  454. //
  455. if ( !DnsDomainName
  456. || !DsDatabasePath
  457. || !DsLogPath
  458. || !SystemVolumeRootPath ) {
  459. return( ERROR_INVALID_PARAMETER );
  460. }
  461. Win32Err = DsRolepCheckPromoteAccess();
  462. if ( ERROR_SUCCESS != Win32Err ) {
  463. return Win32Err;
  464. }
  465. //
  466. // Init the logging
  467. //
  468. DsRolepInitializeLog();
  469. //
  470. // Check that the current OS configuration supports this request
  471. //
  472. Win32Err = DsRolepIsValidProductSuite(FALSE,
  473. TRUE,
  474. DnsDomainName);
  475. if ( ERROR_SUCCESS != Win32Err ) {
  476. goto Cleanup;
  477. }
  478. DsRolepLogPrint(( DEB_TRACE,
  479. "Promotion request for replica domain controller\n" ));
  480. DsRolepLogPrint(( DEB_TRACE,
  481. "DnsDomainName %ws\n",
  482. DnsDomainName ));
  483. DsRolepLogPrint(( DEB_TRACE,
  484. "\tReplicaPartner %ws\n",
  485. DsRolepDisplayOptional( ReplicaPartner ) ));
  486. DsRolepLogPrint(( DEB_TRACE,
  487. "\tSiteName %ws\n",
  488. DsRolepDisplayOptional( SiteName ) ));
  489. DsRolepLogPrint(( DEB_TRACE,
  490. "\tDsDatabasePath %ws, DsLogPath %ws\n",
  491. DsDatabasePath, DsLogPath ));
  492. DsRolepLogPrint(( DEB_TRACE,
  493. "\tSystemVolumeRootPath %ws\n",
  494. SystemVolumeRootPath ));
  495. DsRolepLogPrint(( DEB_TRACE,
  496. "\tAccount %ws\n",
  497. DsRolepDisplayOptional(Account) ));
  498. DsRolepLogPrint(( DEB_TRACE,
  499. "\tOptions %lu\n",
  500. Options ));
  501. //
  502. // Verify the path names we are given
  503. //
  504. DsRolepLogPrint(( DEB_TRACE,"Validate supplied paths\n" ));
  505. Win32Err = DsRolepCheckFilePaths( DsDatabasePath,
  506. DsLogPath,
  507. SystemVolumeRootPath );
  508. if ( ERROR_SUCCESS != Win32Err ) {
  509. goto Cleanup;
  510. }
  511. //
  512. // Do our necessary initializations
  513. //
  514. Win32Err = DsRolepInitializeOperationHandle( );
  515. if ( Win32Err == ERROR_SUCCESS ) {
  516. Win32Err = DsRolepGetMachineType( &MachineRole );
  517. if ( Win32Err == ERROR_SUCCESS ) {
  518. switch ( MachineRole ) {
  519. case DSROLEP_MT_CLIENT:
  520. case DSROLEP_MT_MEMBER:
  521. DsRolepLogPrint(( DEB_TRACE,"This operation is not valid on a workstation or domain controller\n" ));
  522. Win32Err = ERROR_INVALID_SERVER_STATE;
  523. break;
  524. }
  525. }
  526. }
  527. Win32Err = DsRolepDecryptPasswordsWithKey ( RpcBindingHandle,
  528. EncryptedPasswords,
  529. NELEMENTS(EncryptedPasswords),
  530. Passwords,
  531. &Seed );
  532. if (Win32Err == ERROR_SUCCESS) {
  533. Win32Err = DsRolepDecryptHash(Bootkey);
  534. }
  535. //
  536. // If everything is fine, go ahead and do the setup
  537. //
  538. if ( Win32Err == ERROR_SUCCESS ) {
  539. DsRolepLogPrint(( DEB_TRACE,"Start the worker task\n" ));
  540. Win32Err = DsRolepBuildPromoteArgumentBlock( DnsDomainName,
  541. NULL,
  542. SiteName,
  543. DsDatabasePath,
  544. DsLogPath,
  545. RestorePath,
  546. SystemVolumeRootPath,
  547. Bootkey,
  548. NULL,
  549. ReplicaPartner,
  550. Account,
  551. &Passwords[DSROLEP_DC_AS_REPLICA_PWD_INDEX],
  552. NULL,
  553. &Passwords[DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX],
  554. Options,
  555. Seed,
  556. &PromoteArgs );
  557. DsRolepFreePasswords( Passwords,
  558. NELEMENTS(Passwords) );
  559. if ( Win32Err == ERROR_SUCCESS ) {
  560. Win32Err = DsRolepSpinWorkerThread( DSROLEP_OPERATION_REPLICA,
  561. ( PVOID )PromoteArgs );
  562. if ( Win32Err != ERROR_SUCCESS ) {
  563. DsRolepFreeArgumentBlock( &PromoteArgs, TRUE );
  564. }
  565. }
  566. if ( Win32Err != ERROR_SUCCESS ) {
  567. DsRolepResetOperationHandle( DSROLEP_IDLE );
  568. }
  569. }
  570. if ( Win32Err == ERROR_SUCCESS ) {
  571. *DsOperationHandle = (DSROLER_HANDLE)&DsRolepCurrentOperationHandle;
  572. }
  573. Cleanup:
  574. DsRolepLogPrint(( DEB_TRACE,"Request for promotion returning %lu\n", Win32Err ));
  575. return( Win32Err );
  576. }
  577. DWORD
  578. DsRolerDemoteDc(
  579. IN handle_t RpcBindingHandle,
  580. IN LPWSTR DnsDomainName,
  581. IN DSROLE_SERVEROP_DEMOTE_ROLE ServerRole,
  582. IN LPWSTR Account,
  583. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EPassword,
  584. IN ULONG Options,
  585. IN BOOL LastDcInDomain,
  586. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EDomainAdminPassword,
  587. OUT PDSROLER_HANDLE DsOperationHandle
  588. )
  589. /*++
  590. Routine Description:
  591. Rpc server routine for demoting a dc to a server
  592. Arguments:
  593. RpcBindingHandle - the RPC context, used to decrypt the passwords
  594. DnsDomainName - Dns domain name of the domain to be demoted. Null means all of the supported
  595. domain names
  596. ServerRole - The new role this machine should take
  597. Account - OPTIONAL User account to use when deleting the trusted domain object
  598. EPassword - Encrypted password to use with the above account
  599. Options - Options to control the demotion of the domain
  600. LastDcInDomain - If TRUE, the Dc being demoted is the last Dc in the domain.
  601. EDomainAdminPassword - Encrypted password to set on the administrator account if it is a new install
  602. DsOperationHandle - Handle to the operation is returned here.
  603. Returns:
  604. ERROR_SUCCESS - Success
  605. ERROR_INVALID_PARAMETER - A NULL return parameter was given
  606. ERROR_INVALID_STATE - This machine is not a server
  607. --*/
  608. {
  609. DSROLEP_MACHINE_TYPE MachineRole;
  610. DWORD Win32Err;
  611. PDSROLEP_OPERATION_DEMOTE_ARGS DemoteArgs;
  612. UCHAR Seed;
  613. #define DSROLEP_DEMOTE_PWD_INDEX 0
  614. #define DSROLEP_DEMOTE_ADMIN_PWD_INDEX 1
  615. #define DSROLEP_DEMOTE_MAX_PWD_COUNT 2
  616. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DEMOTE_MAX_PWD_COUNT];
  617. UNICODE_STRING Passwords[DSROLEP_DEMOTE_MAX_PWD_COUNT];
  618. EncryptedPasswords[DSROLEP_DEMOTE_PWD_INDEX] = EPassword;
  619. EncryptedPasswords[DSROLEP_DEMOTE_ADMIN_PWD_INDEX] = EDomainAdminPassword;
  620. RtlZeroMemory( Passwords, sizeof(Passwords) );
  621. if ( (LastDcInDomain && (DsRoleServerMember == ServerRole))
  622. || (!LastDcInDomain && (DsRoleServerStandalone == ServerRole)) ) {
  623. //
  624. // These configurations are not supported
  625. //
  626. return ERROR_INVALID_PARAMETER;
  627. }
  628. //
  629. // Check the access right for demote
  630. //
  631. Win32Err = DsRolepCheckDemoteAccess();
  632. if ( ERROR_SUCCESS != Win32Err ) {
  633. return Win32Err;
  634. }
  635. //
  636. // Initialize return value to NULL
  637. //
  638. *DsOperationHandle = NULL;
  639. DsRolepInitializeLog();
  640. DsRolepLogPrint(( DEB_TRACE,
  641. "Request for demotion of domain controller\n" ));
  642. DsRolepLogPrint(( DEB_TRACE,
  643. "DnsDomainName %ws\n",
  644. DsRolepDisplayOptional( DnsDomainName ) ));
  645. DsRolepLogPrint(( DEB_TRACE,
  646. "\tServerRole %lu\n",
  647. ServerRole ));
  648. DsRolepLogPrint(( DEB_TRACE,
  649. "\tAccount %ws ",
  650. DsRolepDisplayOptional( Account ) ));
  651. DsRolepLogPrint(( DEB_TRACE,
  652. "\tOptions %lu\n",
  653. Options ));
  654. DsRolepLogPrint(( DEB_TRACE,
  655. "\tLastDcInDomain %S\n",
  656. LastDcInDomain ? "TRUE" : "FALSE" ));
  657. //
  658. // Do our necessary initializations
  659. //
  660. if ( Win32Err == ERROR_SUCCESS ) {
  661. Win32Err = DsRolepInitializeOperationHandle( );
  662. if ( Win32Err == ERROR_SUCCESS ) {
  663. Win32Err = DsRolepGetMachineType( &MachineRole );
  664. if ( Win32Err == ERROR_SUCCESS ) {
  665. switch ( MachineRole ) {
  666. case DSROLEP_MT_CLIENT:
  667. case DSROLEP_MT_STANDALONE:
  668. DsRolepLogPrint(( DEB_TRACE,"This operation is only valid on a domain controller\n" ));
  669. Win32Err = ERROR_INVALID_SERVER_STATE;
  670. break;
  671. }
  672. }
  673. }
  674. }
  675. Win32Err = DsRolepDecryptPasswordsWithKey ( RpcBindingHandle,
  676. EncryptedPasswords,
  677. NELEMENTS(EncryptedPasswords),
  678. Passwords,
  679. &Seed );
  680. //
  681. // Spawn the demotion thread
  682. //
  683. if ( Win32Err == ERROR_SUCCESS ) {
  684. DsRolepLogPrint(( DEB_TRACE,"Start the worker task\n" ));
  685. Win32Err = DsRolepBuildDemoteArgumentBlock( ServerRole,
  686. DnsDomainName,
  687. Account,
  688. &Passwords[DSROLEP_DEMOTE_PWD_INDEX],
  689. Options,
  690. ( BOOLEAN )LastDcInDomain,
  691. &Passwords[DSROLEP_DEMOTE_ADMIN_PWD_INDEX],
  692. Seed,
  693. &DemoteArgs );
  694. DsRolepFreePasswords( Passwords,
  695. NELEMENTS(Passwords) );
  696. if ( Win32Err == ERROR_SUCCESS ) {
  697. Win32Err = DsRolepSpinWorkerThread( DSROLEP_OPERATION_DEMOTE,
  698. ( PVOID )DemoteArgs );
  699. if ( Win32Err != ERROR_SUCCESS ) {
  700. DsRolepFreeArgumentBlock( &DemoteArgs, FALSE );
  701. }
  702. }
  703. if ( Win32Err != ERROR_SUCCESS ) {
  704. DsRolepResetOperationHandle( DSROLEP_IDLE );
  705. }
  706. }
  707. if ( Win32Err == ERROR_SUCCESS ) {
  708. *DsOperationHandle = (DSROLER_HANDLE)&DsRolepCurrentOperationHandle;
  709. }
  710. DsRolepLogPrint(( DEB_TRACE,"Request for demotion returning %lu\n", Win32Err ));
  711. return( Win32Err );
  712. }
  713. DWORD
  714. DsRolerGetDcOperationProgress(
  715. IN PDSROLE_SERVER_NAME Server,
  716. IN PDSROLER_HANDLE DsOperationHandle,
  717. IN OUT PDSROLER_SERVEROP_STATUS *ServerOperationStatus
  718. )
  719. /*++
  720. Routine Description:
  721. Rpc server routine for determining the present state of the operation
  722. Arguments:
  723. Server - Server the call was remoted to
  724. DsOperationHandle - Handle returned from a previous call
  725. ServerOperationStatus - Where the status information is returned
  726. Returns:
  727. ERROR_SUCCESS - Success
  728. ERROR_INVALID_HANDLE - A bad Operation handle was supplied
  729. --*/
  730. {
  731. DWORD Win32Err = ERROR_SUCCESS;
  732. __try {
  733. if ( DsOperationHandle == NULL ||
  734. *DsOperationHandle != ( DSROLER_HANDLE )&DsRolepCurrentOperationHandle) {
  735. Win32Err = ERROR_INVALID_HANDLE;
  736. }
  737. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  738. Win32Err = GetExceptionCode();
  739. }
  740. if ( Win32Err == ERROR_SUCCESS ) {
  741. Win32Err = DsRolepGetDcOperationProgress( ( PDSROLE_SERVEROP_HANDLE )DsOperationHandle,
  742. ServerOperationStatus );
  743. }
  744. return( Win32Err );
  745. }
  746. DWORD
  747. DsRolerGetDcOperationResults(
  748. IN PDSROLE_SERVER_NAME Server,
  749. IN PDSROLER_HANDLE DsOperationHandle,
  750. OUT PDSROLER_SERVEROP_RESULTS *ServerOperationResults
  751. )
  752. /*++
  753. Routine Description:
  754. Rpc server routine for determining the final results of the operation. If the operation
  755. is not yet completed, this function will block until it does complete.
  756. Arguments:
  757. Server - Server the call was remoted to
  758. DsOperationHandle - Handle returned from a previous call
  759. ServerOperationResults - Where the final operation results are returned.
  760. Returns:
  761. ERROR_SUCCESS - Success
  762. ERROR_INVALID_HANDLE - A bad Operation handle was supplied
  763. --*/
  764. {
  765. DWORD Win32Err = ERROR_SUCCESS;
  766. __try {
  767. if ( DsOperationHandle == NULL ||
  768. *DsOperationHandle != ( DSROLER_HANDLE )&DsRolepCurrentOperationHandle) {
  769. Win32Err = ERROR_INVALID_HANDLE;
  770. }
  771. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  772. Win32Err = GetExceptionCode();
  773. }
  774. if ( Win32Err == ERROR_SUCCESS ) {
  775. Win32Err = DsRolepGetDcOperationResults( ( PDSROLE_SERVEROP_HANDLE )DsOperationHandle,
  776. ServerOperationResults );
  777. DsRolepCloseLog();
  778. }
  779. return( Win32Err );
  780. }
  781. DWORD
  782. WINAPI
  783. DsRolerDnsNameToFlatName(
  784. IN LPWSTR Server OPTIONAL,
  785. IN LPWSTR DnsName,
  786. OUT LPWSTR *FlatName,
  787. OUT PULONG StatusFlag
  788. )
  789. /*++
  790. Routine Description:
  791. Rpc server routine for determining the default flat (netbios) domain name for the given
  792. Dns domain name
  793. Arguments:
  794. Server - Server the call was remoted to
  795. DnsName - Dns name to convert
  796. FlatName - Where the flat name is returned. Alocated via MIDL_user_allocate
  797. StatusFlag - Where the status flag is returned
  798. Returns:
  799. ERROR_SUCCESS - Success
  800. ERROR_INVALID_PARAMETER - A bad input or NULL return parameter was given
  801. --*/
  802. {
  803. DWORD Win32Err = ERROR_SUCCESS;
  804. if ( DnsName == NULL || FlatName == NULL || StatusFlag == NULL ) {
  805. return( ERROR_INVALID_PARAMETER );
  806. }
  807. Win32Err = DsRolepDnsNameToFlatName( DnsName,
  808. FlatName,
  809. StatusFlag );
  810. return( Win32Err );
  811. }
  812. #define GET_PDI_COPY_STRING_AND_INSERT( _unicode_, _buffer_ ) \
  813. if ( ( _unicode_)->Length == 0 ) { \
  814. \
  815. ( _buffer_ ) = NULL; \
  816. \
  817. } else { \
  818. \
  819. ( _buffer_ ) = MIDL_user_allocate( (_unicode_)->Length + sizeof( WCHAR ) ); \
  820. if ( ( _buffer_ ) == NULL ) { \
  821. \
  822. Status = STATUS_INSUFFICIENT_RESOURCES; \
  823. goto GetInfoError; \
  824. \
  825. } else { \
  826. \
  827. BuffersToFree[ BuffersCnt++ ] = ( PBYTE )( _buffer_ ); \
  828. RtlCopyMemory( ( _buffer_ ), \
  829. ( _unicode_ )->Buffer, \
  830. ( _unicode_ )->Length ); \
  831. ( _buffer_ )[ ( _unicode_ )->Length / sizeof( WCHAR ) ] = UNICODE_NULL; \
  832. } \
  833. }
  834. DWORD
  835. WINAPI
  836. DsRolerGetDatabaseFacts(
  837. IN handle_t RpcBindingHandle,
  838. IN LPWSTR lpRestorePath,
  839. OUT LPWSTR *lpDNSDomainName,
  840. OUT PULONG State
  841. )
  842. /*++
  843. Routine Description:
  844. This function will give information about a restore database
  845. 1. the way the syskey is stored
  846. 2. the domain that the database came from
  847. 3. where the backup was taken from a GC or not
  848. Arguments:
  849. lpRestorePath - The location of the restored files.
  850. lpDNSDomainName - This parameter will recieve the name of the domain that this backup came
  851. from
  852. State - The return Values that report How the syskey is stored and If the back was likely
  853. taken form a GC or not.
  854. Return Values:
  855. ERROR_SUCCESS - Success
  856. --*/
  857. {
  858. DWORD Win32Err=ERROR_SUCCESS;
  859. Win32Err = DsRolepCheckPromoteAccess();
  860. if ( ERROR_SUCCESS != Win32Err ) {
  861. return Win32Err;
  862. }
  863. return DsRolepGetDatabaseFacts(lpRestorePath,
  864. lpDNSDomainName,
  865. State);
  866. }
  867. DWORD
  868. DsRolerGetPrimaryDomainInformation(
  869. IN PDSROLE_SERVER_NAME Server,
  870. IN DSROLE_PRIMARY_DOMAIN_INFO_LEVEL InfoLevel,
  871. OUT PDSROLER_PRIMARY_DOMAIN_INFORMATION *DomainInfo
  872. )
  873. /*++
  874. Routine Description:
  875. Determine the principal name to use for authenticated Rpc
  876. Arguments:
  877. Server - Server the call was remoted to
  878. ServerPrincipal - Where the server principal name is returned
  879. Returns:
  880. ERROR_SUCCESS - Success
  881. ERROR_INVALID_PARAMETER - A NULL return parameter was given
  882. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  883. --*/
  884. {
  885. DWORD Win32Err = ERROR_SUCCESS;
  886. NTSTATUS Status;
  887. PBYTE BuffersToFree[ 6 ];
  888. ULONG BuffersCnt = 0, i;
  889. PDSROLER_PRIMARY_DOMAIN_INFO_BASIC BasicInfo;
  890. PDSROLE_UPGRADE_STATUS_INFO Upgrade;
  891. PDSROLE_OPERATION_STATE_INFO OperationStateInfo = 0;
  892. BOOLEAN IsUpgrade;
  893. ULONG PreviousServerRole;
  894. PPOLICY_LSA_SERVER_ROLE_INFO ServerRole;
  895. PPOLICY_DNS_DOMAIN_INFO CurrentDnsInfo = NULL;
  896. PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo;
  897. LSAPR_HANDLE PolicyHandle = NULL;
  898. LSAPR_OBJECT_ATTRIBUTES PolicyObject;
  899. GUID NullGuid;
  900. memset( &NullGuid, 0, sizeof(GUID) );
  901. #define IS_GUID_PRESENT(x) (memcmp(&(x), &NullGuid, sizeof(GUID)))
  902. if ( DomainInfo == NULL ) {
  903. return( ERROR_INVALID_PARAMETER );
  904. }
  905. //
  906. // This particular interface cannot be called until the Lsa and Sam are fully initialized.
  907. // As such, we will have to wait until they are..
  908. //
  909. if ( !DsRolepSamInitialized ) {
  910. Win32Err = DsRolepWaitForSam();
  911. if ( Win32Err != ERROR_SUCCESS ) {
  912. return( Win32Err );
  913. }
  914. DsRolepSamInitialized = TRUE;
  915. }
  916. switch ( InfoLevel ) {
  917. case DsRolePrimaryDomainInfoBasic:
  918. BasicInfo = MIDL_user_allocate( sizeof( DSROLER_PRIMARY_DOMAIN_INFO_BASIC ) );
  919. if ( BasicInfo == NULL ) {
  920. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  921. goto GetInfoError;
  922. } else {
  923. BuffersToFree[ BuffersCnt++ ] = ( PBYTE )BasicInfo;
  924. }
  925. //
  926. // Open a handle to the policy and ensure the callers has access to read it
  927. //
  928. RtlZeroMemory(&PolicyObject, sizeof(PolicyObject));
  929. Status = LsarOpenPolicy(
  930. NULL, // Local LSA
  931. &PolicyObject,
  932. POLICY_VIEW_LOCAL_INFORMATION,
  933. &PolicyHandle );
  934. if ( !NT_SUCCESS(Status) ) {
  935. Win32Err = RtlNtStatusToDosError( Status );
  936. goto GetInfoError;
  937. }
  938. //
  939. // Get the current information
  940. //
  941. Status = LsarQueryInformationPolicy(
  942. PolicyHandle,
  943. PolicyDnsDomainInformationInt,
  944. (PLSAPR_POLICY_INFORMATION *) &CurrentDnsInfo );
  945. if ( NT_SUCCESS( Status ) ) {
  946. //
  947. // Get the machine role
  948. //
  949. switch ( LsapProductType ) {
  950. case NtProductWinNt:
  951. if ( CurrentDnsInfo->Sid == NULL ) {
  952. BasicInfo->MachineRole = DsRole_RoleStandaloneWorkstation;
  953. } else {
  954. BasicInfo->MachineRole = DsRole_RoleMemberWorkstation;
  955. }
  956. break;
  957. case NtProductServer:
  958. if ( CurrentDnsInfo->Sid == NULL ) {
  959. BasicInfo->MachineRole = DsRole_RoleStandaloneServer;
  960. } else {
  961. BasicInfo->MachineRole = DsRole_RoleMemberServer;
  962. }
  963. break;
  964. case NtProductLanManNt:
  965. Status = LsarQueryInformationPolicy(
  966. PolicyHandle,
  967. PolicyLsaServerRoleInformation,
  968. (PLSAPR_POLICY_INFORMATION *) &ServerRole );
  969. if (NT_SUCCESS( Status ) ) {
  970. if ( ServerRole->LsaServerRole == PolicyServerRolePrimary ) {
  971. //
  972. // If we think we're a primary domain controller, we'll need to
  973. // guard against the case where we're actually standalone during setup
  974. //
  975. Status = LsarQueryInformationPolicy(
  976. PolicyHandle,
  977. PolicyAccountDomainInformation,
  978. (PLSAPR_POLICY_INFORMATION *) &AccountDomainInfo );
  979. if ( NT_SUCCESS( Status ) ) {
  980. if ( CurrentDnsInfo->Sid == NULL ||
  981. AccountDomainInfo->DomainSid == NULL ||
  982. !RtlEqualSid( AccountDomainInfo->DomainSid,
  983. CurrentDnsInfo->Sid ) ) {
  984. BasicInfo->MachineRole = DsRole_RoleStandaloneServer;
  985. } else {
  986. BasicInfo->MachineRole = DsRole_RolePrimaryDomainController;
  987. }
  988. LsaIFree_LSAPR_POLICY_INFORMATION(
  989. PolicyAccountDomainInformation,
  990. ( PLSAPR_POLICY_INFORMATION )AccountDomainInfo );
  991. }
  992. } else {
  993. BasicInfo->MachineRole = DsRole_RoleBackupDomainController;
  994. }
  995. LsaIFree_LSAPR_POLICY_INFORMATION( PolicyLsaServerRoleInformation,
  996. ( PLSAPR_POLICY_INFORMATION )ServerRole );
  997. }
  998. break;
  999. default:
  1000. Status = STATUS_INVALID_PARAMETER;
  1001. break;
  1002. }
  1003. }
  1004. //
  1005. // Now, build the rest of the information
  1006. //
  1007. if ( NT_SUCCESS( Status ) ) {
  1008. if ( LsapDsIsRunning ) {
  1009. BasicInfo->Flags = DSROLE_PRIMARY_DS_RUNNING;
  1010. Status = DsRolepGetMixedModeFlags( CurrentDnsInfo->Sid, &( BasicInfo->Flags ) );
  1011. } else {
  1012. BasicInfo->Flags = 0;
  1013. }
  1014. if ( NT_SUCCESS( Status ) ) {
  1015. //
  1016. // Flat name
  1017. //
  1018. GET_PDI_COPY_STRING_AND_INSERT( &CurrentDnsInfo->Name, BasicInfo->DomainNameFlat );
  1019. //
  1020. // Dns domain name
  1021. //
  1022. GET_PDI_COPY_STRING_AND_INSERT( &CurrentDnsInfo->DnsDomainName, BasicInfo->DomainNameDns );
  1023. //
  1024. // Dns tree name
  1025. //
  1026. GET_PDI_COPY_STRING_AND_INSERT( &CurrentDnsInfo->DnsForestName, BasicInfo->DomainForestName );
  1027. //
  1028. // Finally, the Guid.
  1029. //
  1030. if ( IS_GUID_PRESENT(CurrentDnsInfo->DomainGuid) ) {
  1031. RtlCopyMemory( &BasicInfo->DomainGuid,
  1032. &CurrentDnsInfo->DomainGuid,
  1033. sizeof( GUID ) );
  1034. BasicInfo->Flags |= DSROLE_PRIMARY_DOMAIN_GUID_PRESENT;
  1035. }
  1036. }
  1037. }
  1038. if ( NT_SUCCESS( Status ) ) {
  1039. *DomainInfo = ( PDSROLER_PRIMARY_DOMAIN_INFORMATION )BasicInfo;
  1040. BuffersCnt = 0;
  1041. } else {
  1042. Win32Err = RtlNtStatusToDosError( Status );
  1043. }
  1044. break;
  1045. case DsRoleUpgradeStatus:
  1046. Win32Err = DsRolepQueryUpgradeInfo( &IsUpgrade,
  1047. &PreviousServerRole );
  1048. if ( Win32Err == ERROR_SUCCESS ) {
  1049. Upgrade = MIDL_user_allocate( sizeof( DSROLE_UPGRADE_STATUS_INFO ) );
  1050. if ( Upgrade == NULL ) {
  1051. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  1052. goto GetInfoError;
  1053. } else {
  1054. BuffersToFree[ BuffersCnt++ ] = ( PBYTE )Upgrade;
  1055. //
  1056. // Now, build the information
  1057. //
  1058. if ( IsUpgrade ) {
  1059. Upgrade->OperationState = DSROLE_UPGRADE_IN_PROGRESS;
  1060. switch ( PreviousServerRole ) {
  1061. case PolicyServerRoleBackup:
  1062. Upgrade->PreviousServerState = DsRoleServerBackup;
  1063. break;
  1064. case PolicyServerRolePrimary:
  1065. Upgrade->PreviousServerState = DsRoleServerPrimary;
  1066. break;
  1067. default:
  1068. Win32Err = ERROR_INVALID_SERVER_STATE;
  1069. break;
  1070. }
  1071. } else {
  1072. RtlZeroMemory( Upgrade, sizeof( DSROLE_UPGRADE_STATUS_INFO ) );
  1073. }
  1074. //
  1075. // Make sure to return the values if we should
  1076. //
  1077. if ( Win32Err == ERROR_SUCCESS ) {
  1078. *DomainInfo = ( PDSROLER_PRIMARY_DOMAIN_INFORMATION )Upgrade;
  1079. BuffersCnt = 0;
  1080. }
  1081. }
  1082. }
  1083. break;
  1084. case DsRoleOperationState:
  1085. OperationStateInfo = MIDL_user_allocate( sizeof( DSROLE_OPERATION_STATE_INFO ) );
  1086. if ( OperationStateInfo == NULL ) {
  1087. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  1088. goto GetInfoError;
  1089. }
  1090. if ( RtlAcquireResourceExclusive( &DsRolepCurrentOperationHandle.CurrentOpLock, TRUE ) ) {
  1091. DsRoleDebugOut(( DEB_TRACE_LOCK,
  1092. "Lock grabbed in DsRolerGetPrimaryDomainInformation\n"));
  1093. if ( DSROLEP_OPERATION_ACTIVE( DsRolepCurrentOperationHandle.OperationState ) ) {
  1094. OperationStateInfo->OperationState = DsRoleOperationActive;
  1095. } else if ( DSROLEP_IDLE == DsRolepCurrentOperationHandle.OperationState ) {
  1096. OperationStateInfo->OperationState = DsRoleOperationIdle;
  1097. } else {
  1098. ASSERT( DSROLEP_NEED_REBOOT == DsRolepCurrentOperationHandle.OperationState );
  1099. //
  1100. // If the assert isn't true, then we are very confused and should probably
  1101. // indicate we need a reboot.
  1102. //
  1103. OperationStateInfo->OperationState = DsRoleOperationNeedReboot;
  1104. }
  1105. RtlReleaseResource( &DsRolepCurrentOperationHandle.CurrentOpLock );
  1106. DsRoleDebugOut(( DEB_TRACE_LOCK, "Lock released\n" ));
  1107. //
  1108. // Set the out param
  1109. //
  1110. *DomainInfo = ( PDSROLER_PRIMARY_DOMAIN_INFORMATION )OperationStateInfo;
  1111. } else {
  1112. Win32Err = ERROR_BUSY;
  1113. }
  1114. break;
  1115. default:
  1116. Win32Err = ERROR_INVALID_PARAMETER;
  1117. break;
  1118. }
  1119. GetInfoError:
  1120. if ( CurrentDnsInfo != NULL ) {
  1121. LsaIFree_LSAPR_POLICY_INFORMATION( PolicyDnsDomainInformation,
  1122. ( PLSAPR_POLICY_INFORMATION )CurrentDnsInfo );
  1123. }
  1124. //
  1125. // Free any buffers that we may have allocated
  1126. //
  1127. for ( i = 0; i < BuffersCnt; i++ ) {
  1128. MIDL_user_free( BuffersToFree[ i ] );
  1129. }
  1130. if ( PolicyHandle != NULL ) {
  1131. LsarClose( &PolicyHandle );
  1132. }
  1133. return( Win32Err );
  1134. }
  1135. DWORD
  1136. DsRolerCancel(
  1137. IN PDSROLE_SERVER_NAME Server,
  1138. IN PDSROLER_HANDLE DsOperationHandle
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. Cancels a currently running operation
  1143. Arguments:
  1144. Server - Server to remote the call to
  1145. DsOperationHandle - Handle of currently running operation. Returned by one of the DsRoleDcAs
  1146. apis
  1147. Return Values:
  1148. ERROR_SUCCESS - Success
  1149. --*/
  1150. {
  1151. DWORD Win32Err = ERROR_SUCCESS;
  1152. __try {
  1153. if ( DsOperationHandle == NULL ||
  1154. *DsOperationHandle != ( DSROLER_HANDLE )&DsRolepCurrentOperationHandle) {
  1155. Win32Err = ERROR_INVALID_HANDLE;
  1156. }
  1157. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  1158. Win32Err = GetExceptionCode();
  1159. }
  1160. if ( Win32Err == ERROR_SUCCESS ) {
  1161. Win32Err = DsRolepCancel( TRUE ); // Block until done
  1162. }
  1163. return( Win32Err );
  1164. }
  1165. DWORD
  1166. DsRolerServerSaveStateForUpgrade(
  1167. IN PDSROLE_SERVER_NAME Server,
  1168. IN LPWSTR AnswerFile OPTIONAL
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. This function is to be invoked during setup and saves the required server state to
  1173. complete the promotion following the reboot. Following the successful completion
  1174. of this API call, the server will be demoted to a member server in the same domain.
  1175. Arguments:
  1176. AnswerFile -- Optional path to an answer file to be used by DCPROMO during the subsequent
  1177. invocation
  1178. Return Values:
  1179. ERROR_SUCCESS - Success
  1180. --*/
  1181. {
  1182. DWORD Win32Err = ERROR_SUCCESS;
  1183. //
  1184. // Check the access of the caller
  1185. //
  1186. // N.B another access check would be to check that this is GUI mode
  1187. // setup, but checking for admin is safer. It works because setup.exe
  1188. // runs under local system which has builtin\administrators in its
  1189. // token.
  1190. //
  1191. Win32Err = DsRolepCheckPromoteAccess();
  1192. if ( ERROR_SUCCESS != Win32Err ) {
  1193. return Win32Err;
  1194. }
  1195. (VOID) DsRolepInitializeLog();
  1196. Win32Err = DsRolepSaveUpgradeState( AnswerFile );
  1197. return( Win32Err );
  1198. }
  1199. DWORD
  1200. DsRolerUpgradeDownlevelServer(
  1201. IN handle_t RpcBindingHandle,
  1202. IN LPWSTR DnsDomainName,
  1203. IN LPWSTR SiteName,
  1204. IN LPWSTR DsDatabasePath,
  1205. IN LPWSTR DsLogPath,
  1206. IN LPWSTR SystemVolumeRootPath,
  1207. IN LPWSTR ParentDnsDomainName OPTIONAL,
  1208. IN LPWSTR ParentServer OPTIONAL,
  1209. IN LPWSTR Account OPTIONAL,
  1210. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EPassword,
  1211. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EDsRepairPassword,
  1212. IN ULONG Options,
  1213. OUT PDSROLER_HANDLE *DsOperationHandle
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. This routine process the information saved from a DsRoleServerSaveStateForUpgrade to
  1218. promote a downlevel (NT4 or previous) server to an NT5 DC
  1219. Arguments:
  1220. RpcBindingHandle - the RPC context, used to decrypt the passwords
  1221. DnsDomainName - Dns domain name of the domain to install
  1222. SiteName - Name of the site this DC should belong to
  1223. DsDatabasePath - Absolute path on the local machine where the Ds DIT should go
  1224. DsLogPath - Absolute path on the local machine where the Ds log files should go
  1225. SystemVolumeRootPath - Absolute path on the local machine which will be the root of
  1226. the system volume.
  1227. ParentDnsDomainName - Optional. If present, set this domain up as a child of the
  1228. specified domain
  1229. ParentServer - Optional. If present, use this server in the parent domain to replicate
  1230. the required information from
  1231. Account - User account to use when contacting other servers
  1232. EPassword - Encrypted password to use with the above account
  1233. EDsRepairPassword - Encrypted password to use for the admin account of the repair mode
  1234. Options - Options to control the creation of the domain
  1235. DsOperationHandle - Handle to the operation is returned here.
  1236. Return Values:
  1237. ERROR_SUCCESS - Success
  1238. ERROR_INVALID_SERVER_STATE - Not in upgrade mode
  1239. --*/
  1240. {
  1241. DWORD Win32Err = ERROR_SUCCESS;
  1242. BOOLEAN IsUpgrade;
  1243. ULONG PreviousServerState, VerifyOptions, VerifyResults;
  1244. PDSROLEP_OPERATION_PROMOTE_ARGS PromoteArgs;
  1245. NTSTATUS Status;
  1246. HANDLE LocalPolicy = NULL;
  1247. OBJECT_ATTRIBUTES ObjectAttributes;
  1248. PPOLICY_DNS_DOMAIN_INFO PrimaryDomainInfo = NULL;
  1249. UCHAR Seed = 0;
  1250. #define DSROLEP_UPGRADE_PWD_INDEX 0
  1251. #define DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX 1
  1252. #define DSROLEP_UPGRADE_MAX_PWD_COUNT 2
  1253. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_UPGRADE_MAX_PWD_COUNT];
  1254. UNICODE_STRING Passwords[DSROLEP_UPGRADE_MAX_PWD_COUNT];
  1255. EncryptedPasswords[DSROLEP_UPGRADE_PWD_INDEX] = EPassword;
  1256. EncryptedPasswords[DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX] = EDsRepairPassword;
  1257. RtlZeroMemory( Passwords, sizeof(Passwords) );
  1258. *DsOperationHandle = NULL;
  1259. //
  1260. // Do some parameter checking
  1261. //
  1262. if ( !DnsDomainName || !DsDatabasePath || !DsLogPath || !SystemVolumeRootPath ) {
  1263. Win32Err = ERROR_INVALID_PARAMETER;
  1264. goto DsRolepUpgradeError;
  1265. }
  1266. DsRolepInitializeLog();
  1267. DsRolepLogPrint(( DEB_TRACE,
  1268. "DsRolerDcAsDc: DnsDomainName %ws\n",
  1269. DnsDomainName ));
  1270. DsRolepLogPrint(( DEB_TRACE,
  1271. "\tSiteName %ws\n",
  1272. DsRolepDisplayOptional( SiteName ) ));
  1273. DsRolepLogPrint(( DEB_TRACE,
  1274. "\tSystemVolumeRootPath %ws\n",
  1275. SystemVolumeRootPath ));
  1276. DsRolepLogPrint(( DEB_TRACE,
  1277. "\tDsDatabasePath %ws, DsLogPath %ws\n",
  1278. DsDatabasePath, DsLogPath ));
  1279. if ( ParentDnsDomainName ) {
  1280. DsRolepLogPrint(( DEB_TRACE,
  1281. "\tParentDnsDomainName %ws\n",
  1282. ParentDnsDomainName ));
  1283. }
  1284. if ( ParentServer ) {
  1285. DsRolepLogPrint(( DEB_TRACE,
  1286. "\tParentServer %ws\n",
  1287. ParentServer ));
  1288. }
  1289. if ( Account ) {
  1290. DsRolepLogPrint(( DEB_TRACE,
  1291. "\tAccount %ws\n",
  1292. Account ));
  1293. }
  1294. DsRolepLogPrint(( DEB_TRACE,
  1295. "\tOptions %lu\n",
  1296. Options ));
  1297. Win32Err = DsRolepQueryUpgradeInfo( &IsUpgrade, &PreviousServerState );
  1298. if ( Win32Err != ERROR_SUCCESS ) {
  1299. goto DsRolepUpgradeError;
  1300. }
  1301. if ( !IsUpgrade || PreviousServerState == PolicyServerRoleBackup ) {
  1302. Win32Err = ERROR_INVALID_SERVER_STATE;
  1303. goto DsRolepUpgradeError;
  1304. }
  1305. //
  1306. // Verify the path names we are given
  1307. //
  1308. DsRolepLogPrint(( DEB_TRACE,"Validate supplied paths\n" ));
  1309. Win32Err = DsRolepCheckFilePaths( DsDatabasePath,
  1310. DsLogPath,
  1311. SystemVolumeRootPath );
  1312. if ( ERROR_SUCCESS != Win32Err ) {
  1313. goto DsRolepUpgradeError;
  1314. }
  1315. //
  1316. // If we are doing a parent/child setup, verify our name
  1317. //
  1318. if ( Win32Err == ERROR_SUCCESS && ParentDnsDomainName &&
  1319. !FLAG_ON( Options, DSROLE_DC_TRUST_AS_ROOT ) ) {
  1320. Win32Err = DsRolepIsDnsNameChild( ParentDnsDomainName, DnsDomainName );
  1321. }
  1322. //
  1323. // Get the current domain name
  1324. //
  1325. if ( Win32Err == ERROR_SUCCESS ) {
  1326. RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  1327. Status = LsaOpenPolicy( NULL,
  1328. &ObjectAttributes,
  1329. MAXIMUM_ALLOWED,
  1330. &LocalPolicy );
  1331. if ( NT_SUCCESS( Status ) ) {
  1332. Status = LsaQueryInformationPolicy( LocalPolicy,
  1333. PolicyPrimaryDomainInformation,
  1334. &PrimaryDomainInfo );
  1335. LsaClose( LocalPolicy );
  1336. }
  1337. Win32Err = RtlNtStatusToDosError( Status );
  1338. }
  1339. Win32Err = DsRolepDecryptPasswordsWithKey ( RpcBindingHandle,
  1340. EncryptedPasswords,
  1341. NELEMENTS(EncryptedPasswords),
  1342. Passwords,
  1343. &Seed );
  1344. //
  1345. // Finally, we'll do the promotion
  1346. //
  1347. if ( Win32Err == ERROR_SUCCESS ) {
  1348. Win32Err = DsRolepInitializeOperationHandle( );
  1349. if ( Win32Err == ERROR_SUCCESS ) {
  1350. Win32Err = DsRolepBuildPromoteArgumentBlock( DnsDomainName,
  1351. PrimaryDomainInfo->Name.Buffer,
  1352. SiteName,
  1353. DsDatabasePath,
  1354. DsLogPath,
  1355. NULL,
  1356. SystemVolumeRootPath,
  1357. NULL,
  1358. ParentDnsDomainName,
  1359. ParentServer,
  1360. Account,
  1361. &Passwords[DSROLEP_UPGRADE_PWD_INDEX],
  1362. NULL,
  1363. &Passwords[DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX],
  1364. Options | DSROLE_DC_DOWNLEVEL_UPGRADE,
  1365. Seed,
  1366. &PromoteArgs );
  1367. }
  1368. DsRolepFreePasswords( Passwords,
  1369. NELEMENTS(Passwords) );
  1370. if ( Win32Err == ERROR_SUCCESS ) {
  1371. Win32Err = DsRolepSpinWorkerThread( DSROLEP_OPERATION_DC,
  1372. ( PVOID )PromoteArgs );
  1373. if ( Win32Err != ERROR_SUCCESS ) {
  1374. DsRolepFreeArgumentBlock( &PromoteArgs, TRUE );
  1375. }
  1376. }
  1377. if ( Win32Err != ERROR_SUCCESS ) {
  1378. DsRolepResetOperationHandle( DSROLEP_IDLE );
  1379. }
  1380. }
  1381. if ( Win32Err == ERROR_SUCCESS ) {
  1382. *DsOperationHandle = (DSROLER_HANDLE)&DsRolepCurrentOperationHandle;
  1383. }
  1384. LsaFreeMemory( PrimaryDomainInfo );
  1385. DsRolepUpgradeError:
  1386. return( Win32Err );
  1387. }
  1388. DWORD
  1389. DsRolerAbortDownlevelServerUpgrade(
  1390. IN handle_t RpcBindingHandle,
  1391. IN LPWSTR Account, OPTIONAL
  1392. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EAccountPassword,
  1393. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD EAdminPassword,
  1394. IN ULONG Options
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. This routine cleans up the information saved from a DsRoleSaveServerStateForUpgrade call,
  1399. leaving the machine as a member or standalone server
  1400. Arguments:
  1401. RpcBindingHandle - the RPC context, used to decrypt the passwords
  1402. Account - User account to use when contacting other servers
  1403. EPassword - Encrypted password to use with the above account
  1404. EAdminPassword - Encrypted new local administrator account password
  1405. Options - Options to control the behavior. Currently support flags are:
  1406. DSROLEP_ABORT_FOR_REPLICA_INSTALL - The upgrade is being aborted to do a replica install
  1407. Return Values:
  1408. ERROR_SUCCESS - Success
  1409. ERROR_INVALID_PARAMETER - An invalid machine role was specified
  1410. --*/
  1411. {
  1412. DWORD Win32Err = ERROR_SUCCESS, Win32Err2;
  1413. PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
  1414. BOOLEAN AccountInfoSet = FALSE, Impersonated = FALSE;
  1415. UCHAR Seed = 0;
  1416. UNICODE_STRING EPassword, EPassword2;
  1417. WCHAR *OldAccountDn = NULL;
  1418. WCHAR SecurityLogPath[MAX_PATH+1];
  1419. PUNICODE_STRING Password = NULL;
  1420. PUNICODE_STRING AdminPassword = NULL;
  1421. HANDLE ClientToken = NULL;
  1422. #define DSROLEP_ABORT_PWD_INDEX 0
  1423. #define DSROLEP_ABORT_ADMIN_PWD_INDEX 1
  1424. #define DSROLEP_ABORT_MAX_PWD_COUNT 2
  1425. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_ABORT_MAX_PWD_COUNT];
  1426. UNICODE_STRING Passwords[DSROLEP_ABORT_MAX_PWD_COUNT];
  1427. EncryptedPasswords[DSROLEP_ABORT_PWD_INDEX] = EAccountPassword;
  1428. EncryptedPasswords[DSROLEP_ABORT_ADMIN_PWD_INDEX] = EAdminPassword;
  1429. RtlZeroMemory( Passwords, sizeof(Passwords) );
  1430. EPassword.Buffer = NULL;
  1431. EPassword2.Buffer = NULL;
  1432. Win32Err = DsRolepCheckPromoteAccess();
  1433. if ( ERROR_SUCCESS != Win32Err ) {
  1434. return Win32Err;
  1435. }
  1436. Win32Err = DsRolepDecryptPasswordsWithKey ( RpcBindingHandle,
  1437. EncryptedPasswords,
  1438. NELEMENTS(EncryptedPasswords),
  1439. Passwords,
  1440. &Seed );
  1441. if ( Win32Err != ERROR_SUCCESS ) {
  1442. return( Win32Err );
  1443. }
  1444. RtlCopyMemory( &EPassword, &Passwords[DSROLEP_ABORT_ADMIN_PWD_INDEX], sizeof(UNICODE_STRING));
  1445. RtlCopyMemory( &EPassword2, &Passwords[DSROLEP_ABORT_PWD_INDEX], sizeof(UNICODE_STRING));
  1446. //
  1447. // Initialize the operation handle so we pull in the dynamically
  1448. // loaded libraries
  1449. //
  1450. Win32Err = DsRolepInitializeOperationHandle( );
  1451. if ( Win32Err != ERROR_SUCCESS ) {
  1452. return( Win32Err );
  1453. }
  1454. DsRolepInitializeLog();
  1455. if ( FLAG_ON( Options, DSROLEP_ABORT_FOR_REPLICA_INSTALL ) )
  1456. {
  1457. //
  1458. // This is the NT4 to NT5 BDC upgrade. Nothing to do
  1459. //
  1460. //
  1461. DsRolepLogPrint(( DEB_TRACE, "Performing NT4 to NT5 BDC upgrade.\n"));
  1462. Win32Err = ERROR_SUCCESS;
  1463. goto Exit;
  1464. }
  1465. Win32Err = DsRolepGetImpersonationToken( &ClientToken );
  1466. if (ERROR_SUCCESS != Win32Err) {
  1467. goto Exit;
  1468. }
  1469. //
  1470. // First, find the Dc that has this account
  1471. //
  1472. if ( Win32Err == ERROR_SUCCESS ) {
  1473. Win32Err = DsRolepDsGetDcForAccount( NULL,
  1474. NULL,
  1475. NULL,
  1476. DS_DIRECTORY_SERVICE_REQUIRED |
  1477. DS_WRITABLE_REQUIRED |
  1478. DS_FORCE_REDISCOVERY |
  1479. DS_AVOID_SELF,
  1480. UF_SERVER_TRUST_ACCOUNT,
  1481. &DomainControllerInfo );
  1482. if ( Win32Err == ERROR_SUCCESS ) {
  1483. //
  1484. // Set the machine account type
  1485. //
  1486. DsRolepLogPrint(( DEB_TRACE, "Searching for the machine account ...\n"));
  1487. RtlRunDecodeUnicodeString( Seed, &EPassword2 );
  1488. Win32Err = DsRolepSetMachineAccountType( DomainControllerInfo->DomainControllerName,
  1489. ClientToken,
  1490. Account,
  1491. EPassword2.Buffer,
  1492. NULL,
  1493. UF_WORKSTATION_TRUST_ACCOUNT,
  1494. &OldAccountDn );
  1495. RtlRunEncodeUnicodeString( &Seed, &EPassword2 );
  1496. if ( Win32Err == ERROR_SUCCESS ) {
  1497. AccountInfoSet = TRUE;
  1498. } else {
  1499. DsRolepLogPrint(( DEB_TRACE, "DsRolepSetMachineAccountType returned %d\n",
  1500. Win32Err ));
  1501. }
  1502. if ( OldAccountDn ) {
  1503. // the machine object was moved
  1504. DsRolepLogPrint(( DEB_TRACE, "Moved account %ws to %ws\n",
  1505. Account,
  1506. OldAccountDn ));
  1507. }
  1508. }
  1509. }
  1510. if ( ERROR_SUCCESS != Win32Err ) {
  1511. goto Exit;
  1512. }
  1513. //
  1514. // Set the security for a freshly installed NT5 server. See bug 391574
  1515. //
  1516. DsRolepLogPrint(( DEB_TRACE, "Setting security for server ...\n"));
  1517. #define SECURITY_SRV_INF_FILE L"defltsv.inf"
  1518. ZeroMemory( SecurityLogPath, MAX_PATH+1 );
  1519. if ( GetWindowsDirectory( SecurityLogPath, MAX_PATH ) )
  1520. {
  1521. wcsncat( SecurityLogPath, L"\\security\\logs\\scesetup.log", ((sizeof(SecurityLogPath)/sizeof(WCHAR))-wcslen(SecurityLogPath)) );
  1522. Win32Err = DsrSceSetupSystemByInfName(SECURITY_SRV_INF_FILE,
  1523. SecurityLogPath,
  1524. AREA_FILE_SECURITY | AREA_REGISTRY_SECURITY,
  1525. SCESETUP_CONFIGURE_SECURITY,
  1526. NULL, // used only for GUI mode
  1527. NULL ); // used only for GUI mode
  1528. } else {
  1529. Win32Err = GetLastError();
  1530. }
  1531. if ( ERROR_SUCCESS != Win32Err ) {
  1532. DsRolepLogOnFailure( Win32Err,
  1533. DsRolepLogPrint(( DEB_ERROR,
  1534. "Setting security on server files failed with %lu\n",
  1535. Win32Err )) );
  1536. // This error has been handled
  1537. Win32Err = ERROR_SUCCESS;
  1538. }
  1539. DsRolepLogPrint(( DEB_TRACE, "Setting security for server finished\n"));
  1540. //
  1541. // Change the user password
  1542. //
  1543. if ( Win32Err == ERROR_SUCCESS ) {
  1544. RtlRunDecodeUnicodeString( Seed, &EPassword );
  1545. Win32Err = DsRolepSetBuiltinAdminAccountPassword( EPassword.Buffer );
  1546. RtlRunEncodeUnicodeString( &Seed, &EPassword );
  1547. //
  1548. // Delete the upgrade information
  1549. //
  1550. if ( Win32Err == ERROR_SUCCESS ) {
  1551. Win32Err = DsRolepDeleteUpgradeInfo();
  1552. }
  1553. }
  1554. //
  1555. // If that failed, try and restore the machine account info
  1556. //
  1557. if ( Win32Err != ERROR_SUCCESS && AccountInfoSet ) {
  1558. RtlRunDecodeUnicodeString( Seed, &EPassword2 );
  1559. Win32Err2 = DsRolepSetMachineAccountType( DomainControllerInfo->DomainControllerName,
  1560. ClientToken,
  1561. Account,
  1562. EPassword2.Buffer,
  1563. NULL,
  1564. UF_SERVER_TRUST_ACCOUNT,
  1565. &OldAccountDn ); //don't care about dn
  1566. RtlRunEncodeUnicodeString( &Seed, &EPassword2 );
  1567. if ( Win32Err2 != ERROR_SUCCESS ) {
  1568. DsRolepLogPrint(( DEB_TRACE, "DsRolepSetMachineAccountType returned %d\n", Win32Err2 ));
  1569. } else {
  1570. if ( OldAccountDn ) {
  1571. //
  1572. // the machine object was moved back
  1573. //
  1574. DsRolepLogPrint(( DEB_TRACE, "Attempted to move account %ws to %ws\n",
  1575. Account,
  1576. OldAccountDn ));
  1577. }
  1578. }
  1579. }
  1580. Exit:
  1581. DsRolepFreePasswords( Passwords,
  1582. NELEMENTS(Passwords) );
  1583. NetApiBufferFree( DomainControllerInfo );
  1584. if ( OldAccountDn ) {
  1585. RtlFreeHeap( RtlProcessHeap(), 0, OldAccountDn );
  1586. }
  1587. if (ClientToken) {
  1588. CloseHandle(ClientToken);
  1589. }
  1590. (VOID) DsRolepResetOperationHandle( DSROLEP_IDLE );
  1591. return( Win32Err );
  1592. }
  1593. //
  1594. // Local function definitions
  1595. //
  1596. DWORD
  1597. DsRolepWaitForSam(
  1598. VOID
  1599. )
  1600. /*++
  1601. Routine Description:
  1602. This routine waits for the SAM_SERVICE_STARTED event
  1603. Arguments:
  1604. VOID
  1605. Return Values:
  1606. ERROR_SUCCESS - Success
  1607. --*/
  1608. {
  1609. NTSTATUS Status = STATUS_SUCCESS;
  1610. ULONG Response;
  1611. UNICODE_STRING EventName;
  1612. OBJECT_ATTRIBUTES EventAttributes;
  1613. HANDLE EventHandle = NULL;
  1614. //
  1615. // Open the event
  1616. //
  1617. RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED" );
  1618. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  1619. Status = NtCreateEvent( &EventHandle,
  1620. SYNCHRONIZE,
  1621. &EventAttributes,
  1622. NotificationEvent,
  1623. FALSE );
  1624. //
  1625. // If the event already exists, just open it.
  1626. //
  1627. if( Status == STATUS_OBJECT_NAME_EXISTS || Status == STATUS_OBJECT_NAME_COLLISION ) {
  1628. Status = NtOpenEvent( &EventHandle,
  1629. SYNCHRONIZE,
  1630. &EventAttributes );
  1631. }
  1632. if ( NT_SUCCESS( Status ) ) {
  1633. Status = NtWaitForSingleObject( EventHandle, TRUE, NULL );
  1634. NtClose( EventHandle );
  1635. }
  1636. return( RtlNtStatusToDosError( Status ) );
  1637. }
  1638. DWORD
  1639. DsRolepCheckFilePaths(
  1640. IN LPWSTR DsDatabasePath,
  1641. IN LPWSTR DsLogPath,
  1642. IN LPWSTR SystemVolumeRootPath
  1643. )
  1644. /*++
  1645. Routine Description:
  1646. Arguments:
  1647. Returns:
  1648. ERROR_SUCCESS - Success
  1649. --*/
  1650. {
  1651. DWORD WinError = ERROR_SUCCESS;
  1652. ULONG VerifyOptions, VerifyResults;
  1653. ULONG Length;
  1654. //
  1655. // Make sure that niether the log path nor the datapath path
  1656. // is a subset of the SystemVolumeRootPath
  1657. //
  1658. Length = wcslen( SystemVolumeRootPath );
  1659. if ( !_wcsnicmp( SystemVolumeRootPath, DsDatabasePath, Length )
  1660. || !_wcsnicmp( SystemVolumeRootPath, DsLogPath, Length ) ) {
  1661. DsRolepLogPrint(( DEB_TRACE, "Database paths subset of sysvol\n" ));
  1662. WinError = ERROR_BAD_PATHNAME;
  1663. }
  1664. if ( WinError == ERROR_SUCCESS ) {
  1665. VerifyOptions = DSROLEP_PATH_VALIDATE_LOCAL | DSROLEP_PATH_VALIDATE_EXISTENCE;
  1666. WinError = DsRolepValidatePath( DsDatabasePath, VerifyOptions, &VerifyResults );
  1667. if ( WinError == ERROR_SUCCESS ) {
  1668. if ( VerifyResults != VerifyOptions ) {
  1669. WinError = ERROR_BAD_PATHNAME;
  1670. }
  1671. }
  1672. }
  1673. if ( WinError == ERROR_SUCCESS ) {
  1674. WinError = DsRolepValidatePath( DsLogPath, VerifyOptions, &VerifyResults );
  1675. if ( WinError == ERROR_SUCCESS ) {
  1676. if ( VerifyResults != VerifyOptions ) {
  1677. WinError = ERROR_BAD_PATHNAME;
  1678. }
  1679. }
  1680. }
  1681. if ( WinError == ERROR_SUCCESS ) {
  1682. VerifyOptions = DSROLEP_PATH_VALIDATE_LOCAL | DSROLEP_PATH_VALIDATE_NTFS;
  1683. WinError = DsRolepValidatePath( SystemVolumeRootPath, VerifyOptions, &VerifyResults );
  1684. if ( WinError == ERROR_SUCCESS ) {
  1685. if ( VerifyResults != VerifyOptions ) {
  1686. WinError = ERROR_BAD_PATHNAME;
  1687. }
  1688. }
  1689. }
  1690. return WinError;
  1691. }
  1692. BOOL
  1693. IsProductSuiteConfigured(
  1694. WORD Suite
  1695. )
  1696. {
  1697. OSVERSIONINFOEXA osvi;
  1698. DWORDLONG dwlConditionMask = 0;
  1699. //
  1700. // Setup the request for the desired suite
  1701. //
  1702. ZeroMemory(&osvi, sizeof(osvi));
  1703. osvi.dwOSVersionInfoSize = sizeof(osvi);
  1704. osvi.wSuiteMask = Suite;
  1705. //
  1706. // Setup the condition
  1707. //
  1708. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_AND);
  1709. return VerifyVersionInfoA(&osvi,
  1710. VER_SUITENAME,
  1711. dwlConditionMask);
  1712. }
  1713. BOOL
  1714. IsWebBlade(
  1715. VOID
  1716. )
  1717. {
  1718. return IsProductSuiteConfigured(VER_SUITE_BLADE);
  1719. }
  1720. BOOL
  1721. IsSBS(
  1722. VOID
  1723. )
  1724. {
  1725. return IsProductSuiteConfigured(VER_SUITE_SMALLBUSINESS_RESTRICTED);
  1726. }
  1727. DWORD
  1728. DsRolepIsValidProductSuite(
  1729. IN BOOL fNewForest,
  1730. IN BOOL fReplica,
  1731. IN LPWSTR DomainName
  1732. )
  1733. /*++
  1734. Routine Description:
  1735. This routine determines if the promotion request is valid for the
  1736. current configuration of the OS.
  1737. Arguments:
  1738. fNewForest -- a new forest is requested.
  1739. fReplica -- a replica is requested
  1740. DomainName -- the name of the domain to create or join
  1741. Return Values:
  1742. ERROR_SUCCESS, ERROR_NOT_SUPPORTED, resource errors otherwise
  1743. --*/
  1744. {
  1745. DWORD err = ERROR_SUCCESS;
  1746. PDOMAIN_CONTROLLER_INFOW DCInfo = NULL;
  1747. if (IsWebBlade()) {
  1748. // See Windows RAID issue 195265
  1749. err = ERROR_NOT_SUPPORTED;
  1750. goto Exit;
  1751. }
  1752. if (IsSBS()) {
  1753. if (fReplica) {
  1754. err = DsGetDcNameW(NULL,
  1755. DomainName,
  1756. NULL,
  1757. NULL,
  1758. 0,
  1759. &DCInfo);
  1760. if (ERROR_SUCCESS != err) {
  1761. // Return the resource or configuration error
  1762. DsRolepLogPrint((DEB_ERROR,
  1763. "Request to find a DC for %ws failed (%d)\n",
  1764. DomainName,
  1765. err));
  1766. goto Exit;
  1767. }
  1768. if ( !(DnsNameCompareEqual == DnsNameCompareEx_W(DomainName,
  1769. DCInfo->DnsForestName,
  1770. 0 ))) {
  1771. // See Windows issue 373388
  1772. // Must be the root of the forest
  1773. err = ERROR_NOT_SUPPORTED;
  1774. goto Exit;
  1775. }
  1776. } else if (!fNewForest) {
  1777. // See Windows NT issue 353854
  1778. err = ERROR_NOT_SUPPORTED;
  1779. goto Exit;
  1780. }
  1781. }
  1782. Exit:
  1783. if (DCInfo) {
  1784. NetApiBufferFree(DCInfo);
  1785. }
  1786. return err;
  1787. }
  1788. DWORD
  1789. DsRolepDecryptPasswordsWithKey(
  1790. IN handle_t RpcBindingHandle,
  1791. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD * EncryptedPasswords,
  1792. IN ULONG Count,
  1793. IN OUT UNICODE_STRING *EncodedPasswords,
  1794. OUT PUCHAR Seed
  1795. )
  1796. /*++
  1797. Routine Description:
  1798. Decrypts a set of passwords encrypted with the user session key.
  1799. Arguments:
  1800. RpcBindingHandle - Rpc Binding handle describing the session key to use.
  1801. EncryptedPasswords - Encrypted passwords to decrypt.
  1802. Count - the number of passwords
  1803. EncodedPassword - Returns the Encoded password.
  1804. The password has been encoded
  1805. Buffer should be freed using LocalFree.
  1806. Seed - the seed that was used to encode the password
  1807. Return Value:
  1808. ERROR_SUCCESS; a resource or parameter error otherwise
  1809. --*/
  1810. {
  1811. DWORD WinError = ERROR_SUCCESS;
  1812. NTSTATUS Status;
  1813. USER_SESSION_KEY UserSessionKey;
  1814. RC4_KEYSTRUCT Rc4Key;
  1815. MD5_CTX Md5Context;
  1816. LPWSTR PasswordPart;
  1817. ULONG i;
  1818. //
  1819. // Get the session key
  1820. //
  1821. Status = RtlGetUserSessionKeyServer(
  1822. (RPC_BINDING_HANDLE)RpcBindingHandle,
  1823. &UserSessionKey );
  1824. if (!NT_SUCCESS(Status)) {
  1825. return RtlNtStatusToDosError( Status );
  1826. }
  1827. for ( i = 0; i < Count; i++ ) {
  1828. PDSROLEPR_USER_PASSWORD Password = (PDSROLEPR_USER_PASSWORD) EncryptedPasswords[i];
  1829. LPWSTR ClearPassword;
  1830. //
  1831. // Handle the trivial case
  1832. //
  1833. RtlInitUnicodeString( &EncodedPasswords[i], NULL );
  1834. if ( Password == NULL ) {
  1835. continue;
  1836. }
  1837. //
  1838. // The UserSessionKey is the same for the life of the session. RC4'ing multiple
  1839. // strings with a single key is weak (if you crack one you've cracked them all).
  1840. // So compute a key that's unique for this particular encryption.
  1841. //
  1842. //
  1843. MD5Init(&Md5Context);
  1844. MD5Update( &Md5Context, (LPBYTE)&UserSessionKey, sizeof(UserSessionKey) );
  1845. MD5Update( &Md5Context, Password->Obfuscator, sizeof(Password->Obfuscator) );
  1846. MD5Final( &Md5Context );
  1847. rc4_key( &Rc4Key, MD5DIGESTLEN, Md5Context.digest );
  1848. //
  1849. // Decrypt the Buffer
  1850. //
  1851. rc4( &Rc4Key, sizeof(Password->Buffer)+sizeof(Password->Length), (LPBYTE) Password->Buffer );
  1852. //
  1853. // Check that the length is valid. If it isn't bail here.
  1854. //
  1855. if (Password->Length > DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) {
  1856. WinError = ERROR_INVALID_PASSWORD;
  1857. goto Cleanup;
  1858. }
  1859. //
  1860. // Return the password to the caller.
  1861. //
  1862. ClearPassword = LocalAlloc( 0, Password->Length + sizeof(WCHAR) );
  1863. if ( ClearPassword == NULL ) {
  1864. WinError = ERROR_NOT_ENOUGH_MEMORY;
  1865. goto Cleanup;
  1866. }
  1867. //
  1868. // Copy the password into the buffer
  1869. //
  1870. RtlCopyMemory( ClearPassword,
  1871. ((PCHAR) Password->Buffer) +
  1872. (DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
  1873. Password->Length,
  1874. Password->Length );
  1875. ClearPassword[Password->Length/sizeof(WCHAR)] = L'\0';
  1876. RtlInitUnicodeString( &EncodedPasswords[i], ClearPassword );
  1877. //
  1878. // Now encode it
  1879. //
  1880. RtlRunEncodeUnicodeString( Seed, &EncodedPasswords[i] );
  1881. }
  1882. Cleanup:
  1883. if ( WinError != ERROR_SUCCESS ) {
  1884. for ( i = 0; i < Count; i++ ) {
  1885. if ( EncodedPasswords[i].Buffer ) {
  1886. LocalFree( EncodedPasswords[i].Buffer );
  1887. RtlInitUnicodeString( &EncodedPasswords[i], NULL );
  1888. }
  1889. }
  1890. }
  1891. return WinError;
  1892. }
  1893. VOID
  1894. DsRolepFreePasswords(
  1895. IN OUT UNICODE_STRING *Passwords,
  1896. IN ULONG Count
  1897. )
  1898. /*++
  1899. Routine Description:
  1900. Frees the variables returned from DsRolepDecryptPasswordsWithKey
  1901. Arguments:
  1902. Passwords - the encoded passwords to free
  1903. Count - the number of passwords
  1904. Return Value:
  1905. ERROR_SUCCESS; a resource or parameter error otherwise
  1906. --*/
  1907. {
  1908. ULONG i;
  1909. for ( i = 0; i < Count; i++ ) {
  1910. if ( Passwords[i].Buffer ) {
  1911. RtlZeroMemory( Passwords[i].Buffer, Passwords[i].Length );
  1912. LocalFree( Passwords[i].Buffer );
  1913. RtlInitUnicodeString( &Passwords[i], NULL );
  1914. }
  1915. }
  1916. }
  1917. DWORD
  1918. DsRolepDecryptHash(
  1919. IN PUNICODE_STRING BootKey
  1920. )
  1921. /*++
  1922. Routine Description:
  1923. Frees the variables returned from DsRolepDecryptPasswordsWithKey
  1924. Arguments:
  1925. Passwords - the encoded passwords to free
  1926. Count - the number of passwords
  1927. Return Value:
  1928. ERROR_SUCCESS; a resource or parameter error otherwise
  1929. --*/
  1930. {
  1931. return ERROR_SUCCESS;
  1932. }