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.

2062 lines
52 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. rpcapi.c
  5. Abstract:
  6. This module contains the routines for the dssetup APIs that use RPC. The
  7. routines in this module are merely wrappers that work as follows:
  8. Fuke copied lsa\uclient and hacked on to make it work for DsRole apis
  9. Author:
  10. Mac McLain (MacM) April 14, 1997
  11. Revision History:
  12. --*/
  13. #include <lsacomp.h>
  14. #include "dssetup_c.h"
  15. #include <rpcndr.h>
  16. #include <dssetp.h>
  17. #include <winreg.h>
  18. #include <wxlpc.h>
  19. #include <crypt.h>
  20. #include <rc4.h>
  21. #include <md5.h>
  22. //
  23. // Local prototypes
  24. //
  25. DWORD
  26. DsRolepGetPrimaryDomainInformationDownlevel(
  27. IN LPWSTR Server,
  28. OUT PBYTE *Buffer
  29. );
  30. DWORD
  31. DsRolepGetProductTypeForServer(
  32. IN LPWSTR Server,
  33. IN OUT PNT_PRODUCT_TYPE ProductType
  34. );
  35. DWORD
  36. DsRolepEncryptPasswordStart(
  37. IN LPCWSTR ServerName OPTIONAL,
  38. IN LPCWSTR *Passwords,
  39. IN ULONG Count,
  40. OUT RPC_BINDING_HANDLE *RpcBindingHandle,
  41. OUT HANDLE *RedirHandle,
  42. IN OUT PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPassword
  43. );
  44. VOID
  45. DsRolepEncryptPasswordEnd(
  46. IN RPC_BINDING_HANDLE RpcBindingHandle,
  47. IN HANDLE RedirHandle OPTIONAL,
  48. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPassword OPTIONAL,
  49. IN ULONG Count
  50. );
  51. DWORD
  52. DsRolepHashkey(
  53. IN OUT LPWSTR Key,
  54. OUT PVOID Syskey,
  55. IN OUT ULONG cbSyskey
  56. );
  57. DWORD
  58. DsRolepEncryptHash(
  59. OUT PUNICODE_STRING EncryptedSyskey
  60. );
  61. ////////////////////////////////////////////////////////////////////////////
  62. // //
  63. // DS Setup and initialization routines //
  64. // //
  65. ////////////////////////////////////////////////////////////////////////////
  66. BOOLEAN
  67. DsRolepIsSetupRunning(
  68. VOID
  69. )
  70. /*++
  71. Routine Description:
  72. This routine determines if this call is being made during setup or not
  73. Arguments:
  74. VOID
  75. Return Value:
  76. TRUE -- The call is being made during setup
  77. FALSE -- The call is not being made during setup
  78. --*/
  79. {
  80. NTSTATUS Status;
  81. HANDLE InstallationEvent;
  82. OBJECT_ATTRIBUTES EventAttributes;
  83. UNICODE_STRING EventName;
  84. BOOLEAN Setup = FALSE;
  85. //
  86. // If the following event exists, then we are in setup mode
  87. //
  88. RtlInitUnicodeString( &EventName,
  89. L"\\INSTALLATION_SECURITY_HOLD" );
  90. InitializeObjectAttributes( &EventAttributes,
  91. &EventName, 0, 0, NULL );
  92. Status = NtOpenEvent( &InstallationEvent,
  93. SYNCHRONIZE,
  94. &EventAttributes );
  95. if ( NT_SUCCESS( Status) ) {
  96. NtClose( InstallationEvent );
  97. Setup = TRUE;
  98. }
  99. return( Setup );
  100. }
  101. DWORD
  102. DsRolepServerBind(
  103. IN OPTIONAL PDSROLE_SERVER_NAME ServerName,
  104. OUT handle_t *BindHandle
  105. )
  106. /*++
  107. Routine Description:
  108. This routine is called from the LSA client stubs when
  109. it is necessary to bind to the LSA on some server.
  110. Arguments:
  111. ServerName - A pointer to a string containing the name of the server
  112. to bind with.
  113. Return Value:
  114. The binding handle is returned to the stub routine. If the
  115. binding is unsuccessful, a NULL will be returned.
  116. --*/
  117. {
  118. handle_t BindingHandle = NULL;
  119. NTSTATUS Status;
  120. //
  121. // Can't go remote when running in setup mode
  122. //
  123. if ( DsRolepIsSetupRunning() && ServerName != NULL ) {
  124. return( STATUS_INVALID_SERVER_STATE );
  125. }
  126. Status = RpcpBindRpc ( ServerName,
  127. L"lsarpc",
  128. 0,
  129. &BindingHandle );
  130. if (!NT_SUCCESS(Status)) {
  131. DbgPrint("DsRolepServerBind: RpcpBindRpc failed 0x%lx\n", Status);
  132. } else {
  133. *BindHandle = BindingHandle;
  134. }
  135. return( RtlNtStatusToDosError( Status ) );
  136. }
  137. VOID
  138. DsRolepServerUnbind (
  139. IN OPTIONAL PDSROLE_SERVER_NAME ServerName,
  140. IN handle_t BindingHandle
  141. )
  142. /*++
  143. Routine Description:
  144. This routine is called from the LSA client stubs when
  145. it is necessary to unbind from the LSA server.
  146. Arguments:
  147. ServerName - This is the name of the server from which to unbind.
  148. BindingHandle - This is the binding handle that is to be closed.
  149. Return Value:
  150. none.
  151. --*/
  152. {
  153. UNREFERENCED_PARAMETER( ServerName ); // This parameter is not used
  154. RpcpUnbindRpc ( BindingHandle );
  155. return;
  156. }
  157. DWORD
  158. DsRolepApiReturnResult(
  159. ULONG ExceptionCode
  160. )
  161. /*++
  162. Routine Description:
  163. This function converts an exception code or status value returned
  164. from the client stub to a value suitable for return by the API to
  165. the client.
  166. Arguments:
  167. ExceptionCode - The exception code to be converted.
  168. Return Value:
  169. DWORD - The converted Nt Status code.
  170. --*/
  171. {
  172. //
  173. // Return the actual value if compatible with Nt status codes,
  174. // otherwise, return STATUS_UNSUCCESSFUL.
  175. //
  176. NTSTATUS Status;
  177. DWORD Results;
  178. if ( !NT_SUCCESS( ( NTSTATUS )ExceptionCode ) ) {
  179. Results = RtlNtStatusToDosError( ( NTSTATUS )ExceptionCode );
  180. } else {
  181. Results = ExceptionCode;
  182. }
  183. return( Results );
  184. }
  185. VOID
  186. WINAPI
  187. DsRoleFreeMemory(
  188. IN PVOID Buffer
  189. )
  190. /*++
  191. Routine Description:
  192. Some setup services that return a potentially large amount of memory,
  193. such as an enumeration might, allocate the buffer in which the data
  194. is returned. This function is used to free those buffers when they
  195. are no longer needed.
  196. Parameters:
  197. Buffer - Pointer to the buffer to be freed. This buffer must
  198. have been allocated by a previous dssetup service call.
  199. Return Values:
  200. STATUS_SUCCESS - normal, successful completion.
  201. --*/
  202. {
  203. MIDL_user_free( Buffer );
  204. }
  205. DWORD
  206. WINAPI
  207. DsRoleDnsNameToFlatName(
  208. IN LPCWSTR lpServer OPTIONAL,
  209. IN LPCWSTR lpDnsName,
  210. OUT LPWSTR *lpFlatName,
  211. OUT PULONG lpStatusFlag
  212. )
  213. /*++
  214. Routine Description:
  215. This routine will get the default NetBIOS (or flat) domain name for the given Dns domain name
  216. Arguments:
  217. lpServer - Server on which to remote the call (NULL is local)
  218. lpDnsName - Dns domain name to generate the flat name for
  219. lpFlatName - Where the flat name is returned. Must be freed via MIDL_user_free
  220. (or DsRoleFreeMemory)
  221. lpStatusFlag - Flags that indicate information about the returned name. Valid flags are:
  222. DSROLE_FLATNAME_DEFAULT -- This is the default NetBIOS name for this dns domain name
  223. DSROLE_FLATNAME_UPGRADE -- This is the name that is current in use by this machine as
  224. a flat name and cannot be changed.
  225. Return Values:
  226. ERROR_SUCCESS - Success
  227. --*/
  228. {
  229. DWORD Win32Err = ERROR_SUCCESS;
  230. handle_t Handle = NULL;
  231. Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
  232. &Handle );
  233. if ( Win32Err != ERROR_SUCCESS ) {
  234. return( Win32Err );
  235. }
  236. RpcTryExcept {
  237. *lpFlatName = NULL;
  238. *lpStatusFlag = 0;
  239. Win32Err = DsRolerDnsNameToFlatName(
  240. Handle,
  241. ( LPWSTR )lpDnsName,
  242. lpFlatName,
  243. lpStatusFlag );
  244. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  245. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  246. } RpcEndExcept;
  247. DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
  248. return( Win32Err );
  249. }
  250. DWORD
  251. WINAPI
  252. DsRoleDcAsDc(
  253. IN LPCWSTR lpServer OPTIONAL,
  254. IN LPCWSTR lpDnsDomainName,
  255. IN LPCWSTR lpFlatDomainName,
  256. IN LPCWSTR lpDomainAdminPassword OPTIONAL,
  257. IN LPCWSTR lpSiteName OPTIONAL,
  258. IN LPCWSTR lpDsDatabasePath,
  259. IN LPCWSTR lpDsLogPath,
  260. IN LPCWSTR lpSystemVolumeRootPath,
  261. IN LPCWSTR lpParentDnsDomainName OPTIONAL,
  262. IN LPCWSTR lpParentServer OPTIONAL,
  263. IN LPCWSTR lpAccount OPTIONAL,
  264. IN LPCWSTR lpPassword OPTIONAL,
  265. IN LPCWSTR lpDsRepairPassword OPTIONAL,
  266. IN ULONG Options,
  267. OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
  268. )
  269. /*++
  270. Routine Description:
  271. This routine will get the promote a server to be a DC in a domain
  272. Arguments:
  273. lpServer - Server on which to remote the call (NULL is local)
  274. lpDnsDomainName - Dns domain name of the domain to install
  275. lpFlatDomainName - NetBIOS domain name of the domain to install
  276. lpDomainAdminPassword - Password to set on the administrator account if it is a new install
  277. SiteName - Name of the site this DC should belong to
  278. lpDsDatabasePath - Absolute path on the local machine where the Ds DIT should go
  279. lpDsLogPath - Absolute path on the local machine where the Ds log files should go
  280. lpSystemVolumeRootPath - Absolute path on the local machine which will be the root of
  281. the system volume.
  282. lpParentDnsDomainName - Optional. If present, set this domain up as a child of the
  283. specified domain
  284. lpParentServer - Optional. If present, use this server in the parent domain to replicate
  285. the required information from
  286. lpAccount - User account to use when setting up as a child domain
  287. lpPassword - Password to use with the above account
  288. lpDsRepairPassword - Password to use for the admin account of the repair mode
  289. Options - Options to control the creation of the domain
  290. DsOperationHandle - Handle to the operation is returned here.
  291. Return Values:
  292. ERROR_SUCCESS - Success
  293. --*/
  294. {
  295. DWORD Win32Err = ERROR_SUCCESS;
  296. handle_t Handle = NULL;
  297. HANDLE RedirHandle = NULL;
  298. #define DSROLEP_DC_AS_DC_DA_PWD_INDEX 0
  299. #define DSROLEP_DC_AS_DC_PWD_INDEX 1
  300. #define DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX 2
  301. #define DSROLEP_DC_AS_DC_MAX_PWD_COUNT 3
  302. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DC_AS_DC_MAX_PWD_COUNT];
  303. LPCWSTR Passwords[DSROLEP_DC_AS_DC_MAX_PWD_COUNT];
  304. Passwords[DSROLEP_DC_AS_DC_DA_PWD_INDEX] = lpDomainAdminPassword;
  305. Passwords[DSROLEP_DC_AS_DC_PWD_INDEX] = lpPassword;
  306. Passwords[DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX] = lpDsRepairPassword;
  307. RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
  308. Win32Err = DsRolepEncryptPasswordStart( lpServer,
  309. Passwords,
  310. NELEMENTS(Passwords),
  311. &Handle,
  312. &RedirHandle,
  313. EncryptedPasswords );
  314. if ( Win32Err != ERROR_SUCCESS ) {
  315. return( Win32Err );
  316. }
  317. RpcTryExcept {
  318. Win32Err = DsRolerDcAsDc( Handle,
  319. ( LPWSTR )lpDnsDomainName,
  320. ( LPWSTR )lpFlatDomainName,
  321. EncryptedPasswords[DSROLEP_DC_AS_DC_DA_PWD_INDEX],
  322. ( LPWSTR )lpSiteName,
  323. ( LPWSTR )lpDsDatabasePath,
  324. ( LPWSTR )lpDsLogPath,
  325. ( LPWSTR )lpSystemVolumeRootPath,
  326. ( LPWSTR )lpParentDnsDomainName,
  327. ( LPWSTR )lpParentServer,
  328. ( LPWSTR )lpAccount,
  329. EncryptedPasswords[DSROLEP_DC_AS_DC_PWD_INDEX],
  330. EncryptedPasswords[DSROLEP_DC_AS_DC_DS_REPAIR_PWD_INDEX],
  331. Options,
  332. ( PDSROLER_HANDLE )DsOperationHandle );
  333. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  334. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  335. } RpcEndExcept;
  336. DsRolepEncryptPasswordEnd( Handle,
  337. RedirHandle,
  338. EncryptedPasswords,
  339. NELEMENTS(EncryptedPasswords) );
  340. return( Win32Err );
  341. }
  342. DWORD
  343. WINAPI
  344. DsRoleDcAsReplica(
  345. IN LPCWSTR lpServer OPTIONAL,
  346. IN LPCWSTR lpDnsDomainName,
  347. IN LPCWSTR lpReplicaServer,
  348. IN LPCWSTR lpSiteName OPTIONAL,
  349. IN LPCWSTR lpDsDatabasePath,
  350. IN LPCWSTR lpDsLogPath,
  351. IN LPCWSTR lpRestorePath OPTIONAL,
  352. IN LPCWSTR lpSystemVolumeRootPath,
  353. IN OUT LPWSTR lpBootkey OPTIONAL,
  354. IN LPCWSTR lpAccount OPTIONAL,
  355. IN LPCWSTR lpPassword OPTIONAL,
  356. IN LPCWSTR lpDsRepairPassword OPTIONAL,
  357. IN ULONG Options,
  358. OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
  359. )
  360. /*++
  361. Routine Description:
  362. This routine will install a server as a replica of an existing domain.
  363. Arguments:
  364. lpServer - OPTIONAL. Server to remote the call to.
  365. lpDnsDomainName - Dns domain name of the domain to install into
  366. lpReplicaServer - The name of a Dc within the existing domain, against which to replicate
  367. lpSiteName - Name of the site this DC should belong to
  368. lpDsDatabasePath - Absolute path on the local machine where the Ds DIT should go
  369. lpDsLogPath - Absolute path on the local machine where the Ds log files should go
  370. lpRestorepath - This is the path to a restored directory.
  371. lpSystemVolumeRootPath - Absolute path on the local machine which will be the root of
  372. the system volume.
  373. lpAccount - User account to use when setting up as a child domain
  374. lpPassword - Password to use with the above account
  375. lpDsRepairPassword - Password to use for the admin account of the repair mode
  376. Options - Options to control the creation of the domain
  377. DsOperationHandle - Handle to the operation is returned here.
  378. Return Values:
  379. --*/
  380. {
  381. DWORD Win32Err = ERROR_SUCCESS;
  382. NTSTATUS Status = STATUS_SUCCESS;
  383. handle_t Handle = NULL;
  384. HANDLE RedirHandle = NULL;
  385. PVOID Syskey[16];
  386. USHORT cbSyskey=sizeof(Syskey)/sizeof(Syskey[0]);
  387. UNICODE_STRING EncryptedBootKey;
  388. #define DSROLEP_DC_AS_REPLICA_PWD_INDEX 0
  389. #define DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX 1
  390. #define DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT 2
  391. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT];
  392. LPCWSTR Passwords[DSROLEP_DC_AS_REPLICA_MAX_PWD_COUNT];
  393. Passwords[DSROLEP_DC_AS_REPLICA_PWD_INDEX] = lpPassword;
  394. Passwords[DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX] = lpDsRepairPassword;
  395. RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
  396. Win32Err = DsRolepEncryptPasswordStart( lpServer,
  397. Passwords,
  398. NELEMENTS(Passwords),
  399. &Handle,
  400. &RedirHandle,
  401. EncryptedPasswords );
  402. if ( Win32Err != ERROR_SUCCESS ) {
  403. return( Win32Err );
  404. }
  405. RpcTryExcept {
  406. if(lpBootkey)
  407. {
  408. Win32Err = DsRolepHashkey(lpBootkey,
  409. Syskey,
  410. cbSyskey
  411. );
  412. if (Win32Err != ERROR_SUCCESS) {
  413. return Win32Err;
  414. }
  415. EncryptedBootKey.Buffer = (LPWSTR) MIDL_user_allocate(cbSyskey);
  416. if (!EncryptedBootKey.Buffer) {
  417. return ERROR_NOT_ENOUGH_MEMORY;
  418. }
  419. CopyMemory(EncryptedBootKey.Buffer,Syskey,cbSyskey);
  420. ZeroMemory(Syskey,cbSyskey);
  421. EncryptedBootKey.Length=(USHORT)cbSyskey;
  422. EncryptedBootKey.MaximumLength=(USHORT)cbSyskey;
  423. Win32Err = DsRolepEncryptHash(&EncryptedBootKey);
  424. if (Win32Err != ERROR_SUCCESS) {
  425. MIDL_user_free(EncryptedBootKey.Buffer);
  426. return Win32Err;
  427. }
  428. } else {
  429. EncryptedBootKey.Buffer = NULL;
  430. EncryptedBootKey.Length=0;
  431. EncryptedBootKey.MaximumLength=0;
  432. }
  433. Win32Err = DsRolerDcAsReplica( Handle,
  434. ( LPWSTR )lpDnsDomainName,
  435. ( LPWSTR )lpReplicaServer,
  436. ( LPWSTR )lpSiteName,
  437. ( LPWSTR )lpDsDatabasePath,
  438. ( LPWSTR )lpDsLogPath,
  439. ( LPWSTR )lpRestorePath,
  440. ( LPWSTR )lpSystemVolumeRootPath,
  441. &EncryptedBootKey,
  442. ( LPWSTR )lpAccount,
  443. EncryptedPasswords[DSROLEP_DC_AS_REPLICA_PWD_INDEX],
  444. EncryptedPasswords[DSROLEP_DC_AS_REPLICA_DS_REPAIR_PWD_INDEX],
  445. Options,
  446. ( PDSROLER_HANDLE )DsOperationHandle );
  447. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  448. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  449. } RpcEndExcept;
  450. if(EncryptedBootKey.Buffer)
  451. {
  452. MIDL_user_free(EncryptedBootKey.Buffer);
  453. EncryptedBootKey.Length=0;
  454. EncryptedBootKey.MaximumLength=0;
  455. }
  456. DsRolepEncryptPasswordEnd( Handle,
  457. RedirHandle,
  458. EncryptedPasswords,
  459. NELEMENTS(EncryptedPasswords) );
  460. return( Win32Err );
  461. }
  462. DWORD
  463. WINAPI
  464. DsRoleDemoteDc(
  465. IN LPCWSTR lpServer OPTIONAL,
  466. IN LPCWSTR lpDnsDomainName,
  467. IN DSROLE_SERVEROP_DEMOTE_ROLE ServerRole,
  468. IN LPCWSTR lpAccount OPTIONAL,
  469. IN LPCWSTR lpPassword OPTIONAL,
  470. IN ULONG Options,
  471. IN BOOL fLastDcInDomain,
  472. IN LPCWSTR lpAdminPassword OPTIONAL,
  473. OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
  474. )
  475. /*++
  476. Routine Description:
  477. This routine will demote an existing Dc to a standalone or member server.
  478. Arguments:
  479. lpServer - Server to remote the call to
  480. lpDnsDomainName - Name of the domain on this machine to demote. If NULL, demote all of the
  481. domains on this machine
  482. ServerRole - The new role this machine should take
  483. lpAccount - OPTIONAL User account to use when deleting the trusted domain object
  484. lpPassword - Password to use with the above account
  485. Options - Options to control the demotion of the domain
  486. fLastDcInDomain - If TRUE, this is the last dc in the domain
  487. lpAdminPassword - New local addmin password
  488. DsOperationHandle - Handle to the operation is returned here.
  489. Return Values:
  490. ERROR_SUCCESS - Success
  491. --*/
  492. {
  493. DWORD Win32Err = ERROR_SUCCESS;
  494. handle_t Handle = NULL;
  495. HANDLE RedirHandle = NULL;
  496. #define DSROLEP_DEMOTE_PWD_INDEX 0
  497. #define DSROLEP_DEMOTE_ADMIN_PWD_INDEX 1
  498. #define DSROLEP_DEMOTE_MAX_PWD_COUNT 2
  499. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_DEMOTE_MAX_PWD_COUNT];
  500. LPCWSTR Passwords[DSROLEP_DEMOTE_MAX_PWD_COUNT];
  501. Passwords[DSROLEP_DEMOTE_PWD_INDEX] = lpPassword;
  502. Passwords[DSROLEP_DEMOTE_ADMIN_PWD_INDEX] = lpAdminPassword;
  503. RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
  504. Win32Err = DsRolepEncryptPasswordStart( lpServer,
  505. Passwords,
  506. NELEMENTS(Passwords),
  507. &Handle,
  508. &RedirHandle,
  509. EncryptedPasswords );
  510. if ( Win32Err != ERROR_SUCCESS ) {
  511. return( Win32Err );
  512. }
  513. RpcTryExcept {
  514. Win32Err = DsRolerDemoteDc( Handle,
  515. ( LPWSTR )lpDnsDomainName,
  516. ServerRole,
  517. ( LPWSTR )lpAccount,
  518. EncryptedPasswords[DSROLEP_DEMOTE_PWD_INDEX],
  519. Options,
  520. fLastDcInDomain,
  521. EncryptedPasswords[DSROLEP_DEMOTE_ADMIN_PWD_INDEX],
  522. ( PDSROLER_HANDLE )DsOperationHandle );
  523. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  524. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  525. } RpcEndExcept;
  526. DsRolepEncryptPasswordEnd( Handle,
  527. RedirHandle,
  528. EncryptedPasswords,
  529. NELEMENTS(EncryptedPasswords) );
  530. return( Win32Err );
  531. }
  532. DWORD
  533. WINAPI
  534. DsRoleGetDcOperationProgress(
  535. IN LPCWSTR lpServer OPTIONAL,
  536. IN DSROLE_SERVEROP_HANDLE DsOperationHandle,
  537. OUT PDSROLE_SERVEROP_STATUS *ServerOperationStatus
  538. )
  539. /*++
  540. Routine Description:
  541. Gets the progress of the currently running operation
  542. Arguments:
  543. lpServer - Server to remote the call to
  544. DsOperationHandle - Handle of currently running operation. Returned by one of the DsRoleDcAs
  545. apis
  546. ServerOperationStatus - Where the current operation status is returned. Must be freed via
  547. MIDL_user_free (or DsRoleFreeMemory)
  548. Return Values:
  549. ERROR_SUCCESS - Success
  550. --*/
  551. {
  552. DWORD Win32Err = ERROR_SUCCESS;
  553. PDSROLER_SERVEROP_STATUS ServerStatus = NULL;
  554. handle_t Handle = NULL;
  555. Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
  556. &Handle );
  557. if ( Win32Err != ERROR_SUCCESS ) {
  558. return( Win32Err );
  559. }
  560. RpcTryExcept {
  561. Win32Err = DsRolerGetDcOperationProgress(
  562. Handle,
  563. (PDSROLER_HANDLE)&DsOperationHandle,
  564. &ServerStatus );
  565. if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_IO_PENDING ) {
  566. *ServerOperationStatus = ( PDSROLE_SERVEROP_STATUS )ServerStatus;
  567. }
  568. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  569. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  570. } RpcEndExcept;
  571. DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
  572. return( Win32Err );
  573. }
  574. DWORD
  575. WINAPI
  576. DsRoleGetDcOperationResults(
  577. IN LPCWSTR lpServer OPTIONAL,
  578. IN DSROLE_SERVEROP_HANDLE DsOperationHandle,
  579. OUT PDSROLE_SERVEROP_RESULTS *ServerOperationResults
  580. )
  581. /*++
  582. Routine Description:
  583. Gets the final results of an attempted promotion/demotion operation
  584. Arguments:
  585. lpServer - Server to remote the call to
  586. DsOperationHandle - Handle of currently running operation. Returned by one of the DsRoleDcAs
  587. apis
  588. ServerOperationResults - Where the current operation result is returned. Must be freed via
  589. MIDL_user_free (or DsRoleFreeMemory)
  590. Return Values:
  591. ERROR_SUCCESS - Success
  592. --*/
  593. {
  594. DWORD Win32Err = ERROR_SUCCESS;
  595. PDSROLER_SERVEROP_RESULTS ServerResults = NULL;
  596. handle_t Handle = NULL;
  597. Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
  598. &Handle );
  599. if ( Win32Err != ERROR_SUCCESS ) {
  600. return( Win32Err );
  601. }
  602. RpcTryExcept {
  603. *ServerOperationResults = 0;
  604. Win32Err = DsRolerGetDcOperationResults(
  605. Handle,
  606. (PDSROLER_HANDLE)&DsOperationHandle,
  607. &ServerResults );
  608. if ( Win32Err == ERROR_SUCCESS ) {
  609. *ServerOperationResults = ( PDSROLE_SERVEROP_RESULTS )ServerResults;
  610. }
  611. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  612. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  613. } RpcEndExcept;
  614. DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
  615. return( Win32Err );
  616. }
  617. DWORD
  618. WINAPI
  619. DsRoleGetPrimaryDomainInformation(
  620. IN LPCWSTR lpServer OPTIONAL,
  621. IN DSROLE_PRIMARY_DOMAIN_INFO_LEVEL InfoLevel,
  622. OUT PBYTE *Buffer )
  623. /*++
  624. Routine Description:
  625. Gets information on the machine
  626. Arguments:
  627. lpServer - Server to remote the call to
  628. InfoLevel - What level of information is being requested. Currently supported levels are:
  629. DsRolePrimaryDomainInfoBasic
  630. Buffer - Where the information is returned. The returned pointer should be cast to the
  631. appropriate type for the info level passed in. The returned buffer should be freed via
  632. MIDL_user_free (or DsRoleFreeMemory)
  633. Return Values:
  634. ERROR_SUCCESS - Success
  635. --*/
  636. {
  637. DWORD Win32Err = ERROR_SUCCESS;
  638. PDSROLER_PRIMARY_DOMAIN_INFORMATION PrimaryDomainInfo = NULL;
  639. handle_t Handle = NULL;
  640. NTSTATUS Status = STATUS_SUCCESS;
  641. if ( Buffer == NULL ) {
  642. return( ERROR_INVALID_PARAMETER );
  643. }
  644. Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
  645. &Handle );
  646. if ( Win32Err != ERROR_SUCCESS ) {
  647. return( Win32Err );
  648. }
  649. if ( NULL == Handle) {
  650. return( ERROR_NOT_ENOUGH_MEMORY );
  651. }
  652. RpcTryExcept {
  653. *Buffer = NULL;
  654. Win32Err = DsRolerGetPrimaryDomainInformation(
  655. Handle,
  656. InfoLevel,
  657. &PrimaryDomainInfo );
  658. *Buffer = ( PBYTE )PrimaryDomainInfo;
  659. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  660. Status = I_RpcMapWin32Status( RpcExceptionCode() );
  661. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  662. } RpcEndExcept;
  663. DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
  664. //
  665. // If this fails because we are calling a downlevel server, cobble up the information here
  666. //
  667. if ( ( Status == RPC_NT_UNKNOWN_IF || Status == RPC_NT_PROCNUM_OUT_OF_RANGE ) &&
  668. InfoLevel == DsRolePrimaryDomainInfoBasic ) {
  669. Win32Err = DsRolepGetPrimaryDomainInformationDownlevel( ( LPWSTR )lpServer, Buffer );
  670. }
  671. return( Win32Err );
  672. }
  673. DWORD
  674. WINAPI
  675. DsRoleCancel(
  676. IN LPCWSTR lpServer OPTIONAL,
  677. IN DSROLE_SERVEROP_HANDLE DsOperationHandle
  678. )
  679. /*++
  680. Routine Description:
  681. Cancels a currently running operation
  682. Arguments:
  683. lpServer - Server to remote the call to
  684. DsOperationHandle - Handle of currently running operation. Returned by one of the DsRoleDcAs
  685. apis
  686. Return Values:
  687. ERROR_SUCCESS - Success
  688. --*/
  689. {
  690. DWORD Win32Err = ERROR_SUCCESS;
  691. handle_t Handle = NULL;
  692. Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
  693. &Handle );
  694. if ( Win32Err != ERROR_SUCCESS ) {
  695. return( Win32Err );
  696. }
  697. RpcTryExcept {
  698. Win32Err = DsRolerCancel( Handle,
  699. ( PDSROLER_HANDLE )&DsOperationHandle );
  700. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  701. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  702. } RpcEndExcept;
  703. DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
  704. return( Win32Err );
  705. }
  706. DWORD
  707. WINAPI
  708. DsRoleServerSaveStateForUpgrade(
  709. IN LPCWSTR lpAnswerFile OPTIONAL
  710. )
  711. /*++
  712. Routine Description:
  713. This function is to be invoked during setup and saves the required server state to
  714. complete the promotion following the reboot. Following the successful completion
  715. of this API call, the server will be demoted to a member server in the same domain.
  716. Arguments:
  717. lpAnswerFile -- Optional path to an answer file to be used by DCPROMO when it is
  718. invoked to do the upgrade
  719. Return Values:
  720. ERROR_SUCCESS - Success
  721. --*/
  722. {
  723. DWORD Win32Err = ERROR_SUCCESS;
  724. handle_t Handle = NULL;
  725. Win32Err = DsRolepServerBind( NULL,
  726. &Handle );
  727. if ( Win32Err != ERROR_SUCCESS ) {
  728. return( Win32Err );
  729. }
  730. RpcTryExcept {
  731. Win32Err = DsRolerServerSaveStateForUpgrade( Handle, ( LPWSTR )lpAnswerFile );
  732. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  733. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  734. } RpcEndExcept;
  735. DsRolepServerUnbind( NULL, Handle );
  736. return( Win32Err );
  737. }
  738. DWORD
  739. WINAPI
  740. DsRoleUpgradeDownlevelServer(
  741. IN LPCWSTR lpDnsDomainName,
  742. IN LPCWSTR lpSiteName,
  743. IN LPCWSTR lpDsDatabasePath,
  744. IN LPCWSTR lpDsLogPath,
  745. IN LPCWSTR lpSystemVolumeRootPath,
  746. IN LPCWSTR lpParentDnsDomainName OPTIONAL,
  747. IN LPCWSTR lpParentServer OPTIONAL,
  748. IN LPCWSTR lpAccount OPTIONAL,
  749. IN LPCWSTR lpPassword OPTIONAL,
  750. IN LPCWSTR lpDsRepairPassword OPTIONAL,
  751. IN ULONG Options,
  752. OUT DSROLE_SERVEROP_HANDLE *DsOperationHandle
  753. )
  754. /*++
  755. Routine Description:
  756. This routine process the information saved from a DsRoleServerSaveStateForUpgrade to
  757. promote a downlevel (NT4 or previous) server to an NT5 DC
  758. Arguments:
  759. lpDnsDomainName - Dns domain name of the domain to install
  760. SiteName - Name of the site this DC should belong to
  761. lpDsDatabasePath - Absolute path on the local machine where the Ds DIT should go
  762. lpDsLogPath - Absolute path on the local machine where the Ds log files should go
  763. lpSystemVolumeRootPath - Absolute path on the local machine which will be the root of
  764. the system volume.
  765. lpParentDnsDomainName - Optional. If present, set this domain up as a child of the
  766. specified domain
  767. lpParentServer - Optional. If present, use this server in the parent domain to replicate
  768. the required information from
  769. lpAccount - User account to use when setting up as a child domain
  770. lpPassword - Password to use with the above account
  771. lpDsRepairPassword - Password to use for the admin account of the repair mode
  772. Options - Options to control the creation of the domain
  773. DsOperationHandle - Handle to the operation is returned here.
  774. Return Values:
  775. ERROR_SUCCESS - Success
  776. --*/
  777. {
  778. DWORD Win32Err = ERROR_SUCCESS;
  779. handle_t Handle = NULL;
  780. HANDLE RedirHandle = NULL;
  781. #define DSROLEP_UPGRADE_PWD_INDEX 0
  782. #define DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX 1
  783. #define DSROLEP_UPGRADE_MAX_PWD_COUNT 2
  784. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_UPGRADE_MAX_PWD_COUNT];
  785. LPCWSTR Passwords[DSROLEP_UPGRADE_MAX_PWD_COUNT];
  786. Passwords[DSROLEP_UPGRADE_PWD_INDEX] = lpPassword;
  787. Passwords[DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX] = lpDsRepairPassword;
  788. RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
  789. Win32Err = DsRolepEncryptPasswordStart( NULL,
  790. Passwords,
  791. NELEMENTS(Passwords),
  792. &Handle,
  793. &RedirHandle,
  794. EncryptedPasswords );
  795. if ( Win32Err != ERROR_SUCCESS ) {
  796. return( Win32Err );
  797. }
  798. RpcTryExcept {
  799. Win32Err = DsRolerUpgradeDownlevelServer( Handle,
  800. ( LPWSTR )lpDnsDomainName,
  801. ( LPWSTR )lpSiteName,
  802. ( LPWSTR )lpDsDatabasePath,
  803. ( LPWSTR )lpDsLogPath,
  804. ( LPWSTR )lpSystemVolumeRootPath,
  805. ( LPWSTR )lpParentDnsDomainName,
  806. ( LPWSTR )lpParentServer,
  807. ( LPWSTR )lpAccount,
  808. EncryptedPasswords[DSROLEP_UPGRADE_PWD_INDEX],
  809. EncryptedPasswords[DSROLEP_UPGRADE_DS_REPAIR_PWD_INDEX],
  810. Options,
  811. ( PDSROLER_HANDLE )DsOperationHandle );
  812. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  813. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  814. } RpcEndExcept;
  815. DsRolepEncryptPasswordEnd( Handle,
  816. RedirHandle,
  817. EncryptedPasswords,
  818. NELEMENTS(EncryptedPasswords) );
  819. return( Win32Err );
  820. }
  821. DWORD
  822. WINAPI
  823. DsRoleAbortDownlevelServerUpgrade(
  824. IN LPCWSTR lpAdminPassword,
  825. IN LPCWSTR lpAccount, OPTIONAL
  826. IN LPCWSTR lpPassword, OPTIONAL
  827. IN ULONG Options
  828. )
  829. /*++
  830. Routine Description:
  831. This routine cleans up the information saved from a DsRoleSaveServerStateForUpgrade call,
  832. leaving the machine as a member or standalone server
  833. Arguments:
  834. lpAdminPassword - New local administrator account password
  835. lpAccount - User account to use when setting up as a child domain
  836. lpPassword - Password to use with the above account
  837. Return Values:
  838. ERROR_SUCCESS - Success
  839. --*/
  840. {
  841. DWORD Win32Err = ERROR_SUCCESS;
  842. handle_t Handle = NULL;
  843. HANDLE RedirHandle = NULL;
  844. #define DSROLEP_ABORT_PWD_INDEX 0
  845. #define DSROLEP_ABORT_ADMIN_PWD_INDEX 1
  846. #define DSROLEP_ABORT_MAX_PWD_COUNT 2
  847. PDSROLEPR_ENCRYPTED_USER_PASSWORD EncryptedPasswords[DSROLEP_ABORT_MAX_PWD_COUNT];
  848. LPCWSTR Passwords[DSROLEP_ABORT_MAX_PWD_COUNT];
  849. Passwords[DSROLEP_ABORT_PWD_INDEX] = lpPassword;
  850. Passwords[DSROLEP_ABORT_ADMIN_PWD_INDEX] = lpAdminPassword;
  851. RtlZeroMemory( EncryptedPasswords, sizeof(EncryptedPasswords) );
  852. Win32Err = DsRolepEncryptPasswordStart( NULL,
  853. Passwords,
  854. NELEMENTS(Passwords),
  855. &Handle,
  856. &RedirHandle,
  857. EncryptedPasswords );
  858. if ( Win32Err != ERROR_SUCCESS ) {
  859. return( Win32Err );
  860. }
  861. RpcTryExcept {
  862. Win32Err = DsRolerAbortDownlevelServerUpgrade( Handle,
  863. ( LPWSTR )lpAccount,
  864. EncryptedPasswords[DSROLEP_ABORT_PWD_INDEX],
  865. EncryptedPasswords[DSROLEP_ABORT_ADMIN_PWD_INDEX],
  866. Options );
  867. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  868. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  869. } RpcEndExcept;
  870. DsRolepEncryptPasswordEnd( Handle,
  871. RedirHandle,
  872. EncryptedPasswords,
  873. NELEMENTS(EncryptedPasswords) );
  874. return( Win32Err );
  875. }
  876. DWORD
  877. WINAPI
  878. DsRoleGetDatabaseFacts(
  879. IN LPCWSTR lpServer OPTIONAL,
  880. IN LPCWSTR lpRestorePath,
  881. OUT LPWSTR *lpDNSDomainName,
  882. OUT PULONG State
  883. )
  884. /*++
  885. Routine Description:
  886. This function will give information about a restore database
  887. 1. the way the syskey is stored
  888. 2. the domain that the database came from
  889. 3. where the backup was taken from a GC or not
  890. Arguments:
  891. lpServer - The server to get the Facts from
  892. lpRestorePath - The location of the restored files.
  893. lpDNSDomainName - This parameter will recieve the name of the domain that this backup came
  894. from
  895. State - The return Values that report How the syskey is stored and If the back was likely
  896. taken form a GC or not.
  897. Return Values:
  898. ERROR_SUCCESS - Success
  899. --*/
  900. {
  901. DWORD Win32Err = ERROR_SUCCESS;
  902. handle_t Handle = NULL;
  903. if(IsBadWritePtr(lpDNSDomainName,
  904. sizeof(LPWSTR*) )){
  905. return ERROR_INVALID_PARAMETER;
  906. }
  907. Win32Err = DsRolepServerBind( (PDSROLE_SERVER_NAME)lpServer,
  908. &Handle );
  909. if ( Win32Err != ERROR_SUCCESS ) {
  910. return( Win32Err );
  911. }
  912. RpcTryExcept {
  913. Win32Err = DsRolerGetDatabaseFacts( Handle,
  914. ( LPWSTR )lpRestorePath,
  915. lpDNSDomainName,
  916. State );
  917. } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) {
  918. Win32Err = DsRolepApiReturnResult( RpcExceptionCode( ) );
  919. } RpcEndExcept;
  920. DsRolepServerUnbind( (PDSROLE_SERVER_NAME)lpServer, Handle );
  921. return Win32Err;
  922. }
  923. //
  924. // Local functions
  925. //
  926. DWORD
  927. DsRolepGetPrimaryDomainInformationDownlevel(
  928. IN LPWSTR Server,
  929. OUT PBYTE *Buffer
  930. )
  931. {
  932. DWORD Win32Err = ERROR_SUCCESS;
  933. NTSTATUS Status;
  934. LSA_HANDLE PolicyHandle;
  935. PPOLICY_PRIMARY_DOMAIN_INFO PDI = NULL;
  936. PPOLICY_LSA_SERVER_ROLE_INFO ServerRole = NULL;
  937. PPOLICY_ACCOUNT_DOMAIN_INFO ADI = NULL;
  938. UNICODE_STRING UnicodeServer;
  939. OBJECT_ATTRIBUTES OA;
  940. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC PDIB = NULL;
  941. DSROLE_MACHINE_ROLE MachineRole = DsRole_RoleStandaloneServer;
  942. NT_PRODUCT_TYPE ProductType;
  943. Win32Err = DsRolepGetProductTypeForServer( Server, &ProductType );
  944. if ( Win32Err != ERROR_SUCCESS ) {
  945. return( Win32Err );
  946. }
  947. InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL);
  948. if ( Server ) {
  949. RtlInitUnicodeString( &UnicodeServer, Server );
  950. }
  951. Status = LsaOpenPolicy( Server ? &UnicodeServer : NULL,
  952. &OA,
  953. POLICY_VIEW_LOCAL_INFORMATION,
  954. &PolicyHandle );
  955. if ( NT_SUCCESS( Status ) ) {
  956. Status = LsaQueryInformationPolicy( PolicyHandle,
  957. PolicyPrimaryDomainInformation,
  958. ( PVOID * ) &PDI );
  959. if ( NT_SUCCESS( Status ) ) {
  960. switch ( ProductType ) {
  961. case NtProductWinNt:
  962. if ( PDI->Sid == NULL ) {
  963. MachineRole = DsRole_RoleStandaloneWorkstation;
  964. } else {
  965. MachineRole = DsRole_RoleMemberWorkstation;
  966. }
  967. break;
  968. case NtProductServer:
  969. if ( PDI->Sid == NULL ) {
  970. MachineRole = DsRole_RoleStandaloneServer;
  971. } else {
  972. MachineRole = DsRole_RoleMemberServer;
  973. }
  974. break;
  975. case NtProductLanManNt:
  976. Status = LsaQueryInformationPolicy( PolicyHandle,
  977. PolicyLsaServerRoleInformation,
  978. ( PVOID * )&ServerRole );
  979. if ( NT_SUCCESS( Status ) ) {
  980. if ( ServerRole->LsaServerRole == PolicyServerRolePrimary ) {
  981. //
  982. // If we think we're a primary domain controller, we'll need to
  983. // guard against the case where we're actually standalone during setup
  984. //
  985. Status = LsaQueryInformationPolicy( PolicyHandle,
  986. PolicyAccountDomainInformation,
  987. ( PVOID * )&ADI );
  988. if ( NT_SUCCESS( Status ) ) {
  989. if ( PDI->Sid == NULL ||
  990. ADI->DomainSid == NULL ||
  991. !RtlEqualSid( ADI->DomainSid, PDI->Sid ) ) {
  992. MachineRole = DsRole_RoleStandaloneServer;
  993. } else {
  994. MachineRole = DsRole_RolePrimaryDomainController;
  995. }
  996. }
  997. } else {
  998. MachineRole = DsRole_RoleBackupDomainController;
  999. }
  1000. }
  1001. break;
  1002. default:
  1003. Status = STATUS_INVALID_PARAMETER;
  1004. break;
  1005. }
  1006. }
  1007. //
  1008. // Build the return buffer
  1009. //
  1010. if ( NT_SUCCESS( Status ) ) {
  1011. PDIB = MIDL_user_allocate( sizeof( DSROLE_PRIMARY_DOMAIN_INFO_BASIC ) +
  1012. PDI->Name.Length + sizeof( WCHAR ) );
  1013. if ( PDIB == NULL ) {
  1014. Status = STATUS_INSUFFICIENT_RESOURCES;
  1015. } else {
  1016. RtlZeroMemory( PDIB, sizeof( DSROLE_PRIMARY_DOMAIN_INFO_BASIC ) +
  1017. PDI->Name.Length + sizeof( WCHAR ) );
  1018. PDIB->MachineRole = MachineRole;
  1019. PDIB->DomainNameFlat = ( LPWSTR ) ( ( PBYTE )PDIB +
  1020. sizeof( DSROLE_PRIMARY_DOMAIN_INFO_BASIC ) );
  1021. RtlCopyMemory( PDIB->DomainNameFlat, PDI->Name.Buffer, PDI->Name.Length );
  1022. *Buffer = ( PBYTE )PDIB;
  1023. }
  1024. }
  1025. LsaClose( PolicyHandle );
  1026. LsaFreeMemory( PDI );
  1027. if ( ADI != NULL ) {
  1028. LsaFreeMemory( ADI );
  1029. }
  1030. if ( ServerRole != NULL ) {
  1031. LsaFreeMemory( ServerRole );
  1032. }
  1033. }
  1034. Win32Err = RtlNtStatusToDosError( Status );
  1035. return( Win32Err );
  1036. }
  1037. DWORD
  1038. DsRolepGetProductTypeForServer(
  1039. IN LPWSTR Server,
  1040. IN OUT PNT_PRODUCT_TYPE ProductType
  1041. )
  1042. {
  1043. DWORD Win32Err = ERROR_SUCCESS;
  1044. PWSTR RegServer = NULL;
  1045. HKEY RemoteKey, ProductKey;
  1046. PBYTE Buffer = NULL;
  1047. ULONG Type, Size = 0;
  1048. if ( Server == NULL ) {
  1049. if ( RtlGetNtProductType( ProductType ) == FALSE ) {
  1050. Win32Err = RtlNtStatusToDosError( STATUS_UNSUCCESSFUL );
  1051. }
  1052. } else {
  1053. if ( wcslen( Server ) > 2 && *Server == L'\\' && *( Server + 1 ) == L'\\' ) {
  1054. RegServer = Server;
  1055. } else {
  1056. RegServer = LocalAlloc( LMEM_FIXED, ( wcslen( Server ) + 3 ) * sizeof( WCHAR ) );
  1057. if ( RegServer ) {
  1058. swprintf( RegServer, L"\\\\%ws", Server );
  1059. } else {
  1060. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  1061. }
  1062. }
  1063. if ( Win32Err == ERROR_SUCCESS ) {
  1064. Win32Err = RegConnectRegistry( RegServer,
  1065. HKEY_LOCAL_MACHINE,
  1066. &RemoteKey );
  1067. if ( Win32Err == ERROR_SUCCESS ) {
  1068. Win32Err = RegOpenKeyEx( RemoteKey,
  1069. L"system\\currentcontrolset\\control\\productoptions",
  1070. 0,
  1071. KEY_READ,
  1072. &ProductKey );
  1073. if ( Win32Err == ERROR_SUCCESS ) {
  1074. Win32Err = RegQueryValueEx( ProductKey,
  1075. L"ProductType",
  1076. 0,
  1077. &Type,
  1078. 0,
  1079. &Size );
  1080. if ( Win32Err == ERROR_SUCCESS ) {
  1081. Buffer = LocalAlloc( LMEM_FIXED, Size );
  1082. if ( Buffer ) {
  1083. Win32Err = RegQueryValueEx( ProductKey,
  1084. L"ProductType",
  1085. 0,
  1086. &Type,
  1087. Buffer,
  1088. &Size );
  1089. if ( Win32Err == ERROR_SUCCESS ) {
  1090. if ( !_wcsicmp( ( PWSTR )Buffer, L"LanmanNt" ) ) {
  1091. *ProductType = NtProductLanManNt;
  1092. } else if ( !_wcsicmp( ( PWSTR )Buffer, L"ServerNt" ) ) {
  1093. *ProductType = NtProductServer;
  1094. } else if ( !_wcsicmp( ( PWSTR )Buffer, L"WinNt" ) ) {
  1095. *ProductType = NtProductWinNt;
  1096. } else {
  1097. Win32Err = ERROR_UNKNOWN_PRODUCT;
  1098. }
  1099. }
  1100. LocalFree( Buffer );
  1101. } else {
  1102. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  1103. }
  1104. }
  1105. RegCloseKey( ProductKey );
  1106. }
  1107. RegCloseKey( RemoteKey );
  1108. }
  1109. }
  1110. if ( RegServer != Server ) {
  1111. LocalFree( RegServer );
  1112. }
  1113. }
  1114. return( Win32Err );
  1115. }
  1116. NTSTATUS
  1117. DsRolepRandomFill(
  1118. IN ULONG BufferSize,
  1119. IN OUT PUCHAR Buffer
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. This routine fills a buffer with random data.
  1124. Parameters:
  1125. BufferSize - Length of the input buffer, in bytes.
  1126. Buffer - Input buffer to be filled with random data.
  1127. Return Values:
  1128. Errors from NtQuerySystemTime()
  1129. --*/
  1130. {
  1131. ULONG Index;
  1132. LARGE_INTEGER Time;
  1133. ULONG Seed;
  1134. NTSTATUS NtStatus;
  1135. NtStatus = NtQuerySystemTime(&Time);
  1136. if (!NT_SUCCESS(NtStatus)) {
  1137. return(NtStatus);
  1138. }
  1139. Seed = Time.LowPart ^ Time.HighPart;
  1140. for (Index = 0 ; Index < BufferSize ; Index++ )
  1141. {
  1142. *Buffer++ = (UCHAR) (RtlRandom(&Seed) % 256);
  1143. }
  1144. return(STATUS_SUCCESS);
  1145. }
  1146. DWORD
  1147. DsRolepEncryptPasswordStart(
  1148. IN LPCWSTR ServerName OPTIONAL,
  1149. IN LPCWSTR *Passwords,
  1150. IN ULONG Count,
  1151. OUT RPC_BINDING_HANDLE *RpcBindingHandle,
  1152. OUT HANDLE *RedirHandle,
  1153. IN OUT PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPasswords
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. This routine takes a number of cleartext unicode NT password from the user,
  1158. and encrypts them with the session key.
  1159. This routine's algorithm was taken from CliffV's work when encrypting the
  1160. passwords for the NetrJoinDomain2 interface.
  1161. Parameters:
  1162. ServerName - UNC server name of the server to remote the API to
  1163. Passwords - the cleartext unicode NT passwords.
  1164. Count - the number of password
  1165. RpcBindingHandle - RPC handle used for acquiring a session key.
  1166. RedirHandle - Returns a handle to the redir. Since RpcBindingHandles don't represent
  1167. and open connection to the server, we have to ensure the connection stays open
  1168. until the server side has a chance to get this same UserSessionKey. The only
  1169. way to do that is to keep the connect open.
  1170. Returns NULL if no handle is needed.
  1171. EncryptedUserPassword - receives the encrypted cleartext passwords.
  1172. If lpPassword is NULL, a NULL is returned for that entry.
  1173. Return Values:
  1174. If this routine returns NO_ERROR, the returned data must be freed using
  1175. LocalFree.
  1176. --*/
  1177. {
  1178. DWORD WinError = ERROR_SUCCESS;
  1179. NTSTATUS NtStatus;
  1180. USER_SESSION_KEY UserSessionKey;
  1181. RC4_KEYSTRUCT Rc4Key;
  1182. MD5_CTX Md5Context;
  1183. PDSROLEPR_USER_PASSWORD UserPassword = NULL;
  1184. ULONG PasswordSize;
  1185. ULONG i;
  1186. //
  1187. // Initialization
  1188. //
  1189. *RpcBindingHandle = NULL;
  1190. *RedirHandle = NULL;
  1191. for ( i = 0; i < Count; i++ ) {
  1192. EncryptedUserPasswords[i] = NULL;
  1193. }
  1194. //
  1195. // Verify parameters
  1196. //
  1197. for ( i = 0; i < Count; i++ ) {
  1198. if ( Passwords[i] ) {
  1199. PasswordSize = wcslen( Passwords[i] ) * sizeof(WCHAR);
  1200. if ( PasswordSize > DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) {
  1201. WinError = ERROR_PASSWORD_RESTRICTION;
  1202. goto Cleanup;
  1203. }
  1204. }
  1205. }
  1206. //
  1207. // Get an RPC handle to the server.
  1208. //
  1209. WinError = DsRolepServerBind( (PDSROLE_SERVER_NAME) ServerName,
  1210. RpcBindingHandle );
  1211. if ( ERROR_SUCCESS != WinError ) {
  1212. goto Cleanup;
  1213. }
  1214. //
  1215. // Get the session key.
  1216. //
  1217. NtStatus = RtlGetUserSessionKeyClientBinding(
  1218. *RpcBindingHandle,
  1219. RedirHandle,
  1220. &UserSessionKey );
  1221. if ( !NT_SUCCESS(NtStatus) ) {
  1222. WinError = RtlNtStatusToDosError( NtStatus );
  1223. goto Cleanup;
  1224. }
  1225. //
  1226. // Encrypt the passwords
  1227. //
  1228. for ( i = 0; i < Count; i++ ) {
  1229. if ( NULL == Passwords[i] ) {
  1230. // Nothing to encrypt
  1231. continue;
  1232. }
  1233. PasswordSize = wcslen( Passwords[i] ) * sizeof(WCHAR);
  1234. //
  1235. // Allocate a buffer to encrypt and fill it in.
  1236. //
  1237. UserPassword = LocalAlloc( 0, sizeof(DSROLEPR_USER_PASSWORD) );
  1238. if ( UserPassword == NULL ) {
  1239. WinError = ERROR_NOT_ENOUGH_MEMORY;
  1240. goto Cleanup;
  1241. }
  1242. //
  1243. // Copy the password into the tail end of the buffer.
  1244. //
  1245. RtlCopyMemory(
  1246. ((PCHAR) UserPassword->Buffer) +
  1247. (DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
  1248. PasswordSize,
  1249. Passwords[i],
  1250. PasswordSize );
  1251. UserPassword->Length = PasswordSize;
  1252. //
  1253. // Fill the front of the buffer with random data
  1254. //
  1255. NtStatus = DsRolepRandomFill(
  1256. (DSROLE_MAX_PASSWORD_LENGTH * sizeof(WCHAR)) -
  1257. PasswordSize,
  1258. (PUCHAR) UserPassword->Buffer );
  1259. if ( !NT_SUCCESS(NtStatus) ) {
  1260. WinError = RtlNtStatusToDosError( NtStatus );
  1261. goto Cleanup;
  1262. }
  1263. NtStatus = DsRolepRandomFill(
  1264. DSROLE_OBFUSCATOR_LENGTH,
  1265. (PUCHAR) UserPassword->Obfuscator );
  1266. if ( !NT_SUCCESS(NtStatus) ) {
  1267. WinError = RtlNtStatusToDosError( NtStatus );
  1268. goto Cleanup;
  1269. }
  1270. //
  1271. // The UserSessionKey is the same for the life of the session. RC4'ing multiple
  1272. // strings with a single key is weak (if you crack one you've cracked them all).
  1273. // So compute a key that's unique for this particular encryption.
  1274. //
  1275. //
  1276. MD5Init(&Md5Context);
  1277. MD5Update( &Md5Context, (LPBYTE)&UserSessionKey, sizeof(UserSessionKey) );
  1278. MD5Update( &Md5Context, UserPassword->Obfuscator, sizeof(UserPassword->Obfuscator) );
  1279. MD5Final( &Md5Context );
  1280. rc4_key( &Rc4Key, MD5DIGESTLEN, Md5Context.digest );
  1281. //
  1282. // Encrypt it.
  1283. // Don't encrypt the obfuscator. The server needs that to compute the key.
  1284. //
  1285. rc4( &Rc4Key, sizeof(UserPassword->Buffer)+sizeof(UserPassword->Length), (LPBYTE) UserPassword->Buffer );
  1286. EncryptedUserPasswords[i] = (PDSROLEPR_ENCRYPTED_USER_PASSWORD) UserPassword;
  1287. UserPassword = NULL;
  1288. }
  1289. WinError = ERROR_SUCCESS;
  1290. Cleanup:
  1291. if ( WinError != ERROR_SUCCESS ) {
  1292. if ( UserPassword != NULL ) {
  1293. LocalFree( UserPassword );
  1294. }
  1295. if ( *RpcBindingHandle != NULL ) {
  1296. DsRolepServerUnbind( NULL, *RpcBindingHandle );
  1297. *RpcBindingHandle = NULL;
  1298. }
  1299. if ( *RedirHandle != NULL ) {
  1300. NtClose( *RedirHandle );
  1301. *RedirHandle = NULL;
  1302. }
  1303. for ( i = 0; i < Count; i++ ) {
  1304. if ( EncryptedUserPasswords[i] ) {
  1305. LocalFree( EncryptedUserPasswords[i] );
  1306. EncryptedUserPasswords[i] = NULL;
  1307. }
  1308. }
  1309. }
  1310. return WinError;
  1311. }
  1312. VOID
  1313. DsRolepEncryptPasswordEnd(
  1314. IN RPC_BINDING_HANDLE RpcBindingHandle,
  1315. IN HANDLE RedirHandle OPTIONAL,
  1316. IN PDSROLEPR_ENCRYPTED_USER_PASSWORD *EncryptedUserPasswords OPTIONAL,
  1317. IN ULONG Count
  1318. )
  1319. /*++
  1320. Routine Description:
  1321. This routine takes the variables returned by DsRolepEncryptPasswordStart and
  1322. frees them.
  1323. Parameters:
  1324. RpcBindingHandle - RPC handle used for acquiring a session key.
  1325. RedirHandle - Handle to the redirector
  1326. EncryptedUserPasswords - the encrypted cleartext passwords.
  1327. Count - the number of passwords
  1328. Return Values:
  1329. --*/
  1330. {
  1331. ULONG i;
  1332. //
  1333. // Free the RPC binding handle.
  1334. //
  1335. if ( RpcBindingHandle != NULL ) {
  1336. (VOID) DsRolepServerUnbind ( NULL, RpcBindingHandle );
  1337. }
  1338. //
  1339. // Close the redir handle.
  1340. //
  1341. if ( RedirHandle != NULL ) {
  1342. NtClose( RedirHandle );
  1343. }
  1344. //
  1345. // Free the encrypted passwords.
  1346. //
  1347. for ( i = 0; i < Count; i++ ) {
  1348. if ( EncryptedUserPasswords[i] != NULL ) {
  1349. LocalFree( EncryptedUserPasswords[i] );
  1350. }
  1351. }
  1352. return;
  1353. }
  1354. DWORD
  1355. DsRolepHashkey(
  1356. IN OUT LPWSTR key,
  1357. OUT PVOID SysKey,
  1358. IN ULONG cbSysKey
  1359. )
  1360. /*++
  1361. Routine Description
  1362. This routine is used to store the boot type
  1363. in the registry
  1364. Paramaeters
  1365. NewType Indicates the new boot type
  1366. Return Values
  1367. STATUS_SUCCESS
  1368. STATUS_UNSUCCESSFUL
  1369. --*/
  1370. {
  1371. MD5_CTX Md5;
  1372. if(cbSysKey<SYSKEY_SIZE) {
  1373. return ERROR_INSUFFICIENT_BUFFER;
  1374. }
  1375. cbSysKey=wcslen(key)*sizeof(WCHAR);
  1376. MD5Init( &Md5 );
  1377. MD5Update( &Md5, (PUCHAR) key, cbSysKey );
  1378. MD5Final( &Md5 );
  1379. ZeroMemory( key, cbSysKey );
  1380. cbSysKey=SYSKEY_SIZE;
  1381. CopyMemory( SysKey, Md5.digest, cbSysKey );
  1382. return ERROR_SUCCESS;
  1383. }
  1384. DWORD
  1385. DsRolepEncryptHash(
  1386. IN OUT PUNICODE_STRING EncryptedSyskey
  1387. )
  1388. /*++
  1389. Routine Description
  1390. This routine is used to store the boot type
  1391. in the registry
  1392. Paramaeters
  1393. NewType Indicates the new boot type
  1394. Return Values
  1395. STATUS_SUCCESS
  1396. STATUS_UNSUCCESSFUL
  1397. --*/
  1398. {
  1399. return ERROR_SUCCESS;
  1400. }