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.

2422 lines
57 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. setutl.c
  5. Abstract:
  6. Miscellaneous helper functions
  7. Author:
  8. Mac McLain (MacM) Feb 10, 1997
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <setpch.h>
  14. #include <dssetp.h>
  15. #include <lsarpc.h>
  16. #include <samrpc.h>
  17. #include <samisrv.h>
  18. #include <db.h>
  19. #include <confname.h>
  20. #include <loadfn.h>
  21. #include <ntdsa.h>
  22. #include <dsconfig.h>
  23. #include <attids.h>
  24. #include <samisrv.h>
  25. #include <dsp.h>
  26. #include <lsaisrv.h>
  27. #include <malloc.h>
  28. #include <dsgetdc.h>
  29. #include <lmcons.h>
  30. #include <lmaccess.h>
  31. #include <lmapibuf.h>
  32. #include <lmerr.h>
  33. #include <netsetp.h>
  34. #include <winsock2.h>
  35. #include <nspapi.h>
  36. #include <dsgetdcp.h>
  37. #include <lmremutl.h>
  38. #include <spmgr.h> // For SetupPhase definition
  39. #include <ntdsetup.h>
  40. #include <shlwapi.h>
  41. #include "threadman.h"
  42. #include "secure.h"
  43. #include "cancel.h"
  44. #if DBG
  45. DEFINE_DEBUG2(DsRole);
  46. DEBUG_KEY DsRoleDebugKeys[] = {
  47. {DEB_ERROR, "Error"},
  48. {DEB_WARN, "Warn"},
  49. {DEB_TRACE, "Trace"},
  50. {DEB_TRACE_DS, "NtDs"},
  51. {DEB_TRACE_UPDATE, "Update"},
  52. {DEB_TRACE_LOCK, "Lock"},
  53. {DEB_TRACE_SERVICES,"Services"},
  54. {DEB_TRACE_NET, "Net"},
  55. {0, NULL }
  56. };
  57. VOID
  58. DsRoleDebugInitialize()
  59. {
  60. DsRoleInitDebug(DsRoleDebugKeys);
  61. }
  62. #endif // DBG
  63. BOOL
  64. DsRolepShutdownNotification(
  65. DWORD dwCtrlType
  66. );
  67. //
  68. // Global data for this module
  69. //
  70. BOOLEAN GlobalOpLockHeld = FALSE;
  71. RPC_STATUS
  72. DsRolepIsLRPC(
  73. void *ctx,
  74. BOOL *fIsLRPC
  75. )
  76. /*++
  77. Routine Description:
  78. Will check to see if the call was made over LRPC or not.
  79. Arguments:
  80. Context - Pointer to an RPC_IF_ID server binding handle representing the client.
  81. Returns:
  82. RPC_S_OK - Success
  83. --*/
  84. {
  85. BOOL fAllowProtocol = FALSE;
  86. BOOL fCorrectEndpoint = FALSE;
  87. PWCHAR pBinding = NULL;
  88. PWCHAR pProtSeq = NULL;
  89. PWCHAR pEndPoint = NULL;
  90. RPC_STATUS rpcErr = RPC_S_OK;
  91. *fIsLRPC = FALSE;
  92. rpcErr = RpcBindingToStringBinding(ctx,
  93. &pBinding);
  94. if (rpcErr != RPC_S_OK)
  95. {
  96. goto Cleanup;
  97. }
  98. // We're only interested in the protocol sequence
  99. // so we can use NULL for all other parameters.
  100. rpcErr = RpcStringBindingParse(pBinding,
  101. NULL,
  102. &pProtSeq,
  103. NULL,
  104. &pEndPoint,
  105. NULL);
  106. if (rpcErr != RPC_S_OK)
  107. {
  108. goto Cleanup;
  109. }
  110. // Check that the client request
  111. // was made using LRPC.
  112. if (_wcsicmp(L"ncalrpc",(LPCTSTR)pProtSeq) == 0)
  113. fAllowProtocol = TRUE;
  114. // Check that the endpoint use was dsrole
  115. if (_wcsicmp(L"dsrole",(LPCTSTR)pEndPoint) == 0)
  116. fCorrectEndpoint = TRUE;
  117. if (fCorrectEndpoint && fAllowProtocol) {
  118. *fIsLRPC = TRUE;
  119. }
  120. Cleanup:
  121. if (pProtSeq)
  122. RpcStringFree(&pProtSeq);
  123. if (pBinding)
  124. RpcStringFree(&pBinding);
  125. if (pEndPoint) {
  126. RpcStringFree(&pEndPoint);
  127. }
  128. return rpcErr;
  129. }
  130. RPC_STATUS
  131. RPC_ENTRY
  132. DsRolepSecurityCallback(
  133. IN RPC_IF_HANDLE *Interface,
  134. IN void *Context
  135. )
  136. /*++
  137. Routine Description:
  138. Security callback for the DsRole APIs. Called from LsaSrv
  139. DsRolerGetDcOperationProgress return init
  140. Arguments:
  141. Interface - UUID and version of the interface.
  142. Context - Pointer to an RPC_IF_ID server binding handle representing the client.
  143. Returns:
  144. RPC_S_OK - Success
  145. --*/
  146. {
  147. DWORD Win32Err = ERROR_SUCCESS;
  148. RPC_STATUS rpcErr = RPC_S_OK;
  149. BOOL fIsLRPC = FALSE;
  150. //
  151. // Check the access of the caller
  152. //
  153. Win32Err = DsRolepCheckCallDsRoleInterfaceAccess();
  154. if ( ERROR_SUCCESS != Win32Err ) {
  155. rpcErr = RPC_S_ACCESS_DENIED;
  156. goto Exit;
  157. }
  158. //
  159. // Check to see that the call came over LRPC
  160. //
  161. rpcErr = DsRolepIsLRPC(Context,
  162. &fIsLRPC);
  163. if ( RPC_S_OK == rpcErr ) {
  164. if(!fIsLRPC)
  165. rpcErr = RPC_S_ACCESS_DENIED;
  166. } else {
  167. goto Exit;
  168. }
  169. Exit:
  170. return rpcErr;
  171. }
  172. VOID
  173. DsRolepRegisterDsRoleInterfaceOnServer(
  174. VOID
  175. )
  176. /*++
  177. Routine Description:
  178. Registers the DsRole interface on Server machines.
  179. Arguments:
  180. VOID
  181. Returns:
  182. VOID
  183. --*/
  184. {
  185. RPC_STATUS RPCError = RPC_S_OK;
  186. NT_PRODUCT_TYPE NtProductType = 0;
  187. if ( RtlGetNtProductType(&NtProductType) ) {
  188. if ( NtProductLanManNt == NtProductType ||
  189. NtProductServer == NtProductType )
  190. {
  191. RPCError = RpcServerRegisterIfEx( dsrole_ServerIfHandle,
  192. NULL,
  193. NULL,
  194. RPC_IF_ALLOW_SECURE_ONLY,
  195. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  196. DsRolepSecurityCallback);
  197. if (RPC_S_OK != RPCError) {
  198. DsRoleDebugOut(( DEB_ERROR,
  199. "RpcServerRegisterIfEx failed %d\n",
  200. RPCError ));
  201. }
  202. RPCError = RpcServerUseProtseqEp(
  203. L"ncalrpc",
  204. RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // max concurrent calls
  205. L"dsrole", // end point
  206. NULL // security descriptor
  207. );
  208. if ( RPCError != RPC_S_OK )
  209. {
  210. DsRoleDebugOut((DEB_ERROR,
  211. "RpcServerUseProtseqEp failed for ncalrpc: %d\n",
  212. RPCError));
  213. }
  214. }
  215. }
  216. }
  217. NTSTATUS
  218. DsRolepInitialize(
  219. VOID
  220. )
  221. /*++
  222. Routine Description:
  223. Initializes the server portion of the DsRole APIs. Called from LsaSrv
  224. DsRolerGetDcOperationProgress return init
  225. Arguments:
  226. VOID
  227. Returns:
  228. STATUS_SUCCESS - Success
  229. --*/
  230. {
  231. NTSTATUS Status = STATUS_SUCCESS;
  232. RPC_STATUS RPCError = RPC_S_OK;
  233. PWSTR KerbPrinc;
  234. //
  235. // Zero out global operation handle
  236. //
  237. RtlZeroMemory( &DsRolepCurrentOperationHandle, sizeof(DsRolepCurrentOperationHandle));
  238. //
  239. // Init the lock
  240. //
  241. RtlInitializeResource( &DsRolepCurrentOperationHandle.CurrentOpLock );
  242. //
  243. // Grab the lock
  244. //
  245. LockOpHandle();
  246. GlobalOpLockHeld = TRUE;
  247. DsRolepResetOperationHandleLockHeld();
  248. DsRoleDebugInitialize();
  249. RPCError = RpcServerRegisterIf( dssetup_ServerIfHandle,
  250. NULL,
  251. NULL );
  252. if (RPC_S_OK != RPCError) {
  253. DsRoleDebugOut(( DEB_ERROR,
  254. "RpcServerRegisterIf failed %d\n",
  255. RPCError ));
  256. }
  257. DsRolepRegisterDsRoleInterfaceOnServer();
  258. DsRolepInitSetupFunctions();
  259. //
  260. // Create the SD's that are used to perform access checks for DsRoler
  261. // callers
  262. //
  263. if ( !DsRolepCreateInterfaceSDs() ) {
  264. return STATUS_NO_MEMORY;
  265. }
  266. try {
  267. Status = RtlInitializeCriticalSection( &LogFileCriticalSection );
  268. } except ( 1 ) {
  269. Status = STATUS_NO_MEMORY;
  270. }
  271. if(NT_SUCCESS(Status)) {
  272. //
  273. // Register our shutdown routine
  274. //
  275. if (!SetConsoleCtrlHandler(DsRolepShutdownNotification, TRUE)) {
  276. DsRoleDebugOut(( DEB_ERROR,
  277. "SetConsoleCtrlHandler failed %d\n",
  278. GetLastError() ));
  279. }
  280. if (!SetProcessShutdownParameters(480, SHUTDOWN_NORETRY)) {
  281. DsRoleDebugOut(( DEB_ERROR,
  282. "SetProcessShutdownParameters failed %d\n",
  283. GetLastError() ));
  284. }
  285. }
  286. return( Status );
  287. }
  288. NTSTATUS
  289. DsRolepInitializePhase2(
  290. VOID
  291. )
  292. /*++
  293. Routine Description:
  294. Second phase of the promotion/demotion api initialization. This initialization is slated
  295. to happen after the Lsa has finished all of it's initializations
  296. Arguments:
  297. VOID
  298. Returns:
  299. STATUS_SUCCESS - Success
  300. STATUS_UNSUCCESSFUL -- The function was called when the global lock wasn't held
  301. --*/
  302. {
  303. ULONG RpcStatus = STATUS_SUCCESS;
  304. PWSTR KerbPrinc;
  305. ASSERT( GlobalOpLockHeld );
  306. if ( !GlobalOpLockHeld ) {
  307. return( STATUS_UNSUCCESSFUL );
  308. }
  309. if ( !SetupPhase ) {
  310. //
  311. // Register the Rpc authenticated server info
  312. //
  313. RpcStatus = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_KERBEROS,
  314. &KerbPrinc);
  315. if ( RpcStatus == RPC_S_OK ) {
  316. DsRoleDebugOut(( DEB_TRACE_DS, "Kerberos Principal name: %ws\n",
  317. KerbPrinc ));
  318. RpcStatus = RpcServerRegisterAuthInfo(KerbPrinc,
  319. RPC_C_AUTHN_GSS_NEGOTIATE,
  320. NULL,
  321. NULL);
  322. RpcStringFree( &KerbPrinc );
  323. } else {
  324. DsRoleDebugOut(( DEB_TRACE_DS, "RpcServerInqDefaultPrincName failed with %lu\n",
  325. RpcStatus ));
  326. RpcStatus = RPC_S_OK;
  327. }
  328. if ( RpcStatus == RPC_S_OK) {
  329. RpcStatus = RpcServerRegisterAuthInfo( DSROLEP_SERVER_PRINCIPAL_NAME,
  330. RPC_C_AUTHN_GSS_NEGOTIATE,
  331. NULL,
  332. NULL );
  333. if ( RpcStatus != RPC_S_OK ) {
  334. DsRoleDebugOut(( DEB_ERROR,
  335. "RpcServerRegisterAuthInfo for %ws failed with 0x%lx\n",
  336. DSROLEP_SERVER_PRINCIPAL_NAME,
  337. RpcStatus ));
  338. RpcStatus = RPC_S_OK;
  339. }
  340. }
  341. }
  342. //
  343. // Release the lock, as was opened in Initialization, phase 1
  344. //
  345. GlobalOpLockHeld = FALSE;
  346. RtlReleaseResource( &DsRolepCurrentOperationHandle.CurrentOpLock );
  347. return( RpcStatus == RPC_S_OK ? STATUS_SUCCESS : RPC_NT_UNKNOWN_AUTHZ_SERVICE );
  348. }
  349. DWORD
  350. DsRolepGetMachineType(
  351. IN OUT PDSROLEP_MACHINE_TYPE MachineType
  352. )
  353. /*++
  354. Routine Description:
  355. Determines the type of machine this is being run on.
  356. Arguments:
  357. MachineType - Where the machine type is being returned
  358. Returns:
  359. STATUS_SUCCESS - Success
  360. --*/
  361. {
  362. DWORD Win32Err = ERROR_SUCCESS;
  363. if ( LsapProductType == NtProductWinNt ) {
  364. *MachineType = DSROLEP_MT_CLIENT;
  365. } else if ( LsapProductType == NtProductServer ) {
  366. *MachineType = DSROLEP_MT_STANDALONE;
  367. } else {
  368. *MachineType = DSROLEP_MT_MEMBER;
  369. }
  370. return( Win32Err );
  371. }
  372. DWORD
  373. DsRolepSetProductType(
  374. IN DSROLEP_MACHINE_TYPE MachineType
  375. )
  376. /*++
  377. Routine Description:
  378. Changes the role of the product to the type specified.
  379. Arguments:
  380. MachineType - Type of ProductRole to set
  381. Returns:
  382. ERROR_SUCCESS - Success
  383. ERROR_INVALID_PARAMETER - A bad service option was given
  384. --*/
  385. {
  386. DWORD Win32Err = ERROR_SUCCESS;
  387. PWSTR MachineSz = NULL;
  388. HKEY ProductHandle;
  389. ULONG Size = 0;
  390. switch ( MachineType ) {
  391. case DSROLEP_MT_STANDALONE:
  392. MachineSz = L"ServerNT";
  393. Size = sizeof( L"ServerNT" );
  394. break;
  395. case DSROLEP_MT_MEMBER:
  396. MachineSz = L"LanmanNT";
  397. Size = sizeof( L"LanmanNT");
  398. break;
  399. case DSROLEP_MT_CLIENT:
  400. default:
  401. Win32Err = ERROR_INVALID_PARAMETER;
  402. break;
  403. }
  404. if ( Win32Err == ERROR_SUCCESS ) {
  405. Win32Err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  406. DSROLEP_PROD_KEY_PATH,
  407. REG_OPTION_NON_VOLATILE,
  408. KEY_WRITE, // desired access
  409. &ProductHandle );
  410. if ( Win32Err == ERROR_SUCCESS ) {
  411. Win32Err = RegSetValueEx( ProductHandle,
  412. (LPCWSTR)DSROLEP_PROD_VALUE,
  413. 0,
  414. REG_SZ,
  415. (CONST BYTE *)MachineSz,
  416. Size );
  417. RegCloseKey( ProductHandle );
  418. }
  419. }
  420. DsRoleDebugOut(( DEB_TRACE_DS, "SetProductType to %ws returned %lu\n",
  421. MachineSz, Win32Err ));
  422. DsRolepLogPrint(( DEB_TRACE,
  423. "SetProductType to %lu [%ws] returned %lu\n",
  424. MachineType,
  425. DsRolepDisplayOptional(MachineSz),
  426. Win32Err ));
  427. DSROLEP_FAIL1( Win32Err, DSROLERES_PRODUCT_TYPE, MachineSz );
  428. return( Win32Err );
  429. }
  430. DWORD
  431. DsRolepCreateAuthIdentForCreds(
  432. IN PWSTR Account,
  433. IN PWSTR Password,
  434. OUT PSEC_WINNT_AUTH_IDENTITY *AuthIdent
  435. )
  436. /*++
  437. Routine Description:
  438. Internal routine to create an AuthIdent structure for the given creditentials
  439. Arguments:
  440. Account - Account name
  441. Password - Password for the account
  442. AuthIdent - AuthIdentity struct to allocate and fill in.
  443. Returns:
  444. ERROR_SUCCESS - Success
  445. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed.
  446. --*/
  447. {
  448. DWORD Win32Err = ERROR_SUCCESS;
  449. PWSTR UserCredentialString = NULL;
  450. ASSERT( AuthIdent );
  451. //
  452. // If there are no creds, just return
  453. //
  454. if ( Account == NULL ) {
  455. *AuthIdent = NULL;
  456. return( Win32Err );
  457. }
  458. *AuthIdent = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( SEC_WINNT_AUTH_IDENTITY ) );
  459. if ( *AuthIdent == NULL ) {
  460. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  461. } else {
  462. RtlZeroMemory( *AuthIdent, sizeof( SEC_WINNT_AUTH_IDENTITY ) );
  463. UserCredentialString = RtlAllocateHeap( RtlProcessHeap(), 0,
  464. ( wcslen( Account ) + 1 ) * sizeof( WCHAR ) );
  465. if ( UserCredentialString ) {
  466. wcscpy( UserCredentialString, Account );
  467. ( *AuthIdent )->User = wcsstr( UserCredentialString, L"\\" );
  468. if ( ( *AuthIdent )->User ) {
  469. //
  470. // There is a domain name
  471. //
  472. *( ( *AuthIdent )->User ) = L'\0';
  473. ( ( *AuthIdent )->User )++;
  474. ( *AuthIdent )->Domain = UserCredentialString;
  475. } else {
  476. ( *AuthIdent )->User = UserCredentialString;
  477. ( *AuthIdent )->Domain = L"";
  478. }
  479. if ( ( *AuthIdent )->User ) {
  480. ( *AuthIdent )->UserLength = wcslen( ( *AuthIdent )->User );
  481. }
  482. if ( ( *AuthIdent )->Domain ) {
  483. ( *AuthIdent )->DomainLength = wcslen( ( *AuthIdent )->Domain );
  484. }
  485. ( *AuthIdent )->Password = Password;
  486. if ( Password ) {
  487. ( *AuthIdent )->PasswordLength = wcslen( Password );
  488. }
  489. ( *AuthIdent )->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  490. } else {
  491. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  492. //
  493. // Free the memory allocated for the top level structure
  494. //
  495. RtlFreeHeap( RtlProcessHeap(), 0, *AuthIdent );
  496. *AuthIdent = NULL;
  497. }
  498. }
  499. return( Win32Err );
  500. }
  501. VOID
  502. DsRolepFreeAuthIdentForCreds(
  503. IN PSEC_WINNT_AUTH_IDENTITY AuthIdent
  504. )
  505. /*++
  506. Routine Description:
  507. Free the authident structure allocated above
  508. Arguments:
  509. AuthIdent - AuthIdentity struct to free
  510. Returns:
  511. VOID
  512. --*/
  513. {
  514. if ( AuthIdent ) {
  515. if ( AuthIdent->Domain == NULL ) {
  516. RtlFreeHeap( RtlProcessHeap(), 0, AuthIdent->User );
  517. } else {
  518. if ( *AuthIdent->Domain != L'\0' ) {
  519. RtlFreeHeap( RtlProcessHeap(), 0, AuthIdent->Domain );
  520. }
  521. }
  522. RtlFreeHeap( RtlProcessHeap(), 0, AuthIdent );
  523. }
  524. }
  525. NTSTATUS
  526. ImpLsaOpenPolicy(
  527. IN HANDLE CallerToken,
  528. IN PLSA_UNICODE_STRING SystemName OPTIONAL,
  529. IN PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
  530. IN ACCESS_MASK DesiredAccess,
  531. IN OUT PLSA_HANDLE PolicyHandle
  532. )
  533. /*++
  534. Routine Description:
  535. This routine impersonates CallerToken and then calls into LsaOpenPolicy.
  536. This purpose of this routine is call into the LSA on a different machine
  537. using the RDR session for the caller of the DsRole API. The caller is
  538. represented by CallerToken. This is necessary because the RDR sessions
  539. are keyed by (logon id/remote server name) and we don't want to use the
  540. logon id of the lsass.exe process since this is a shared logon id for
  541. lsass.exe and services.exe and will lead to unresolable credentials
  542. conflict.
  543. N.B. The LSA rpc calls that follow the (Imp)LsaOpenPolicy will use the
  544. handle returned by this function and then magically uses the right RDR
  545. session to make the RPC call.
  546. Arguments:
  547. CallerToken - the token of the DsRole involker
  548. Others -- see LsaOpenPolicy
  549. Returns:
  550. STATUS_ACCESS_DENIED if the impersonattion fails.
  551. --*/
  552. {
  553. NTSTATUS Status = STATUS_SUCCESS;
  554. BOOL fSuccess;
  555. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  556. if ( fSuccess ) {
  557. Status = LsaOpenPolicy( SystemName,
  558. ObjectAttributes,
  559. DesiredAccess,
  560. PolicyHandle );
  561. fSuccess = RevertToSelf();
  562. ASSERT( fSuccess );
  563. } else {
  564. DsRolepLogPrint(( DEB_TRACE,
  565. "Failed to impersonate caller, error %lu\n",
  566. GetLastError() ));
  567. //
  568. // We couldn't impersonate?
  569. //
  570. Status = STATUS_ACCESS_DENIED;
  571. }
  572. return Status;
  573. }
  574. DWORD
  575. ImpDsRolepDsGetDcForAccount(
  576. IN HANDLE CallerToken,
  577. IN LPWSTR Server OPTIONAL,
  578. IN LPWSTR Domain,
  579. IN LPWSTR Account,
  580. IN ULONG Flags,
  581. IN ULONG AccountBits,
  582. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  583. )
  584. /*++
  585. Routine Description:
  586. This function will impersoniate logged on user and call DsRolepDsGetDcForAccount
  587. Arguments:
  588. CallerToken - The Token of the DsRole involker.
  589. Server - The server to call GetDc on.
  590. Domain - Domain to find the Dc for
  591. Account - Account to look for. If NULL, the current computer name is used
  592. Flags - Flags to bas in to the GetDc call
  593. AccountBits - Account control bits to search for
  594. DomainControllerInfo - Where the info is returned
  595. Returns:
  596. ERROR_SUCCESS - Success
  597. --*/
  598. {
  599. DWORD WinError = ERROR_SUCCESS;
  600. BOOL fSuccess;
  601. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  602. if ( fSuccess ) {
  603. WinError = DsRolepDsGetDcForAccount(Server,
  604. Domain,
  605. Account,
  606. Flags,
  607. AccountBits,
  608. DomainControllerInfo
  609. );
  610. fSuccess = RevertToSelf();
  611. ASSERT( fSuccess );
  612. } else {
  613. DsRolepLogPrint(( DEB_TRACE,
  614. "Failed to impersonate caller, error %lu\n",
  615. GetLastError() ));
  616. //
  617. // We couldn't impersonate?
  618. //
  619. WinError = ERROR_ACCESS_DENIED;
  620. }
  621. return WinError;
  622. }
  623. NET_API_STATUS
  624. NET_API_FUNCTION
  625. ImpNetpManageIPCConnect(
  626. IN HANDLE CallerToken,
  627. IN LPWSTR lpServer,
  628. IN LPWSTR lpAccount,
  629. IN LPWSTR lpPassword,
  630. IN ULONG fOptions
  631. )
  632. /*++
  633. Routine Description:
  634. This routine impersonates CallerToken and then calls into
  635. NetpManageIPCConnect.
  636. This purpose of this routine is to create a RDR using the logon id of
  637. the caller of the DsRole api's. The caller is represented by CallerToken.
  638. This is necessary because the RDR sessions are keyed by
  639. (logon id/remote server name) and we don't want to use the
  640. logon id of the lsass.exe process since this is a shared logon id for
  641. lsass.exe and services.exe and will lead to unresolable credentials
  642. conflict.
  643. Arguments:
  644. CallerToken - the token of the DsRole involker
  645. Others -- see LsaOpenPolicy
  646. Returns:
  647. STATUS_ACCESS_DENIED if the impersonattion fails.
  648. --*/
  649. {
  650. DWORD WinError = ERROR_SUCCESS;
  651. BOOL fSuccess;
  652. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  653. if ( fSuccess ) {
  654. WinError = NetpManageIPCConnect( lpServer,
  655. lpAccount,
  656. lpPassword,
  657. fOptions );
  658. fSuccess = RevertToSelf();
  659. ASSERT( fSuccess );
  660. } else {
  661. DsRolepLogPrint(( DEB_TRACE,
  662. "Failed to impersonate caller, error %lu\n",
  663. GetLastError() ));
  664. //
  665. // We couldn't impersonate?
  666. //
  667. WinError = ERROR_ACCESS_DENIED;
  668. }
  669. return WinError;
  670. }
  671. DWORD
  672. DsRolepGenerateRandomPassword(
  673. IN ULONG Length,
  674. IN WCHAR *Buffer
  675. )
  676. /*++
  677. Routine Description:
  678. This local function is used to generate a random password of no more than the
  679. specified length. It is assumed that the destination buffer is of sufficient length.
  680. Arguments:
  681. Length - Length of the buffer
  682. Buffer - Buffer to fill
  683. Return Values:
  684. ERROR_SUCCESS - Success
  685. --*/
  686. {
  687. DWORD Win32Err = ERROR_SUCCESS;
  688. ULONG PwdLength, i;
  689. LARGE_INTEGER Time;
  690. HCRYPTPROV CryptProvider = 0;
  691. PwdLength = Length;
  692. //
  693. // Generate a random password.
  694. //
  695. if ( CryptAcquireContext( &CryptProvider,
  696. NULL,
  697. NULL,
  698. PROV_RSA_FULL,
  699. CRYPT_VERIFYCONTEXT ) ) {
  700. if ( CryptGenRandom( CryptProvider,
  701. PwdLength * sizeof( WCHAR ),
  702. ( LPBYTE )Buffer ) ) {
  703. Buffer[ PwdLength ] = UNICODE_NULL;
  704. //
  705. // Make sure there are no NULL's in the middle of the list
  706. //
  707. for ( i = 0; i < PwdLength; i++ ) {
  708. if ( Buffer[ i ] == UNICODE_NULL ) {
  709. Buffer[ i ] = 0xe;
  710. }
  711. }
  712. } else {
  713. Win32Err = GetLastError();
  714. }
  715. CryptReleaseContext( CryptProvider, 0 );
  716. } else {
  717. Win32Err = GetLastError();
  718. }
  719. return( Win32Err );
  720. }
  721. DWORD
  722. DsRolepCopyDsDitFiles(
  723. IN LPWSTR DsPath
  724. )
  725. /*++
  726. Routine Description:
  727. This function copies the initial database files from the install point to the
  728. specified Ds database directory
  729. Arguments:
  730. DsPath - Path where the Ds database files are to reside
  731. Returns:
  732. ERROR_SUCCESS - Success
  733. --*/
  734. {
  735. DWORD Win32Err = ERROR_SUCCESS;
  736. WCHAR Source[MAX_PATH + 1];
  737. WCHAR Dest[MAX_PATH + 1];
  738. ULONG SrcLen = 0, DestLen = 0;
  739. PWSTR Current;
  740. ULONG i;
  741. PWSTR DsDitFiles[] = {
  742. L"ntds.dit"
  743. };
  744. ASSERT(wcslen(DsPath) < MAX_PATH);
  745. if( ExpandEnvironmentStrings( L"%WINDIR%\\system32\\", Source, MAX_PATH ) == FALSE ) {
  746. Win32Err = GetLastError();
  747. } else {
  748. SrcLen = wcslen( Source );
  749. wcscpy( Dest, DsPath );
  750. if ( *(Dest + (wcslen( DsPath ) - 1 )) != L'\\' ) {
  751. wcscat( Dest, L"\\" );
  752. }
  753. DestLen = wcslen( Dest );
  754. }
  755. //
  756. // Then, create the destination directory
  757. //
  758. if ( Win32Err == ERROR_SUCCESS ) {
  759. Current = wcschr( DsPath + 4, L'\\' );
  760. while ( Win32Err == ERROR_SUCCESS ) {
  761. if ( Current != NULL ) {
  762. *Current = UNICODE_NULL;
  763. }
  764. if ( CreateDirectory( DsPath, NULL ) == FALSE ) {
  765. Win32Err = GetLastError();
  766. if ( Win32Err == ERROR_ALREADY_EXISTS) {
  767. Win32Err = ERROR_SUCCESS;
  768. } else if ( Win32Err == ERROR_ACCESS_DENIED ) {
  769. if ( PathIsRoot(DsPath) ) {
  770. //If the path given to CreateDirectory is a root path then
  771. //it will fail with ERROR_ACCESS_DENIED instead of
  772. //ERROR_ALREADY_EXISTS but the path is still a valid one for
  773. //ntds.dit and the log files to be placed in.
  774. Win32Err = ERROR_SUCCESS;
  775. }
  776. }
  777. }
  778. if ( Current != NULL ) {
  779. *Current = L'\\';
  780. Current = wcschr( Current + 1, L'\\' );
  781. } else {
  782. break;
  783. }
  784. }
  785. }
  786. //
  787. // Then copy them.
  788. //
  789. for ( i = 0; i < sizeof( DsDitFiles) / sizeof( PWSTR ) && Win32Err == ERROR_SUCCESS ; i++ ) {
  790. //make sure that the last char is a NULL
  791. Source[sizeof(Source)/sizeof(*Source)-1] = L'\0';
  792. Dest[sizeof(Dest)/sizeof(*Dest)-1] = L'\0';
  793. wcsncpy( Source + SrcLen, DsDitFiles[i], sizeof(Source)/sizeof(*Source)-1-SrcLen );
  794. wcsncpy( Dest + DestLen, DsDitFiles[i], sizeof(Dest)/sizeof(*Dest)-1-DestLen );
  795. DSROLEP_CURRENT_OP2( DSROLEEVT_COPY_DIT, Source, Dest );
  796. if ( CopyFile( Source, Dest, TRUE ) == FALSE ) {
  797. Win32Err = GetLastError();
  798. if ( Win32Err == ERROR_ALREADY_EXISTS ||
  799. Win32Err == ERROR_FILE_EXISTS ) {
  800. Win32Err = ERROR_SUCCESS;
  801. } else {
  802. DsRolepLogPrint(( DEB_ERROR, "Failed to copy install file %ws to %ws: %lu\n",
  803. Source, Dest, Win32Err ));
  804. }
  805. }
  806. }
  807. return( Win32Err );
  808. }
  809. #define DSROLEP_SEC_SYSVOL L"SYSVOL"
  810. #define DSROLEP_SEC_DSDIT L"DSDIT"
  811. #define DSROLEP_SEC_DSLOG L"DSLOG"
  812. DWORD
  813. DsRolepSetDcSecurity(
  814. IN HANDLE ClientToken,
  815. IN LPWSTR SysVolRootPath,
  816. IN LPWSTR DsDatabasePath,
  817. IN LPWSTR DsLogPath,
  818. IN BOOLEAN Upgrade,
  819. IN BOOLEAN Replica
  820. )
  821. /*++
  822. Routine Description:
  823. This function will invoke the security editor to set the security on the Dc install files
  824. Arguments:
  825. SysVolRootPath - Root used for the system volume
  826. DsDatabasePath - Path to where the Ds database files go
  827. DsLogPath - Path to where the Ds log files go
  828. Upgrade - If TRUE, the machine is undergoing an upgrade
  829. Replica - If TRUE, the machine is going through an upgrade
  830. Returns:
  831. ERROR_SUCCESS - Success
  832. --*/
  833. {
  834. DWORD Win32Err = ERROR_SUCCESS, i;
  835. PWSTR Paths[ 3 ], Tags[ 3 ];
  836. ULONG Options = 0;
  837. Paths[ 0 ] = SysVolRootPath;
  838. Paths[ 1 ] = DsDatabasePath;
  839. Paths[ 2 ] = DsLogPath;
  840. Tags[ 0 ] = DSROLEP_SEC_SYSVOL;
  841. Tags[ 1 ] = DSROLEP_SEC_DSDIT;
  842. Tags[ 2 ] = DSROLEP_SEC_DSLOG;
  843. //
  844. // Set the environment variables. secedt uses the environment variables to pass around
  845. // information, so we will set the for the duration of this function
  846. //
  847. if ( Win32Err == ERROR_SUCCESS ) {
  848. ASSERT( sizeof( Paths ) / sizeof( PWSTR ) == sizeof( Tags ) / sizeof( PWSTR ) );
  849. for ( i = 0; i < sizeof( Paths ) / sizeof( PWSTR ) && Win32Err == ERROR_SUCCESS; i++ ) {
  850. if ( SetEnvironmentVariable( Tags[ i ], Paths[ i ] ) == FALSE ) {
  851. Win32Err = GetLastError();
  852. DsRolepLogPrint(( DEB_TRACE,
  853. "SetEnvironmentVariable %ws = %ws failed with %lu\n",
  854. Tags[ i ],
  855. Paths[ i ],
  856. Win32Err ));
  857. break;
  858. }
  859. }
  860. }
  861. //
  862. // Now, invoke the security editing code
  863. //
  864. if ( Win32Err == ERROR_SUCCESS ) {
  865. DsRolepSetAndClearLog();
  866. DSROLEP_CURRENT_OP0( DSROLEEVT_SETTING_SECURITY );
  867. Options |= Upgrade ? SCE_PROMOTE_FLAG_UPGRADE : 0;
  868. Options |= Replica ? SCE_PROMOTE_FLAG_REPLICA : 0;
  869. Win32Err = ( *DsrSceDcPromoteSecurityEx )( ClientToken,
  870. Options,
  871. DsRolepStringUpdateCallback );
  872. DsRolepSetAndClearLog();
  873. DsRolepLogOnFailure( Win32Err,
  874. DsRolepLogPrint(( DEB_ERROR,
  875. "Setting security on Dc files failed with %lu\n",
  876. Win32Err )) );
  877. }
  878. //
  879. // Delete the environment variables
  880. //
  881. for ( i = 0; i < sizeof( Paths ) / sizeof( PWSTR ); i++ ) {
  882. if ( SetEnvironmentVariable( Tags[ i ], NULL ) == FALSE ) {
  883. DsRolepLogPrint(( DEB_TRACE,
  884. "SetEnvironmentVariable %ws = NULL failed with %lu\n",
  885. Tags[ i ],
  886. GetLastError() ));
  887. }
  888. }
  889. //
  890. // Currently, setting the security will not cause the promote to fail
  891. //
  892. if ( Win32Err != ERROR_SUCCESS ) {
  893. //
  894. // Raise an event
  895. //
  896. SpmpReportEvent( TRUE,
  897. EVENTLOG_WARNING_TYPE,
  898. DSROLERES_FAIL_SET_SECURITY,
  899. 0,
  900. sizeof( ULONG ),
  901. &Win32Err,
  902. 1,
  903. SCE_DCPROMO_LOG_PATH );
  904. DSROLEP_SET_NON_FATAL_ERROR( Win32Err );
  905. }
  906. Win32Err = ERROR_SUCCESS;
  907. return( Win32Err );
  908. }
  909. DWORD
  910. DsRolepDsGetDcForAccount(
  911. IN LPWSTR Server OPTIONAL,
  912. IN LPWSTR Domain,
  913. IN LPWSTR Account,
  914. IN ULONG Flags,
  915. IN ULONG AccountBits,
  916. OUT PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo
  917. )
  918. /*++
  919. Routine Description:
  920. This function is equivalent to DsGetDcName but will search for the Dc that holds the
  921. specified account.
  922. Arguments:
  923. ReplicaServer - The server to call GetDc on.
  924. Domain - Domain to find the Dc for
  925. Account - Account to look for. If NULL, the current computer name is used
  926. Flags - Flags to bas in to the GetDc call
  927. AccountBits - Account control bits to search for
  928. DomainControllerInfo - Where the info is returned
  929. Returns:
  930. ERROR_SUCCESS - Success
  931. --*/
  932. {
  933. DWORD Win32Err = ERROR_SUCCESS;
  934. WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 2 ];
  935. ULONG Length = MAX_COMPUTERNAME_LENGTH + 1;
  936. //
  937. // If we have no account, use the computer name
  938. //
  939. if ( Account == NULL ) {
  940. if ( GetComputerName( ComputerName, &Length ) == FALSE ) {
  941. Win32Err = GetLastError();
  942. } else {
  943. wcscat( ComputerName, SSI_SECRET_PREFIX );
  944. Account = ComputerName;
  945. }
  946. }
  947. //
  948. // Now, do the find
  949. //
  950. if ( Win32Err == ERROR_SUCCESS ) {
  951. DSROLEP_CURRENT_OP2( DSROLEEVT_FIND_DC_FOR_ACCOUNT, Domain, Account );
  952. Win32Err = DsGetDcNameWithAccountW( Server,
  953. Account,
  954. AccountBits,
  955. Domain,
  956. NULL,
  957. NULL,
  958. Flags,
  959. DomainControllerInfo );
  960. if ( ERROR_NO_SUCH_USER == Win32Err ) {
  961. //
  962. // The error should read "no machine account", not "no user"
  963. // since we are searching for a machine account.
  964. //
  965. Win32Err = ERROR_NO_TRUST_SAM_ACCOUNT;
  966. }
  967. if ( Win32Err == ERROR_SUCCESS ) {
  968. DSROLEP_CURRENT_OP2( DSROLEEVT_FOUND_DC,
  969. ( PWSTR ) ( ( *DomainControllerInfo )->DomainControllerName + 2 ),
  970. Domain );
  971. } else {
  972. DsRolepLogPrint(( DEB_ERROR, "Failed to find a DC for domain %ws: %lu\n",
  973. Domain, Win32Err ));
  974. }
  975. }
  976. return( Win32Err );
  977. }
  978. DWORD
  979. DsRolepSetMachineAccountType(
  980. IN LPWSTR Dc,
  981. IN HANDLE ClientToken,
  982. IN LPWSTR User,
  983. IN LPWSTR Password,
  984. IN LPWSTR AccountName,
  985. IN ULONG AccountBits,
  986. IN OUT WCHAR** AccountDn
  987. )
  988. {
  989. DWORD Win32Err = ERROR_SUCCESS, Win32Err2;
  990. USER_INFO_1 *CurrentUI1;
  991. WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 2 ];
  992. ULONG Length = MAX_COMPUTERNAME_LENGTH + 1;
  993. PSEC_WINNT_AUTH_IDENTITY AuthIdent = NULL;
  994. //
  995. // If we have no account, use the computer name
  996. //
  997. if ( AccountName == NULL ) {
  998. if ( GetComputerName( ComputerName, &Length ) == FALSE ) {
  999. Win32Err = GetLastError();
  1000. } else {
  1001. wcscat( ComputerName, SSI_SECRET_PREFIX );
  1002. AccountName = ComputerName;
  1003. }
  1004. }
  1005. if ( Win32Err == ERROR_SUCCESS ) {
  1006. Win32Err = DsRolepCreateAuthIdentForCreds( User, Password, &AuthIdent );
  1007. }
  1008. //
  1009. // Call the support dll
  1010. //
  1011. if ( Win32Err == ERROR_SUCCESS ) {
  1012. DsRolepLogPrint(( DEB_TRACE, "Searching for the machine account for %ws on %ws...\n",
  1013. AccountName, Dc ));
  1014. DSROLEP_CURRENT_OP0( DSROLEEVT_MACHINE_ACCT );
  1015. DSROLE_GET_SETUP_FUNC( Win32Err, DsrNtdsSetReplicaMachineAccount );
  1016. if ( Win32Err == ERROR_SUCCESS ) {
  1017. if ( Dc && *Dc == L'\\' ) {
  1018. Dc += 2;
  1019. }
  1020. Win32Err = (*DsrNtdsSetReplicaMachineAccount)( AuthIdent,
  1021. ClientToken,
  1022. Dc,
  1023. AccountName,
  1024. AccountBits,
  1025. AccountDn );
  1026. }
  1027. DsRolepLogPrint(( DEB_TRACE, "NtdsSetReplicaMachineAccount returned %d\n", Win32Err ));
  1028. DsRolepFreeAuthIdentForCreds( AuthIdent );
  1029. }
  1030. return( Win32Err );
  1031. }
  1032. DWORD
  1033. DsRolepTimeSyncAndManageIPCConnect(
  1034. IN PVOID vpPromoteArgs,
  1035. IN PWSTR ReplicaServer
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This function forces a time sync with the specified server and will
  1040. Manage the IPC connection
  1041. Arguments:
  1042. PromoteArgs - Args passed to the dsrole api's
  1043. ReplicaServer - The target of the operation
  1044. Returns:
  1045. ERROR_SUCCESS - Success
  1046. --*/
  1047. {
  1048. DWORD WinError = ERROR_SUCCESS;
  1049. PDSROLEP_OPERATION_PROMOTE_ARGS PromoteArgs = (PDSROLEP_OPERATION_PROMOTE_ARGS)vpPromoteArgs;
  1050. //
  1051. // Force the time synch
  1052. //
  1053. DsRolepLogPrint(( DEB_TRACE, "Forcing time sync\n"));
  1054. if ( FLAG_ON( PromoteArgs->Options, DSROLE_DC_FORCE_TIME_SYNC ) ) {
  1055. WinError = DsRolepForceTimeSync( PromoteArgs->ImpersonateToken,
  1056. ReplicaServer );
  1057. if ( ERROR_SUCCESS != WinError ) {
  1058. // the machine object was moved
  1059. DsRolepLogPrint(( DEB_WARN, "Time sync with %ws failed with %d\n",
  1060. ReplicaServer,
  1061. WinError ));
  1062. WinError = ERROR_SUCCESS;
  1063. }
  1064. }
  1065. //
  1066. // Attempt to start a RDR connection because we will need one later on
  1067. //
  1068. RtlRunDecodeUnicodeString( PromoteArgs->Decode, &PromoteArgs->Password );
  1069. WinError = ImpNetpManageIPCConnect( PromoteArgs->ImpersonateToken,
  1070. ReplicaServer,
  1071. PromoteArgs->Account,
  1072. PromoteArgs->Password.Buffer,
  1073. NETSETUPP_CONNECT_IPC );
  1074. RtlRunEncodeUnicodeString( &PromoteArgs->Decode, &PromoteArgs->Password );
  1075. if ( WinError != ERROR_SUCCESS ) {
  1076. DSROLEP_FAIL1( WinError, DSROLERES_NET_USE, ReplicaServer );
  1077. DsRolepLogPrint(( DEB_ERROR,
  1078. "Failed to establish the session with %ws: 0x%lx\n", ReplicaServer,
  1079. WinError ));
  1080. }
  1081. return WinError;
  1082. }
  1083. DWORD
  1084. DsRolepForceTimeSync(
  1085. IN HANDLE ImpToken,
  1086. IN PWSTR TimeSource
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. This function forces a time sync with the specified server
  1091. Arguments:
  1092. TimeSource - Server to use for the time source
  1093. Returns:
  1094. ERROR_SUCCESS - Success
  1095. --*/
  1096. {
  1097. DWORD Win32Err = ERROR_SUCCESS;
  1098. NTSTATUS Status = STATUS_SUCCESS;
  1099. PWSTR ServerName = NULL;
  1100. PTIME_OF_DAY_INFO TOD;
  1101. HANDLE ThreadToken = 0;
  1102. TOKEN_PRIVILEGES Enabled, Previous;
  1103. DWORD PreviousSize;
  1104. TIME_FIELDS TimeFields;
  1105. LARGE_INTEGER SystemTime;
  1106. BOOL connected=FALSE;
  1107. NETRESOURCE NetResource;
  1108. WCHAR *remotename=NULL;
  1109. BOOL fSuccess = FALSE;
  1110. if ( !TimeSource ) {
  1111. Win32Err = ERROR_INVALID_PARAMETER;
  1112. goto cleanup;
  1113. }
  1114. //
  1115. // Build the server name with preceeding \\'s
  1116. //
  1117. if ( *TimeSource != L'\\' ) {
  1118. ServerName = RtlAllocateHeap( RtlProcessHeap(), 0,
  1119. ( wcslen( TimeSource ) + 3 ) * sizeof( WCHAR ) );
  1120. if ( ServerName == NULL ) {
  1121. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  1122. DsRolepLogPrint(( DEB_ERROR, "Failed to open a NULL session with %ws for time sync. Out of Memory. Failed with %d\n",
  1123. TimeSource,
  1124. Win32Err ));
  1125. goto cleanup;
  1126. } else {
  1127. swprintf( ServerName, L"\\\\%ws", TimeSource );
  1128. }
  1129. } else {
  1130. ServerName = TimeSource;
  1131. }
  1132. //
  1133. // Enable the systemtime privilege
  1134. //
  1135. if ( Win32Err == ERROR_SUCCESS ) {
  1136. Status = NtOpenThreadToken( NtCurrentThread(),
  1137. TOKEN_READ | TOKEN_WRITE,
  1138. TRUE,
  1139. &ThreadToken );
  1140. if ( Status == STATUS_NO_TOKEN ) {
  1141. Status = NtOpenProcessToken( NtCurrentProcess(),
  1142. TOKEN_WRITE | TOKEN_READ,
  1143. &ThreadToken );
  1144. }
  1145. if ( NT_SUCCESS( Status ) ) {
  1146. Enabled.PrivilegeCount = 1;
  1147. Enabled.Privileges[0].Luid.LowPart = SE_SYSTEMTIME_PRIVILEGE;
  1148. Enabled.Privileges[0].Luid.HighPart = 0;
  1149. Enabled.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1150. PreviousSize = sizeof( Previous );
  1151. Status = NtAdjustPrivilegesToken( ThreadToken,
  1152. FALSE,
  1153. &Enabled,
  1154. sizeof( Enabled ),
  1155. &Previous,
  1156. &PreviousSize );
  1157. //
  1158. // Since we modified the thread token and the thread is shortlived, we won't bother
  1159. // restoring it later.
  1160. //
  1161. }
  1162. if ( ThreadToken ) {
  1163. NtClose( ThreadToken );
  1164. }
  1165. Win32Err = RtlNtStatusToDosError( Status );
  1166. DsRolepLogOnFailure( Win32Err,
  1167. DsRolepLogPrint(( DEB_ERROR,
  1168. "Failed to enable the SE_SYSTEMTIME_PRIVILEGE: %lu\n",
  1169. Win32Err )) );
  1170. }
  1171. //
  1172. // Get the remote time
  1173. //
  1174. if ( Win32Err == ERROR_SUCCESS ) {
  1175. DSROLEP_CURRENT_OP1( DSROLEEVT_TIMESYNC, TimeSource );
  1176. fSuccess = ImpersonateLoggedOnUser( ImpToken );
  1177. if ( !fSuccess ) {
  1178. DsRolepLogPrint(( DEB_TRACE,
  1179. "Failed to impersonate caller, error %lu\n",
  1180. GetLastError() ));
  1181. //
  1182. // We couldn't impersonate?
  1183. //
  1184. // We will continue anyway
  1185. }
  1186. }
  1187. remotename = RtlAllocateHeap(
  1188. RtlProcessHeap(), 0,
  1189. sizeof(WCHAR)*(wcslen(L"\\ipc$")+wcslen(ServerName)+1));
  1190. if ( remotename == NULL ) {
  1191. Win32Err = ERROR_NOT_ENOUGH_MEMORY;
  1192. DsRolepLogPrint(( DEB_ERROR, "Failed to open a NULL session with %ws for time sync. Out of Memory. Failed with %d\n",
  1193. ServerName,
  1194. Win32Err ));
  1195. }
  1196. wsprintf(remotename,L"%s\\ipc$",ServerName);
  1197. NetResource.dwType=RESOURCETYPE_ANY;
  1198. NetResource.lpLocalName=NULL;
  1199. NetResource.lpRemoteName=remotename;
  1200. NetResource.lpProvider=NULL;
  1201. //get permission to access the server
  1202. Win32Err=WNetAddConnection2W(&NetResource,
  1203. L"",
  1204. L"",
  1205. 0);
  1206. if ( Win32Err == NO_ERROR ) {
  1207. connected=TRUE;
  1208. }
  1209. else {
  1210. DsRolepLogPrint(( DEB_WARN, "Failed to open a NULL session with %ws for time sync. Failed with %d\n",
  1211. ServerName,
  1212. Win32Err ));
  1213. //We will attempt to Time sync anyway
  1214. }
  1215. Win32Err = NetRemoteTOD( ServerName, ( LPBYTE * )&TOD );
  1216. if ( Win32Err == ERROR_SUCCESS ) {
  1217. TimeFields.Hour = ( WORD )TOD->tod_hours;
  1218. TimeFields.Minute = ( WORD )TOD->tod_mins;
  1219. TimeFields.Second = ( WORD )TOD->tod_secs;
  1220. TimeFields.Milliseconds = ( WORD )TOD->tod_hunds * 10;
  1221. TimeFields.Day = ( WORD )TOD->tod_day;
  1222. TimeFields.Month = ( WORD )TOD->tod_month;
  1223. TimeFields.Year = ( WORD )TOD->tod_year;
  1224. if ( !RtlTimeFieldsToTime( &TimeFields, &SystemTime ) ) {
  1225. Status = STATUS_INVALID_PARAMETER;
  1226. } else {
  1227. if ( connected ) {
  1228. WNetCancelConnection2(remotename,
  1229. 0,
  1230. TRUE);
  1231. }
  1232. if( remotename ) {
  1233. RtlFreeHeap( RtlProcessHeap(), 0, remotename );
  1234. }
  1235. fSuccess = RevertToSelf();
  1236. ASSERT( fSuccess );
  1237. connected=FALSE;
  1238. Status = NtSetSystemTime( &SystemTime, NULL );
  1239. if ( !NT_SUCCESS( Status ) ) {
  1240. DsRolepLogPrint(( DEB_ERROR, "NtSetSystemTime failed with 0x%lx\n", Status ));
  1241. }
  1242. }
  1243. Win32Err = RtlNtStatusToDosError( Status );
  1244. NetApiBufferFree( TOD );
  1245. } else {
  1246. DsRolepLogPrint(( DEB_ERROR, "Failed to get the current time on %ws: %lu\n",
  1247. TimeSource, Win32Err ));
  1248. }
  1249. //
  1250. // For the IDS, consider a failure here non-fatal
  1251. //
  1252. if ( Win32Err != ERROR_SUCCESS ) {
  1253. DsRolepLogPrint(( DEB_ERROR, "NON-FATAL error forcing a time sync (%lu). Ignoring\n",
  1254. Win32Err ));
  1255. Win32Err = ERROR_SUCCESS;
  1256. }
  1257. cleanup:
  1258. if ( connected ) {
  1259. WNetCancelConnection2(remotename,
  1260. 0,
  1261. TRUE);
  1262. if( remotename ) {
  1263. RtlFreeHeap( RtlProcessHeap(), 0, remotename );
  1264. }
  1265. fSuccess = RevertToSelf();
  1266. ASSERT( fSuccess );
  1267. }
  1268. return( Win32Err );
  1269. }
  1270. NTSTATUS
  1271. DsRolepGetMixedModeFlags(
  1272. IN PSID DomainSid,
  1273. OUT PULONG Flags
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. This routine will determine whether the machine is currently in mixed mode or not
  1278. Arguments:
  1279. Flags - Pointer to a flags value to be altered. If the machine is a mixed mode, we simply
  1280. or in the proper value.
  1281. Return Values:
  1282. NTSTATUS
  1283. --*/
  1284. {
  1285. NTSTATUS Status = STATUS_SUCCESS;
  1286. BOOLEAN mixedDomain;
  1287. Status = SamIMixedDomain2( DomainSid, &mixedDomain );
  1288. if ( NT_SUCCESS( Status ) && mixedDomain) {
  1289. *Flags |= DSROLE_PRIMARY_DS_MIXED_MODE;
  1290. }
  1291. return( Status );
  1292. }
  1293. BOOL
  1294. DsRolepShutdownNotification(
  1295. DWORD dwCtrlType
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. This routine is called by the system when system shutdown is occuring.
  1300. It stops a role change if one is in progress.
  1301. Arguments:
  1302. dwCtrlType -- the notification
  1303. Return Value:
  1304. FALSE - to allow any other shutdown routines in this process to
  1305. also be called.
  1306. --*/
  1307. {
  1308. if ( dwCtrlType == CTRL_SHUTDOWN_EVENT ) {
  1309. //
  1310. // Cancel the operation
  1311. //
  1312. (VOID) DsRolepCancel( FALSE ); // Don't block
  1313. }
  1314. return FALSE;
  1315. }
  1316. DWORD
  1317. DsRolepDeregisterNetlogonDnsRecords(
  1318. PNTDS_DNS_RR_INFO pInfo
  1319. )
  1320. /*++
  1321. Routine Description:
  1322. This routine is called during demotion to call netlogon to deregister
  1323. its the service DNS records for this domain controller
  1324. Arguments:
  1325. pInfo -- structure containing the parameters for the deregistration
  1326. Return Value:
  1327. An error from DsDeregisterDnsHostRecordsW
  1328. --*/
  1329. {
  1330. DWORD WinError = ERROR_SUCCESS;
  1331. HKEY hNetlogonParms = NULL;
  1332. BOOL fDoDeregistration = TRUE;
  1333. if ( !pInfo ) {
  1334. return STATUS_SUCCESS;
  1335. }
  1336. #define NETLOGON_PATH L"SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters"
  1337. #define AVOID_DNS_DEREG_KEY L"AvoidDnsDeregOnShutdown"
  1338. WinError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1339. NETLOGON_PATH,
  1340. 0,
  1341. KEY_READ,
  1342. &hNetlogonParms );
  1343. if ( ERROR_SUCCESS == WinError ) {
  1344. DWORD val = 0;
  1345. DWORD len = sizeof(DWORD);
  1346. DWORD type;
  1347. WinError = RegQueryValueEx( hNetlogonParms,
  1348. AVOID_DNS_DEREG_KEY,
  1349. 0,
  1350. &type,
  1351. (BYTE*)&val,
  1352. &len );
  1353. if ( (ERROR_SUCCESS == WinError)
  1354. && (type == REG_DWORD)
  1355. && (val == 0) ) {
  1356. //
  1357. // Don't bother; netlogon has already done the deregistration.
  1358. //
  1359. fDoDeregistration = FALSE;
  1360. }
  1361. RegCloseKey( hNetlogonParms );
  1362. }
  1363. if ( fDoDeregistration ) {
  1364. //
  1365. // Ask netlogon to do the deregistration
  1366. //
  1367. WinError = DsDeregisterDnsHostRecordsW( NULL, // go local
  1368. pInfo->DnsDomainName,
  1369. &pInfo->DomainGuid,
  1370. &pInfo->DsaGuid,
  1371. pInfo->DnsHostName );
  1372. } else {
  1373. WinError = ERROR_SUCCESS;
  1374. }
  1375. return WinError;
  1376. }
  1377. NTSTATUS
  1378. ImpLsaDelete(
  1379. IN HANDLE CallerToken,
  1380. IN LSA_HANDLE ObjectHandle
  1381. )
  1382. /*++
  1383. Routine Description:
  1384. This routine is a wrapper for the Lsa call. See The comments for
  1385. ImpOpenLsaPolicy for details.
  1386. --*/
  1387. {
  1388. NTSTATUS Status = STATUS_SUCCESS;
  1389. BOOL fSuccess;
  1390. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1391. if ( fSuccess ) {
  1392. Status = LsaDelete( ObjectHandle );
  1393. fSuccess = RevertToSelf();
  1394. ASSERT( fSuccess );
  1395. } else {
  1396. DsRolepLogPrint(( DEB_TRACE,
  1397. "Failed to impersonate caller, error %lu\n",
  1398. GetLastError() ));
  1399. //
  1400. // We couldn't impersonate?
  1401. //
  1402. Status = STATUS_ACCESS_DENIED;
  1403. }
  1404. return Status;
  1405. }
  1406. NTSTATUS
  1407. ImpLsaQueryInformationPolicy(
  1408. IN HANDLE CallerToken,
  1409. IN LSA_HANDLE PolicyHandle,
  1410. IN POLICY_INFORMATION_CLASS InformationClass,
  1411. OUT PVOID *Buffer
  1412. )
  1413. /*++
  1414. Routine Description:
  1415. This routine is a wrapper for the Lsa call. See The comments for
  1416. ImpOpenLsaPolicy for details.
  1417. --*/
  1418. {
  1419. NTSTATUS Status = STATUS_SUCCESS;
  1420. BOOL fSuccess;
  1421. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1422. if ( fSuccess ) {
  1423. Status = LsaQueryInformationPolicy( PolicyHandle,
  1424. InformationClass,
  1425. Buffer );
  1426. fSuccess = RevertToSelf();
  1427. ASSERT( fSuccess );
  1428. } else {
  1429. DsRolepLogPrint(( DEB_TRACE,
  1430. "Failed to impersonate caller, error %lu\n",
  1431. GetLastError() ));
  1432. //
  1433. // We couldn't impersonate?
  1434. //
  1435. Status = STATUS_ACCESS_DENIED;
  1436. }
  1437. return Status;
  1438. }
  1439. NTSTATUS
  1440. ImpLsaOpenTrustedDomainByName(
  1441. IN HANDLE CallerToken,
  1442. IN LSA_HANDLE PolicyHandle,
  1443. IN PLSA_UNICODE_STRING TrustedDomainName,
  1444. IN ACCESS_MASK DesiredAccess,
  1445. OUT PLSA_HANDLE TrustedDomainHandle
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. This routine is a wrapper for the Lsa call. See The comments for
  1450. ImpOpenLsaPolicy for details.
  1451. --*/
  1452. {
  1453. NTSTATUS Status = STATUS_SUCCESS;
  1454. BOOL fSuccess;
  1455. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1456. if ( fSuccess ) {
  1457. Status = LsaOpenTrustedDomainByName( PolicyHandle,
  1458. TrustedDomainName,
  1459. DesiredAccess,
  1460. TrustedDomainHandle );
  1461. fSuccess = RevertToSelf();
  1462. ASSERT( fSuccess );
  1463. } else {
  1464. DsRolepLogPrint(( DEB_TRACE,
  1465. "Failed to impersonate caller, error %lu\n",
  1466. GetLastError() ));
  1467. //
  1468. // We couldn't impersonate?
  1469. //
  1470. Status = STATUS_ACCESS_DENIED;
  1471. }
  1472. return Status;
  1473. }
  1474. NTSTATUS
  1475. ImpLsaOpenTrustedDomain(
  1476. IN HANDLE CallerToken,
  1477. IN LSA_HANDLE PolicyHandle,
  1478. IN PSID TrustedDomainSid,
  1479. IN ACCESS_MASK DesiredAccess,
  1480. OUT PLSA_HANDLE TrustedDomainHandle
  1481. )
  1482. /*++
  1483. Routine Description:
  1484. This routine is a wrapper for the Lsa call. See The comments for
  1485. ImpOpenLsaPolicy for details.
  1486. --*/
  1487. {
  1488. NTSTATUS Status = STATUS_SUCCESS;
  1489. BOOL fSuccess;
  1490. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1491. if ( fSuccess ) {
  1492. Status = LsaOpenTrustedDomain( PolicyHandle,
  1493. TrustedDomainSid,
  1494. DesiredAccess,
  1495. TrustedDomainHandle );
  1496. fSuccess = RevertToSelf();
  1497. ASSERT( fSuccess );
  1498. } else {
  1499. DsRolepLogPrint(( DEB_TRACE,
  1500. "Failed to impersonate caller, error %lu\n",
  1501. GetLastError() ));
  1502. //
  1503. // We couldn't impersonate?
  1504. //
  1505. Status = STATUS_ACCESS_DENIED;
  1506. }
  1507. return Status;
  1508. }
  1509. NTSTATUS
  1510. ImpLsaCreateTrustedDomainEx(
  1511. IN HANDLE CallerToken,
  1512. IN LSA_HANDLE PolicyHandle,
  1513. IN PTRUSTED_DOMAIN_INFORMATION_EX TrustedDomainInformation,
  1514. IN PTRUSTED_DOMAIN_AUTH_INFORMATION AuthenticationInformation,
  1515. IN ACCESS_MASK DesiredAccess,
  1516. OUT PLSA_HANDLE TrustedDomainHandle
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. This routine is a wrapper for the Lsa call. See The comments for
  1521. ImpOpenLsaPolicy for details.
  1522. --*/
  1523. {
  1524. NTSTATUS Status = STATUS_SUCCESS;
  1525. BOOL fSuccess;
  1526. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1527. if ( fSuccess ) {
  1528. Status = LsaCreateTrustedDomainEx( PolicyHandle,
  1529. TrustedDomainInformation,
  1530. AuthenticationInformation,
  1531. DesiredAccess,
  1532. TrustedDomainHandle );
  1533. fSuccess = RevertToSelf();
  1534. ASSERT( fSuccess );
  1535. } else {
  1536. DsRolepLogPrint(( DEB_TRACE,
  1537. "Failed to impersonate caller, error %lu\n",
  1538. GetLastError() ));
  1539. //
  1540. // We couldn't impersonate?
  1541. //
  1542. Status = STATUS_ACCESS_DENIED;
  1543. }
  1544. return Status;
  1545. }
  1546. NTSTATUS
  1547. ImpLsaQueryTrustedDomainInfoByName(
  1548. IN HANDLE CallerToken,
  1549. IN LSA_HANDLE PolicyHandle,
  1550. IN PLSA_UNICODE_STRING TrustedDomainName,
  1551. IN TRUSTED_INFORMATION_CLASS InformationClass,
  1552. OUT PVOID *Buffer
  1553. )
  1554. /*++
  1555. Routine Description:
  1556. This routine is a wrapper for the Lsa call. See The comments for
  1557. ImpOpenLsaPolicy for details.
  1558. --*/
  1559. {
  1560. NTSTATUS Status = STATUS_SUCCESS;
  1561. BOOL fSuccess;
  1562. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1563. if ( fSuccess ) {
  1564. Status = LsaQueryTrustedDomainInfoByName( PolicyHandle,
  1565. TrustedDomainName,
  1566. InformationClass,
  1567. Buffer );
  1568. fSuccess = RevertToSelf();
  1569. ASSERT( fSuccess );
  1570. } else {
  1571. DsRolepLogPrint(( DEB_TRACE,
  1572. "Failed to impersonate caller, error %lu\n",
  1573. GetLastError() ));
  1574. //
  1575. // We couldn't impersonate?
  1576. //
  1577. Status = STATUS_ACCESS_DENIED;
  1578. }
  1579. return Status;
  1580. }
  1581. NTSTATUS
  1582. ImpLsaQueryInfoTrustedDomain(
  1583. IN HANDLE CallerToken,
  1584. IN LSA_HANDLE TrustedDomain,
  1585. IN TRUSTED_INFORMATION_CLASS InformationClass,
  1586. OUT PVOID *Buffer
  1587. )
  1588. /*++
  1589. Routine Description:
  1590. This routine is a wrapper for the Lsa call. See The comments for
  1591. ImpOpenLsaPolicy for details.
  1592. --*/
  1593. {
  1594. NTSTATUS Status = STATUS_SUCCESS;
  1595. BOOL fSuccess;
  1596. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1597. if ( fSuccess ) {
  1598. Status = LsaQueryInfoTrustedDomain( TrustedDomain,
  1599. InformationClass,
  1600. Buffer );
  1601. fSuccess = RevertToSelf();
  1602. ASSERT( fSuccess );
  1603. } else {
  1604. DsRolepLogPrint(( DEB_TRACE,
  1605. "Failed to impersonate caller, error %lu\n",
  1606. GetLastError() ));
  1607. //
  1608. // We couldn't impersonate?
  1609. //
  1610. Status = STATUS_ACCESS_DENIED;
  1611. }
  1612. return Status;
  1613. }
  1614. NTSTATUS
  1615. ImpLsaQueryDomainInformationPolicy(
  1616. IN HANDLE CallerToken,
  1617. IN LSA_HANDLE PolicyHandle,
  1618. IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass,
  1619. OUT PVOID *Buffer
  1620. )
  1621. /*++
  1622. Routine Description:
  1623. This routine is a wrapper for the Lsa call. See The comments for
  1624. ImpOpenLsaPolicy for details.
  1625. --*/
  1626. {
  1627. NTSTATUS Status = STATUS_SUCCESS;
  1628. BOOL fSuccess;
  1629. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1630. if ( fSuccess ) {
  1631. Status = LsaQueryDomainInformationPolicy( PolicyHandle,
  1632. InformationClass,
  1633. Buffer );
  1634. fSuccess = RevertToSelf();
  1635. ASSERT( fSuccess );
  1636. } else {
  1637. DsRolepLogPrint(( DEB_TRACE,
  1638. "Failed to impersonate caller, error %lu\n",
  1639. GetLastError() ));
  1640. //
  1641. // We couldn't impersonate?
  1642. //
  1643. Status = STATUS_ACCESS_DENIED;
  1644. }
  1645. return Status;
  1646. }
  1647. NTSTATUS
  1648. ImpLsaClose(
  1649. IN HANDLE CallerToken,
  1650. IN LSA_HANDLE ObjectHandle
  1651. )
  1652. /*++
  1653. Routine Description:
  1654. This routine is a wrapper for the Lsa call. See The comments for
  1655. ImpOpenLsaPolicy for details.
  1656. --*/
  1657. {
  1658. NTSTATUS Status = STATUS_SUCCESS;
  1659. BOOL fSuccess;
  1660. fSuccess = ImpersonateLoggedOnUser( CallerToken );
  1661. if ( fSuccess ) {
  1662. Status = LsaClose( ObjectHandle );
  1663. fSuccess = RevertToSelf();
  1664. ASSERT( fSuccess );
  1665. } else {
  1666. DsRolepLogPrint(( DEB_TRACE,
  1667. "Failed to impersonate caller, error %lu\n",
  1668. GetLastError() ));
  1669. //
  1670. // We couldn't impersonate?
  1671. //
  1672. Status = STATUS_ACCESS_DENIED;
  1673. }
  1674. return Status;
  1675. }