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.

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