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.

781 lines
21 KiB

  1. /*++
  2. Copyright (c) 1987-1996 Microsoft Corporation
  3. Module Name:
  4. ftinfo.c
  5. Abstract:
  6. Utilities routine to manage the forest trust info list
  7. Author:
  8. 27-Jul-00 (cliffv)
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. //
  16. // Common include files.
  17. //
  18. #include "logonsrv.h" // Include files common to entire service
  19. #pragma hdrstop
  20. #include <ftnfoctx.h>
  21. NTSTATUS
  22. NlpUpdateFtinfo(
  23. IN PDOMAIN_INFO DomainInfo,
  24. IN LPWSTR TrustedDomainName,
  25. IN BOOLEAN ImpersonateCaller,
  26. IN PLSA_FOREST_TRUST_INFORMATION NewForestTrustInfo
  27. )
  28. /*++
  29. Routine Description:
  30. This function write the specified NewForestTrustInfo onto the named TDO.
  31. The NewForestTrustInfo is merged with the exsiting information using the following algorithm:
  32. The FTinfo records written are described in the NetpMergeFTinfo routine.
  33. Arguments:
  34. DomainInfo - Hosted Domain that trusts the domain to query.
  35. TrustedDomainName - Trusted domain that is to be updated. This domain must have the
  36. TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set.
  37. ImpersonateCaller - TRUE if the caller is to be impersonated.
  38. FALSE, if the trusted policy handle should be used to write the local LSA.
  39. NewForestTrustInfo - Specified the new array of FTinfo records as returned from the
  40. trusted domain.
  41. Return Value:
  42. STATUS_SUCCESS: Success.
  43. --*/
  44. {
  45. NTSTATUS Status;
  46. LSAPR_HANDLE PolicyHandle = NULL;
  47. UNICODE_STRING TrustedDomainNameString;
  48. //
  49. // Open a handle to the LSA.
  50. //
  51. if ( ImpersonateCaller ) {
  52. OBJECT_ATTRIBUTES ObjectAttributes;
  53. //
  54. // Get some handle to LSA. Note that this
  55. // handle will not be trusted even though
  56. // we open it as LocalSystem.
  57. //
  58. InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
  59. Status = LsarOpenPolicy( NULL, // local server
  60. (PLSAPR_OBJECT_ATTRIBUTES) &ObjectAttributes,
  61. POLICY_TRUST_ADMIN,
  62. &PolicyHandle );
  63. if ( !NT_SUCCESS(Status) ) {
  64. NlPrint(( NL_CRITICAL,
  65. "NlpUpdateTdo: %ws: Cannot LsarOpenPolicy 0x%lx\n",
  66. TrustedDomainName,
  67. Status ));
  68. goto Cleanup;
  69. }
  70. } else {
  71. PolicyHandle = DomainInfo->DomLsaPolicyHandle;
  72. }
  73. //
  74. // Set FTINFO
  75. //
  76. // Note that, if ImpersonateCaller is TRUE, the handle
  77. // we pass is not trusted. In this case, the LSA will
  78. // impersonate the caller and do the access check.
  79. //
  80. RtlInitUnicodeString( &TrustedDomainNameString, TrustedDomainName );
  81. Status = LsaIUpdateForestTrustInformation(
  82. PolicyHandle,
  83. &TrustedDomainNameString,
  84. NewForestTrustInfo
  85. );
  86. if ( !NT_SUCCESS( Status )) {
  87. goto Cleanup;
  88. }
  89. Cleanup:
  90. if ( PolicyHandle != NULL ) {
  91. if ( ImpersonateCaller ) {
  92. (VOID) LsarClose( &PolicyHandle );
  93. }
  94. }
  95. return Status;
  96. }
  97. NTSTATUS
  98. NlpGetForestTrustInfoHigher(
  99. IN PCLIENT_SESSION ClientSession,
  100. IN DWORD Flags,
  101. IN BOOLEAN ImpersonateCaller,
  102. IN BOOLEAN SessionAlreadyAuthenticated,
  103. OUT PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo
  104. )
  105. /*++
  106. Routine Description:
  107. This function is the client side stub for getting the forest trust info from a
  108. trusted forest.
  109. Arguments:
  110. ClientSession - Trusted domain that is to be queried. This domain must have the
  111. TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set.
  112. Flags - Specifies a set of bits that modify the behavior of the API.
  113. Valid bits are:
  114. DS_GFTI_UPDATE_TDO - If this bit is set, the API will update
  115. the FTinfo attribute of the TDO named by the ClientSession
  116. parameter.
  117. The caller must have access to modify the FTinfo attribute or
  118. ERROR_ACCESS_DENIED will be returned. The algorithm describing
  119. how the FTinfo from the trusted domain is merged with the FTinfo
  120. from the TDO is described below.
  121. This bit in only valid if ServerName specifies the PDC of its domain.
  122. ImpersonateCaller - TRUE if the caller is to be impersonated.
  123. FALSE, if the trusted policy handle should be used to write the local LSA.
  124. SessionAlreadyAuthenticated - If TRUE, the caller already authenticated
  125. the session, so there is no need to check or to reauthenticate.
  126. ForestTrustInfo - Returns a pointer to a structure containing a count and an
  127. array of FTInfo records describing the namespaces claimed by the
  128. domain specified by ClientSession. The Accepted field and Time
  129. field of all returned records will be zero. The buffer should be freed
  130. by calling NetApiBufferFree.
  131. Return Value:
  132. STATUS_SUCCESS: Message successfully sent
  133. --*/
  134. {
  135. NTSTATUS Status = STATUS_SUCCESS;
  136. NETLOGON_AUTHENTICATOR OurAuthenticator;
  137. NETLOGON_AUTHENTICATOR ReturnAuthenticator;
  138. SESSION_INFO SessionInfo;
  139. BOOLEAN FirstTry = TRUE;
  140. NlAssert( ClientSession->CsReferenceCount > 0 );
  141. NlAssert( ClientSession->CsFlags & CS_WRITER );
  142. //
  143. // Only allow TDO update on the PDC.
  144. //
  145. if ( (Flags & DS_GFTI_UPDATE_TDO) != 0 &&
  146. ClientSession->CsDomainInfo->DomRole != RolePrimary ) {
  147. Status = STATUS_BACKUP_CONTROLLER;
  148. goto Cleanup;
  149. }
  150. //
  151. // Ensure the F bit is set.
  152. //
  153. if ( (ClientSession->CsTrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE) == 0 ) {
  154. NlPrintCs((NL_CRITICAL, ClientSession,
  155. "NlpGetForestTrustInfoHigher: trust isn't marked as cross forest trust: 0x%lX\n",
  156. ClientSession->CsTrustAttributes ));
  157. Status = STATUS_NO_SUCH_DOMAIN;
  158. goto Cleanup;
  159. }
  160. //
  161. // If the session isn't authenticated,
  162. // do so now.
  163. //
  164. FirstTryFailed:
  165. if ( !SessionAlreadyAuthenticated ) {
  166. Status = NlEnsureSessionAuthenticated( ClientSession, 0 );
  167. if ( !NT_SUCCESS(Status) ) {
  168. goto Cleanup;
  169. }
  170. }
  171. SessionInfo.SessionKey = ClientSession->CsSessionKey;
  172. SessionInfo.NegotiatedFlags = ClientSession->CsNegotiatedFlags;
  173. //
  174. // If the DC doesn't support the new function,
  175. // fail now.
  176. //
  177. if ( (SessionInfo.NegotiatedFlags & NETLOGON_SUPPORTS_CROSS_FOREST) == 0 ) {
  178. NlPrintCs((NL_CRITICAL, ClientSession,
  179. "NlpGetForestTrustInfoHigher: remote DC doesn't support this function.\n" ));
  180. Status = STATUS_NOT_SUPPORTED;
  181. goto Cleanup;
  182. }
  183. //
  184. // Build the Authenticator for this request to the PDC.
  185. //
  186. NlBuildAuthenticator(
  187. &ClientSession->CsAuthenticationSeed,
  188. &ClientSession->CsSessionKey,
  189. &OurAuthenticator);
  190. //
  191. // Remote the request to the trusted DC.
  192. //
  193. NL_API_START( Status, ClientSession, TRUE ) {
  194. NlAssert( ClientSession->CsUncServerName != NULL );
  195. Status = I_NetGetForestTrustInformation(
  196. ClientSession->CsUncServerName,
  197. ClientSession->CsDomainInfo->DomUnicodeComputerNameString.Buffer,
  198. &OurAuthenticator,
  199. &ReturnAuthenticator,
  200. 0, // No flags yet
  201. ForestTrustInfo );
  202. if ( !NT_SUCCESS(Status) ) {
  203. NlPrintRpcDebug( "I_NetGetForestTrustInformation", Status );
  204. }
  205. // NOTE: This call may drop the secure channel behind our back
  206. } NL_API_ELSE( Status, ClientSession, TRUE ) {
  207. //
  208. // We might have been called from NlSessionSetup,
  209. // So we have to indicate the failure to our caller.
  210. //
  211. if ( NT_SUCCESS(Status) ) {
  212. Status = ClientSession->CsConnectionStatus;
  213. goto Cleanup;
  214. }
  215. } NL_API_END;
  216. //
  217. // Now verify authenticator and update our seed
  218. //
  219. if ( NlpDidDcFail( Status ) ||
  220. !NlUpdateSeed( &ClientSession->CsAuthenticationSeed,
  221. &ReturnAuthenticator.Credential,
  222. &ClientSession->CsSessionKey) ) {
  223. NlPrintCs(( NL_CRITICAL, ClientSession,
  224. "NlpDidDcFail: denying access after status: 0x%lx\n",
  225. Status ));
  226. //
  227. // Preserve any status indicating a communication error.
  228. //
  229. if ( NT_SUCCESS(Status) ) {
  230. Status = STATUS_ACCESS_DENIED;
  231. }
  232. NlSetStatusClientSession( ClientSession, Status );
  233. //
  234. // Perhaps the netlogon service on the server has just restarted.
  235. // Try just once to set up a session to the server again.
  236. // However, if the caller set up the session, there is
  237. // no need for a new session setup.
  238. //
  239. if ( FirstTry && !SessionAlreadyAuthenticated ) {
  240. FirstTry = FALSE;
  241. goto FirstTryFailed;
  242. }
  243. }
  244. //
  245. // Handle failures
  246. //
  247. if ( !NT_SUCCESS(Status) ) {
  248. goto Cleanup;
  249. }
  250. //
  251. // Handle updating the FTINFO on the TDO
  252. //
  253. if ( (Flags & DS_GFTI_UPDATE_TDO) != 0 ) {
  254. LOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  255. Status = NlpUpdateFtinfo( ClientSession->CsDomainInfo,
  256. ClientSession->CsDnsDomainName.Buffer,
  257. ImpersonateCaller,
  258. *ForestTrustInfo );
  259. if ( !NT_SUCCESS(Status) ) {
  260. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  261. goto Cleanup;
  262. }
  263. //
  264. // Set the FTInfo refresh timestamp
  265. //
  266. NlQuerySystemTime( &ClientSession->CsLastFtInfoRefreshTime );
  267. UNLOCK_TRUST_LIST( ClientSession->CsDomainInfo );
  268. }
  269. Status = STATUS_SUCCESS;
  270. //
  271. // Common exit
  272. //
  273. Cleanup:
  274. if ( !NT_SUCCESS(Status) ) {
  275. NlPrintCs((NL_CRITICAL, ClientSession,
  276. "NlpGetForestTrustInfoHigher: failed %lX\n",
  277. Status));
  278. }
  279. return Status;
  280. }
  281. NET_API_STATUS
  282. DsrGetForestTrustInformation (
  283. IN LPWSTR ServerName OPTIONAL,
  284. IN LPWSTR TrustedDomainName OPTIONAL,
  285. IN ULONG Flags,
  286. OUT PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo
  287. )
  288. /*++
  289. Routine Description:
  290. This is the server side stub for DsGetForestTrustInformationW. See that routine
  291. for documentation.
  292. Arguments:
  293. See DsGetForestTrustInformationW
  294. Return Value:
  295. See DsGetForestTrustInformationW
  296. --*/
  297. {
  298. NET_API_STATUS NetStatus;
  299. PDOMAIN_INFO DomainInfo = NULL;
  300. PCLIENT_SESSION ClientSession = NULL;
  301. BOOLEAN AmWriter = FALSE;
  302. //
  303. // Perform access validation on the caller
  304. //
  305. NetStatus = NetpAccessCheck(
  306. NlGlobalNetlogonSecurityDescriptor, // Security descriptor
  307. NETLOGON_FTINFO_ACCESS, // Desired access
  308. &NlGlobalNetlogonInfoMapping ); // Generic mapping
  309. if ( NetStatus != NERR_Success) {
  310. NetStatus = ERROR_ACCESS_DENIED;
  311. goto Cleanup;
  312. }
  313. //
  314. // This API is not supported on workstations.
  315. //
  316. if ( NlGlobalMemberWorkstation ) {
  317. NetStatus = ERROR_NOT_SUPPORTED;
  318. goto Cleanup;
  319. }
  320. //
  321. // Validate the Flags parameter
  322. //
  323. if ((Flags & ~DS_GFTI_VALID_FLAGS) != 0 ) {
  324. NetStatus = ERROR_INVALID_FLAGS;
  325. goto Cleanup;
  326. }
  327. //
  328. // Find the referenced domain
  329. //
  330. DomainInfo = NlFindDomainByServerName( ServerName ); // Primary domain
  331. if ( DomainInfo == NULL ) {
  332. // Default to primary domain to handle the case where the ComputerName
  333. // is an IP address.
  334. DomainInfo = NlFindNetbiosDomain( NULL, TRUE );
  335. if ( DomainInfo == NULL ) {
  336. NetStatus = ERROR_INVALID_COMPUTERNAME;
  337. goto Cleanup;
  338. }
  339. }
  340. NlPrintDom((NL_SESSION_SETUP, DomainInfo,
  341. "DsrGetForestTrustInformation: %ws called: 0x%lx\n", TrustedDomainName, Flags ));
  342. //
  343. // Get the ForestTrustInformation for a particular TDO
  344. //
  345. if ( TrustedDomainName != NULL &&
  346. *TrustedDomainName != L'\0' ) {
  347. NTSTATUS Status;
  348. UNICODE_STRING TrustedDomainNameString;
  349. //
  350. // Only allow TDO update on the PDC.
  351. //
  352. if ( (Flags & DS_GFTI_UPDATE_TDO) != 0 &&
  353. DomainInfo->DomRole != RolePrimary ) {
  354. NetStatus = NERR_NotPrimary;
  355. goto Cleanup;
  356. }
  357. //
  358. // Find the client session to the trusted domain.
  359. //
  360. RtlInitUnicodeString(&TrustedDomainNameString, TrustedDomainName );
  361. ClientSession = NlFindNamedClientSession( DomainInfo,
  362. &TrustedDomainNameString,
  363. NL_DIRECT_TRUST_REQUIRED,
  364. NULL );
  365. if( ClientSession == NULL ) {
  366. NlPrintDom((NL_CRITICAL, DomainInfo,
  367. "DsrGetForestTrustInformation: %ws: can't find the client structure of the domain specified.\n",
  368. TrustedDomainName ));
  369. NetStatus = ERROR_NO_SUCH_DOMAIN;
  370. goto Cleanup;
  371. }
  372. //
  373. // Become a Writer of the ClientSession.
  374. //
  375. if ( !NlTimeoutSetWriterClientSession( ClientSession, WRITER_WAIT_PERIOD ) ) {
  376. NlPrintCs((NL_CRITICAL, ClientSession,
  377. "NlpGetForestTrustInfoHigher: Can't become writer of client session.\n" ));
  378. Status = STATUS_NO_LOGON_SERVERS;
  379. goto Cleanup;
  380. }
  381. AmWriter = TRUE;
  382. //
  383. // Call the DC in the trusted domain.
  384. //
  385. Status = NlpGetForestTrustInfoHigher( ClientSession,
  386. Flags,
  387. TRUE, // Impersonate caller
  388. FALSE, // We didn't set up the session
  389. ForestTrustInfo );
  390. if ( !NT_SUCCESS(Status ) ) {
  391. NetStatus = NetpNtStatusToApiStatus( Status );
  392. goto Cleanup;
  393. }
  394. //
  395. // Get the local ForestTrustInformation.
  396. //
  397. } else {
  398. NTSTATUS Status;
  399. //
  400. // Don't allow an Update TDO request if there is no TDO.
  401. //
  402. if ( Flags & DS_GFTI_UPDATE_TDO ) {
  403. NetStatus = ERROR_INVALID_FLAGS;
  404. goto Cleanup;
  405. }
  406. //
  407. // Simply grab the local ForestTrustInformation
  408. //
  409. Status = LsaIGetForestTrustInformation( ForestTrustInfo );
  410. if ( !NT_SUCCESS( Status )) {
  411. NetStatus = NetpNtStatusToApiStatus( Status );
  412. goto Cleanup;
  413. }
  414. }
  415. NetStatus = NO_ERROR;
  416. Cleanup:
  417. if ( ClientSession != NULL ) {
  418. if ( AmWriter ) {
  419. NlResetWriterClientSession( ClientSession );
  420. }
  421. NlUnrefClientSession( ClientSession );
  422. }
  423. NlPrintDom(( NL_SESSION_SETUP, DomainInfo,
  424. "DsrGetForestTrustInformation: %ws returns %ld\n",
  425. TrustedDomainName,
  426. NetStatus ));
  427. if ( DomainInfo != NULL ) {
  428. NlDereferenceDomain( DomainInfo );
  429. }
  430. return NetStatus;
  431. }
  432. NTSTATUS
  433. NetrGetForestTrustInformation (
  434. IN LPWSTR ServerName OPTIONAL,
  435. IN LPWSTR ComputerName,
  436. IN PNETLOGON_AUTHENTICATOR Authenticator,
  437. OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
  438. IN DWORD Flags,
  439. OUT PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo
  440. )
  441. /*++
  442. Routine Description:
  443. The server side of the secure channel version of DsGetForestTrustInformation.
  444. The inbound secure channel identified by ComputerName must be for an interdomain trust
  445. and the inbound TDO must have the TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set.
  446. Arguments:
  447. ServerName - The name of the domain controller this API is remoted to.
  448. ComputerName -- Name of the DC server making the call.
  449. Authenticator -- supplied by the server.
  450. ReturnAuthenticator -- Receives an authenticator returned by the PDC.
  451. Flags - Specifies a set of bits that modify the behavior of the API.
  452. No values are currently defined. The caller should pass zero.
  453. ForestTrustInfo - Returns a pointer to a structure containing a count and an
  454. array of FTInfo records describing the namespaces claimed by the
  455. domain specified by TrustedDomainName. The Accepted field and Time
  456. field of all returned records will be zero. The buffer should be freed
  457. by calling NetApiBufferFree.
  458. Return Value:
  459. STATUS_SUCCESS -- The function completed successfully.
  460. STATUS_ACCESS_DENIED -- The replicant should re-authenticate with
  461. the PDC.
  462. --*/
  463. {
  464. NTSTATUS Status;
  465. NET_API_STATUS NetStatus;
  466. PDOMAIN_INFO DomainInfo = NULL;
  467. PSERVER_SESSION ServerSession;
  468. NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType;
  469. //
  470. // Lookup which domain this call pertains to.
  471. //
  472. *ForestTrustInfo = NULL;
  473. DomainInfo = NlFindDomainByServerName( ServerName );
  474. NlPrintDom((NL_SESSION_SETUP, DomainInfo,
  475. "NetrGetForestTrustInformation: %ws called: 0x%lx\n", ComputerName, Flags ));
  476. if ( DomainInfo == NULL ) {
  477. Status = STATUS_INVALID_COMPUTER_NAME;
  478. goto Cleanup;
  479. }
  480. //
  481. // This API is not supported on workstations.
  482. //
  483. if ( NlGlobalMemberWorkstation ) {
  484. Status = STATUS_NOT_SUPPORTED;
  485. goto Cleanup;
  486. }
  487. //
  488. // Find the server session entry for this secure channel.
  489. //
  490. LOCK_SERVER_SESSION_TABLE( DomainInfo );
  491. ServerSession = NlFindNamedServerSession( DomainInfo, ComputerName );
  492. if (ServerSession == NULL) {
  493. UNLOCK_SERVER_SESSION_TABLE( DomainInfo );
  494. Status = STATUS_ACCESS_DENIED;
  495. goto Cleanup;
  496. }
  497. //
  498. // Now verify the Authenticator and update seed if OK
  499. //
  500. Status = NlCheckAuthenticator(
  501. ServerSession,
  502. Authenticator,
  503. ReturnAuthenticator);
  504. if ( !NT_SUCCESS(Status) ) {
  505. UNLOCK_SERVER_SESSION_TABLE( DomainInfo );
  506. goto Cleanup;
  507. }
  508. SecureChannelType = ServerSession->SsSecureChannelType;
  509. //
  510. // This call is only valid on FOREST_TRANSITIVE trusts
  511. //
  512. if ( (ServerSession->SsFlags & SS_FOREST_TRANSITIVE) == 0 ) {
  513. UNLOCK_SERVER_SESSION_TABLE( DomainInfo );
  514. NlPrintDom((NL_SESSION_SETUP, DomainInfo,
  515. "NetrGetForestTrustInformation: %ws failed because F bit isn't set on the TDO\n",
  516. ComputerName ));
  517. Status = STATUS_NOT_IMPLEMENTED;
  518. goto Cleanup;
  519. }
  520. UNLOCK_SERVER_SESSION_TABLE( DomainInfo );
  521. if ( !IsDomainSecureChannelType( SecureChannelType ) ) {
  522. NlPrintDom((NL_SESSION_SETUP, DomainInfo,
  523. "NetrGetForestTrustInformation: %ws failed because secure channel isn't a domain secure channel\n",
  524. ComputerName ));
  525. Status = STATUS_NOT_IMPLEMENTED;
  526. goto Cleanup;
  527. }
  528. //
  529. // Get the forest trust information for the local machine
  530. //
  531. Status = LsaIGetForestTrustInformation( ForestTrustInfo );
  532. if ( !NT_SUCCESS( Status )) {
  533. goto Cleanup;
  534. }
  535. Status = STATUS_SUCCESS;
  536. Cleanup:
  537. //
  538. // If the request failed, be carefull to not leak authentication
  539. // information.
  540. //
  541. if ( Status == STATUS_ACCESS_DENIED ) {
  542. if ( ReturnAuthenticator != NULL ) {
  543. RtlSecureZeroMemory( ReturnAuthenticator, sizeof(*ReturnAuthenticator) );
  544. }
  545. }
  546. NlPrintDom(( NL_SESSION_SETUP, DomainInfo,
  547. "NetrGetForestTrustInformation: %ws returns %lX\n",
  548. ComputerName,
  549. Status ));
  550. if ( DomainInfo != NULL ) {
  551. NlDereferenceDomain( DomainInfo );
  552. }
  553. return Status;
  554. }