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

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